#!/bin/sh # dist-tools/git-commit-po-updates.sh # A helper script to commit translation updates into Git. # Assumes translation updates are visible to git, # and one directory above. # # © Copyright 2019 - 2020 by Matthias Andree. # Licensed under the GNU General Public License V2 or, # at your choice, any later version. # # Supported modes: # -n: dry-run, only print commands, but do not run them. # -c: commit, print commands and run them. # Exit codes: # 0: success, no new po/*.po files. # 1: error # 2: usage was printed, nothing was done # 3: new po/*.po files detected set -eu cd "$(realpath $(dirname $0))/.." # see if Perl has Carp::Always available, # and implicitly fail (set -e) if it hasn't. perl -MCarp::Always -e '' usage() { printf 'Usage: %s {-n|-c}\n-n: dry-run; -c: commit\n' "$0" exit $1 } # print and potentially run a shell command run() { cmd="$1 '$2'" printf '+ %s\n' "$cmd" $dryrun_pfx eval "$cmd" return $? } # try to parse features of a po file and build a git command handle_po() { pofile="$1" logmsg1="$2" # "Update", or "Add new" logmsg2="$3" # "to", or "for" export logmsg1 logmsg2 if ! cmd="$(perl -WT - "$pofile" <<'_EOF' use Encode::Locale; use Encode; use strict; use Carp::Always (); use warnings FATAL => 'uninitialized'; my ($ver, $dat, $translator, $lang, $lcod, $cset, $found); while(<>) { if (/^"Project-Id-Version: (.+)\\n"/) { $ver=$1; }; if (/^"PO-Revision-Date: (.+)\\n"/) { $dat=$1; }; if (/^"Last-Translator: (.+)\\n"/) { $translator=$1; }; if (/^"Language-Team: ([^<]+?)\s+<.*>\\n"/) { $lang=$1; }; if (/^"Language: (.+)\\n"/) { $lcod=$1; }; if (/^"Content-Type: text\/plain; charset=(.+)\\n"/) { $cset = $1; }; if ($ver and $dat and $translator and $lang and $lcod and $cset) { $found = 1; last; } } $translator = Encode::decode($cset, $translator); if ($found) { print Encode::encode(locale => "git commit --author '$translator' --date '$dat' -m '$ENV{logmsg1} <$lcod> $lang translation $ENV{logmsg2} $ver'", Encode::FB_CROAK); } else { exit(1); } _EOF )" then echo >&2 "Parsing $pofile failed, skipping." return 23 fi run "$cmd" "$pofile" return $? } dryrun_pfx= docommit= while getopts 'nc' opt ; do case $opt in n) dryrun_pfx=: ;; c) docommit=y ;; ?) usage 2 ; esac done rc=0 if [ -z "$dryrun_pfx" -a -z "$docommit" ] ; then usage 2 ; fi new_po_files=$(git status --porcelain=v1 po/*.po | egrep '^\?|^.\?' | cut -c4-) printf "%s" "$new_po_files" \ | while read nfile ; do run "git add" "$nfile" r=$? handle_po "$nfile" "Add new" "for" if [ $r -ne 0 -o $? -ne 0 ] ; then echo "There were errors adding $nfile" >&2 ; rc=1 fi done git diff -G '^"(Project-Id-Version|PO-Revision-Date):' --name-only po/*.po \ | while read pofile ; do if ! handle_po "$pofile" "Update" "to" ; then echo "There were errors updating $nfile" >&2 ; rc=1 fi done if [ -n "$new_po_files" ] ; then printf "Remember to add these codes to po/LINGUAS:" for i in $new_po_files ; do j=${i%.po} j=${j#po/} printf " %s" "$j" done printf '\n' rc=3 fi exit $rc