UI とアプリ パッケージ マニフェスト内の文字列をローカライズする

アプリのローカライズの価値提案の詳細については、「グローバリゼーションとローカライズ」をご覧ください。

アプリで複数の表示言語をサポートする必要があり、コード、XAML マークアップ、アプリ パッケージ マニフェスト内に文字列リテラルが含まれている場合は、その文字列をリソース ファイル (.resw) に移動します。 アプリでサポートする各言語用に、このリソース ファイルを翻訳したコピーを作成することができます。

ハードコードされた文字列リテラルは、命令型コードや XAML マークアップに (たとえば、TextBlockText プロパティとして)表示できます。 また、アプリ パッケージ マニフェスト ソース ファイル (Package.appxmanifest ファイル) に (たとえば、Visual Studio マニフェスト デザイナーの [アプリケーション] タブで表示名の値として) 表示することもできます。 これらの文字列をリソース ファイル (.resw) に移動し、アプリやリソース内のハードコードされた文字列リテラルをリソース識別子への参照に置き換えます。

画像リソース ファイルに画像リソースが 1 つだけ含まれている画像リソースとは異なり、文字列リソース ファイルには複数の文字列リソースが含まれています。 文字列リソース ファイルはリソース ファイル (.resw) であり、通常、この種類のリソース ファイルはプロジェクトの \Strings フォルダー内に作成します。 リソース ファイル (.resw) の名前に修飾子を使用する方法の詳細については、「言語、スケール、その他の修飾子用にリソースを調整する」をご覧ください。

リソース ファイルに文字列を格納する

  1. アプリの既定の言語を設定します。

    1. Visual Studio でソリューションを開いた状態で、Package.appxmanifest を開きます。
    2. [アプリケーション] タブで、既定の言語が適切に設定されている ("en"や "en-us" など) ことを確認します。 残りの手順では、既定の言語を "en-US" に設定していることを前提としています。
      注: 最低でも、この既定の言語のローカライズされた文字列リソースを提供する必要があります。 これらは、ユーザーの優先する言語や表示言語の設定に一致するものが見つからない場合に読み込まれるリソースです。
  2. 既定の言語のリソース ファイル (.resw) を作成します。

    1. プロジェクト ノードで、新しいフォルダーを作成し、"Strings" という名前を付けます。
    2. Strings で、新しいサブフォルダーを作成し、"en-US" という名前を付けます。
    3. en-US で、新しいリソース ファイル (.resw) を作成し、その名前が "Resources.resw" になっていることを確認します。
      注: .NET リソース ファイル (.resx) を移植する場合は、「XAML と UI の移植」をご覧ください。
  3. Resources.resw を開き、次の文字列リソースを追加します。

    Strings/en-US/Resources.resw

    Screenshot of the Add Resource table of the Strings > E N U S > Resources.resw file.

    この例では、"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 が読み込まれます (現時点では、プロジェクト内の唯一のリソース ファイルであるためです)。 TextBlockx:Uid ディレクティブによって、参照が実行され、Resources.resw 内の "Greeting" 文字列リソース識別子を含むプロパティ識別子が見つかります。 "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" は解決されます。 ただし、ボタンに設定x:Uid="Greeting"すると、ボタンの種類に Text プロパティがないため、"Greeting.Text" によって実行時エラーが発生します。 その場合の解決策の 1 つは、"ButtonGreeting.Content" という名前のプロパティ識別子を作成し、Button に設定x:Uid="ButtonGreeting"することです。

リソース ファイルから Width を設定する代わりに、コンテンツに合わせてコントロールのサイズを動的に変更できるようにすることが必要になる場合があります。

添付プロパティの場合、.resw ファイルの [名前] 列で特別な構文が必要です。 たとえば、"Greeting" 識別子用に AutomationProperties.Name 添付プロパティの値を設定するには、これが [名前] 列に入力する内容です。

Greeting.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name

コードから文字列リソース識別子を参照する

