Appendix F. Localization

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 #
   3 # Script by Stephane Chazelas, modified by Bruno Haible
   5 .
   7 E_CDERROR=65
   9 error()
  10 {
  11   printf "$@" >&2
  12   exit $E_CDERROR
  13 }
  15 cd $var || error "`eval_gettext \"Can't cd to \$var.\"`"
  16 read -p "`gettext \"Enter the value: \"`" var
  17 # ...

 bash$ bash -D
 "Can't cd to %s."
 "Enter the value: "
This lists all the localized text. (The -D option lists double-quoted strings prefixed by a $, without executing the script.)

 bash$ bash --dump-po-strings
 #: a:6
 msgid "Can't cd to %s."
 msgstr ""
 #: a:7
 msgid "Enter the value: "
 msgstr ""
The --dump-po-strings option to Bash resembles the -D option, but uses gettext "po" format.


Bruno Haible points out:

Starting with gettext-0.12.2, xgettext -o - is recommended instead of bash --dump-po-strings, 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. As an example:

   1 #: a:6
   2 msgid "Can't cd to %s."
   3 msgstr "Impossible de se positionner dans le répertoire %s."
   4 #: a:7
   5 msgid "Enter the value: "
   6 msgstr "Entrez la valeur : "

Then, run msgfmt.

msgfmt -o fr.po

Place the resulting 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

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:

   1 #!/bin/bash
   2 #
   4 E_CDERROR=65
   6 error() {
   7   local format=$1
   8   shift
   9   printf "$(gettext -s "$format")" "$@" >&2
  10   exit $E_CDERROR
  11 }
  12 cd $var || error "Can't cd to %s." "$var"
  13 read -p "$(gettext -s "Enter the value: ")" var
  14 # ...

The TEXTDOMAIN and TEXTDOMAINDIR variables need to be exported to the environment.


This appendix written by Stephane Chazelas, with modifications suggested by Bruno Haible, maintainer of GNU gettext.