Skip to content

Commit e885dc8

Browse files
committed
chapter: Localization
1 parent 63c3f6c commit e885dc8

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed

index.ptree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ pages/bibliography.poly.pm
124124
pages/command_line_opt.poly.pm
125125
pages/important_files.poly.pm
126126
pages/completion_intro.poly.pm
127+
pages/localization.poly.pm
127128
}
128129

129130
}

pages/localization.poly.pm

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#lang pollen
2+
3+
◊page-init{}
4+
◊define-meta[page-title]{Localization}
5+
◊define-meta[page-description]{Localization}
6+
7+
Localization is an undocumented Bash feature.
8+
9+
A localized shell script echoes its text output in the language
10+
defined as the system's locale. A Linux user in Berlin, Germany, would
11+
get script output in German, whereas his cousin in Berlin, Maryland,
12+
would get output from the same script in English.
13+
14+
To create a localized script, use the following template to write all
15+
messages to the user (error messages, prompts, etc.).
16+
17+
◊example{
18+
#!/bin/bash
19+
# localized.sh
20+
# Script by Stéphane Chazelas,
21+
#+ modified by Bruno Haible, bugfixed by Alfredo Pironti.
22+
23+
. gettext.sh
24+
25+
E_CDERROR=65
26+
27+
error()
28+
{
29+
printf "$@" >&2
30+
exit $E_CDERROR
31+
}
32+
33+
cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
34+
# The triple backslashes (escapes) in front of $var needed
35+
#+ "because eval_gettext expects a string
36+
#+ where the variable values have not yet been substituted."
37+
# -- per Bruno Haible
38+
read -p "`gettext \"Enter the value: \"`" var
39+
# ...
40+
41+
42+
# ------------------------------------------------------------------
43+
# Alfredo Pironti comments:
44+
45+
# This script has been modified to not use the $"..." syntax in
46+
#+ favor of the "`gettext \"...\"`" syntax.
47+
# This is ok, but with the new localized.sh program, the commands
48+
#+ "bash -D filename" and "bash --dump-po-string filename"
49+
#+ will produce no output
50+
#+ (because those command are only searching for the $"..." strings)!
51+
# The ONLY way to extract strings from the new file is to use the
52+
# 'xgettext' program. However, the xgettext program is buggy.
53+
54+
# Note that 'xgettext' has another bug.
55+
#
56+
# The shell fragment:
57+
# gettext -s "I like Bash"
58+
# will be correctly extracted, but . . .
59+
# xgettext -s "I like Bash"
60+
# . . . fails!
61+
# 'xgettext' will extract "-s" because
62+
#+ the command only extracts the
63+
#+ very first argument after the 'gettext' word.
64+
65+
66+
# Escape characters:
67+
#
68+
# To localize a sentence like
69+
# echo -e "Hello\tworld!"
70+
#+ you must use
71+
# echo -e "`gettext \"Hello\\tworld\"`"
72+
# The "double escape character" before the `t' is needed because
73+
#+ 'gettext' will search for a string like: 'Hello\tworld'
74+
# This is because gettext will read one literal `\')
75+
#+ and will output a string like "Bonjour\tmonde",
76+
#+ so the 'echo' command will display the message correctly.
77+
#
78+
# You may not use
79+
# echo "`gettext -e \"Hello\tworld\"`"
80+
#+ due to the xgettext bug explained above.
81+
82+
83+
84+
# Let's localize the following shell fragment:
85+
# echo "-h display help and exit"
86+
#
87+
# First, one could do this:
88+
# echo "`gettext \"-h display help and exit\"`"
89+
# This way 'xgettext' will work ok,
90+
#+ but the 'gettext' program will read "-h" as an option!
91+
#
92+
# One solution could be
93+
# echo "`gettext -- \"-h display help and exit\"`"
94+
# This way 'gettext' will work,
95+
#+ but 'xgettext' will extract "--", as referred to above.
96+
#
97+
# The workaround you may use to get this string localized is
98+
# echo -e "`gettext \"\\0-h display help and exit\"`"
99+
# We have added a \0 (NULL) at the beginning of the sentence.
100+
# This way 'gettext' works correctly, as does 'xgettext.'
101+
# Moreover, the NULL character won't change the behavior
102+
#+ of the 'echo' command.
103+
# ------------------------------------------------------------------
104+
}
105+
106+
Run it:
107+
108+
◊example{
109+
bash$ bash -D localized.sh
110+
"Can't cd to %s."
111+
"Enter the value: "
112+
}
113+
114+
This lists all the localized text. (The ◊code{-D} option lists
115+
double-quoted strings prefixed by a ◊code{$}, without executing the
116+
script.)
117+
118+
◊example{
119+
bash$ bash --dump-po-strings localized.sh
120+
#: a:6
121+
msgid "Can't cd to %s."
122+
msgstr ""
123+
#: a:7
124+
msgid "Enter the value: "
125+
msgstr ""
126+
}
127+
128+
The ◊code{--dump-po-strings} option to Bash resembles the ◊code{-D}
129+
option, but uses gettext "po" format.
130+
131+
Bruno Haible points out:
132+
133+
Starting with gettext-0.12.2, ◊command{xgettext -o - localized.sh} is
134+
recommended instead of ◊command{bash --dump-po-strings localized.sh},
135+
because ◊command{xgettext} . . .
136+
137+
1. understands the ◊command{gettext} and ◊command{eval_gettext}
138+
commands (whereas ◊command{bash --dump-po-strings} understands only
139+
its deprecated ◊code{$"..."} syntax)
140+
141+
2. can extract comments placed by the programmer, intended to be read
142+
by the translator.
143+
144+
This shell code is then not specific to Bash any more; it works the
145+
same way with Bash 1.x and other ◊fname{/bin/sh} implementations.
146+
147+
Now, build a ◊fname{language.po} file for each language that the
148+
script will be translated into, specifying the msgstr. Alfredo Pironti
149+
gives the following example:
150+
151+
fr.po:
152+
153+
◊example{
154+
#: a:6
155+
msgid "Can't cd to $var."
156+
msgstr "Impossible de se positionner dans le repertoire $var."
157+
#: a:7
158+
msgid "Enter the value: "
159+
msgstr "Entrez la valeur : "
160+
161+
# The string are dumped with the variable names, not with the %s syntax,
162+
#+ similar to C programs.
163+
#+ This is a very cool feature if the programmer uses
164+
#+ variable names that make sense!
165+
}
166+
167+
Then, run ◊command{msgfmt -o localized.sh.mo fr.po}
168+
169+
Place the resulting ◊fname{localized.sh.mo} file in the
170+
◊fname{/usr/local/share/locale/fr/LC_MESSAGES} directory, and at the
171+
beginning of the script, insert the lines:
172+
173+
◊example{
174+
TEXTDOMAINDIR=/usr/local/share/locale
175+
TEXTDOMAIN=localized.sh
176+
}
177+
178+
If a user on a French system runs the script, she will get French
179+
messages.
180+
181+
Note: With older versions of Bash or other shells, localization
182+
requires ◊command{gettext}, using the ◊code{-s} option. In this case,
183+
the script becomes:
184+
185+
◊example{
186+
#!/bin/bash
187+
# localized.sh
188+
189+
E_CDERROR=65
190+
191+
error() {
192+
local format=$1
193+
shift
194+
printf "$(gettext -s "$format")" "$@" >&2
195+
exit $E_CDERROR
196+
}
197+
cd $var || error "Can't cd to %s." "$var"
198+
read -p "$(gettext -s "Enter the value: ")" var
199+
# ...
200+
}
201+
202+
The ◊code{TEXTDOMAIN} and ◊code{TEXTDOMAINDIR} variables need to be
203+
set and exported to the environment. This should be done within the
204+
script itself.
205+
206+
---
207+
208+
This appendix written by Stéphane Chazelas, with modifications
209+
suggested by Alfredo Pironti, and by Bruno Haible, maintainer of GNU
210+
gettext.

0 commit comments

Comments
 (0)