単純な文字列リソース識別子に基づいて、文字列リソースを明示的に読み込むことができます。

注意

バックグラウンド/ワーカー スレッドで実行された可能性のある任意の GetForCurrentView メソッドの呼び出しがある場合、if (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null) テストでその呼び出しを保護します。 バックグラウンド/ワーカー スレッドから GetForCurrentView を呼び出すと、"<typename> が CoreWindow のないスレッドで作成されない可能性がある" という例外が発生します。

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) プロジェクト内からこの同じコードを使用することができます。 実行時に、ライブラリをホストしているアプリのリソースが読み込まれます。 アプリはローカライズの度合いが大きくなる可能性があるため、ライブラリでは、ライブラリをホストしているアプリからリソースを読み込むことをお勧めします。 ライブラリがリソースを提供する必要がある場合、ライブラリをホストしているアプリがそれらのリソースを入力に置き換えられるようにするオプションを提供する必要があります。

リソース名がセグメントに分かれている ("." 文字が含まれる) 場合は、リソース名のドットをスラッシュ ("/") 文字に置き換えます。 たとえば、プロパティ識別子にはドットが含まれます。そのため、コードからそれらを読み込むには、この置換を行う必要があります。

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">...

アプリ パッケージ マニフェストから文字列リソース識別子を参照する

  1. アプリ パッケージ マニフェスト ソース ファイル (Package.appxmanifest ファイル) を開きます。既定では、アプリの Display name は文字列リテラルで表されます。

    Screenshot of the Package.appxmanifest file showing the Application tab with the Display name set to Adventure Works Cycles.

  2. この文字列のローカライズ可能なバージョンを作成するには、Resources.resw を開き、"AppDisplayName"という名前で、"Adventure Works Cycles" という値の新しい文字列リソースを追加します。

  3. 表示名の文字列リテラルを、作成した文字列リソース識別子 ("AppDisplayName") への参照に置き換えます。 これを行うには、ms-resource URI (Uniform Resource Identifier) スキームを使用します。

    Screenshot of the Package.appxmanifest file showing the Application tab with the Display name set to M S resource App Display Name.

  4. マニフェスト内のローカライズする各文字列について、この手順を繰り返します。 たとえば、アプリの短い名前 (スタート画面でアプリのタイルに表示されるように構成できる) です。 アプリ パッケージ マニフェスト内で、ローカライズできるすべての項目の一覧については、「マニフェストのローカライズ可能な項目」をご覧ください。

文字列リソースをローカライズする

  1. 別の言語用にリソース ファイル (.resw) のコピーを作成します。

    1. "Strings" の下に新しいサブフォルダーを作成し、Deutsch (Deutschland) を表す "de-DE" という名前を付けます。
      フォルダー名には、任意の BCP 47 言語タグを使用できます。 言語修飾子の詳しい情報と共通の言語タグの一覧は、「言語、スケール、その他の修飾子用にリソースを調整する」をご覧ください。
    2. Strings/de-DE フォルダー内に Strings/en-US/Resources.resw のコピーを作成します。
  2. 文字列に変換します。

    1. Strings/de-DE/Resources.resw を開き、[値] 列の値を翻訳します。 コメントを翻訳する必要はありません。

    Strings/de-DE/Resources.resw

    add resource, german

必要に応じて、他の言語について手順 1. と 2. を繰り返すことができます。

Strings/fr-FR/Resources.resw

add resource, french

アプリをテストする

既定の表示言語に対してアプリをテストします。 その後、[設定]>[時刻と言語]>[地域と言語]>[言語] で表示言語を変更し、アプリを再テストできます。 UI やシェルの文字列 (タイトル バー (表示名) やタイルの短い名前など) を確認します。

表示言語の設定に一致するフォルダー名が見つかった場合、そのフォルダー内のリソース ファイルが読み込まれます。 それ以外の場合、フォールバックが行われ、最終的にはアプリの既定の言語用のリソースになります。

