As part of my work for the F123 Project I've had to learn how to prepare
scripts for translation into multiple languages using
This is a little workflow document I have written on the subject.
Shell Internationalisation Workflow
To provide translations for shell scripts we use the gettext package.
Preparing a Shell Script for Translation
Shell scripts contain
echo commands to provide user feedback.
We need for the strings displayed by an
echo command to be displayed in the language the user of
the machine is using.
In the top of the script we put these lines:
export TEXTDOMAIN=myscript export TEXTDOMAINDIR=/usr/share/locale . gettext.sh
In the above example
myscript is an example script name.
TEXTDOMAINDIR above contains the usual path to localization for a typical Linux installation.
It may be raplaced with:
For testing a script's translation.
The script author changes typical
cho of this syntax:
echo 'Press any key to continue'
echo $(gettext "Press any key to continue") ; echo
We place an extra
echo with no arguments at the end because the
gettext function does not add a line-feed.
gettext function is contained in the
gettext.sh script included at the top of the script.
If an echoed string contains any shell variables they must be replaced.
echo "Program name: $0"
PROGNAME=$0 echo $(eval_gettext "Prog name: \$PROGNAME") ; echo
eval_gettext function is used instead of
gettext and the dolla-sign is
escaped with a
Again an extra
echo is put in after the command to echo a translated string.
Extracting Strings into a Portable Object Template (.pot)
Now we run
xgettext against our script to create a file of strings to translate.
We do this in this fashion:
xgettext -L Shell -o myscript.pot myscript
This reads all the
echo commands which contain references to the
eval_gettext functions and writes them to a
.pot (portable object template) file.
Here is a simple example of the contents of a
.pot file for a script which contains only one
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-19 22:52+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" # #: myscript:10 #, sh-format msgid "Hello world: $PROGNAME" msgstr ""
In the above example there are values in upper-case at the top in the comments which should be filled out with the details of the package-name, and the author details etc.
And this line:
"Content-Type: text/plain; charset=CHARSET\n"
Should be changed to read:
"Content-Type: text/plain; charset=UTF-8\n"
Or whichever character-set we are using.
The Translation Process
.pot file should be passed to a translator with the name changed to drop the ending
cp myscript.pot myscript.po
Now give the
.po (portable object) file to a translator.
After the line which reads:
There will be entries of the form:
msgid "Some string in the original language" msgstr ""
A translator places the translation of the string in the
msgid entry in the
msgstr entry between the quotes.
The translator MUST preserve any shell variable reference that is in the original string. For example:
msgid "Attention! $ERRORCODE" msgstr "Achtung! $ERRORCODE"
In this way a translator goes right through the file and translates the strings, leaving the
msgid entries as-is, and placing their translations in the corresponding
Machine Object Files
The files which will actually be used when a script runs, to provide translated strings is a
We create this from a
.po file like this:
msgfmt -o myscript.mo myscript.po
Which will create
Merging New Strings
Of course the development of a complex script is never static and it may be necessary to add new strings, or to remove old ones. We can use another utility to
merge strings from a new
.pot file into our
.po file and re-create our
For this we use
msgmerge, like this:
msgmerge -U myscript.po myscript.pot
This will search the
.pot file for new or deleted strings and merge them into the
.po file. In this way previous translation work is not lost when things change.
And again we then create a new
.mo file from the update
Installing a Translation
myscript example from above, the
.mo file is installed in:
For example, for Brazilian Portuguese:
The Worklow in Short
- Script is written and tested, including gettext support.
xgettextto extract all
echostrings into a
- Rename the
.poand pass to translator.
- When step 3 is done, run
msgfmtto create the
- Install the
.mofile (after testing).
- If something new is written in the script, go to step 2 and repeat to step 5.
.po files to be translated should probably either be contained in a directory structure which clearly defines the language, or should contain the language in the file-name, although the completed
.mo file cannot.
myscript/ en/myscript.en.po (English) fr/myscript.fr.po (French) pt_BR/myscript.pt_BR.po (Brazilian Portuguese)