彷徨えるフジワラ

年がら年中さまよってます

システムワイドなロケール設定 〜 Cygwin

Cygwin でのシステムワイドなロケール設定の取り扱いに関して、調べた結果を備忘録代わりにまとめておきます。

表題で「システムワイド」と謳いつつ「ユーザ毎」の設定について書いている点は、前回のWindows のエントリと同様です(笑)。

設定更新方法

Cygwin でのシステムワイドなロケール設定は、Windows でのロケール設定を参照しているので、「コントロールパネル」⇒「地域と言語」で表示されるダイアログ経由で変更します。

「地域と言語」での設定変更は、Cygwin のパスで言う /etc/profile.d/lang.sh 中の以下の記述によって、環境変数に反映されます。

# if no locale variable is set, indicate terminal charset via LANG
test -z "${LC_ALL:-${LC_CTYPE:-$LANG}}" &&
    export LANG=$(/usr/bin/locale -uU)

Windows環境変数として、 LC_ALLLC_CTYPELANG のいずれも定義されていない場合、"locale -uU" の実行結果が LANG 環境変数に設定されます。
"locale -uU" は、オプション指定に対応する以下の機能によって、"ja_JP.UTF-8" 形式の情報を表示します。

  • -u: 「地域と言語」で設定された地域/言語の表示
  • -U: 末尾に ".UTF-8" を追加

設定を実施するファイルが /etc/profile.d 配下のファイルであることから、ログインシェル以外では設定されないことがわかります。

「スタート」メニューに追加される「Cygwin bash shell」の実体である Cygwin.bat などは、以下のように「ログインシェル」であることを明示して bash を起動しています。

bash --login -i

その一方で、他の Windows プログラムから bash が起動されるケースでは、「ログインシェル」扱いにはなりません。また、Emacs のシェルバッファでのシェル起動の様なケースを除けば、「対話的実行」になることも無いでしょう。

「ログインシェル」でも「対話的実行」でもない場合は、.bashrc は読み込まれませんから、いくら .bashrcロケール設定を書いても役に立ちません。

そのため、必要であれば、Windows環境変数として、ロケール環境変数を明示的に設定しておいた方が良いでしょう。

あるいは、Windows環境変数 BASH_ENV を使い、 bash の「非ログイン」且つ「非対話的実行」時限定の設定ファイル読み込み挙動として、"${HOME}/.bashrc" を読み込ませる、という手もありますね。

ただ、こちらの方法だと、コマンドラインでの bash -c "コマンド" 実行等でも、都度設定ファイルの読み込みが実施されてしまうので、個人的にはあまりお勧めしません

Cygwin のファイル名文字コード

Cygwin のファイル API におけるファイル名の符号化方式は、Cygwin 1.7 からロケール設定の影響を受けるように変更されました。デフォルト値は "LC_CTYPE=C.UTF-8" 相当になります。

Cygwin 上で全てが完結するのであれば、UTF-8 でも全然構わないでしょう。むしろ、Mercurialファイル名文字コードの問題も解決するので、歓迎したいくらいです。

しかし、Cygwin コマンドと他の Windows プログラムの併用/連携が必要なケースなどでは、使用する文字コードの差異によって、連携が上手く行かない可能性が出てきます。

そのため私個人は、Windows環境変数として "LC_CTYPE=ja_JP.cp932" を明示的に設定することで、ファイル名文字コードには常時 Shift-JIS を使用する運用を続けています。

ちなみに、インストール時の環境設定由来なのか、私の環境では Meadow 起動時の環境変数設定に "LANG=JPN" が追加されてしまうのですが、この設定が Cygwinロケール判定処理を混乱させるらしく、Meadow から起動したシェルでは、"LC_CTYPE=ja_JP.UTF-8" が設定されていても、Cロケール設定相当とみなされる (locale コマンド出力での確認)、という残念な状況になっていました。

$ env | grep LANG
LANG=JPN
$ env | grep LC_
LC_CTYPE=ja_JP.cp932
$ locale
LANG=JPN
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_ALL=

国際化周りの elisp ライブラリをザックリと検索した限りでは、set-language-environment 関数に明示的に言語環境名を指定する前提であれば、LANG 環境変数が未設定でも大丈夫そうなので、Emacs の個人設定ファイルに以下の記述を追加して凌いでいます。

(setenv "LANG" nil)