12

bash には、ローカリゼーション (言語翻訳) に関する優れた機能があります。

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

(注:この作業でfr_CH.utf8は、システム上で既に生成されています...それ以外の場合は、独自のロケールで試すか、インストールlocalesして生成してください。)

問題:

ただし、これが単純な文字列でうまく機能する場合、文字列に\n(または最悪の場合: バッククォート)が含まれている場合、`事態はより複雑になります。

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

これは出席された回答ではありません。

(注 2:この作業では、正確なメッセージをメッセージ ファイルに用意する必要があり.moます。このサンプル/テストでは、コマンドでフォーマット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.

(2 つの二重引用符が表示されます...あまりセクシーではありません...)

そして最後に私はできました:

WRITTERS=(Hans Pierre Jackob Heliott)
eval printf \$\""$msg"\" ${WRITTERS[@]}
Écrit par Hans, Pierre, Jackob,
et Heliott.

しかし、最近聞いたように、eval は悪であると... ;-)

実際、ハード コードされた part のみでeval実行される には問題はありませんが、この eval を除外して、この種の part をより自然な、または読みやすい方法で記述する方法をいただければ幸いです。

すべての @techno の答えで、私の最初のアイデアは、サンプルのために、何かが含まれているかのように危険なものであることがわかりました...WRITTERS;ls

編集:だから質問は:

どうすればこれを隠しevalたり、よりセクシーな方法でこれを書いたりできますか

注:

$ printf "I use bash %s on Debian %s\n" $BASH_VERSION $(</etc/debian_version)
I use bash 4.1.5(1)-release on Debian 6.0.6
4

5 に答える 5

6

私はこの機能を少し試してみましたが、これが私が思いついたものです:改行をそのまま含めることができます:

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

スクリプトで:

#!/bin/bash

message=$"Written by %s.
"

printf "$message" Gniourf

このスクリプトは次を出力します。

Écrit par Gniourf.

わかりました、これは実際には答えではありませんが、少しは役立つかもしれません (少なくとも、悪を使用していませんeval)。

個人的な意見: この機能は本当に扱いにくいと思います!

于 2012-12-25T13:56:42.410 に答える
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.

(変換された文字列の末尾にあるドットは、先頭の改行を含む文字列全体が variable に渡されることを保証しますsFormat。それらは でドロップされます${sFormat%.})

于 2012-12-27T09:05:43.323 に答える
2

OK、最終的には正しくなったと思います。

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
于 2012-12-25T21:22:36.790 に答える
1

翻訳関数を構築するための簡単なソリューション:

f() {
    eval 'local msg=$"'"${1//[\"\$\`]}"\"
    shift
    printf "${msg}" "$@"
}

テスト:

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

f $'Written by %s, %s, %s,\nand %s.\n' Athos Portos Aramis Shreck
Écrit par Athos, Portos, Aramis
et Shreck.

しかし、私は関数をフォークする代わりに変数を設定することを好むので:

f() {
    eval 'local msg=$"'"${1//[\"\$\`]}"\"
    local -n variable=$2
    shift 2
    printf -v variable "$msg" "$@"
}

それで

f $'Written by %s, %s, %s,\nand %s.\n' string Huey Dewey Louie Batman
echo ${string@Q}
$'Écrit par Huey, Dewey, Louie\net Batman.\n'

echo "$string"
Écrit par Huey, Dewey, Louie
et Batman.

または、完全な翻訳機能としてさらに優れています。

f() {
    local store=false OPTIND OPTARG OPTERR varname
    while getopts 'd:v:' opt ;do
        case $opt in
            d ) local TEXTDOMAIN=$OPTARG ;;
            v ) varname=$OPTARG ;;
        esac
    done
    shift $((OPTIND-1))
    eval 'local msg=$"'"${1//[\"\$\`]}"\"
    shift
    printf ${varname+-v} $varname "$msg" "$@"
}

それで

f -d libc -v string "Permission denied"
echo $string
Permission non accordée

f -d coreutils $'Written by %s, %s, %s,\nand %s.\n' Riri Fifi Loulou Georges
Écrit par Riri, Fifi, Loulou
et Georges.

古い答え(2013年1月)

さて、私の自己回答があります:

これは現在うまく実装されていないようです。多くの状況で機能しますが、

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

簡単に言えば、このバシズムを使用して同じ文字列を翻訳することは不可能のようです。

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

2つのバッククォートを含むこの文字列を翻訳している間、うまく機能します:

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時間以内に?!)

みなさん、ありがとうございました。(私の報奨金は、8時間以内に最良の回答がない限り、@ gniourf_gniourfに送られます。しかし、@ technoのおかげで、私はあなたのlPrintfが好きです!)

于 2013-01-03T21:13:55.830 に答える