CRM-15832: Initial commit of tools/bin/scripts/create-pot-files.sh (moved from the...
authorMathieu Lutfy <mathieu@bidon.ca>
Fri, 13 Mar 2015 01:51:34 +0000 (21:51 -0400)
committerMathieu Lutfy <mathieu@bidon.ca>
Fri, 13 Mar 2015 01:51:34 +0000 (21:51 -0400)
tools/bin/scripts/create-pot-files.sh [new file with mode: 0755]

diff --git a/tools/bin/scripts/create-pot-files.sh b/tools/bin/scripts/create-pot-files.sh
new file mode 100755 (executable)
index 0000000..e873318
--- /dev/null
@@ -0,0 +1,424 @@
+#!/bin/bash
+set -e
+
+#####################################################################
+## Variables
+
+## Source code path
+SRC=
+
+## Output path
+POTDIR=
+
+## The component *.pot files are based roughly on CRM/Foo templates/CRM/Foo.
+COMPONENT_POTS="Admin Badge Batch Campaign Case Contribute Event Extension Financial Grant Mailing Member PCP Pledge Project Queue Report"
+
+## The adhoc *.pot files are based on clear file list (but may have some special/less predictable rules).
+ADHOC_POTS="common-base countries drupal-civicrm install menu provinces"
+
+## The magic *.pot files are derived from other *.pot files.
+MAGIC_POTS="common-components"
+
+## List of chosen *.pot files
+POTS=
+
+## Header file to prepend to any *.pot
+HEADER_TMPL=bin/header
+HEADER=
+
+## Flags to control which actions are performed
+DO_SCAN=
+DO_DIGEST=
+DO_CLEANUP=
+FORCE=
+
+#####################################################################
+function usage() {
+  cat <<EOT
+create-pot-files.sh - builds .pot files for CiviCRM.
+
+Usage:
+  ./bin/create-pot-files.sh [options] [srcdir] [destdir] [pot1...]
+
+Examples:
+  ./bin/create-pot-files.sh ~/repository/civicrm/ ~/repository/l10n/po/pot/
+  ./bin/create-pot-files.sh -sd ~/repository/civicrm/ ~/repository/l10n/po/pot/ common-base Admin Contribute
+
+Options:
+  -s    Scan targets for strings (Pass #1)
+  -d    Digest/dedupe scanned strings (Pass #2)
+  -c    Cleanup temp files
+  -a    All (scan+digest+cleanup; default)
+  -f    Force (Ignore cached results from previous scan)
+  -h    Help
+
+Targets:
+  $COMPONENT_POTS
+  $ADHOC_POTS $MAGIC_POTS
+
+Although you should probably not call this directly. Use build-unified-pots.sh
+if you are exporting the strings to Transifex.
+http://wiki.civicrm.org/confluence/display/CRMDOC/Pushing+new+strings+to+Transifex
+
+EOT
+
+  exit 1;
+}
+
+#####################################################################
+## Assert that CLI dependencies are met
+function check_deps() {
+  for cmd in sponge civistrings msgcomm msguniq tempfile tr grep cut date sed ; do
+    if ! which $cmd > /dev/null ; then
+      echo "Missing required command: $cmd"
+      echo
+      case "$cmd" in
+        sponge)
+          echo 'This program uses the "sponge" command which you can get by installing the'
+          echo '"moreutils" package under Debian/Ubuntu or by visting'
+          echo 'https://joeyh.name/code/moreutils/'
+          ;;
+        civistrings)
+          echo 'This program uses the "civistrings" command which is bundled with buildkit.'
+          echo 'You can download it separately from https://github.com/civicrm/civistrings'
+      esac
+      exit 1
+    fi
+  done
+}
+
+#####################################################################
+## civistrings wrapper with some default options
+function _civistrings() {
+  civistrings --header="$HEADER" "$@"
+}
+
+#####################################################################
+## usage: HEADER=$(build_header "$HEADER_TMPL")
+function build_header() {
+  local tmpl="$1"
+  local out="$POTDIR/.header"
+  local now=`date +'%F %R%z'`
+
+  cat "$tmpl" \
+    | sed "s/NOW/$now/" \
+    > "$out"
+
+  echo "$out"
+}
+
+#####################################################################
+## Build an individual POT file
+## usage: build_raw_pot <name>
+## example: build_raw_pot Mailing
+## example: build_raw_pot install
+function build_raw_pot() {
+  local name="$1"
+  local filepath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
+
+  if [ -f "$filepath" -a -z "$FORCE" ]; then
+    echo "[[ Found raw strings for ${name} from previous scan. ]]"
+    return
+  fi
+
+  echo "[[ Building raw strings for ${name} ]]"
+
+  case "$name" in
+
+    ## Adhoc targets, sorted alphabetically
+
+    common-base)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/{ACL,Activity,Block,common,Contact,Core} \
+        {CRM,templates/CRM}/{Custom,Dashlet,Dedupe,Export,Form,Friend} \
+        {CRM,templates/CRM}/{Group,Import,Logging,Note,Price,Profile} \
+        {CRM,templates/CRM}/{Relationship,SMS,Standalone,Tag,UF,Utils} \
+        xml/templates/civicrm_acl.tpl \
+        xml/templates/civicrm_data.tpl \
+        xml/templates/languages.tpl \
+        xml/templates/civicrm_msg_template.tpl \
+        xml/templates/message_templates/friend_* \
+        xml/templates/message_templates/uf_notify_* \
+        packages/HTML/QuickForm \
+        partials/ \
+        js/
+
+      ## The CRM/Upgrade folder includes *.tpl files which, for some reason,
+      ## have been omitted from past pot's. Omitting these requires more
+      ## precise file selection.
+      find CRM/Upgrade -name '*.php' | _civistrings -ao "$filepath" -
+      _civistrings -ao "$filepath" templates/CRM/Upgrade
+      ;;
+
+    common-components)
+      ## Not yet; handled in the digest phase. That why it's in MAGIC_POTS
+      return
+      ;;
+
+    countries)
+      cat "$HEADER" > "$filepath"
+      grep ^INSERT xml/templates/civicrm_country.tpl \
+        | cut -d\" -f4 \
+        | while read entry; do
+          echo -e "msgctxt \"country\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
+        done \
+        >> "$filepath"
+      ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
+      ;;
+
+    drupal-civicrm)
+      _civistrings -o "$filepath" \
+        drupal \
+        CRM/Core/Permission.php
+      ;;
+
+    install)
+      _civistrings -o "$filepath" \
+        install/
+      ;;
+
+    menu)
+      cat "$HEADER" > "$filepath"
+      grep -h '<title>' CRM/*/xml/Menu/*.xml \
+        | sed 's/^.*<title>\(.*\)<\/title>.*$/\1/' \
+        | while read entry; do
+          echo -e "msgctxt \"menu\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
+        done \
+        >> "$filepath"
+      _civistrings --msgctxt=menu xml/templates/civicrm_navigation.tpl -ao "$filepath"
+      ;;
+
+    provinces)
+      cat "$HEADER" > "$filepath"
+      grep '^(' xml/templates/civicrm_state_province.tpl \
+        | cut -d\" -f4 \
+        | while read entry; do
+          echo -e "msgctxt \"province\"\nmsgid \"$entry\"\nmsgstr \"\"\n"
+        done \
+        >> "$filepath"
+        ## Hmm, if civicrm_country.tpl used {ts}, then we could just call "civistrings --msgctxt=country"
+      ;;
+
+    ## Standard targets, sorted alphabetically
+
+    Campaign)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/petition_*
+      ;;
+
+    Case)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/case_*
+      ;;
+
+    Contribute)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/contribution_* \
+        xml/templates/message_templates/test_*
+      ;;
+
+    Event)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/event_* \
+        xml/templates/message_templates/participant_*
+      ;;
+
+    Member)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/membership_*
+      ;;
+
+    PCP)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/pcp_*
+      ;;
+
+    Pledge)
+      _civistrings -o "$filepath" \
+        {CRM,templates/CRM}/$name \
+        xml/templates/message_templates/pledge_*
+      ;;
+
+    *)
+      if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
+        _civistrings -o "$filepath" {CRM,templates/CRM}/$name
+      else
+        echo "unrecognized pot: $name"
+      fi
+      ;;
+
+  esac
+
+  find "$filepath" ! -empty | while read f; do
+    msguniq "$filepath" | sponge "$filepath"
+  done
+}
+
+#####################################################################
+## usage: make_stat <name>
+## example: make_stat Mailing
+function make_stat() {
+  local name="$1"
+  local filepath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
+  grep ^msgid "$filepath" | sort -u > "$filepath.msgid"
+  grep '^#:' "$filepath" | sed 's/#://' | tr ' ' '\n' | sort -u > "$filepath.files"
+}
+
+#####################################################################
+## Scan .raw-*.pot for common strings and put them in common-components.pot
+## usage: build_common_components
+function build_common_components() {
+  echo "[[ Building common-components.pot ]]"
+  local paths=""
+  local has_multiple=0
+  for comp in $COMPONENT_POTS ; do
+    local rawfile=".raw-"$(echo $comp | tr '[:upper:]' '[:lower:]').pot
+    if [ -f "$rawfile" ]; then
+      paths="$paths $rawfile"
+      has_multiple=1
+    fi
+  done
+  if [ $has_multiple -eq 1 ]; then
+    msgcomm $paths > .raw-common-components.pot
+  else
+    cat $HEADER > .raw-common-components.pot
+  fi
+}
+
+#####################################################################
+## example: build_final_pot Mailing
+## example: build_final_pot install
+function build_final_pot() {
+  local name="$1"
+  local rawpath="$POTDIR/.raw-"$(echo $name | tr '[:upper:]' '[:lower:]').pot
+  local finalpath="$POTDIR/"$(echo $name | tr '[:upper:]' '[:lower:]').pot
+  local tmpfile=`tempfile`
+
+  echo "[[ Building final strings for ${name} ]]"
+
+  cp -f "$rawpath" "$finalpath"
+
+  if echo " $COMPONENT_POTS " | grep -q " $name " > /dev/null ; then
+    msgcomm "$finalpath" .raw-common-components.pot > $tmpfile
+    msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
+
+    msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
+    msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
+
+  elif [ "$name" == "install" ]; then
+    msgcomm "$finalpath" .raw-common-base.pot | sponge $tmpfile
+    msgcomm --unique "$finalpath" $tmpfile | sponge "$finalpath"
+  fi
+
+  rm -f "$tmpfile"
+}
+
+#####################################################################
+## Delete temp files
+function do_cleanup() {
+  echo "[[ Cleanup temp files ]]"
+  rm .header .raw*pot -f
+}
+
+#####################################################################
+## Main
+
+[ "$1" == "--help" ] && usage
+[ "$1" == "-h" ] && usage
+
+check_deps
+
+FOUND_ACTION=
+while getopts "asfdc" opt; do
+  case $opt in
+    a)
+      DO_SCAN=1
+      DO_DIGEST=1
+      DO_CLEANUP=1
+      FOUND_ACTION=1
+      ;;
+    s)
+      DO_SCAN=1
+      FOUND_ACTION=1
+      ;;
+    d)
+      DO_DIGEST=1
+      FOUND_ACTION=1
+      ;;
+    c)
+      DO_CLEANUP=1
+      FOUND_ACTION=1
+      ;;
+    f)
+      FORCE=1
+      ;;
+    \?)
+      echo "Invalid option: -$OPTARG" >&2
+      exit 1
+      ;;
+    :)
+      echo "Option -$OPTARG requires an argument." >&2
+      exit 1
+      ;;
+  esac
+done
+
+if [ -z "$FOUND_ACTION" ]; then
+  DO_SCAN=1
+  DO_DIGEST=1
+  DO_CLEANUP=1
+fi
+
+shift $((OPTIND-1))
+
+[ "$1" == "" ] && echo 'source dir missing'     && usage
+test ! -e "$1" && echo 'source does not exist'  && usage
+test ! -d "$1" && echo 'source not a directory' && usage
+
+[ "$2" == "" ] && echo 'target dir missing'     && usage
+test ! -e "$2" && echo 'target does not exist'  && usage
+test ! -d "$2" && echo 'target not a directory' && usage
+
+# use absolute paths so that we can chdir/pushd
+SRC=$(php -r 'echo realpath($argv[1]);' "$1")
+POTDIR=$(php -r 'echo realpath($argv[1]);' "$2")
+HEADER=$(build_header "$HEADER_TMPL")
+## TODO: substitute "NOW" in HEADER
+shift 2
+
+if [ -z "$1" ]; then
+  POTS="$COMPONENT_POTS $ADHOC_POTS $MAGIC_POTS"
+else
+  POTS="$@"
+fi
+
+if [ -n "$DO_SCAN" ]; then
+  pushd "$SRC" >> /dev/null
+    for POT in $POTS ; do
+      build_raw_pot "$POT"
+    done
+  popd >> /dev/null
+fi
+
+if [ -n "$DO_DIGEST" ]; then
+  pushd "$POTDIR" >> /dev/null
+    echo "POTS : $POTS"
+    build_common_components
+    for POT in $POTS ; do
+      echo "+++++++++ $POT"
+      build_final_pot "$POT"
+    done
+  popd >> /dev/null
+fi
+
+if [ -n "$DO_CLEANUP" ]; then
+  pushd "$POTDIR" >> /dev/null
+    do_cleanup
+  popd >> /dev/null
+fi