彷徨えるフジワラ

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

システムワイドなロケール設定 〜 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 に英語の追加は不可)

詳細は、Windows8Windows7Windows Vista 等の、エディション間比較における、「多言語ほにゃらら」の項目を参照してください。

※ 2014-10-16 追記: ここまで <<<<

これらの設定は、変更内容が適用された時点から有効になります。

なお、各種ロケールの設定を行っても、実行されるプログラムに対して、ロケール環境変数が設定されることはありません。まぁ、POSIX 仕様に準拠してない Windows が、POSIX 仕様が定めるロケール環境変数を設定しなくても、不思議ではないですからね。

システムロケール

Windows には、バイトシーケンスで表現された文字列を使う "ANSI API" と、ワイド文字 (wchar_t) シーケンスで表現された文字列を使う "Unicode API" の2つが用意されています。

例えば、日本語文字のような非 ASCII 文字が使われているファイル名を、ファイル API 経由で受け取る場合:

  • Unicode API なら、内部で格納されているワイド文字シーケンスがそのまま返却
  • ANSI 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文字コード設定とロケール設定

Pythonlocale モジュールが提供する getdefaultlocale() は、POSIX 環境では、LC_ALL, LC_CTYPE, LANG といった環境変数を元に、言語/地域情報と、文字コード情報のタプルを返却します。例えば "LC_ALL=ja_JP.cp932" な場合であれば、('ja_JP', 'cp932') が返却されます。

しかし、Windows ネイティブ版の Python 処理系での返却値は、以下の情報から得た値で構成されます。

  • 「地域と言語」の「形式」設定から、言語/地域情報 (ja_JP 部分)
  • 「地域と言語」の「システムロケール」設定から、文字コード情報(cp932 部分)

LC_ALL 等の環境変数定義の有無には、全く影響を受けませんので注意してください。

Windows 環境で Mercurial/TortoiseHg を使用する場合は、この挙動のお陰で、文字コードに関する環境変数の設定が不要となっています。

但し、Mercurial 自体のメッセージ/ヘルプ表示の言語選択に関しては、自前でロケール環境変数から取得しているため、LANGUAGE, LC_ALL, LC_MESSAGES, LANG 等の環境変数で、明示的に表示対象言語を指定する必要があります。