Merge pull request #12072 from civicrm/5.1
[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_* \
25ff64b0 142 ang/crm{App,Attachment,Example,Ui,Util}{,.js} \
c9a3a453
ML
143 js/Common.js \
144 js/crm.ajax.js \
145 js/crm.backbone.js \
146 js/jquery/jquery.crmeditable.js \
147 js/jquery/jquery.crmProfileSelector.js \
148 js/jquery/jquery.crmRevisionLink.js \
149 js/jquery/jquery.dashboard.js \
150 js/model/crm.designer.js \
151 js/model/crm.uf.js \
45799e07 152 js/view/crm.designer.js \
25ff64b0 153 packages/HTML/QuickForm
7773dd1e
ML
154
155 ## The CRM/Upgrade folder includes *.tpl files which, for some reason,
156 ## have been omitted from past pot's. Omitting these requires more
157 ## precise file selection.
158 find CRM/Upgrade -name '*.php' | _civistrings -ao "$filepath" -
159 _civistrings -ao "$filepath" templates/CRM/Upgrade
160 ;;
161
162 common-components)
163 ## Not yet; handled in the digest phase. That why it's in MAGIC_POTS
164 return
165 ;;
166
167 countries)
168 cat "$HEADER" > "$filepath"
169 grep ^INSERT xml/templates/civicrm_country.tpl \
170 | cut -d\" -f4 \
171 | while read entry; do
172 echo -e "msgctxt \"country\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
173 done \
174 >> "$filepath"
175 ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
176 ;;
177
178 drupal-civicrm)
179 _civistrings -o "$filepath" \
180 drupal \
181 CRM/Core/Permission.php
182 ;;
183
184 install)
185 _civistrings -o "$filepath" \
186 install/
187 ;;
188
189 menu)
190 cat "$HEADER" > "$filepath"
191 grep -h '<title>' CRM/*/xml/Menu/*.xml \
192 | sed 's/^.*<title>\(.*\)<\/title>.*$/\1/' \
193 | while read entry; do
194 echo -e "msgctxt \"menu\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
195 done \
196 >> "$filepath"
197 _civistrings --msgctxt=menu xml/templates/civicrm_navigation.tpl -ao "$filepath"
198 ;;
199
200 provinces)
201 cat "$HEADER" > "$filepath"
202 grep '^(' xml/templates/civicrm_state_province.tpl \
203 | cut -d\" -f4 \
204 | while read entry; do
205 echo -e "msgctxt \"province\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
206 done \
207 >> "$filepath"
208 ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
209 ;;
210
211 ## Standard targets, sorted alphabetically
212
213 Campaign)
214 _civistrings -o "$filepath" \
215 {CRM,templates/CRM}/$name \
216 xml/templates/message_templates/petition_*
217 ;;
218
219 Case)
220 _civistrings -o "$filepath" \
221 {CRM,templates/CRM}/$name \
25ff64b0 222 ang/crmCaseType{,.js} \
7773dd1e
ML
223 xml/templates/message_templates/case_*
224 ;;
225
226 Contribute)
227 _civistrings -o "$filepath" \
228 {CRM,templates/CRM}/$name \
229 xml/templates/message_templates/contribution_* \
230 xml/templates/message_templates/test_*
231 ;;
232
233 Event)
234 _civistrings -o "$filepath" \
235 {CRM,templates/CRM}/$name \
236 xml/templates/message_templates/event_* \
237 xml/templates/message_templates/participant_*
238 ;;
239
c9a3a453
ML
240 Mailing)
241 _civistrings -o "$filepath" \
242 {CRM,templates/CRM}/$name \
25ff64b0 243 ang/crm{Mailing,MailingAB}{,.js}
c9a3a453
ML
244 ;;
245
7773dd1e
ML
246 Member)
247 _civistrings -o "$filepath" \
248 {CRM,templates/CRM}/$name \
249 xml/templates/message_templates/membership_*
250 ;;
251
252 PCP)
253 _civistrings -o "$filepath" \
254 {CRM,templates/CRM}/$name \
255 xml/templates/message_templates/pcp_*
256 ;;
257
258 Pledge)
259 _civistrings -o "$filepath" \
260 {CRM,templates/CRM}/$name \
261 xml/templates/message_templates/pledge_*
262 ;;
263
264 *)
265 if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
266 _civistrings -o "$filepath" {CRM,templates/CRM}/$name
267 else
268 echo "unrecognized pot: $name"
269 fi
270 ;;
271
272 esac
273
274 find "$filepath" ! -empty | while read f; do
275 msguniq "$filepath" | sponge "$filepath"
276 done
277}
278
279#####################################################################
280## usage: make_stat <name>
281## example: make_stat Mailing
282function make_stat() {
283 local name="$1"
284 local filepath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
285 grep ^msgid "$filepath" | sort -u > "$filepath.msgid"
286 grep '^#:' "$filepath" | sed 's/#://' | tr ' ' '\n' | sort -u > "$filepath.files"
287}
288
289#####################################################################
290## Scan .raw-*.pot for common strings and put them in common-components.pot
291## usage: build_common_components
292function build_common_components() {
293 echo "[[ Building common-components.pot ]]"
294 local paths=""
295 local has_multiple=0
296 for comp in $COMPONENT_POTS ; do
297 local rawfile=".raw-"$(echo $comp | tr '[:upper:]' '[:lower:]').pot
298 if [ -f "$rawfile" ]; then
299 paths="$paths $rawfile"
300 has_multiple=1
301 fi
302 done
303 if [ $has_multiple -eq 1 ]; then
304 msgcomm $paths > .raw-common-components.pot
305 else
306 cat $HEADER > .raw-common-components.pot
307 fi
308}
309
310#####################################################################
311## example: build_final_pot Mailing
312## example: build_final_pot install
313function build_final_pot() {
314 local name="$1"
315 local rawpath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
316 local finalpath="$POTDIR/"$(echo $name | tr '[:upper:]' '[:lower:]').pot
317 local tmpfile=`tempfile`
318
319 echo "[[ Building final strings for ${name} ]]"
320
321 cp -f "$rawpath" "$finalpath"
322
323 if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
324 msgcomm "$finalpath" .raw-common-components.pot > $tmpfile
325 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
326
327 msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
328 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
329
330 elif [ "$name" == "install" ]; then
331 msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
332 msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
333 fi
334
335 rm -f "$tmpfile"
336}
337
338#####################################################################
339## Delete temp files
340function do_cleanup() {
341 echo "[[ Cleanup temp files ]]"
342 rm .header .raw*pot -f
343}
344
345#####################################################################
346## Main
347
348[ "$1" == "--help" ] && usage
349[ "$1" == "-h" ] && usage
350
351check_deps
352
353FOUND_ACTION=
354while getopts "asfdc" opt; do
355 case $opt in
356 a)
357 DO_SCAN=1
358 DO_DIGEST=1
359 DO_CLEANUP=1
360 FOUND_ACTION=1
361 ;;
362 s)
363 DO_SCAN=1
364 FOUND_ACTION=1
365 ;;
366 d)
367 DO_DIGEST=1
368 FOUND_ACTION=1
369 ;;
370 c)
371 DO_CLEANUP=1
372 FOUND_ACTION=1
373 ;;
374 f)
375 FORCE=1
376 ;;
377 \?)
378 echo "Invalid option: -$OPTARG" >&2
379 exit 1
380 ;;
381 :)
382 echo "Option -$OPTARG requires an argument." >&2
383 exit 1
384 ;;
385 esac
386done
387
388if [ -z "$FOUND_ACTION" ]; then
389 DO_SCAN=1
390 DO_DIGEST=1
391 DO_CLEANUP=1
392fi
393
394shift $((OPTIND-1))
395
396[ "$1" == "" ] && echo 'source dir missing' && usage
397test ! -e "$1" && echo 'source does not exist' && usage
398test ! -d "$1" && echo 'source not a directory' && usage
399
400[ "$2" == "" ] && echo 'target dir missing' && usage
401test ! -e "$2" && echo 'target does not exist' && usage
402test ! -d "$2" && echo 'target not a directory' && usage
403
404# use absolute paths so that we can chdir/pushd
405SRC=$(php -r 'echo realpath($argv[1]);' "$1")
406POTDIR=$(php -r 'echo realpath($argv[1]);' "$2")
407HEADER=$(build_header "$HEADER_TMPL")
408## TODO: substitute "NOW" in HEADER
409shift 2
410
411if [ -z "$1" ]; then
412 POTS="$COMPONENT_POTS $ADHOC_POTS $MAGIC_POTS"
413else
414 POTS="$@"
415fi
416
417if [ -n "$DO_SCAN" ]; then
418 pushd "$SRC" >> /dev/null
419 for POT in $POTS ; do
420 build_raw_pot "$POT"
421 done
422 popd >> /dev/null
423fi
424
425if [ -n "$DO_DIGEST" ]; then
426 pushd "$POTDIR" >> /dev/null
427 echo "POTS : $POTS"
428 build_common_components
429 for POT in $POTS ; do
430 echo "+++++++++ $POT"
431 build_final_pot "$POT"
432 done
433 popd >> /dev/null
434fi
435
436if [ -n "$DO_CLEANUP" ]; then
437 pushd "$POTDIR" >> /dev/null
438 do_cleanup
439 popd >> /dev/null
440fi