There is a nice feature in bash, about localization (language translation):
TEXTDOMAIN=coreutils
LANG=fr_CH.utf8
echo $\"system boot\"
démarrage système
If using eval
is bad with arbitrary variables, there is a way to do this only when called/needed, in running eval
only on message part:
function lPrintf() {
local sFormat="$(
eval 'echo $"'"${1}"'"'.
)"
shift
printf "${sFormat%.}" $@
}
lPrintf "system boot"
démarrage système
lPrintf $'Written by %s, %s, %s,\nand %s.\n' techno moi lui-même bibi
Écrit par techno, moi, lui-même,
et bibi.
( The dot at end of translated string ensure that whole string, including leading line-break, where passed to variable sFormat
. They will be dropped with ${sFormat%.}
)
OK I think finally got it right.
iprintf() {
msg="$2"
domain="$1"
shift
shift
imsg=$(gettext -ed "$domain" "$msg" ; echo EOF)
imsg="${imsg%EOF}"
printf "$imsg" "$@"
}
Usage example:
LANG=fr_CH.utf8 iprintf coreutils "If FILE is not specified, use %s. %s as FILE is common.\n\n" foo bar
Well, there is my self answer:
This seem not well implemented now. Work in many situations, but, while
echo "$(gettext 'missing character class name `[::]'\')"
caractère de nom de classe « [::] » manquant
work simply, the same string seem impossible to translate using this bashism:
echo $"missing character class name `[::]'"
>
the console stay locked (waiting for such an end of string) adding `"
would immerse bash in a complex interpretation process :->>
> `"
bash: command substitution: line 1: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « ' » correspondant
bash: command substitution: line 2: Erreur de syntaxe : fin de fichier prématurée
missing character class name
And, of course:
echo $"missing character class name \`[::]'"
missing character class name `[::]'
make no translation. :-p
While translating this string containing two backticks work finely:
echo $"%s}: integer required between `{' and `}'"
%s} : entier requis entre « { » et « } »
There is a script where you may see some of mine unsuccessfull trys.
#!/bin/bash
echo "Localized tests"
export TEXTDOMAIN=coreutils
export LANG=fr_CH.UTF-8
export WRITTERS=(Athos Portos Aramis Dartagnan\ Le\ Beau)
echo '#First method# whitout eval'
declare -A MyMessages;
MyMessages[sysReboot]=$"system boot"
MyMessages[writtenBy]=$"Written by %s, %s, %s,
and %s.
"
MyMessages[intReq]=$"%s}: integer required between `{' and `}'"
MyMessages[trClass]=$"when translating, the only character classes that may appear in
string2 are `upper' and `lower'"
# MyMessages[missClass]=$"missing character class name `[::]'"
for msgIdx in ${!MyMessages[@]} ;do
printf "\n--- Test chain '%s' ---\n" $msgIdx
case $msgIdx in
writ* )
printf "${MyMessages[$msgIdx]}\n" "${WRITTERS[@]}"
;;
intReq )
printf "ARRAY{${MyMessages[$msgIdx]}\n" NaN
;;
* )
printf "${MyMessages[$msgIdx]}\n"
;;
esac
done
echo $'###\n#Second method# whith limited eval'
unset MyMessages;
declare -A MyMessages;
lPrintf() {
local sFormat="$(
eval 'echo $"'"${1}"'"'.
)"
shift
printf "${sFormat%.}" "$@"
}
MyMessages[sysReboot]="system boot"
MyMessages[writtenBy]=$'Written by %s, %s, %s,\nand %s.\n'
MyMessages[intReq]="%s}: integer required between \`{' and \`}'"
MyMessages[trClass]="when translating, the only character classes that "
MyMessages[trClass]+=$'may appear in\nstring2 '
MyMessages[trClass]+="are \`upper' and \`lower'"
MyMessages[missClass]="missing character class name \`[::]'"
for msgIdx in ${!MyMessages[@]} ;do
printf "\n--- Test chain '%s' ---\n" $msgIdx
case $msgIdx in
writ* )
lPrintf "${MyMessages[$msgIdx]}" "${WRITTERS[@]}"
;;
intReq )
lPrintf "${MyMessages[$msgIdx]}" NaN
;;
* )
lPrintf "${MyMessages[$msgIdx]}"
;;
esac
done
and his output:
Localized tests
#First method# whitout eval
--- Test chain 'trClass' ---
à la traduction, les seules classes de caractères qui peuvent apparaître
dans string2 sont « upper » ou « lower »
--- Test chain 'intReq' ---
ARRAY{NaN} : entier requis entre « { » et « } »
--- Test chain 'sysReboot' ---
démarrage système
--- Test chain 'writtenBy' ---
Écrit par Athos, Portos, Aramis,
et Dartagnan Le Beau.
###
#Second method# whith limited eval
--- Test chain 'trClass' ---
à la traduction, les seules classes de caractères qui peuvent apparaître
dans string2 sont « upper » ou « lower »
--- Test chain 'missClass' ---
./localized.sh: eval: line 44: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « ` » correspondant
./localized.sh: eval: line 45: Erreur de syntaxe : fin de fichier prématurée
--- Test chain 'intReq' ---
NaN} : entier requis entre « { » et « } »
--- Test chain 'sysReboot' ---
démarrage système
--- Test chain 'writtenBy' ---
Écrit par Athos, Portos, Aramis,
et Dartagnan Le Beau.
If anyone could help my to remove comments and/or error message in this script!? ... (in less then 8 hours?!)
At all, thanks to everyone. (My bounty will go to @gniourf_gniourf unless best answer in 8 hours. But thanks to @techno too, I like your lPrintf! )
I've played a little bit with this feature and this is what I came up with: you can include the newline verbatim as:
$ echo $"Written by %s.
> "
Écrit par %s.
$
In a script:
#!/bin/bash
message=$"Written by %s.
"
printf "$message" Gniourf
This script will output:
Écrit par Gniourf.
Ok, this is not really an answer, but it might help a little bit (at least, we're not using the evil eval
).
Personal remark: I find this feature really clunky!