約 2 年ぶりの BlogEngine.NET 2.0 の不具合修正の話です。
BlogEngine は国際化対応がされていて、ブラウザの言語指定に応じてリソースファイルの自動切り替えが行われ、ラベルに表示される文字列の言語が変わります。
例えばブラウザが IE の場合、言語の優先順位の設定を下の画像のように日本語を最優先にしておくと、アプリケーションルート直下の App_GlobalResources フォルダにある日本語のリソースファイル labels.ja.resx からラベルに表示する文字列を取得して設定します。
(詳しい仕組みに興味がありましたら、別の記事 aspx ページでのリソースの利用 を見てください)
ところが、ブログ2で使用している BlogEngine.NET 2.0 の場合、レーティングや APML フィルターのラベルの国際化対応にバグがあるらしく、下の画像で赤枠で囲った部分のように英文になってしまいます。(ちなみに、ブログ1で使用している BlogEngine.NET 1.6.1 の場合はこの問題ありません)
ブログ2開設当時からこの問題には気づいていたのですが、原因を探すのが面倒だったし、致命的な問題ではないので放置してきました。(汗)
何年も放置しておいて今さらなんですが、やっぱり気になるので修正しました。ブラウザの言語設定が日本語になっていれば、レーティングのラベル部分も日本語で表示されているはずです。ブラウザの設定で英語とかフランス語を最上位に持ってくれば、その言語で表示されるはずです。
どこが問題だったか、どのように修正したかを以下に備忘録として書いておきます。
最初は App_GlobalResources フォルダにあるリソースファイルの問題かと思っていましたが、リソースファイルはこの問題のないバージョン 1.6.1 のものと同じでした。ということは、リソースを取得する方法に問題があるということになります。
レーティングの表示は、バージョン 1.6.1, 2.0 いずれも blog.js という名前の外部スクリプトファイルを読み込んで、その中の showRating, applyRatings というメソッドで html ソースを生成しています。
その際、ラベルに表示する文字列は、BlogEngine.i18n.beTheFirstToRate とか BlogEngine.i18n.currentlyRated という変数に定義されます。この定義の仕方がバージョン 1.6.1 と 2.0 とでは異なっています。
バージョン 1.6 では BlogBasePage クラスに AddLocalizationKeys というメソッドがあり、これにより BlogEngine.i18n.beTheFirstToRate 等の変数定義をインラインでページに書き込んでいます。書き込む際、GetGlobalResourceObject メソッドを利用して、ブラウザの言語設定に従って自動的に正しいリソースファイルを選択して文字列を取得しているので、正しい言語の文字列が変数に設定されます。
バージョン 2.0 ではこの部分が異なっていて、1.6.1 のようにページに変数定義をインラインで埋め込むのではなく、BlogBasePage クラスの Utils.AddJavaScriptResourcesToPage(this); によって、以下のような外部スクリプトファイルとして定義されます。(キャッシュを利用できるようにするため)
<script
type="text/javascript"
src="http://surferonwww.info/BlogEngine2/res.axd?lang=en-gb">
</script>
問題は、上記 src 属性に設定される url のクエリ文字列 lang=en-gb です。この en-gb は BlogSettings.Instance.Language から取得していますが、ブラウザの言語設定に関係なく常に "en-GB" になってしまいます。
HTTP ハンドラ res.axd(ResourceHandler.cs に定義されている)はクエリ文字列を見て、これに該当するリソースファイルから文字列を取得します。クエリ文字列は常に lang=en-gb なので、レーティング等に表示されるラベルは常に英語になってしまいます。
修正は AddJavaScriptResourcesToPage メソッドで BlogSettings.Instance.Language を使用せず、Thread.CurrentUICulture プロパティで現在のカルチャを取得して設定するようにしました。
具体的には以下の通りです。
Utils.cs の AddJavaScriptResourcesToPage メソッド
public static void AddJavaScriptResourcesToPage(Page page)
{
// BlogSettings.Instance.Language は "en-GB" になってしまい、
// ブラウザの言語設定が反映されない。結果レーティング等に表示
// される文字列が英語で固定となってしまう。
// var resourcePath =
// Web.HttpHandlers.ResourceHandler.GetScriptPath(
// new CultureInfo(BlogSettings.Instance.Language));
// それを以下のように修正:
CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentUICulture;
string resourcePath =
Web.HttpHandlers.ResourceHandler.GetScriptPath(ci);
var script = string.Format(
"<script type=\"text/javascript\" src=\"{0}\"></script>",
resourcePath);
page.ClientScript.RegisterStartupScript(
page.GetType(),
resourcePath.GetHashCode().ToString(),
script);
}
その他、この修正に伴って、日本語にすると AMPL の入力窓の幅が不足して表示が崩れる問題が出ましたので、blog.js の filterByAPML: function () の中の div.style.width = '400px'; を 450px に変更しました。(マイナーな問題ですが忘れないように書いておきます)