Localization is an undocumented Bash feature.
A localized shell script echoes its text output in the language defined as the system's locale. A Linux user in Berlin, Germany, would get script output in German, whereas his cousin in Berlin, Maryland, would get output from the same script in English.
To create a localized script, use the following template to write all messages to the user (error messages, prompts, etc.).
1 #!/bin/bash
2 # localized.sh
3 # Script by Stéphane Chazelas,
4 #+ modified by Bruno Haible, bugfixed by Alfredo Pironti.
5
6 . gettext.sh
7
8 E_CDERROR=65
9
10 error()
11 {
12 printf "$@" >&2
13 exit $E_CDERROR
14 }
15
16 cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
17 # The triple backslashes (escapes) in front of $var needed
18 #+ "because eval_gettext expects a string
19 #+ where the variable values have not yet been substituted."
20 # -- per Bruno Haible
21 read -p "`gettext \"Enter the value: \"`" var
22 # ...
23
24
25 # ------------------------------------------------------------------
26 # Alfredo Pironti comments:
27
28 # This script has been modified to not use the $"..." syntax in
29 #+ favor of the "`gettext \"...\"`" syntax.
30 # This is ok, but with the new localized.sh program, the commands
31 #+ "bash -D filename" and "bash --dump-po-string filename"
32 #+ will produce no output
33 #+ (because those command are only searching for the $"..." strings)!
34 # The ONLY way to extract strings from the new file is to use the
35 # 'xgettext' program. However, the xgettext program is buggy.
36
37 # Note that 'xgettext' has another bug.
38 #
39 # The shell fragment:
40 # gettext -s "I like Bash"
41 # will be correctly extracted, but . . .
42 # xgettext -s "I like Bash"
43 # . . . fails!
44 # 'xgettext' will extract "-s" because
45 #+ the command only extracts the
46 #+ very first argument after the 'gettext' word.
47
48
49 # Escape characters:
50 #
51 # To localize a sentence like
52 # echo -e "Hello\tworld!"
53 #+ you must use
54 # echo -e "`gettext \"Hello\\tworld\"`"
55 # The "double escape character" before the `t' is needed because
56 #+ 'gettext' will search for a string like: 'Hello\tworld'
57 # This is because gettext will read one literal `\')
58 #+ and will output a string like "Bonjour\tmonde",
59 #+ so the 'echo' command will display the message correctly.
60 #
61 # You may not use
62 # echo "`gettext -e \"Hello\tworld\"`"
63 #+ due to the xgettext bug explained above.
64
65
66
67 # Let's localize the following shell fragment:
68 # echo "-h display help and exit"
69 #
70 # First, one could do this:
71 # echo "`gettext \"-h display help and exit\"`"
72 # This way 'xgettext' will work ok,
73 #+ but the 'gettext' program will read "-h" as an option!
74 #
75 # One solution could be
76 # echo "`gettext -- \"-h display help and exit\"`"
77 # This way 'gettext' will work,
78 #+ but 'xgettext' will extract "--", as referred to above.
79 #
80 # The workaround you may use to get this string localized is
81 # echo -e "`gettext \"\\0-h display help and exit\"`"
82 # We have added a \0 (NULL) at the beginning of the sentence.
83 # This way 'gettext' works correctly, as does 'xgettext.'
84 # Moreover, the NULL character won't change the behavior
85 #+ of the 'echo' command.
86 # ------------------------------------------------------------------ |
bash$ bash -D localized.sh "Can't cd to %s." "Enter the value: " |
bash$ bash --dump-po-strings localized.sh #: a:6 msgid "Can't cd to %s." msgstr "" #: a:7 msgid "Enter the value: " msgstr "" |
![]() | Bruno Haible points out: Starting with gettext-0.12.2, xgettext -o - localized.sh is recommended instead of bash --dump-po-strings localized.sh, because xgettext . . . 1. understands the gettext and eval_gettext commands (whereas bash --dump-po-strings understands only its deprecated $"..." syntax) 2. can extract comments placed by the programmer, intended to be read by the translator. This shell code is then not specific to Bash any more; it works the same way with Bash 1.x and other /bin/sh implementations. |
Now, build a language.po file for each language that the script will be translated into, specifying the msgstr. Alfredo Pironti gives the following example:
fr.po:
1 #: a:6 2 msgid "Can't cd to $var." 3 msgstr "Impossible de se positionner dans le repertoire $var." 4 #: a:7 5 msgid "Enter the value: " 6 msgstr "Entrez la valeur : " 7 8 # The string are dumped with the variable names, not with the %s syntax, 9 #+ similar to C programs. 10 #+ This is a very cool feature if the programmer uses 11 #+ variable names that make sense! |
Then, run msgfmt.
msgfmt -o localized.sh.mo fr.po
Place the resulting localized.sh.mo file in the /usr/local/share/locale/fr/LC_MESSAGES directory, and at the beginning of the script, insert the lines:
1 TEXTDOMAINDIR=/usr/local/share/locale 2 TEXTDOMAIN=localized.sh |
If a user on a French system runs the script, she will get French messages.
![]() | With older versions of Bash or other shells, localization requires gettext, using the -s option. In this case, the script becomes:
|
The TEXTDOMAIN and TEXTDOMAINDIR variables need to be set and exported to the environment. This should be done within the script itself.
---
This appendix written by Stéphane Chazelas, with modifications suggested by Alfredo Pironti, and by Bruno Haible, maintainer of GNU gettext.