Skip to content

MS_Culture

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

カルチャ

概要

  • Windows では、ロケール(win32)をカルチャ(.NET)と呼ぶ。

  • .NET では、カルチャ設定によって自動的に動作が変わる国際化(多言語化)機能を持っている。

    • Date 型の文字列化時の既定のフォーマットが変化する。
    • 画面上のコントロールの配置・キャプションなどの各種プロパティ、
      カレンダ コントロールなどの表示が変化する。
  • 参考

補足(「自動的に動作が変わる」ことの怖さ): 本ページの内容を
実務の観点で一言にすると、
**「意識していないと、環境によって動作が変わる」**という点に尽きる。

// 実行環境のカルチャに依存する(=環境で結果が変わる)
DateTime.Parse("01/02/2026")     // ja-JP: 1月2日 / en-US: 1月2日 / en-GB: 2月1日
1234.5.ToString()                // ja-JP: "1234.5" / de-DE: "1234,5"
"ABC".ToLower()                  // tr-TR: "I" が "ı" になる(トルコ問題)

**「開発機では動くのに本番で落ちる」**という不具合の
典型的な原因の一つがこれである。

原則:

用途 使うもの
ユーザーに見せる(画面表示) CurrentCulture(=そのまま)
機械可読な入出力(ファイル、DB、API、ログ) InvariantCulture
識別子の比較(キー、コード値) StringComparison.Ordinal
// 保存・通信は常に InvariantCulture(または ISO 8601)
var s = value.ToString("O", CultureInfo.InvariantCulture);
var v = decimal.Parse(s, CultureInfo.InvariantCulture);

// 識別子の比較は Ordinal(カルチャに依存させない)
if (string.Equals(code, "ADMIN", StringComparison.Ordinal)) { }

種類

アプリケーションの国際化(多言語化)に利用される Windows ロケールに
対応するカルチャには以下の 3 種類がある。

既定カルチャ(Invariant Culture)

  • 特定の言語や国・地域に依存しない特別なカルチャ
  • 英語圏で使われるものを基本とする書式・規則が設定されていて、
    特定のカルチャに依存しない形式への変換や比較を行いたい場合に使用する。

ニュートラル・カルチャ(en, ja, fr など)

  • 「日本語」などのように「<言語名>」形式で記述されたカルチャ
  • 国や地域に依存せず、言語のみに依存する。

固有カルチャ(en-US, en-GB, ja-JP, fr-FR など)

  • 「日本語 (日本)」などのように「<言語名> (<国・地域名>)」形式で記述されたカルチャ
  • 国や地域に依存する。

補足(用語の対応): 3 種類の使い分けを整理しておく。

種類 主な用途
既定(Invariant) ""(空文字列) 永続化・通信。人に見せない値
ニュートラル ja, en リソースの選択リソースファイル
固有 ja-JP, en-US 書式(日付・通貨)

**「文言は言語だけで足りるが、書式は地域まで要る」**という
非対称性が、この 2 段構えの理由である。

文言:  英語なら en で十分(米英で文言を分けることは稀)
書式:  en-US は 8/19/2026、en-GB は 19/08/2026 → 地域が要る

構造

カルチャには階層関係があり、基本的に 3 階層となっている。

既定カルチャ
 ├ja 日本語
 │└ja-JP 日本
 │
 ├en 英語
 │├en-US 米国
 │├en-GB 英国
 │├en-AU オーストラリア
 :

例外的に中国語のカルチャは 5 階層となる。
※ zh, zh-Hans, zh-CHS, zh-Hant, zh-CHT はニュートラルカルチャ

既定カルチャ
 └zh 中国語
  ├zh-Hans 簡体字中国語
  │└zh-CHS 簡体字中国語(古いカルチャ名)
  │ ├zh-CN 中国
  │ └zh-SG シンガポール
  │
  └zh-Hant 繁体字中国語
   └zh-CHT 繁体字中国語(古いカルチャ名)
    ├zh-HK 香港
    ├zh-MO マカオ
    └zh-TW 台湾

