彷徨えるフジワラ

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

システムワイドなロケール設定 〜 Mac OS X (その1)

Mac OS X でのロケール設定の取り扱いに関して、調べた結果を備忘録代わりにまとめておきます。

なお、私自身がもっぱら「Mac miniSSH 経由でアクセス」をメインとする、相当な「ニワカ Mac ユーザ」なので、本エントリの情報精度は、他のエントリに輪をかけて悪い可能性がありますのでご了承ください(笑)。

また、動作確認等は、今時ではちょっと古目の Mac OS X 10.7.5 ベースで行っていますので、最新版とは多少事情が異なるかもしれません。

設定更新方法

Mac OS X でのロケール設定は、「システム環境設定」→「言語とテキスト」→「書式」画面において、「地域」を選択することで更新できます。

「書式」設定画面の各項目は:

  • 「日付」/「時刻」は LC_TIME
  • 「数値」は LC_NUMERIC
  • 「通貨」は LC_MONETARY

また、「言語」設定画面の各項目は:


  • 言語リストは LANGUAGE (or LC_MESSAGES)
  • 「並べ替えリストに使う順序」は LC_COLLATE

といったロケールカテゴリに対応しているものと思われます。

但し、これらはあくまで「各項目の機能が、どのロケールカテゴリに相当するか?」であって、「各項目の設定内容が、対応するロケール環境変数に反映される」わけではない点に注意してください (詳細は後述)。

設定格納先

「言語とテキスト」で設定したロケール設定の内容は、プリファレンス (preference) のグローバルドメイン領域に格納されます。具体的な格納先ファイルは、~/Library/Preferences/.GlobalPreferences.plist になります。

但し、このファイルはバイナリ形式なので、参照するためには、defaults コマンドを使用する必要があります。

$ defaults read -g AppleLocale
ja_JP

-g オプションは、参照先の名前空間として NSGlobalDomain を選択するためのオプションです。"defaults read NSGlobalDomain AppleLocale" 実行と等価です。

例えば、「言語とテキスト」の「書式」設定の画面で、「地域」を「日本」にしたまま、「暦法」指定を「ユダヤ歴」、「通貨」指定を「米ドル」に変更すると、AppleLocale キーで取得できる値が、ja_JP から ja_JP@currency=USD;calendar=hebrew に変わります。

また、キーに AppleLanguages を指定することで、「言語」設定画面での言語のリストを:

