CRM-15832: rename create-pot-files.sh to create-pot-files (language-neutral).
[civicrm-core.git] / tools / bin / scripts / create-pot-files
CommitLineData
7773dd1e
ML
1#!/bin/bash
2set -e
3
4#####################################################################
5## Variables
6
7## Source code path
8SRC=
9
10## Output path
11POTDIR=
12
13## The component *.pot files are based roughly on CRM/Foo templates/CRM/Foo.
14COMPONENT_POTS="Admin Badge Batch Campaign Case Contribute Event Extension Financial Grant Mailing Member PCP Pledge Project Queue Report"
15
16## The adhoc *.pot files are based on clear file list (but may have some special/less predictable rules).
17ADHOC_POTS="common-base countries drupal-civicrm install menu provinces"
18
19## The magic *.pot files are derived from other *.pot files.
20MAGIC_POTS="common-components"
21
22## List of chosen *.pot files
23POTS=
24
25## Header file to prepend to any *.pot
26HEADER_TMPL=bin/header
27HEADER=
28
29## Flags to control which actions are performed
30DO_SCAN=
31DO_DIGEST=
32DO_CLEANUP=
33FORCE=
34
35#####################################################################
36function usage() {
37 cat <<EOT
38create-pot-files.sh - builds .pot files for CiviCRM.
39
40Usage:
41 ./bin/create-pot-files.sh [options] [srcdir] [destdir] [pot1...]
42
43Examples:
44 ./bin/create-pot-files.sh ~/repository/civicrm/ ~/repository/l10n/po/pot/
45 ./bin/create-pot-files.sh -sd ~/repository/civicrm/ ~/repository/l10n/po/pot/ common-base Admin Contribute
46
47Options:
48 -s Scan targets for strings (Pass #1)
49 -d Digest/dedupe scanned strings (Pass #2)
50 -c Cleanup temp files
51 -a All (scan+digest+cleanup; default)
52 -f Force (Ignore cached results from previous scan)
53 -h Help
54
55Targets:
56 $COMPONENT_POTS
57 $ADHOC_POTS $MAGIC_POTS
58
59Although you should probably not call this directly. Use build-unified-pots.sh
60if you are exporting the strings to Transifex.
61http://wiki.civicrm.org/confluence/display/CRMDOC/Pushing+new+strings+to+Transifex
62
63EOT
64
65 exit 1;
66}
67
68#####################################################################
69## Assert that CLI dependencies are met
70function check_deps() {
71 for cmd in sponge civistrings msgcomm msguniq tempfile tr grep cut date sed ; do
72 if ! which $cmd > /dev/null ; then
73 echo "Missing required command: $cmd"
74 echo
75 case "$cmd" in
76 sponge)
77 echo 'This program uses the "sponge" command which you can get by installing the'
78 echo '"moreutils" package under Debian/Ubuntu or by visting'
79 echo 'https://joeyh.name/code/moreutils/'
80 ;;
81 civistrings)
82 echo 'This program uses the "civistrings" command which is bundled with buildkit.'
83 echo 'You can download it separately from https://github.com/civicrm/civistrings'
84 esac
85 exit 1
86 fi
87 done
88}
89
90#####################################################################
91## civistrings wrapper with some default options
92function _civistrings() {
93 civistrings --header="$HEADER" "$@"
94}
95
96#####################################################################
97## usage: HEADER=$(build_header "$HEADER_TMPL")
98function build_header() {
99 local tmpl="$1"
100 local out="$POTDIR/.header"
101 local now=`date +'%F %R%z'`
102
103 cat "$tmpl" \
104 | sed "s/NOW/$now/" \
105 > "$out"
106
107 echo "$out"
108}
109
110#####################################################################
111## Build an individual POT file
112## usage: build_raw_pot <name>
113## example: build_raw_pot Mailing
114## example: build_raw_pot install
115function build_raw_pot() {
116 local name="$1"
117 local filepath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
118
119 if [ -f "$filepath" -a -z "$FORCE" ]; then
120 echo "[[ Found raw strings for ${name} from previous scan. ]]"
121 return
122 fi
123
124 echo "[[ Building raw strings for ${name} ]]"
125
126 case "$name" in
127
128 ## Adhoc targets, sorted alphabetically
129
130 common-base)
131 _civistrings -o "$filepath" \
132 {CRM,templates/CRM}/{ACL,Activity,Block,common,Contact,Core} \
133 {CRM,templates/CRM}/{Custom,Dashlet,Dedupe,Export,Form,Friend} \
134 {CRM,templates/CRM}/{Group,Import,Logging,Note,Price,Profile} \
135 {CRM,templates/CRM}/{Relationship,SMS,Standalone,Tag,UF,Utils} \
136 xml/templates/civicrm_acl.tpl \
137 xml/templates/civicrm_data.tpl \
138 xml/templates/languages.tpl \
139 xml/templates/civicrm_msg_template.tpl \
140 xml/templates/message_templates/friend_* \
141 xml/templates/message_templates/uf_notify_* \
c9a3a453
ML
142 js/angular-crmApp.js \
143 js/angular-crmAttachment.js \
144 js/angular-crm-ui.js \
145 js/Common.js \
146 js/crm.ajax.js \
147 js/crm.backbone.js \
148 js/jquery/jquery.crmeditable.js \
149 js/jquery/jquery.crmProfileSelector.js \
150 js/jquery/jquery.crmRevisionLink.js \
151 js/jquery/jquery.dashboard.js \
152 js/model/crm.designer.js \
153 js/model/crm.uf.js \
154 js/view/crm.designer.js
7773dd1e 155 packages/HTML/QuickForm \
c9a3a453
ML
156 partials/crmAttachment \
157 partials/crmExample \
158 partials/crmUi
159
7773dd1e
ML
160
161 ## The CRM/Upgrade folder includes *.tpl files which, for some reason,
162 ## have been omitted from past pot's. Omitting these requires more
163 ## precise file selection.
164 find CRM/Upgrade -name '*.php' | _civistrings -ao "$filepath" -
165 _civistrings -ao "$filepath" templates/CRM/Upgrade
166 ;;
167
168 common-components)
169 ## Not yet; handled in the digest phase. That why it's in MAGIC_POTS
170 return
171 ;;
172
173 countries)
174 cat "$HEADER" > "$filepath"
175 grep ^INSERT xml/templates/civicrm_country.tpl \
176 | cut -d\" -f4 \
177 | while read entry; do
178 echo -e "msgctxt \"country\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
179 done \
180 >> "$filepath"
181 ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
182 ;;
183
184 drupal-civicrm)
185 _civistrings -o "$filepath" \
186 drupal \
187 CRM/Core/Permission.php
188 ;;
189
190 install)
191 _civistrings -o "$filepath" \
192 install/
193 ;;
194
195 menu)
196 cat "$HEADER" > "$filepath"
197 grep -h '<title>' CRM/*/xml/Menu/*.xml \
198 | sed 's/^.*<title>\(.*\)<\/title>.*$/\1/' \
199 | while read entry; do
200 echo -e "msgctxt \"menu\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
201 done \
202 >> "$filepath"
203 _civistrings --msgctxt=menu xml/templates/civicrm_navigation.tpl -ao "$filepath"
204 ;;
205
206 provinces)
207 cat "$HEADER" > "$filepath"
208 grep '^(' xml/templates/civicrm_state_province.tpl \
209 | cut -d\" -f4 \
210 | while read entry; do
211 echo -e "msgctxt \"province\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
212 done \
213 >> "$filepath"
214 ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
215 ;;
216
217 ## Standard targets, sorted alphabetically
218
219 Campaign)
220 _civistrings -o "$filepath" \
221 {CRM,templates/CRM}/$name \
222 xml/templates/message_templates/petition_*
223 ;;
224
225 Case)
226 _civistrings -o "$filepath" \
227 {CRM,templates/CRM}/$name \
c9a3a453 228 partials/crmCaseType \
7773dd1e
ML
229 xml/templates/message_templates/case_*
230 ;;
231
232 Contribute)
233 _civistrings -o "$filepath" \
234 {CRM,templates/CRM}/$name \
235 xml/templates/message_templates/contribution_* \
236 xml/templates/message_templates/test_*
237 ;;
238
239 Event)
240 _civistrings -o "$filepath" \
241 {CRM,templates/CRM}/$name \
242 xml/templates/message_templates/event_* \
243 xml/templates/message_templates/participant_*
244 ;;
245
c9a3a453
ML
246 Mailing)
247 _civistrings -o "$filepath" \
248 {CRM,templates/CRM}/$name \
249 js/angular-crmCaseType.js \
250 js/angular-crmMailingAB.js \
251 js/angular-crmMailingAB/services.js \
252 js/angular-crmMailing/directives.js \
253 js/angular-crmMailing.js \
254 js/angular-crmMailing/services.js \
255 partials/crmMailing \
256 partials/crmMailingAB
257 ;;
258
7773dd1e
ML
259 Member)
260 _civistrings -o "$filepath" \
261 {CRM,templates/CRM}/$name \
262 xml/templates/message_templates/membership_*
263 ;;
264
265 PCP)
266 _civistrings -o "$filepath" \
267 {CRM,templates/CRM}/$name \
268 xml/templates/message_templates/pcp_*
269 ;;
270
271 Pledge)
272 _civistrings -o "$filepath" \
273 {CRM,templates/CRM}/$name \
274 xml/templates/message_templates/pledge_*
275 ;;
276
277 *)
278 if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
279 _civistrings -o "$filepath" {CRM,templates/CRM}/$name
280 else
281 echo "unrecognized pot: $name"
282 fi
283 ;;
284
285 esac
286
287 find "$filepath" ! -empty | while read f; do
288 msguniq "$filepath" | sponge "$filepath"
289 done
290}
291
292#####################################################################
293## usage: make_stat <name>
294## example: make_stat Mailing
295function make_stat() {
296 local name="$1"
297 local filepath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
298 grep ^msgid "$filepath" | sort -u > "$filepath.msgid"
299 grep '^#:' "$filepath" | sed 's/#://' | tr ' ' '\n' | sort -u > "$filepath.files"
300}
301
302#####################################################################
303## Scan .raw-*.pot for common strings and put them in common-components.pot
304## usage: build_common_components
305function build_common_components() {
306 echo "[[ Building common-components.pot ]]"
307 local paths=""
308 local has_multiple=0
309 for comp in $COMPONENT_POTS ; do
310 local rawfile=".raw-"$(echo $comp | tr '[:upper:]' '[:lower:]').pot
311 if [ -f "$rawfile" ]; then
312 paths="$paths $rawfile"
313 has_multiple=1
314 fi
315 done
316 if [ $has_multiple -eq 1 ]; then
317 msgcomm $paths > .raw-common-components.pot
318 else
319 cat $HEADER > .raw-common-components.pot
320 fi
321}
322
323#####################################################################
324## example: build_final_pot Mailing
325## example: build_final_pot install
326function build_final_pot() {
327 local name="$1"
328 local rawpath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
329 local finalpath="$POTDIR/"$(echo $name | tr '[:upper:]' '[:lower:]').pot
330 local tmpfile=`tempfile`
331
332 echo "[[ Building final strings for ${name} ]]"
333
334 cp -f "$rawpath" "$finalpath"
335
336 if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
337 msgcomm "$finalpath" .raw-common-components.pot > $tmpfile
338 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
339
340 msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
341 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
342
343 elif [ "$name" == "install" ]; then
344 msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
345 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
346 fi
347
348 rm -f "$tmpfile"
349}
350
351#####################################################################
352## Delete temp files
353function do_cleanup() {
354 echo "[[ Cleanup temp files ]]"
355 rm .header .raw*pot -f
356}
357
358#####################################################################
359## Main
360
361[ "$1" == "--help" ] && usage
362[ "$1" == "-h" ] && usage
363
364check_deps
365
366FOUND_ACTION=
367while getopts "asfdc" opt; do
368 case $opt in
369 a)
370 DO_SCAN=1
371 DO_DIGEST=1
372 DO_CLEANUP=1
373 FOUND_ACTION=1
374 ;;
375 s)
376 DO_SCAN=1
377 FOUND_ACTION=1
378 ;;
379 d)
380 DO_DIGEST=1
381 FOUND_ACTION=1
382 ;;
383 c)
384 DO_CLEANUP=1
385 FOUND_ACTION=1
386 ;;
387 f)
388 FORCE=1
389 ;;
390 \?)
391 echo "Invalid option: -$OPTARG" >&2
392 exit 1
393 ;;
394 :)
395 echo "Option -$OPTARG requires an argument." >&2
396 exit 1
397 ;;
398 esac
399done
400
401if [ -z "$FOUND_ACTION" ]; then
402 DO_SCAN=1
403 DO_DIGEST=1
404 DO_CLEANUP=1
405fi
406
407shift $((OPTIND-1))
408
409[ "$1" == "" ] && echo 'source dir missing' && usage
410test ! -e "$1" && echo 'source does not exist' && usage
411test ! -d "$1" && echo 'source not a directory' && usage
412
413[ "$2" == "" ] && echo 'target dir missing' && usage
414test ! -e "$2" && echo 'target does not exist' && usage
415test ! -d "$2" && echo 'target not a directory' && usage
416
417# use absolute paths so that we can chdir/pushd
418SRC=$(php -r 'echo realpath($argv[1]);' "$1")
419POTDIR=$(php -r 'echo realpath($argv[1]);' "$2")
420HEADER=$(build_header "$HEADER_TMPL")
421## TODO: substitute "NOW" in HEADER
422shift 2
423
424if [ -z "$1" ]; then
425 POTS="$COMPONENT_POTS $ADHOC_POTS $MAGIC_POTS"
426else
427 POTS="$@"
428fi
429
430if [ -n "$DO_SCAN" ]; then
431 pushd "$SRC" >> /dev/null
432 for POT in $POTS ; do
433 build_raw_pot "$POT"
434 done
435 popd >> /dev/null
436fi
437
438if [ -n "$DO_DIGEST" ]; then
439 pushd "$POTDIR" >> /dev/null
440 echo "POTS : $POTS"
441 build_common_components
442 for POT in $POTS ; do
443 echo "+++++++++ $POT"
444 build_final_pot "$POT"
445 done
446 popd >> /dev/null
447fi
448
449if [ -n "$DO_CLEANUP" ]; then
450 pushd "$POTDIR" >> /dev/null
451 do_cleanup
452 popd >> /dev/null
453fi