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にしておけばよい、という確認まで。

2021/01/28

Dellモニタースタンドの限界突破(下方向)

Dell U2415をサブモニターとして使っていますが、設置場所の関係でやや高い位置に置かざるを得ず、モニタースタンドの下限一杯にしてもモニターの位置が視線の高さに対して高くなるという問題がありました。

こういう場合の解決策としてモニターアームの使用が考えられますが、あれはあれで設置に手がかかり、かつ位置調整も全く融通無碍にできるわけではありません。そこでモニタースタンドの改造で何とかできないかと検討。

スタンドのモニターとの接続部のプレートを一旦取り外し、カバーを外して取り付け直したところ。

この左右の端の中央の高さにある横長の穴は、カバーのダボがはまっていた部分で、組み立て時の位置決め用と推測しますが、もしかしてこれにVESAマウントのネジを通せないかと思い付き、穴の間の距離を測ったところ、ネジの中心になる位置の間で101mm。VESAマウントは100mmなので、微妙に合いません。

穴をそれぞれ内側に削る手もなくはないですが、このスチールのプレートを手作業で加工するのは率直に言って苦行。どうしたものかと手持ちの金具を漁っていたら、ピカーンと。

モニターのVESAマウントのネジ穴に黒いクランク型の金具を少し傾けて取り付けることで、ネジ位置をスタンドのプレートの穴に合わせることができると。いずれにせよスペーサーが必要だったので、一石二鳥。何かの用に使おうと買ったまま長らく死蔵していたものですが、まさか役に立つ日が来ようとは、「こんなこともあろうかと」が本当にあるとは、自分でも少々びっくり。

とりあえずスタンドに取り付けてみたところ。横2点だけの固定なので縦の揺れはあるものの、厚みのあるスチールの金具なので、それ自体の強度には問題なさそう。

まあ大丈夫そうなので、根本のカバーを戻し、プレートの下型の爪の部分にゴムを挟んで揺れ止めにして、一応の完成。

この結果、モニターの位置を大きく4cm弱下げることに成功(スタンドの台座との隙間は8mm)。このスタンドのプレートの穴はU2720QMのスタンドにもあったので、Dellのモニターで割と汎用的に使えるテクではないかと思います。あくまで緊急避難的なものですが。