$ defaults read -g AppleLanguages
(
    ja,
    en,
    fr,
    de,
    es,
    :
    :

AppleCollationOrder を指定することで、同じく「言語」設定画面での「並べ替えリストに使う順序」を取得できます。

$ defaults read -g AppleCollationOrder
ja

なお、格納先ファイルが ~/Library/Preferences 配下であることからもわかるように、「言語とテキスト」での設定の有効範囲は、個々のユーザに限定されますから、「システムワイドなロケール設定」という表現は実は正しくありません。

本エントリのタイトルである「システムワイドなロケール設定」は、その点で看板に偽りありなのですが、他の OS 向けの情報を載せたエントリとの兼ね合いもありますので、表題は「システムワイドなロケール設定」のままにしておきます(笑)

ちなみに、グローバルドメイン以外にも、ロケール設定らしき情報が保持されているドメインがあります。

$ defaults read com.apple.systempreferences AppleIntlCustomFormat
{
    AppleIntlCustomICUDictionary =     {
    };
    AppleIntlCustomLocale = "ja_JP";
}

ドメイン名的には、こちらの方が「システムワイドなロケール設定」な雰囲気がしないでもありませんが、グローバルドメインとどういった役割分担になっているんでしょうね?

詳細をご存知の方は、お知らせ頂けると助かります。

ターミナル環境での設定内容反映

標準同梱されている「ターミナル」アプリケーションでは、個々のターミナル起動の際に、「言語とテキスト」でのロケール設定を反映させるか否かを、指定することができます。

「ターミナル」メニューの「環境設定」から、「設定」→「詳細」と進みます。

「起動時にロケール環境変数を設定」項目のチェックが入っている場合、それ以降に開かれたターミナルでのシェル起動の際に、「書式」設定での「地域」選択に相当する値 (+文字エンコーディング) が、LANG 環境変数設定に設定されます。

設定対象が LANG 環境変数限定である点に注意してください (ヘルプでもその旨明記されています)。

「言語とテキスト」設定では、各ロケールカテゴリに相当する値を、個別に設定可能ですが、それらの設定値が、対応するロケール環境変数 (LC_*LANGUAGE) に反映されることはありません。

SSH アクセスでの設定内容反映

Mac OS X では、「システム環境設定」→「共有」で「リモートログイン」を有効にすることで、外部から SSH 経由でアクセスすることが可能になります。

他の OS 上で稼動する SSH サーバの場合は、~/.bashrc 等で明示的にロケール設定を行わなくても:

  • Linux であれば、PAM 機能経由で /etc/default/locale の読み込み
  • Solaris であれば、/etc/default/init を読み込んだ init プロセスからの引き継ぎ

上記のような手段により、SSH アクセスで起動されるシェルに対して、システムワイドなロケール設定が反映されます。

しかし、Mac OS X における SSH のデフォルト設定では、「言語とテキスト」におけるロケール設定を、SSH 経由で起動されるシェルに対して反映させることができません。

とりあえず、ユーザ権限の範囲で実現可能な、一番手軽な方法は、~/.bashrc 設定で、「言語とテキスト」でのロケール設定を反映させる、というものでしょう。

例えば以下のような記述になるでしょうか?ついでに、"defaults read -g AppleLanguages" で取得できる言語候補一覧を、コロン区切りで LANGUAGE 環境変数に設定しても良いかもしれませんね。

LANG="`defaults read -g AppleLocale | sed 's/@.*$//g'`.UTF-8"
export LANG

Mac OS X の場合、ファイルシステム (HFS+) が受け付ける文字コードUTF-8 のみですし、「ターミナル」アプリのデフォルト文字コードUTF-8 ですから、上記例では、問答無用に UTF-8 を指定しています。

但し、個人的には、以下のような設定にしています。

if test "${SHLVL}"x = "1"x; then
    # 初回の ~/.bashrc 評価時
    case "$-" in
    *i*)
        # 対話的実行時
        if test -n "${SSH_CLIENT}"; then
            # SSH 経由アクセス時
            LANG="`defaults read -g AppleLocale | sed 's/@.*$//g'`.UTF-8"
            export LANG
        fi
        ;;
    esac
fi
  • 「初回の ~.bashrc 評価時」限定は、入れ子のシェル実行の際に、親側での意図的な LANG 設定を、子シェル側で上書きしないため
  • 「対話的実行」限定は、SSH での対話的実行 (個人的には、Mercurial による hg pushhg pull) の際に、クライアント側 (= Shift-JIS/cp932 な Windows) とサーバ側 (= UTF-8Mac OS X) で、複数の文字コードが混在する状況を回避するため
  • SSH 経由アクセス時」限定は、「ターミナル」アプリでの「起動時にロケール環境変数を設定」の有無を尊重するため

なお、他の環境から持ってきた ~/.bashrc を流用する場合、対話的実行の有無により、設定ファイルへの追加記述が無効になる可能性がありますので、注意してください。Mac OS X のデフォルト (= /etc/skel/.bashrc 由来) のものは大丈夫そうですが……

ちなみに、ユーザ毎の ~/.bashrc 記述以外で、「言語とテキスト」におけるロケール設定を、SSH 接続時に反映させる方法として、一応以下のような可能性が考えられます。

  • PAM 機能経由で頑張る (or 独自モジュール実装等) ことで、defaults コマンド (あるいは相応の API 呼び出し) で読み出した情報を LANG 環境変数に設定
    (私自身あまり PAM には詳しくないので、そんなことが可能か否か、なんとも判断がつきません)
  • sshd プロセスは root ユーザ権限で起動されるので、root ユーザの Global Preferences に対して、グローバルドメインAppleLocale を変更すれば良いかも?
    (OpenSSH ベースの sshd 実装に、そこまで Mac OS X 環境固有の実装が入っているかは微妙な気が……)
  • SSH 接続の都度実行される /etc/sshrc*1 ファイルで、defaults read 結果を元に LANG 環境変数を設定する
    (対象ユーザの ~/.ssh/rc が存在する場合、/etc/sshrc は評価されないことになっているので、実行されない可能性も……)

実現性が怪しかったり、用途的に微妙だったりと、いずれもあまり積極的には考えたくない選択肢ですねぇ(笑)。

以下、その2に続きます。

*1:オンラインマニュアル上は、/etc/ssh 配下に格納されていることになっていますが、Mac OS X の場合、ssh 関連設定ファイルは全て /etc 直下に配置されます。なんでなんだろう?