システムワイドなロケール設定 〜 Windows
Windows でのシステムワイドなロケール設定の取り扱いに関して、調べた結果を備忘録代わりにまとめておきます。
なお、表題で「システムワイド」と謳いつつ、本エントリで扱うロケール設定は、Mac OS X (その1) と同様に、「ユーザ毎」の設定だったりしますが、他の OS 向けの情報を載せたエントリとの兼ね合いから、「システムワイド」という表現を通します。
設定更新方法
システムワイドなロケール設定は、「コントロールパネル」⇒「地域と言語」で表示されるダイアログ経由で変更します。
「形式」欄がメインのロケール設定になります。
このダイアログからもロケール設定のカスタマイズが可能ですが、「追加の設定…」ボタンで表示されるダイアログでは、より詳細なカスタマイズができます。
各項目は、以下の様なロケールカテゴリに対応しているものと思われます。
- 「数値」は
LC_NUMERIC
- 「通貨」は
LC_MONETARY
- 「時刻」/「日付」は
LC_TIME
- 「並べ替え」は
LC_COLLATE
優先度の関係で考えると、「形式」は POSIX 環境における LANG
設定相当だと思われます。
LC_MESSAGES
に相当する設定は、「キーボードと言語」タブから行える模様です。
「模様です」というのは、日本語環境で日本語以外の表示言語を選択するには、追加の表示言語をインストールする必要があるのですが、流石に面倒なので、そこまでは確認していないためです(笑)。
追加の表示言語がインストールされていない状態だと、表示言語は選択できません。詳細は「追加の言語をインストールする方法」経由で表示されるヘルプを参照してください。
※ 2014-10-16 追記: ここから >>>>
OS のバージョン・エディションによって、言語追加の可否が異なる模様です。例えば:
- Windows8 以降の場合、どのエディションでも任意の言語が追加可能
- Windows7 以前の場合:
- Ultimate/Enterprise 相当のエディションは、任意の言語を追加可能
- それ以外のエディションは、限定的な言語のみ追加可能 (例えば、日本語 OS に英語の追加は不可)
詳細は、Windows8、Windows7、Windows Vista 等の、エディション間比較における、「多言語ほにゃらら」の項目を参照してください。
※ 2014-10-16 追記: ここまで <<<<
これらの設定は、変更内容が適用された時点から有効になります。
なお、各種ロケールの設定を行っても、実行されるプログラムに対して、ロケール系環境変数が設定されることはありません。まぁ、POSIX 仕様に準拠してない Windows が、POSIX 仕様が定めるロケール系環境変数を設定しなくても、不思議ではないですからね。
システムロケール
Windows には、バイトシーケンスで表現された文字列を使う "ANSI API" と、ワイド文字 (wchar_t
) シーケンスで表現された文字列を使う "Unicode API" の2つが用意されています。
例えば、日本語文字のような非 ASCII 文字が使われているファイル名を、ファイル API 経由で受け取る場合:
上記の様な挙動になります。
ANSI API において、ワイド文字シーケンスからバイトシーケンスに変換するための符号化方式は、「システムロケール」で決定されます。
「システムロケール」は、「管理」タブ⇒「システムロケールの変更」で表示されるダイアログで選択できます (設定変更が有効になるのは、OS 再起動後になります)。
選択方式は「言語」+「地域」ベースになっていて、「文字コード」は選択内容によって、自動的に決定されます。例えば:
- 「日本語(日本)」なら Shift-JIS (code page 932)
- 「英語(米国)」なら拡張 ASCII (code page 437)
NTFS 自体は内部的に Unicode 化されているので、Unicode API を使用すれば、格納されているファイルの名前を正しく取得できます。
その一方で ANSI API を使用した場合、システムロケール指定によって間接的に決定された文字コードを使って、「ワイド文字シーケンス ⇒ バイトシーケンス」の変換が実施されます。その結果、対象文字コードで網羅されていない文字は、正しく変換されないかもしれません。
このような場合、ANSI API 経由で取得されたファイル名は、単なる「文字化け」ではなく、完全に使い物にならないバイト列になります。
例えば、「英語(米国)」指定によって拡張 ASCII (code page 437) が選択されている場合、日本語文字は網羅範囲外になります。このようなケースで、ANSI API によって取得されるファイル名は、網羅範囲外の文字が "?" (0x3F) で置換されています。
気分的には、「システムロケール」は LC_CTYPE
相当、といったところでしょうか?
コマンドプロンプトとロケール設定
Windows のコマンドプロンプト (cmd.exe
) は、chcp
(CHange Code Page) コマンドを使うことで、システムロケール設定とは別に、出力に使用する文字コードを変更することが可能です。
但し、chcp
によるコードページ変更は、Windows における表示とファイル出力の API 分離を理解しておかないと、思わぬ挙動に面食らうことになります。
例えば、chcp 932
実施済みの状態でも、cp932 の範囲外の文字を使ったファイル名表示が正常に機能します。その一方で、出力をリダイレクトすると、範囲外文字が "?" で置き換えられた cp932 文字コードなファイルが生成されます。
他にも、選択したコードページ/表示内容/フォント設定の組み合わせ次第では、プログラム実行時に処理が中断されてしまう、という問題も発生します(コマンドプロンプト組み込みの dir
コマンドでも発生)。
また、このエントリを書くために chcp
で色々実験した際にも、何かの拍子で、どんなに「規定値」設定の上書きや再起動を繰り返しても、コマンドプロンプト起動時のコードページが 932 に戻せなくなってしまったりもしました(元に戻る際も、理由がわからないままでした……)。
というわけで、個人的には chcp
周りは、そっと箱にしまって、封印してしまいたいところです(笑)。
Python の文字コード設定とロケール設定
Python の locale
モジュールが提供する getdefaultlocale()
は、POSIX 環境では、LC_ALL
, LC_CTYPE
, LANG
といった環境変数を元に、言語/地域情報と、文字コード情報のタプルを返却します。例えば "LC_ALL=ja_JP.cp932
" な場合であれば、('ja_JP', 'cp932')
が返却されます。
しかし、Windows ネイティブ版の Python 処理系での返却値は、以下の情報から得た値で構成されます。
LC_ALL
等の環境変数定義の有無には、全く影響を受けませんので注意してください。
Windows 環境で Mercurial/TortoiseHg を使用する場合は、この挙動のお陰で、文字コードに関する環境変数の設定が不要となっています。
但し、Mercurial 自体のメッセージ/ヘルプ表示の言語選択に関しては、自前でロケール系環境変数から取得しているため、LANGUAGE
, LC_ALL
, LC_MESSAGES
, LANG
等の環境変数で、明示的に表示対象言語を指定する必要があります。