読者です 読者をやめる 読者になる 読者になる

銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

ASP.NET Core でローカライズする場合のリソースファイル名について

ASP.NET Coreのローカライズする際のリソースファイル名についてこのドキュメントを読んで気になったことがあったのでまとめました。

Globalization and localization | Microsoft Docs

ローカライズそのものについてはこのドキュメントを参考にしてください。また、ローカライズに必要なNuGetパッケージですが、MVCの機能を使うためにMicrosoft.AspNetCore.Mvcを追加している場合は、依存しているMicrosoft.AspNetCore.Mvc.Localizationとさらにこれが依存しているMicrosoft.AspNetCore.Localizationがインストールされるので特に追加は不要です。MVCを使わずにローカライズしたい場合はMicrosoft.AspNetCore.Localizationが必要です。

はじめに

ASP.NET Coreでローカライズする場合、IStringLocalizer<T>IHtmlLocalizer<T>を指定してDIでローカライザーを注入します。この時、クラスTごろにリソースファイルを準備します。Viewの場合はIViewLocalizer、ViewModelの場合は特に指定は不要ですが、クラスごとにリソースファイルを準備するのは同じです。さて、このクラスTごとにリソースファイルを準備する際に、ファイル名が規約で決まっており規約に従っていないと正しく読み込めません。ここで少しはまったので説明します。

起点フォルダ

まず、リソースファイル名を置く起点となるフォルダですが、これはStartup.csResourcesPathに指定したフォルダ名になります。これは空白でも可能でその場合はプロジェクトのルートフォルダと同一になります。以下の説明では下記のコードの通り "Resources" を指定しているものとします。

public void ConfigureServices(IServiceCollection services)
{
    //省略
    services.AddLocalization(options => 
    {
        options.ResourcesPath = "Resources";
    });
    //省略
}
ファイル名とアセンブリ名とクラス名と

そしてここを起点としたリソースファイルのファイルパスですが、これがリソースを指定するクラスTのクラス名が、アセンブリ名で始まっているか否かで分かれます。

どういうことかといいますと、例えばdotnet new -t webでASP.Core MVCプロジェクトを作成するとまずアセンブリ名はプロジェクトを作成したフォルダ名と一致します。これはproject.jsonにnameプロパティが指定されていないため、フォルダ名が利用されるためです*1

docs.microsoft.com

しかし、デフォルトの名前空間はWebApplicationで固定であるため、クラス名がアセンブル名で始まらないケースになってしまいます。一方、Visual StudioでASP.NET Coreプロジェクトを作成するとデフォルトではプロジェクト名がアセンブル名かつデフォルトの名前空間になるので、デフォルトの名前空間以外の名前空間にわざわざクラスを作らない限りは同じになります。

クラスTのFQDNがアセンブル名で始まる場合

例として、アセンブリ名がAspNetCore.StarterWebだとして、リソースを作りたいクラスがAspNetCore.StarterWeb.Controllers.HomeControllerでjaロケールのリソースを作りたいとしましょう。この場合リソースファイルはプロジェクトのルートから見て、Resources\Controllers\Homecontroller.ja.resxもしくはResources\Controllers.Homecontroller.ja.resxとなります。Resources以下を.区切りにしてフラットに配置するか\でフォルダ階層を切って配置するかはどちらでもよく、1つのプロジェクトで混在させることも可能です。つまり、クラスTのFQDNからアセンブリ名を省略した名前となります。これは省略できるではなく省略しないといけません

クラスTのFQDNがアセンブル名で始まらない場合

例として、アセンブリ名がAspNetCore.StarterWebだとして、リソースを作りたいクラスがWebApplication.Controllers.HomeControllerでjaロケールのリソースを作りたいとします。この場合はFQDNを省略できなく、Resources\WebApplication\Controllers\Homecontroller.ja.resxもしくはResources\WebApplication.Controllers.Homecontroller.ja.resxとなります。

まとめ
  • .NET Coreのアセンブリ名はproject.jsonのnameプロパティの値が使われる。指定していない場合はプロジェクトのルートフォルダのフォルダ名。
  • ASP.NET Coreのリソースファイルの名前は、クラスのFQDNがアセンブリ名で始まっている場合はアセンブリ名を省略する
  • そうでない場合は省略しない

ドキュメントがちょっとわかりにくいなあということでissueを投げているので、そのうち改善すると思われます。

github.com

*1:そのためフォルダ名に空白が入っていたりするとデバッグ実行のパス指定がデフォルトでは動かなくなったりと何かと面倒