補足(この階層が「フォールバック」を決める): 階層構造は
リソースファイルフォールバックの探索順
そのものである。

CurrentUICulture = zh-TW のとき
  zh-TW → zh-Hant → zh → 既定  の順にリソースを探す

中国語が 5 階層になっているのは、
**「言語(zh)と表記体系(簡体字/繁体字)が独立している」**ためで、
中間層(zh-Hans / zh-Hant)が挟まっている。

誤: zh-CN と zh-TW でリソースを 2 つ作る
正: zh-Hans と zh-Hant でリソースを 2 つ作る
      → zh-CN / zh-SG は zh-Hans に、
        zh-TW / zh-HK / zh-MO は zh-Hant にフォールバックする

zh-CHS / zh-CHT は非推奨(原文も「古いカルチャ名」と注記)で、
新規では zh-Hans / zh-Hant を使う

Culture

  • .NET では、カルチャを指定することによって、ユーザの文化的慣習に応じた、
    「文字列」、「日付の形式」、「数値の形式」などの情報に対する
    一般的な設定のセットを使用できる。

  • カルチャには UICulture と Culture の 2 つのカルチャ値があり、
    2 つのカルチャ設定に別々の値を設定することができる。

CurrentUICulture 概要

  • UI に表示される言語に関するカルチャ、例外メッセージ等も、こちらのカルチャを使用する。
  • カルチャ固有の「リソースファイル」を検索するために
    使用されるリソース専用カルチャ。
  • 命名規則によりカルチャ毎に読み込むリソース ファイルが選択される。

サンプルコード

//CurrentUICultureの取得
System.Globalization.CultureInfo uiCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;

//CurrentUICultureの設定
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");

参考

CurrentCulture 概要

  • .NET Framework API の内部動作で使用されるスレッドのカルチャ。

  • CurrentUICulture の UI 以外のすべて(「日付の形式」、「数値の形式」など)を決定する。

  • 設定

    • .NET Framework 3.5 以前は、en-US や en-GB などの「特定カルチャ」だけ設定できる。
      ニュートラル・カルチャを設定しようとすると NotSupportedException 例外が発生する。
    • .NET 4 からはニュートラル・カルチャを設定可能になっている。
      これにより、en-US と en-GB で異なる通貨記号が使用され、
      en に使用する正しい通貨記号を識別する必要がなくなる。
  • 用途(例)

    • フォーマット

      • DateTime.ToString() の既定のフォーマット
      • 通貨の書式指定子のフォーマット
    • メソッド

      • Microsoft.VisualBasic.Strings.StrConv メソッド(全角半角変換)
        全角文字が存在しないカルチャではエラーとなる。

サンプルコード

  • 基本
//CurrentCultureの取得
System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;

//CurrentCultureの設定
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
//CurrentCultureの取得 ※Windows Forms限定
System.Globalization.CultureInfo culture = Application.CurrentCulture;

//CurrentCultureの設定 ※Windows Forms限定
Application.CurrentCulture = new System.Globalization.CultureInfo("en-US");

参考

補足(現在は CultureInfo の静的プロパティを使う): Thread.CurrentThread
経由の書き方は動作するが、現在は
CultureInfo.CurrentCulture を使うのが標準である。

CultureInfo.CurrentCulture   = new CultureInfo("en-US");
CultureInfo.CurrentUICulture = new CultureInfo("en");

// アプリ全体の既定(.NET 4.5+)— 新規スレッドにも継承される
CultureInfo.DefaultThreadCurrentCulture   = new CultureInfo("ja-JP");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("ja");

DefaultThreadCurrent* が後述のスレッド問題の解決策である。

動作まとめ

デフォルト値

何も設定せずにアプリケーションを実行した際の値は、
それぞれ以下の環境設定が使用される。

CurrentCulture

地域と言語の設定値によって決定される。

  • WindowsXP
    [コントロールパネル]-[地域と言語のオプション]-[地域オプション]タブ-[標準と形式]グループ

  • Windows7
    [コントロールパネル]-[時計、言語、および地域]-[地域と言語]-[形式]タブ-[形式]

CurrentUICulture

