WPFの文字列リソース(resx)をそのままUWPとXamarin.Formsで共有したおはなし

あすかです。

UWPで国際化(ローカライズ)というと、すでに先人が記事をかかれているとおり、いろいろな方法があります。

aile.hatenablog.com

これ見てる限り、リソース名は「なんとか.Text」だとか「あーだこーだ.Content」だとか、「ユニーク名+プロパティ名」という形で指定するようですね。

f:id:kmynews:20170625095632p:plain

これによって、テキストだけでなく、その他の、なんかの数値や色とかも国際化することができるみたいです。
中国は赤!ロジアは赤!イギリスは黄色!うーん、ロマンチックですね。

ところで、WPFで国際化するときの方法を見てみます。

grabacr.net

WPFは、UWPと違ってプロパティ名を指定する必要が無いみたいですね。
みんなそうしてますよね、仕方ないですね。

なお、Xamarin.Formsのローカライズでも、PCLプロジェクトに「AppResources.resx」「AppResources.ja.resx」を作ります。ここはWPFと似ていますね。

UWPでも今までのresxを使いたいんじゃ

さて、ここに、WPFで作ったアプリのリソースファイルがあります。
アプリをWPFからUWPに乗り換えることになりました、さて、これはどうすればいいんでしょうか。

f:id:kmynews:20170625095737p:plain

いちいち全項目に「Text」ってつけるんでしょうか。
しかも、TextBlockは「Text」プロパティでいいんですけど、ContentDialogは「PrimaryButtonText」とかですよね。
いちいち直してたら時間かかること間違いなしです。

もちろん、本気でやるならUWPの仕様にあわせるべきですが、こんなのいちいちやってらんねー!ということで、調べました。

WPFと同じ感じで書けない?

ということで、やってみました。

f:id:kmynews:20170625101842p:plain

なんか波線が出てますが気にせずコンパイル

f:id:kmynews:20170625101907p:plain

(^ω^)
(^ω^)ペロペロ

グギー!!!!!!

このほかにもStaticResourcelocal:Resources.String1のように直書きしたりもしましたが全てうまくいかず。

マークアップ拡張を自作?

UWPで決められた方法以外の国際化を、しかもXAML上で使うためには、自分でXAMLの機能を拡張しなければいけません。
まず、UWPにマークアップ拡張の独自定義機能が存在するか?WPFやXamarin.Formsではできるんですよね。

ところがどっこい‥‥‥‥
夢じゃありません‥‥‥‥!

UWPのマークアップ拡張は自作できません。

現実です‥‥‥!これが現実‥!

かといってビヘイビアとかで指定すると、XAMLが冗長になってしまいます。
なんとしても、WPFみたいに「<Label Content="{p:Resources.Greeting}">」みたいな感じで、お手軽に指定したいんです。

CustomResource

次に目をつけたのが、CustomResourceです。

docs.microsoft.com

マークアップ拡張を自作できないなら、やっぱりこういうものに頼るしかないです。

この手法は比較的高度なものであり、Windows ランタイム アプリのほとんどのシナリオでは使われていません。

とか書いていますが、無視して使ってみます。

まず、CustomXamlResourceLoaderを継承したクラスを1つ作り、GetResourceメソッドをオーバーライトします。
リフレクションを使っています。System.Reflection名前空間を使います。

作りましたね?作りました!さて、次にApp.xaml.csを開いて、Appクラスのコンストラクタの最初に一行追加します。

はい、これだけです。
次に、XAMLでCustomResourceを呼び出します。

これを実行してみます。

f:id:kmynews:20170625103616p:plain

うまくいきました。

まとめ

CustomResourceは、ひとつのアプリで1種類しか指定できないんですよね。
なので、これからまた別の需要が出てきたら、そのときはどうしようかなって不安もあります。
うーん、マークアップ拡張、自作できるようになってほしい!!