文字列を複数のリソース ファイルにファクタリングする

1 つのリソース ファイル (resw) にすべての文字列を保持することも、複数のリソース ファイルに文字列をファクタリングすることもできます。 たとえば、エラー メッセージを 1 つのリソース ファイルに、アプリ パッケージ マニフェストの文字列を別のリソース ファイルに、UI の文字列を第 3 のリソース ファイルに保持することができます。 この場合、フォルダー構造は次のようになります。

Screenshot of the Solution panel showing the Adventure Works Cycles > Strings folder with German, U S English, and French locale folders and files.

文字列リソース識別子の参照を特定のファイルに限定する場合は、識別子の前に /<resources-file-name>/ を追加するだけです。 次のマークアップの例では、ErrorMessages.resw にリソースが含まれており、その名前が "PasswordTooWeak.Text" であり、その値がエラーの説明であることを想定しています。

<TextBlock x:Uid="/ErrorMessages/PasswordTooWeak"/>

Resources.resw以外のリソース ファイルの場合にのみ、文字列リソース識別子の前に /<resources-file-name>/ を追加する必要があります。 これは、"Resources.resw" が既定のファイル名であり、(このトピックの前の例で行ったように) ファイル名を省略した場合に既定のファイル名が想定されるためです。

次のコードの例では、ErrorMessages.resw にリソースが含まれており、その名前が "MismatchedPasswords" であり、その値がエラーの説明であることを想定しています。

注意

バックグラウンド/ワーカー スレッドで実行された可能性のある任意の GetForCurrentView メソッドの呼び出しがある場合、if (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null) テストでその呼び出しを保護します。 バックグラウンド/ワーカー スレッドから GetForCurrentView を呼び出すと、"<typename> が CoreWindow のないスレッドで作成されない可能性がある" という例外が発生します。

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:AppDisplayNamems-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 の呼び出しで一度値を設定すると、ResourceContext を検索に使用するたびに、これらの値が既定の 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.QualifierValuesMapChanged イベントを呼び出します。

このイベントへの応答で、既定の 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 ランタイム ライブラリから文字列を読み込んだりすることができます。

パッケージ化されていないアプリケーションでリソースを使うには、いくつかのことを行う必要があります。

  1. パッケージ化されていないシナリオには "現在のビュー" が存在しないので、コードからリソースを解決するときは、GetForCurrentView の代わりに GetForViewIndependentUse を使います。 パッケージ化されていないシナリオで GetForCurrentView を呼び出した場合、次の例外が発生します: "CoreWindow のないスレッドにリソース コンテキストは作成できません"。
  2. 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 インデクサーが有効になっていることを確認します (これを行う方法については、既定の構成を確認してください)。

      注意

      /IndexName を省略し、プロジェクトにアプリ マニフェストがないと、PRI ファイルの IndexName/root 名前空間が自動的に Application に設定されます。これにより、ランタイムはパッケージ化されていないアプリを認識します (これにより、パッケージ ID に対する以前のハードな依存関係が削除されます)。 リソース URI を指定するとき、root 名前空間を省略した ms-resource:/// 参照は、パッケージ化されていないアプリの root 名前空間として Application を示します (または、ms-resource://Application/ のように明示的に Application を指定することもできます)。

  3. .exe のビルド出力ディレクトリに PRI ファイルをコピーします
  4. .exe を実行します

    注意

    リソース管理システムによって、パッケージ化されていないアプリの言語に基づいてリソースが解決されるときは、ユーザー指定の優先言語リストではなく、システム表示言語が使われます。 ユーザー優先言語リストは、UWP アプリでのみ使われます。

重要

リソースが変更されたときは常に、PRI ファイルを手動でリビルドする必要があります。 MakePri.exe コマンドを処理し、resources.pri の出力を .exe ディレクトリにコピーする、ビルド後スクリプトを使用することをお勧めします。

重要な API