OS の言語バージョンによって決定される。

  • 日本語 OS の場合は、ja-JP
  • マルチ言語 OS の場合は、選択中の言語

補足(Linux / コンテナでの既定値/最新化): .NET Core 以降は
Windows 以外でも動くため、既定値の決まり方が増えている。

環境 既定のカルチャ
Windows 地域設定 / 表示言語(原文の通り)
Linux / macOS LANG / LC_ALL 環境変数(ICU 経由)
コンテナ(多くの公式イメージ) InvariantCulture(ICU が入っていない)

コンテナでの落とし穴が特に重要である。

.NET の公式イメージ(alpine 系や runtime-deps)では、
サイズ削減のため ICU が含まれないことがある
  → InvariantGlobalization モードで動く
  → ja-JP を指定しても書式が英語圏のものになる
  → 文字列の比較・並べ替えも序数比較になる
# ICU を入れる(Debian 系)
RUN apt-get update && apt-get install -y libicu-dev
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
<!-- 逆に、意図的に Invariant で動かす(サイズ・起動速度を優先) -->
<InvariantGlobalization>true</InvariantGlobalization>

InvariantGlobalization=true にすると、
new CultureInfo("ja-JP") は例外にならないが、
中身は Invariant と同じになる
(静かに壊れる)ため、
国際化が必要なアプリでは必ず ICU を入れる
.NET CoreのDockerコンテナ化)。

リッチ・クライアントのカルチャ

  • Windows Forms、WPF などの
    ウィンドウ・システム(メッセージ・ループ)を処理する
    UI サブシステムは、基本的に UI 処理を行うスレッド=1つの主スレッドである。

  • このため、モーダルダイアログ、モードレスダイアログで表示される子画面は、
    親画面と同一スレッドとなり、カルチャ値は子画面と親画面で同一となる。

ASP.NET のカルチャ

Web アプリケーション(ASP.NET, ASP.NET AJAX, Web サービス)では
config 設定にて動作の定義が可能である。
※ Windows アプリケーションに config 設定は存在しない。

既定値の設定

Web.configの globalization 要素を設定する。

  • culture 属性に CurrentCulture の既定値
  • uiCulture 属性に CurrentUICulture の既定値
<system.web>
  <globalization culture="ja-JP" uiCulture="ja-JP" />
</system.web>

※ 空文字を設定するとデフォルト値が使用される。
既定カルチャ(Invariant Culture)は定義できない。

ブラウザの言語設定の使用

culture 属性、uiCulture 属性に "auto" を定義すると、
クライアントのブラウザの言語設定の値が既定値となる。

<system.web>
  <globalization culture="auto" uiCulture="auto" />
</system.web>
  • Internet Explorer 8
    • [ツール]-[インターネットオプション]-[全般]タブ-[言語]
    • ここの設定により、HTTP ヘッダに言語情報が追加される(Accept-Language)。

※ クライアントのブラウザの言語設定がされていない(全て削除している)場合、
デフォルト値が既定値となる。
※ Request.UserLanguages プロパティ(string[] 型)にて
ブラウザの言語設定に登録されている言語を全て取得できる。
言語設定がされていない場合は、null 値となる。

参考

補足(ASP.NET Core での設定): <globalization> は無く、
RequestLocalizationMiddleware が同じ役割を担う
ASP.NET の 国際化対応 の補足を参照)。

app.UseRequestLocalization(new RequestLocalizationOptions()
    .SetDefaultCulture("ja-JP")
    .AddSupportedCultures("ja-JP", "en-US")     // ← CurrentCulture
    .AddSupportedUICultures("ja", "en"));       // ← CurrentUICulture

AddSupportedCultures に無いカルチャは既定値に落ちる
(ホワイトリスト方式)ため、
「対応していない言語で表示が崩れる」ことを防げる。
auto 相当の挙動は AcceptLanguageHeaderRequestCultureProvider が担う。

作成されたスレッドのカルチャ

新しく作成されたスレッドのカルチャはデフォルト値となる。
Web.configの設定は適用されない。

サンプルコード
  • 基本
