stormux/build/doc/i18n/shell/workflow.md

198 lines
6.0 KiB
Markdown
Raw Normal View History

# Shell Internationalization 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.
The `TEXTDOMAINDIR` above contains the usual path to localization for a typical Linux installation.
It may be raplaced with:
export TEXTDOMAINDIR=$PWD/locale
For testing a script's translation.
The script author changes typical `cho` of this syntax:
echo 'Press any key to continue'
With:
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.
The `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.
For example:
echo "Program name: $0"
Becomes:
PROGNAME=$0
echo $(eval_gettext "Prog name: \$PROGNAME") ; echo
The `eval_gettext` function is used instead of `gettext` and the dolla-sign is `escaped` with a
back-slash.
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 `gettext` and `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 `echo` command:
# 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
The first-cut `.pot` file should be passed to a translator with the name changed to drop the ending `t`:
cp myscript.pot myscript.po
Now give the `.po` (portable object) file to a translator.
After the line which reads:
"Content-Transfer-Encoding: 8bit\n"
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 `msgstr` entries.
## Creating `Machine Object` Files
The files which will actually be used when a script runs, to provide translated strings is a `.mo` file.
We create this from a `.po` file like this:
msgfmt -o myscript.mo myscript.po
Which will create `myscript.mo` from `myscript.po`.
## 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 `.mo` file.
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 `.po` file.
## Installing a Translation
Using our `myscript` example from above, the `.mo` file is installed in:
/usr/share/locale/<LANG>/LC_MESSAGES/myscript.mo
Where <ALANG> is the language into which the script has been translated.
For example, for Brazilian Portuguese:
/usr/share/locale/pt_BR/LC_MESSAGES/myscript.mo
## The Worklow in Short
1. Script is written and tested, including gettext support.
2. Run `xgettext` to extract all `echo` strings into a `.pot` file.
3. Rename the `.pot` file to `.po` and pass to translator.
4. When step 3 is done, run `msgfmt` to create the `.mo` file.
5. Install the `.mo` file (after testing).
6. If something new is written in the script, go to step 2 and repeat to step 5.
## Notes/Suggestions
The `.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.
So, for `myscript`, perhaps:
myscript/
en/myscript.en.po (English)
fr/myscript.fr.po (French)
pt_BR/myscript.pt_BR.po (Brazilian Portuguese)
## License
This document is licensed under the creativecommons.org, 'Attribution-NonCommercial-ShareAlike 4.0
International' license:
https://creativecommons.org/licenses/by-nc-sa/4.0/
2017 Mike Ray, <mike.ray@btinternet.com>