2021/01/31

階層的なロケール

.NETアプリではリソースファイル(.resx)をロケールごとに用意しておけば、実行時にユーザーの表示言語に合ったリソースが自動的に選択されます。ロケールは基本的に[言語名]-[地域名]の構成ですが、中国語だけはこれが簡体字と繁体字のために階層的になっているので、確認してみました。

各ロケールのCultureInfoのParentプロパティを辿るとInvariantCultureに辿り着きますが、その一つ前までをまとめてMarkdownの表を生成するコードが以下のとおり。
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
static string CreateLocaleTable(string cultureName)
{
var paths = CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => x.Name.StartsWith(cultureName))
.Select(x => (culture: x, path: GetParent(x)))
.ToArray();
var length = paths.Max(x => x.path.Length);
var lines = new StringBuilder()
.AppendLine(string.Join("|", Enumerable.Repeat("<--", length - 1).Prepend(null).Prepend(null).Append(null).Append(null)))
.AppendLine(string.Join("|", Enumerable.Repeat("---", length + 1).Prepend(null).Append(null)));
var buffer = paths.Select(x => (x.culture, path: x.path.Concat(new CultureInfo[length - 1]).Take(length).ToArray()))
.OrderBy(x => x.path[0].Name);
for (int i = 1; i < length; i++)
{
int index = i;
buffer = buffer.ThenBy(x => x.path[index]?.Name);
}
foreach (var (culture, path) in buffer)
{
lines.AppendLine(string.Join("|", path.Select(x => x?.Name).Append(culture.DisplayName).Prepend(null).Append(null)));
}
return lines.ToString();
static CultureInfo[] GetParent(CultureInfo c, List<CultureInfo> list = null)
{
list ??= new List<CultureInfo>();
list.Insert(0, c);
return (c.Parent == CultureInfo.InvariantCulture)
? list.ToArray()
: GetParent(c.Parent, list);
}
}
view raw Program.cs hosted with ❤ by GitHub
これを.NET Framework 4.8の上で実行した結果。
<-- <-- <--
zh 中国語
zh zh-Hans 簡体字中国語
zh zh-Hans zh-CHS 簡体字中国語レガシ
zh zh-Hans zh-CHS zh-CN 中国語 (簡体字、中国)
zh zh-Hans zh-CHS zh-Hans-HK 中国語 (簡体字、香港特別行政区)
zh zh-Hans zh-CHS zh-Hans-MO 中国語 (簡体字、マカオ SAR)
zh zh-Hans zh-CHS zh-SG 中国語 (簡体字、シンガポール)
zh zh-Hant 繁体字中国語
zh zh-Hant zh-CHT 繁体字中国語レガシ
zh zh-Hant zh-CHT zh-HK 中国語 (繁体字、香港)
zh zh-Hant zh-CHT zh-MO 中国語 (繁体字、マカオ)
zh zh-Hant zh-CHT zh-TW 中国語 (繁体字、台湾)
view raw zh_locale.md hosted with ❤ by GitHub
自動選択では表示言語と同じリソースがあればそれが、なければ上に辿って存在するリソースが選択されるはずなので、簡体字の場合、表示言語がzh-CN(中国本土)のときはzh-CNのリソースがあればそれが、なければ(zh-CHSは古いものなのでスルーするとして)zh-Hansのリソースがあればそれが選択されることになります。ここで、簡体字なのは中国本土だけだろうと思っていたら、実はシンガポールも簡体字を使っていて、リソースをzh-CNで作成すると表示言語がzh-SGのときには選択されません。

同じように、繁体字の場合、表示言語がzh-TW(台湾)のときはzh-TWのリソースがあればそれが、なければ(zh-CHTはスルーするとして)zh-Hantが存在すればそれが選択されますが、リソースをzh-TWで作成すると香港かマカオで表示言語に繁体字を使っているときには選択されないことになります。

したがって、簡体字のリソースはzh-Hansで、簡体字のリソースはzh-Hantで作成するのが正解で、もし分ける必要が出てきた場合に、その下のロケールで該当部分を上書きすればいいわけです。

念のため、.NET 5.0の上で実行した結果。
<-- <--
zh 中国語
zh zh-Hans 中国語 (簡体字)
zh zh-Hans zh-CN 中国語 (中国)
zh zh-Hans zh-Hans-HK 中文(简体,香港特别行政区)
zh zh-Hans zh-Hans-MO 中文(简体,澳门特别行政区)
zh zh-Hans zh-SG 中国語 (シンガポール)
zh zh-Hant 中国語 (繁体字)
zh zh-Hant zh-HK 中国語 (中華人民共和国香港特別行政区)
zh zh-Hant zh-MO 中国語 (中華人民共和国マカオ特別行政区)
zh zh-Hant zh-TW 中国語 (台湾)
view raw zh_locale.md hosted with ❤ by GitHub
これも古いzh-CHSとzh-CHTが消えた以外は同じですが、説明に簡体字か繁体字か明記していないのが不親切。

以上、中国語のロケールはそれぞれzh-Hansかzh-Hantにしておけばよい、という確認まで。

0 コメント :