|
| 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