UI とアプリ パッケージ マニフェスト内の文字列をローカライズする
アプリのローカライズの価値提案の詳細については、「グローバリゼーションとローカライズ」 を参照してください。
アプリで複数の表示言語をサポートする必要があり、コード、XAML マークアップ、アプリ パッケージ マニフェスト内に文字列リテラルが含まれている場合は、その文字列をリソース ファイル (.resw) に移動します。 アプリでサポートする各言語用に、このリソース ファイルを翻訳したコピーを作成することができます。
ハードコーディングされた文字列リテラルは、命令型コードまたは XAML マークアップ (TextBlock の Text プロパティなど) で表示できます。 また、アプリ パッケージ マニフェスト ソース ファイル (Package.appxmanifest
ファイル) に、たとえば Visual Studio マニフェスト デザイナーの [アプリケーション] タブの [表示名] の値として表示することもできます。 これらの文字列をリソース ファイル (.resw) に移動し、アプリとマニフェスト内のハードコーディングされた文字列リテラルをリソース識別子への参照に置き換えます。
1 つのイメージ リソース ファイルに 1 つのイメージ リソースのみが含まれるイメージ リソースとは異なり、複数の文字列リソースが文字列リソース ファイルに含まれています。 文字列リソース ファイルはリソース ファイル (.resw) であり、通常、この種のリソース ファイルはプロジェクトの \Strings フォルダーに作成します。 リソース ファイル (.resw) の名前で修飾子を使用する方法の背景については、「言語、スケール、その他の修飾子に合わせてリソースを調整する」を参照してください。
リソース ファイルに文字列を格納する
アプリのデフォルト言語を設定します。
- Visual Studio でソリューションを開いた状態で、
Package.appxmanifest
を開きます。 - [アプリケーション] タブで、[既定の言語] が適切に設定されていることを確認します (たとえば、"en" や "en-US")。 残りの手順では、既定の言語を "en-US" に設定していることを前提としています。
Note
少なくとも、この既定の言語にローカライズされた文字列リソースを提供する必要があります。 これらは、ユーザーの優先言語または表示言語設定に一致するものが見つからない場合に読み込まれるリソースです。
- Visual Studio でソリューションを開いた状態で、
既定の言語のリソース ファイル (.resw) を作成します。
- プロジェクト ノードで、新しいフォルダーを作成し、
Strings
という名前を付けます。 Strings
の下に新しいサブフォルダーを作成し、en-US
の名前を付けます。en-US
の下に、新しいリソース ファイル (.resw) ([新しい項目の追加] ダイアログの [XAML ファイルの種類] の下) を作成し、名前がResources.resw
であることを確認します。
Note
移植する .NET リソース ファイル (.resx) がある場合は、「XAML と UI の移植」を参照してください。
- プロジェクト ノードで、新しいフォルダーを作成し、
Resources.resw
を開き、これらの文字列リソースを追加します。Strings/en-US/Resources.resw
この例では、"Greeting" は、マークアップから参照できる文字列リソース識別子です。 識別子 "Greeting" の場合、Text プロパティには文字列が提供され、Width プロパティには文字列が提供されます。 "Greeting.Text" は、UI 要素のプロパティに対応するため、プロパティ識別子の例です。 たとえば、[名前] 列に "Greeting.Foreground" を追加し、その [値] を "Red" に設定することもできます。 "Farewell" 識別子は、単純な文字列リソース識別子です。サブプロパティはなく、後で示すように、命令型コードから読み込むことができます。 コメント欄は、翻訳者に特別な指示を与えるのに適した場所です。
この例では、"Farewell" という名前の単純な文字列リソース識別子エントリがあるため、同じ識別子に基づくプロパティ識別子も持つことはできません。 そのため、"Farewell.Text" を追加すると、
Resources.resw
のビルド時に重複エントリ エラーが発生します。リソース識別子では大文字と小文字が区別されず、リソース ファイルごとに一意である必要があります。 意味のあるリソース識別子を使用して、翻訳者に追加のコンテキストを提供してください。 また、文字列リソースが翻訳のために送信された後は、リソース識別子を変更しないでください。 ローカリゼーション チームは、リソース識別子を使用して、リソースの追加、削除、更新を追跡します。 リソース識別子の変更 ("リソース識別子のシフト" とも呼ばれる) を行うと、文字列が削除されて他の文字列が追加されたような表示状態になります。このため、リソース識別子を変更した場合は、文字列を翻訳し直す必要があります。
XAML から文字列リソース識別子を参照する
x:Uid ディレクティブを使用して、マークアップ内のコントロールまたはその他の要素を文字列リソース識別子に関連付けます。
<TextBlock x:Uid="Greeting"/>
実行時に、\Strings\en-US\Resources.resw
が読み込まれます (現時点では、プロジェクト内のリソース ファイルのみが A ファイルであるため)。 TextBlock の x:Uid ディレクティブにより、文字列リソース識別子 "Greeting" を含む Resources.resw
内のプロパティ識別子を検索するための検索が行われます。 "Greeting.Text" プロパティ識別子と "Greeting.Width" プロパティ識別子が見つかり、その値が TextBlock に適用され、マークアップでローカルに設定された値がオーバーライドされます。 "Greeting.Foreground" 値を追加すると、それも適用されます。 ただし、XAML マークアップ要素のプロパティの設定に使用されるのはプロパティ識別子のみであるため、この TextBlock で x:Uid を "Farewell" に設定しても効果はありません。 Resources.resw
は文字列リソース識別子 "Farewell" を含みますが、それに対するプロパティ識別子は含んでいません。
文字列リソース識別子を XAML 要素に割り当てる場合は、その識別子のすべてのプロパティ識別子が XAML 要素に適していることを確認してください。 たとえば、TextBlock に x:Uid="Greeting"
を設定した場合、TextBlock 型には Text プロパティがあるため、"Greeting.Text" は解決されます。 ただし、Button に x:Uid="Greeting"
を設定した場合、Button 型には Text プロパティがないため、"Greeting.Text" は実行時エラーを引き起こします。 この場合の解決策の 1 つは、"ButtonGreeting.Content" という名前のプロパティ識別子を作成し、Button に x:Uid="ButtonGreeting"
を設定することです。
リソース ファイルから Width を設定する代わりに、コントロールのサイズをコンテンツに合わせて動的に調整できるようにすることをお勧めします。
注: 添付プロパティの場合は、.resw ファイルの [名前] 列に特別な構文が必要です。 たとえば、"Greeting" 識別子の AutomationProperties.Name添付プロパティの値を設定するには、次のように [名前] 列に入力します。
Greeting.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name
コードから文字列リソース識別子を参照する
単純な文字列リソース識別子に基づいて、文字列リソースを明示的に読み込むことができます。
Note
バックグラウンド/ワーカー スレッドで実行される可能性がある GetForCurrentView メソッドの呼び出しがある場合は、その呼び出しをif (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null)
テストで保護します。 バックグラウンド/ワーカー スレッドから GetForCurrentView を呼び出すと、"CoreWindow を持たないスレッドでは <typename> を作成できない" という例外が発生します。
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
auto resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() };
myXAMLTextBlockElement().Text(resourceLoader.GetString(L"Farewell"));
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
this->myXAMLTextBlockElement->Text = resourceLoader->GetString("Farewell");
クラス ライブラリ (ユニバーサル Windows) または Windows ランタイム ライブラリ (ユニバーサル Windows) プロジェクト内から、この同じコードを使用できます。 実行時に、ライブラリをホストしているアプリのリソースが読み込まれます。 ライブラリは、アプリのローカライズの度合いが高い可能性が高いため、ライブラリをホストするアプリからリソースを読み込むことをお勧めします。 ライブラリがリソースを提供する必要がある場合は、それらのリソースを入力として置き換えるオプションをホスティング アプリに提供する必要があります。
リソース名がセグメントに分かれている ("." 文字が含まれる) 場合は、リソース名のドットをスラッシュ ("/") 文字に置き換えます。 たとえば、プロパティ識別子にはドットが含まれています。したがって、コードからそれらの1つをロードするには、この置換を行う必要があります。
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Fare/Well"); // <data name="Fare.Well" ...> ...
わからない場合は、MakePri.exe を使用してアプリの PRI ファイルをダンプできます。 各リソースの uri
が、ダンプされたファイルで示されています。
<ResourceMapSubtree name="Fare"><NamedResource name="Well" uri="ms-resource://<GUID>/Resources/Fare/Well">...
アプリ パッケージ マニフェストの文字列リソース識別子を参照する
アプリ パッケージ マニフェスト ソース ファイル (
Package.appxmanifest
ファイル) を開きます。既定では、アプリのDisplay name
は文字列リテラルで表されます。この文字列のローカライズ可能なバージョンを作成するには、
Resources.resw
を開き、名前が "AppDisplayName" で値が "Adventure Works Cycles" の新しい文字列リソースを追加します。表示名の文字列リテラルを、先ほど作成した文字列リソース識別子 ("AppDisplayName") への参照に置き換えます。 これを行うには、
ms-resource
URI (Uniform Resource Identifier) スキームを使用します。ローカライズするマニフェスト内の文字列ごとに、このプロセスを繰り返します。 たとえば、アプリの短い名前 (スタート画面のアプリのタイルに表示されるように構成できます)。 ローカライズできるアプリ パッケージ マニフェスト内のすべての項目の一覧については、「ローカライズ可能なマニフェスト項目」を参照してください。
文字列リソースをローカライズする
別の言語のリソース ファイル (.resw) のコピーを作成します。
- [Strings] の下に新しいサブフォルダを作成し、Deutsch (Deutschland) の "de-DE" という名前を付けます。
注: フォルダー名には、任意 の BCP-47 言語タグを使用できます。 言語修飾子の詳細と共通言語タグの一覧については、「言語、スケール、およびその他の修飾子用にリソースを調整する」を参照してください。 Strings/de-DE
フォルダー内のStrings/en-US/Resources.resw
コピーを作成します。
- [Strings] の下に新しいサブフォルダを作成し、Deutsch (Deutschland) の "de-DE" という名前を付けます。
文字列を翻訳します。
Strings/de-DE/Resources.resw
を開き、[値] 列の値を変換します。 コメントを翻訳する必要はありません。
Strings/de-DE/Resources.resw
必要に応じて、手順 1 と 2 を繰り返して、さらに言語を作成できます。
Strings/fr-FR/Resources.resw
アプリをテストする
アプリの既定の表示言語をテストします。 その後、設定 >時刻と言語>地域と言語>言語 で表示言語を変更し、アプリを再テストできます。 UI やシェルの文字列 (タイトル バー (表示名) やタイルの短い名前など) を確認します。
注: 表示言語の設定と一致するフォルダー名が見つかった場合は、そのフォルダー内のリソース ファイルが読み込まれます。 それ以外の場合、フォールバックが行われ、アプリの既定の言語のリソースで終わります。
文字列を複数のリソースファイルに分解する
すべての文字列を 1 つのリソース ファイル (resw) に保持することも、複数のリソース ファイルにまたがってファクタリングすることもできます。 たとえば、エラー メッセージを 1 つのリソース ファイルに保持し、アプリ パッケージ マニフェスト文字列を別のリソース ファイルに保持し、UI 文字列を 3 番目のリソース ファイルに保持できます。 この場合のフォルダ構造は次のようになります。
文字列リソース識別子参照のスコープを特定のファイルに設定するには、識別子の前に /<resources-file-name>/
を追加するだけです。 次のマークアップの例では、ErrorMessages.resw
に "PasswordTooWeak.Text" という名前のリソースが含まれており、その値がエラーを記述していることを前提としています。
<TextBlock x:Uid="/ErrorMessages/PasswordTooWeak"/>
リソース ファイルの文字列リソース識別子の前に/<resources-file-name>/
を追加する必要があるのは、 Resources.resw
以外必要です。 これは、"Resources.resw" が既定のファイル名であるため、ファイル名を省略した場合に想定されます (このトピックの前の例で行ったように)。
次のコード例では、ErrorMessages.resw
に "MismatchedPasswords" という名前のリソースが含まれており、その値がエラーを記述していることを前提としています。
Note
バックグラウンド/ワーカー スレッドで実行される可能性がある GetForCurrentView メソッドの呼び出しがある場合は、その呼び出しをif (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null)
テストで保護します。 バックグラウンド/ワーカー スレッドから GetForCurrentView を呼び出すと、"CoreWindow を持たないスレッドでは < typename > を作成できない" という例外が発生します。
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("ErrorMessages");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("MismatchedPasswords");
auto resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView(L"ErrorMessages") };
myXAMLTextBlockElement().Text(resourceLoader.GetString(L"MismatchedPasswords"));
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView("ErrorMessages");
this->myXAMLTextBlockElement->Text = resourceLoader->GetString("MismatchedPasswords");
"AppDisplayName" リソースを Resources.resw
から ManifestResources.resw
に移動する場合は、アプリ パッケージ マニフェストで ms-resource:AppDisplayName
を ms-resource:/ManifestResources/AppDisplayName
に変更します。
リソース ファイル名がセグメントに分かれている ("." 文字が含まれる) 場合、参照するときは名前のドットを残します。 リソース名の場合のように、リソース名のドットをスラッシュ ("/") 文字に置き換えることはしません。
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("Err.Msgs");
わからない場合は、MakePri.exe を使用してアプリの PRI ファイルをダンプできます。 各リソースの uri
が、ダンプされたファイルで示されています。
<ResourceMapSubtree name="Err.Msgs"><NamedResource name="MismatchedPasswords" uri="ms-resource://<GUID>/Err.Msgs/MismatchedPasswords">...
特定の言語またはその他のコンテキストの文字列を読み込む
既定の ResourceContext (ResourceContext.GetForCurrentView から取得) には、既定のランタイム コンテキスト (つまり、現在のユーザーとコンピューターの設定) を表す各修飾子名の修飾子値が含まれています。 リソース ファイル (.resw) は、(その名前に含まれる修飾子に基づいて) 実行時コンテキストでの修飾子の値と比較されます。
ただし、アプリでシステム設定をオーバーライドし、読み込む一致するリソース ファイルを探すときに使用する言語、スケール、またはその他の修飾子の値を明示的に指定したい場合があります。 たとえば、ユーザーがツールヒントやエラー メッセージの代替言語を選択できるようにすることができます。
これを行うには、新しい ResourceContext を (既定のリソースを使用するのではなく) 構築し、その値をオーバーライドしてから、文字列参照でそのコンテキスト オブジェクトを使用します。
var resourceContext = new Windows.ApplicationModel.Resources.Core.ResourceContext(); // not using ResourceContext.GetForCurrentView
resourceContext.QualifierValues["Language"] = "de-DE";
var resourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
this.myXAMLTextBlockElement.Text = resourceMap.GetValue("Farewell", resourceContext).ValueAsString;
上記のコード例のように QualifierValues を使用すると、任意の修飾子に対して機能します。 言語の特殊なケースでは、代わりにこれを行うこともできます。
resourceContext.Languages = new string[] { "de-DE" };
グローバル レベルで同じ効果を得る場合、既定の ResourceContext で修飾子の値をオーバーライド。 ただし、代わりに ResourceContext.SetGlobalQualifierValue を呼び出すようにお勧めします。 SetGlobalQualifierValue の呼び出しで値を 1 回設定すると、それらの値は、参照に使用するたびに既定の ResourceContext で有効になります。
Windows.ApplicationModel.Resources.Core.ResourceContext.SetGlobalQualifierValue("Language", "de-DE");
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
一部の修飾子には、システム データ プロバイダーがあります。 そのため、SetGlobalQualifierValue を呼び出す代わりに、独自の API を使用してプロバイダーを調整できます。 たとえば、このコードは PrimaryLanguageOverrideを設定する方法を示しています。
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "de-DE";
修飾子の値の変更イベントへの応答で画像を更新する
実行中のアプリは、既定 の ResourceContext の修飾子の値に影響を与えるシステム設定の変更に応答できます。 これらのシステム設定は、ResourceContext.QualifierValues で MapChanged イベントを呼び出します。
このイベントに応答して、既定の ResourceContext から文字列を再読み込みできます。
public MainPage()
{
this.InitializeComponent();
...
// Subscribe to the event that's raised when a qualifier value changes.
var qualifierValues = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues;
qualifierValues.MapChanged += new Windows.Foundation.Collections.MapChangedEventHandler<string, string>(QualifierValues_MapChanged);
}
private async void QualifierValues_MapChanged(IObservableMap<string, string> sender, IMapChangedEventArgs<string> @event)
{
var dispatcher = this.myXAMLTextBlockElement.Dispatcher;
if (dispatcher.HasThreadAccess)
{
this.RefreshUIText();
}
else
{
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => this.RefreshUIText());
}
}
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
}
クラス ライブラリまたは Windows ランタイム ライブラリから文字列を読み込む
参照されるクラス ライブラリ (ユニバーサル Windows) または Windows ランタイム ライブラリ (ユニバーサル Windows) の文字列リソースは、通常、ビルド プロセス中に含まれるパッケージのサブフォルダーに追加されます。 このような文字列のリソース識別子は通常LibraryName/ResourcesFileName/ResourceIdentifier の形式を取ります。
ライブラリは、独自のリソースの ResourceLoader を取得できます。 たとえば、次のコードは、ライブラリまたはそれを参照するアプリが、ライブラリの文字列リソースの ResourceLoader を取得する方法を示しています。
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("ContosoControl/Resources");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("exampleResourceName");
Windows ランタイム ライブラリ (ユニバーサル Windows) で、既定の名前空間がセグメントに分かれている ("." 文字が含まれる) 場合、リソース マップ名ではドットを使用します。
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("Contoso.Control/Resources");
クラス ライブラリ (ユニバーサル Windows) の場合は、これを行う必要はありません。 わからない場合は、MakePri.exe コマンド ライン オプションを指定して、コンポーネントまたはライブラリの PRI ファイルをダンプできます。 各リソースの uri
が、ダンプされたファイルで示されています。
<NamedResource name="exampleResourceName" uri="ms-resource://Contoso.Control/Contoso.Control/ReswFileName/exampleResourceName">...
他のパッケージからの文字列の読み込み
アプリ パッケージのリソースは、現在の ResourceManager からアクセスできる、パッケージ独自のトップ レベルの ResourceMap を介して管理され、アクセスされます。 各パッケージ内では、さまざまなコンポーネントが独自の ResourceMap サブツリーを持つことができ、ResourceMap.GetSubtree を介してアクセスできます。
フレームワーク パッケージは、絶対リソース識別子 URI を使用して独自のリソースにアクセスできます。 URI スキームも参照してください。
パッケージ化されていないアプリケーションでの文字列の読み込み
Windows バージョン 1903 (2019 年 5 月の更新プログラム) では、パッケージ化されていないアプリケーションでもリソース管理システムを利用できます。
UWP のユーザー コントロールやライブラリを作成し、任意の文字列をリソース ファイルに格納するだけです。 その後は、XAML から文字列リソース識別子を参照したり、コードから文字列リソース識別子を参照したり、クラス ライブラリや Windows ランタイム ライブラリから文字列を読み込んだりすることができます。
パッケージ化されていないアプリケーションでリソースを使用するには、いくつかのことを行う必要があります。
- パッケージ化されていないシナリオには "現在のビュー" が存在しないので、コードからリソースを解決するときは、GetForCurrentView の代わりに GetForViewIndependentUse を使います。 パッケージ化されていないシナリオで GetForCurrentView を呼び出した場合、次の例外が発生します: "CoreWindow のないスレッドにリソース コンテキストは作成できません"。
- MakePri.exe を使用して、アプリの resources.pri ファイルを手動で生成します。
makepri new /pr <PROJECTROOT> /cf <PRICONFIG> /of resources.pri
を実行します。- <PRICONFIG> では、すべてのリソースが 1 つの resources.pri ファイルにバンドルされるように、"<packaging>" セクションを省略する必要があります。 createconfig によって作成された既定の MakePri.exe 構成ファイルを使用する場合は、作成した後、"<packaging>" セクションを手動で削除する必要があります。
- <PRICONFIG> には、プロジェクト内のすべてのリソースを 1 つの resources.pri ファイルにマージするために必要なすべての関連インデクサーが含まれている必要があります。 createconfig によって作成される既定の MakePri.exe 構成ファイルには、すべてのインデクサーが含まれます。
- 既定の構成を使用しない場合は、プロジェクト ルート内にある、UWP プロジェクト参照や NuGet 参照などから見つかった PRI をマージするため、PRI インデクサーが有効になっていることを確認します (これを行う方法については、既定の構成を確認してください)。
Note
/IndexName
を省略し、プロジェクトにアプリ マニフェストがない場合、PRI ファイルの IndexName/ルート名前空間は自動的に Application に設定され、ランタイムはパッケージ化されていないアプリについて認識します (これにより、パッケージ ID に対する以前のハード依存関係が削除されます)。 リソース URI を指定する場合、ルート名前空間を省略した ms-resource:/// 参照は、パッケージ化されていないアプリのルート名前空間として Application を推論します (または、ms-resource://Application/ のように Application を明示的に指定することもできます)。
- .exe のビルド出力ディレクトリに PRI ファイルをコピーします
- .exe を実行します
Note
リソース管理システムは、パッケージ化されていないアプリの言語に基づいてリソースを解決するときに、ユーザーの優先言語リストではなくシステム表示言語を使用します。 ユーザー優先言語リストは、UWP アプリでのみ使われます。
重要
リソースが変更されたときは常に、PRI ファイルを手動でリビルドする必要があります。 MakePri.exe コマンドを処理し、resources.pri の出力を .exe ディレクトリにコピーする、ビルド後スクリプトを使用することをお勧めします。