macOSでは、homebrewにbashをインストールした後、設定が現在のシェルのロケールにいくつかの影響を与えるように見えましたが、メッセージはエクスポートされるLC_MESSAGES
まで実際には変更されませんでした。LC_MESSAGES
設定を解除するLANG
と、LC_MESSAGES
予想されるエラーメッセージが英語で表示されます。
bash-4.4$ unset LANG LC_MESSAGES
bash-4.4$ if :; fi
bash: syntax error near unexpected token `fi'
無効な値に設定すると、LC_MESSAGES
次のエラーが発生しますsetlocale
。
bash-4.4$ LC_MESSAGES=foo
bash: warning: setlocale: LC_MESSAGES: cannot change locale (foo): No such file or directory
だから何私が設定すると変更されますLC_MESSAGES
。しかし、合理的な値に設定しても効果はありません。
bash-4.4$ LC_MESSAGES=ja_JP.UTF-8
bash-4.4$ if :; fi
bash: syntax error near unexpected token `fi'
エクスポートするまで:
bash-4.4$ export LC_MESSAGES
bash-4.4$ if :; fi
bash: 予期しないトークン `fi' 周辺に構文エラーがあります
LANG
(すべて適用されるようです。)
Bash マニュアルセクションバッシュ変数LC_MESSAGES
エクスポートまたはエクスポートする必要はありませんLANG
(そしてここにリストされている他のほとんどの変数はエクスポートする必要はありません)。
なぜこれですか?
答え1
あなたは正しいです。シェル変数を割り当てると、エクスポートするかどうかに関係なく、そのカテゴリのPOSIXが変数値として呼び出さLC_*
れます。の場合は、すべての変数を再度呼び出します。の場合には効果がありません。bash
setlocale()
LANG
setlocale(LC_ALL, thevalue)
setlocale(LC_*)
LC_*
LANGUAGE
これでbash
GNUプロジェクトのシェルです。テキストローカライゼーションのgettext
場合libintl
。bash
configure
--with-included-gettext
gettext
各言語のデータベースでメッセージ翻訳を見つけます。どの言語であるかはカテゴリ値によって決まりますが、環境変数で上書きLC_MESSAGES
できます。$LANGUAGE
gettextドキュメントによると、以前の呼び出しはsetlocale()
カテゴリ値を決定する呼び出しでなければなりませんが、いくつかの複雑な問題があります。
マルチスレッドアプリケーションの場合、現在、この値を取得するために使用できる標準API gettextはありません。。bash
マルチスレッドアプリケーションではありませんが、それが何であってもsetlocale(category, NULL)
返品は実装定義実際には常に使用できるわけではありません。。
したがって、実際にはgettextは、setlocale()
GNU libcの一部として構築されたシステム、またはlibcがGNU libcのシステム(たとえば、GNU libcで構築されたシステム)から言語名を取得するためbash
にのみ使用されます。--with-included-gettext
。
getenv()
他のシステムでは、以前に呼び出された方法に関係なくロケールを決定するために使用されるため、これらのsetlocale()
動作が表示されます。
これらの変数をエクスポートするのは簡単な回避策です。輸出されていない場合は、環境の一部ではないと言うこともできます。 POSIXはこれについては明確ではありません。別の観点では、翻訳がによって行われるのではなく、サードパーティのbash
メカニズムによって実行されるということです。実装する他のコマンドでは、環境変数を使用して2つのソフトウェア(ここbash
とgettext
)の間でロケール情報を渡す必要があります。
GNUシステムでは、状況は実際には悪化しています。
上記のように、gettextはGNU libcに含まれています。$LANGUAGE
POSIXロケールAPIよりも先行します$LC_MESSAGE
が、$LANGUAGE
一部ではなくその上にある拡張です。
setlocale(LC_MESSAGES, NULL)
したがって、GNUシステムでは、LC_MESSAGESカテゴリの名前を取得するためにgettextが使用されます。なぜなら、LC_MESSAGESLANGUAGE
カテゴリは常にロケールカテゴリではなくgetenv()
使用されるからです。LANGUAGE
問題は、bash
変数処理の一部としてenviron[]
libc配列との接続が失われた独自の環境を管理することです。独自のものがあり、getenv()
独自のバージョンの環境を照会しますが、gettext
libcの一部として構築され、bash
動的にリンクされるとdgettext()
libcから呼び出されます。これはlibcではなくlibc内の内部呼び出しであるため、単に開始時刻から値を取得します。getenv()
bash
$LANGUAGE
bash
したがって、GNUシステムでは、静的にリンクされているかビルドを使用しない限り、生成されたメッセージに対するすべての変更は、変数のエクスポートのbash
有無にかかわらず無視されます。--with-included-gettext
他のシステムでは、gettextはlibcの一部ではないので(エクスポートする限り)大丈夫です。したがって、sを呼び出します。$LANGUAGE
bash
$LANGUAGE
bash
getenv()
Debian で:
$ LANGUAGE=fr bash -c 'LANGUAGE=es; eval fi'
bash: eval: ligne 0: erreur de syntaxe près du symbole inattendu « fi »
bash: eval: ligne 0: `fi'
$LANGUAGE
(bash
スペイン語ではなくフランス語のメッセージ、当時呼び出された値)。
実際、他の殻に比べてあまり良くありません。
zsh
他の言語に翻訳されていませんが、GNUシステムで内部的に使用されていますstrerror()
。gettext
$ LANGUAGE=fr zsh -c 'LANGUAGE=es; true</x; LANGUAGE=en; true</a; true < /etc/shadow'
zsh:1: no existe el archivo o el directorio: /x
zsh:1: no existe el archivo o el directorio: /a
zsh:1: permission denied: /etc/shadow
ありがとうございますLANGUAGE=es
。しかし、ENOENTに関する2番目のメッセージがどのように英語で表示されないかを見てください(とにかくgettextによってキャッシュされているはずです。キャッシュは変更された$LANGUAGE
ときに無効にする必要がありましたが、そうではありませんでした)。
答え2
見てこの回答シェル変数と環境変数の違いを説明します。本質的に:
シェル変数を設定します。
LANG=en_US.UTF-8
環境変数を設定します。
export LANG=en_US.UTF-8
シェル変数はシェル専用で、子プロセスに渡されないため、ロケールの環境変数を設定する必要があります。