public void Method1()
{
    System.Threading.Thread th = new System.Threading.Thread(StaticMethod1);
    th.Start();
}

public static void StaticMethod1()
{
    Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture.ToString());     // → デフォルト値
    Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString());   // → デフォルト値
}
  • 新しく作成されたスレッドにカルチャを設定する
public void Method1()
{
    System.Threading.Thread th = new System.Threading.Thread(StaticMethod1);
    th.CurrentCulture   = System.Threading.Thread.CurrentThread.CurrentCulture;    // ← 作成したスレッドにカルチャ値をコピー
    th.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;  // ← 作成したスレッドにカルチャ値をコピー
    th.Start();
}

public static void StaticMethod1()
{
    Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture.ToString());     // → 親カルチャと同じ値
    Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString());   // → 親カルチャと同じ値
}

移行メモ(誤記): 原文のサンプルには次の誤りがあり、
C# として成立しないため修正した。

  • public sub Method1() … VB の構文が混在(public void
  • th,Start() … カンマとピリオドの誤り(th.Start();
  • public static StaticMethod1() … 戻り値の型が無い(static void
  • th.CurrentCulture に 2 回とも CurrentCulture を代入していた
    → 2 行目は th.CurrentUICulture = ...CurrentUICulture が正しい

並列処理のカルチャ

  • Parallel.For、Parallel.Invoke を利用した並列処理では、
    本体スレッドによる処理と別スレッドによる処理が混在する。

  • 別スレッドのカルチャはデフォルト値となる。
    Web.configの設定は適用されない。

サンプルコード
  • 基本
System.Threading.Tasks.Parallel.For(0, 5, i =>
    {
        Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture.ToString());     // → 別スレッドで実行される場合はデフォルト値
        Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString());   // → 別スレッドで実行される場合はデフォルト値
    });
  • 別スレッドにカルチャを設定する
System.Globalization.CultureInfo culture   = System.Threading.Thread.CurrentThread.CurrentCulture;     // ← 本体スレッドのカルチャ値をコピー
System.Globalization.CultureInfo uiCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;   // ← 本体スレッドのカルチャ値をコピー

System.Threading.Tasks.Parallel.For(0, 5, i =>
    {
        System.Threading.Thread.CurrentThread.CurrentCulture   = culture;     // ← コピーしたカルチャを設定
        System.Threading.Thread.CurrentThread.CurrentUICulture = uiCulture;   // ← コピーしたカルチャを設定

        Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture.ToString());     // → 本体スレッドと同じカルチャ
        Debug.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString());   // → 本体スレッドと同じカルチャ
    });
参考

補足(.NET 4.5 以降は引き継がれる/最新化): この 2 節が扱う
**「新しいスレッドではカルチャが既定値に戻る」**という問題は、
.NET Framework 4.5 で改善されている

新規スレッド / Task のカルチャ
〜.NET 4.0 既定値に戻る(本ページの記述)
.NET 4.5 以降 DefaultThreadCurrent* で既定を設定できる
.NET Framework 4.6 以降 / .NET Core CurrentCulture が非同期の流れで引き継がれる
// アプリ起動時に 1 度だけ書けば、以降のスレッド・Task に継承される
CultureInfo.DefaultThreadCurrentCulture   = new CultureInfo("ja-JP");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("ja");

.NET Framework 4.6 以降では CurrentCulture
AsyncLocal 相当の仕組みで保持される
ようになったため、
async/await をまたいでも引き継がれる

CultureInfo.CurrentCulture = new CultureInfo("en-US");
await Task.Run(() => Console.WriteLine(CultureInfo.CurrentCulture));
//  .NET 4.6+ / .NET Core → en-US(引き継がれる)
//  .NET 4.5 以前          → 既定値

ただし、明示的に new Thread(...) した場合は引き継がれない
(原文のサンプルの通り、手でコピーが要る)。

ASP.NET Core では RequestLocalizationMiddleware
リクエストごとに設定する
ため、
アプリ コード側で意識する必要はほぼ無い。

参考

Microsoft Learn


Tags: 移行, .NET開発, 国際化対応

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally