Skip to content

多言語の言語定義を設定ファイルで管理する(改修案) ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

本体の標準機能ではありません

このページは本体を改修する場合の設計メモです。前提にした現行の実装は 1.5.8.1 です。

プリザンターの 7 言語(en・zh・ja・de・ko・es・vn)は、表示文字列の Display JSON こそ Languages 配列で言語を増やせる形ですが、それ以外はソースのあちこちに言語コードが固定で書かれています。新しい言語を足すにはコードの変更と CodeDefiner の実行が要ります。ここでは言語の定義を 1 つの JSON にまとめ、ファイルの追加だけで言語を足せるようにする改修を、段階を分けて整理します。

現行の仕組み(Display JSON・DisplayHash・言語の決まり方)は 多言語対応の実装 を参照してください。

現行で言語コードが固定されている箇所 ​

図を読み込み中…

根本は、カラム定義の言語別ラベルが LabelText_en・LabelText_zh のように言語コードをプロパティ名に含む形になっていることです。言語を足すことがスキーマ(プロパティ)の追加になり、Def.cs の再生成と Initializer.cs の手修正が連鎖します。各箇所のファイルと行は 多言語対応の実装の「実践的なポイント」 にまとめています。

改修の方針 ​

方針内容
言語の定義を 1 か所に対応言語の一覧を 1 つの JSON で持ち、すべてのコードがそれを見る
プロパティ名から言語を外すLabelText_xx の固定プロパティをやめ、Dictionary<string, string> にする
フォールバックをそろえる見つからなければ英語 → DefaultLanguage の順
Display JSON はそのままApp_Data/Displays/*.json の Languages 配列は今の形を使う

Languages.json ​

App_Data/Parameters/Languages.json を新設します。

json
{
    "Languages": [
        {
            "Code": "en",
            "Name": "English",
            "CultureInfo": "en-US",
            "AcceptLanguageMapping": ["en"],
            "CurrencySymbol": "$",
            "CurrencyPattern": "prefix",
            "DateFormat": "M/d/Y",
            "DatePickerLocale": null,
            "Default": true
        },
        {
            "Code": "ja",
            "Name": "Japanese",
            "CultureInfo": "ja-JP",
            "AcceptLanguageMapping": ["ja"],
            "CurrencySymbol": "¥",
            "CurrencyPattern": "prefix",
            "DateFormat": "Y/m/d",
            "DatePickerLocale": "ja"
        },
        {
            "Code": "vn",
            "Name": "Vietnamese",
            "CultureInfo": "vi-VN",
            "AcceptLanguageMapping": ["vi", "vn"],
            "CurrencySymbol": "₫",
            "CurrencyPattern": "suffix",
            "DateFormat": "d/m/Y"
        }
    ]
}

(zh・de・ko・es も同じ形で並べます。)AcceptLanguageMapping に vi を入れておけば、今 switch で書いている vi → vn の変換も設定で表せます。

段階ごとの改修 ​

Phase 1: サーバー側の言語設定をまとめる ​

対象今改修後
ParameterAccessor/Parts/Languages.cs(新規)なしLanguages.json を読むクラス
ParameterAccessor/Parameters.csなしParameters.Languages を足す
Context.SessionLanguage()switch で 6 言語と vi → vnAcceptLanguageMapping から作った辞書で引く
Context.CultureInfoCurrency()switch で 7 言語CultureInfo フィールドから作る
MultilingualLabelExportImportSupportedLanguages の固定リストParameters.Languages から作る
Initializer.SetLanguage()フォールバックの "en" が固定Default: true の言語を使う
csharp
// SessionLanguage() の Accept-Language 判定の置き換えイメージ
private static Dictionary<string, string> acceptLanguageMap;

private static Dictionary<string, string> AcceptLanguageMap
    => acceptLanguageMap ??= Parameters.Languages.Languages
        .SelectMany(l => l.AcceptLanguageMapping
            .Select(m => new { Key = m, Value = l.Code }))
        .ToDictionary(x => x.Key, x => x.Value);

// ...
var lang = HttpAcceptLanguage()?.Split_1st('-');
language = lang != null && AcceptLanguageMap.TryGetValue(lang, out var mapped)
    ? mapped
    : Parameters.Service?.DefaultLanguage;

Phase 1 だけでも、Context と CSV の言語一覧の固定は外れます。ただしカラムのラベルは LabelText_xx のままなので、表示文字列(Display JSON)は新しい言語にできても、テーブルの項目名の新しい言語にはまだコードの変更が要ります。

Phase 2: カラム定義を辞書にする ​

対象今改修後
__ColumnSettings.jsonLabelText_en 〜 LabelText_vn を個別に定義LabelTexts(Dictionary<string, string>)
Def.cs の ColumnDefinitionLabelText_xx フィールドLabelTexts にまとめる
Initializer.SetDisplayAccessor()7 言語の匿名型を手で組むLabelTexts を回して DisplayElement を作る
Definition_Column/*.jsonLabelText_xx プロパティ"LabelTexts": { "ja": "言語", "en": "Language" } に移行
Displays_Body.txt"_ja" を固定Parameters.Languages から生成
CodeDefiner のテンプレート固定フィールド前提辞書前提の生成に変える
json
{
    "Id": "Users_Language",
    "LabelTexts": {
        "ja": "言語",
        "en": "Language",
        "zh": "语言",
        "de": "Sprache",
        "ko": "언어",
        "es": "Idioma",
        "vn": "Ngôn ngữ"
    }
}

影響範囲がとても大きいので、LabelText_xx → LabelTexts の移行ツールを用意し、しばらくは両方を読めるようにします。

Phase 3: フロントエンド ​

対象今改修後
validator.js通貨の書式が switchページに埋め込んだ言語設定から組み立てる
jqueryui.jscase 'ja' だけ日時ピッカーを日本語化DatePickerLocale を使う
ページ言語は hidden の #Language だけLanguages.json の通貨・日付の設定を JSON で埋め込む

改修後に言語を足す手順 ​

図を読み込み中…

Display JSON を言語単位のファイルにするか ​

1.5.8.1 の App_Data/Displays/ は 1 表示文字列 1 ファイルで、1,353 ファイルあります。言語を足すたびに全ファイルを書き換えることになるため、言語ごとのファイルにする案も比べます。

text
App_Data/Displays/
├── _meta.json     ← Id ごとの Type・ClientScript
├── en.json        ← { "Add": "Add", "Cancel": "Cancel", ... }
├── ja.json        ← { "Add": "追加", "Cancel": "キャンセル", ... }
└── ...
観点ID 単位(現行)言語単位
ファイル数約 1,350言語数 + 1
新しい言語の追加全ファイルに要素を足すファイルを 1 つ足す
新しい表示文字列の追加ファイルを 1 つ足す全言語のファイルとメタを直す
Git での競合起きにくい(ID ごとに別ファイル)起きやすい(同じ言語ファイルに集中)
訳の抜け漏れ確認全ファイルを走査en.json と対象言語のキーを比べる
翻訳ツールとの連携しにくいしやすい
起動時の読み込みファイルを約 1,350 回開く言語数 + 1 回
改修の要否不要Initializer.DisplayHash() の読み込みを変える

両方の良さを取るなら、ベースの訳は言語単位(languages/{言語コード}.json)で持ち、ID 単位のファイル(overrides/*.json)で個別に上書きできるハイブリッドにします。読み込みは「言語ファイル → 上書きファイル → _meta.json で Type・ClientScript を付ける」の順です。Phase 1〜3 の Languages.json と組み合わせれば、言語の追加は Languages.json への追記と言語ファイル 1 つの追加で済みます。

どれを選ぶかの目安は次のとおりです。

重視すること向く方式
言語の追加・翻訳者との作業言語単位かハイブリッド
表示文字列の追加・削除が多い、CodeDefiner の改修を減らしたいID 単位(現行のまま)
起動の速さ言語単位
既存の運用との互換ハイブリッド

関連ページ ​

変更履歴

第1版拡張ライブラリの読み込みと開発・デバッグ、拡張ヘッドリンク、SMTP の OAuth 送信の解説と、多言語・外部公開カレンダー・スレッド型サイトなどの改修・設計メモを追加