bash本地化不适用于多行字符串(具有强语法或通过`eval`)

时间:2012-12-25 01:36:11

标签: bash localization

bash有一个很好的功能,关于本地化(语言翻译):

TEXTDOMAIN=coreutils
LANG=fr_CH.utf8
echo $"system boot"
démarrage système

Nota:对于这项工作,fr_CH.utf8已在您的系统上生成 ...否则您可以尝试使用自己的语言环境...或者安装locales并生成一个。)

问题:

但是如果使用简单字符串工作正常,那么当字符串包含\n(或最差:反引号`时,事情会更复杂:

echo $"Written by %s, %s, %s,\nand %s.\n"
Written by %s, %s, %s,\nand %s.\n

这不是参加的答案。

Nota2:对于这项工作,必须在.mo消息文件中准备完全消息,在此示例/测试中,我使用existant {{ 1}}文件,可以使用命令coreutils.mo 未格式化。)

根本没有,我发现进行翻译的唯一方法是:

msgunfmt

eval echo \$\"$'Written by %s, %s, %s,\nand %s.\n'\"
Écrit par %s, %s, %s,
et %s.

(你可以看到两个双引号......不是很性感......)

最后我可以:

msg=$'Written by %s, %s, %s,\nand %s.\n'
eval echo \$\""$msg"\"
Écrit par %s, %s, %s,
et %s.

但是我最近听说 eval是邪恶的 ...; - )

事实上,我没有使用仅使用硬编码部分运行WRITTERS=(Hans Pierre Jackob Heliott) eval printf \$\""$msg"\" ${WRITTERS[@]} Écrit par Hans, Pierre, Jackob, et Heliott. 的问题,但我希望有一种方法可以保持这个eval并写出这种部分采用更自然可读方式。

根据@techno的回答,让我看到我的第一个想法是危险,好像eval包含一些WRITTERS,样本......

修改:问题是:

我怎么能保持这个;ls和/或以更性感的方式写这个

诺塔:

eval

5 个答案:

答案 0 :(得分:6)

我已经使用了这个功能,这就是我想出的:你可以将换行符逐字地包括在内:

$ echo $"Written by %s.
> "
Écrit par %s.
$ 

在剧本中:

#!/bin/bash

message=$"Written by %s.
"

printf "$message" Gniourf

此脚本将输出:

Écrit par Gniourf.

好的,这不是一个真正的答案,但它可能会有所帮助(至少,我们没有使用邪恶的eval)。

个人评论:我觉得这个功能真的很笨重!

答案 1 :(得分:4)

如果使用eval对任意变量不好,只有在调用/需要时才能执行此操作,仅在消息部分运行eval

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.

(翻译后的字符串末尾的点确保整个字符串,包括前导换行符,传递给变量sFormat。它们将被${sFormat%.}删除

答案 2 :(得分:2)

好的,我认为最终做对了。

iprintf() {
    msg="$2"
    domain="$1"
    shift
    shift
    imsg=$(gettext -ed "$domain" "$msg" ; echo EOF)
    imsg="${imsg%EOF}"
    printf "$imsg" "$@"
}

用法示例:

LANG=fr_CH.utf8 iprintf coreutils "If FILE is not specified, use %s.  %s as FILE is common.\n\n" foo bar

答案 3 :(得分:1)

嗯,有我自己的回答:

现在似乎没有很好地实施。在许多情况下工作,但是,而

echo "$(gettext 'missing character class name `[::]'\')"
caractère de nom de classe « [::] » manquant

工作简单,使用此 bashism

,似乎无法翻译相同的字符串
echo $"missing character class name `[::]'"
> 

控制台保持锁定(等待字符串结尾)添加`"会将bash置于复杂的解释过程中: - >>

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

当然还有:

echo $"missing character class name \`[::]'"
missing character class name `[::]'

不做翻译。 :-P

在翻译包含两个反引号的字符串时,精细

echo $"%s}: integer required between `{' and `}'"
%s} : entier requis entre « { » et « } »

有一个脚本,你可能会看到我的一些不成功的尝试。

#!/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

和他的输出:

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.

如果有人可以帮助我删除此脚本中的评论和/或错误消息!? ......(不到8个小时?!)

总之,感谢大家。 (我的赏金将转到@gniourf_gniourf,除非在8小时内得到最佳答案。但是也要感谢@techno,我喜欢你的lPrintf!)

答案 4 :(得分:0)

说服你不要这样做

从根本上说,您可能不应该关心这个问题,因为 C 和 Bash 在 printf 的工作方式上是不同的:C 的 printf 不会翻译反斜杠转义,而 Bash 会。因此,在理想的世界中,您应该只做 printf $"%s, %s,\n%s" some thing more 并使模板字符串保留原始反斜杠转义符(因此它可能看起来像 po 文件中的 msgid "%s, %s,\\n%s")。

正如您已经意识到的,$"" 结构也不允许使用对 bash 的双引号语法无效的 msgids。根本无法使用此条目:

msgid "`"
msgstr "« "

通过剥离这些有问题的字符,它只会掩盖问题。 (同样,对于 bash 来说很好,因为您会一直在编写 echo $"\`"msgid "\\`")。

另一方面,确实存在good reason to not use the $"" construct。该构造允许翻译器运行任意命令,与 eval 相比,创建了更真实的不安全级别。使用 gettext.sh functions 没有问题,因为任何变量替换都由单独的 envsubst 程序处理。它还可以让您随心所欲地使用 $''