对 UI 和应用包清单中的字符串进行本地化

有关对 Windows App SDK 应用进行本地化的价值主张的详细信息,请参阅全球化和本地化

如果你希望应用支持其他显示语言,并且你的代码或 XAML 标记或应用包清单中有字符串文本,则将这些字符串移到资源文件 (.resw) 中。 然后,你可以针对应用支持的每种语言制作该资源文件的翻译副本。

硬编码的字符串文本可以出现在命令性代码或 XAML 标记中,例如,作为 TextBlockText 属性。 它们也会出现在应用包清单源文件(Package.appxmanifest 文件)中,例如,Visual Studio 清单设计器的“视觉对象资产”选项卡上的应用图标值。 将这些字符串移动到资源文件 (.resw),并将应用中和清单中的硬编码字符串文本替换为对资源标识符的引用。

与图像资源不同,一个图像资源文件中只包含一个图像资源,而一个字符串资源文件中包含‭‬多份‭‬多个‬字符串资源。 字符串资源文件是资源文件(.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)(在“添加新项目”对话框中的“WinUI”文件类型下)并确认其已命名为 Resources.resw

    注意

    如果要移植 .NET 资源文件(.resx),请参阅 移植 XAML 和 UI

  3. 打开 Resources.resw 并添加这些字符串资源。

    Strings/en-US/Resources.resw

    Strings > E N U > Resources.resw 文件的“添加资源”表的屏幕截图。

    在此示例中,“Greeting”是可从标记中引用的字符串资源标识符,如下所示。 对于标识符“Greeting”,会为 Text 属性提供字符串,并为 Width 属性提供字符串。 “Greeting.Text”是属性标识符的示例,因为它对应于 UI 元素的属性。 例如,还可以在名称列中添加“Greeting.Foreground”,并将其值设置为“Red”。 “告别”标识符是一个简单的字符串资源标识符;它没有子属性,可以由命令性代码加载,请见下文。 批注列适合向翻译人员提供特殊说明。

    在此示例中,由于名为“Farewell”的简单字符串资源标识符条目已存在,因此我们不能为相同的标识符创建属性标识符。 因此,添加“Farewell.Text”会导致构建 ‭Resources.resw‬ 时出现重复条目错误。

    资源标识符不区分大小写,并且对于每个资源文件都必须是唯一的。 请务必使用有意义的资源标识符为翻译人员提供其他上下文。 在发送字符串资源以供翻译后,不要更改资源标识符。 本地化团队使用资源标识符跟踪资源中的添加、删除和更新。 资源标识符中的更改(也称为“资源标识符转换”)需要重新翻译字符串,因为它看起来就像删除了字符串并添加了其他字符串。

引用 XAML 中的字符串资源标识符

使用 x:Uid 指令 将标记中的控件或其他元素与字符串资源标识符相关联。

<TextBlock x:Uid="Greeting"/>

运行时将加载 \Strings\en-US\Resources.resw (因为这是此时项目中唯一的资源文件)。 TextBlock 上的 x:Uid 指令会查找 Resources.resw 中包含字符串资源标识符“Greeting”的属性标识符。 找到“Greeting.Text”和“Greeting.Width”属性标识符后,将它们的值应用于 TextBlock,覆盖本地设置的标记值。 如果已添加,也会应用“Greeting.Foreground”值。 但是,只有属性标识符用于设置 XAML 标记元素上的属性,因此在该 Textbook 中将 x:Uid 设置为“Farewell”将无效。 Resources.resw确实包含字符串资源标识符“Farewell”,但它不包含其属性标识符。

将字符串资源标识符分配给 XAML 元素时,请确保该标识符的所有属性标识符都适用于 XAML 元素。 例如,如果在 TextBlock 上设置 x:Uid="Greeting",则“Greeting.Text”将解析,因为 TextBlock 类型具有 Text 属性。 但是,如果在 按钮 上设置 x:Uid="Greeting",则“Greeting.Text”将导致运行时错误,因为 按钮 类型没有 Text 属性。 这种情况的另一种解决方案是创建名为“ButtonGreeting.Content”的属性标识符,并对按钮设置 x:Uid="ButtonGreeting"

你可能希望允许控件动态调整内容大小,而不是在资源文件中设置 Width

注意

对于附加属性,需要在 .resw 文件的 名称 列中使用特殊语法。 例如,若要为“Greeting”标识符的 AutomationProperties.Name 附加属性设置值,即你要在名称列中输入的值。

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

引用编码中的字符串资源标识符

可以根据简单的字符串资源标识符显式加载字符串资源。

var resourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");

可以从类库项目中使用此相同的代码。 在运行时,将加载托管库的应用资源。 建议库从托管它的应用中加载资源,因为应用的本地化程度可能更高。 如果库确实需要提供资源,则应作为输入为托管应用提供替换资源选项。

如果资源名称已分段(包含“.”字符),则将资源名称中的点替换为正斜杠(“/”)字符。 例如,属性标识符包含点;因此需要执行替换后才能从代码中加载其中一个标识符。

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 表示为字符串文本。

    Package.appxmanifest 文件的屏幕截图,其中显示了“应用程序”选项卡,其中显示名称设置为 Adventure Works Cycles。

  2. 要制作此字符串的本地化版本,请打开 Resources.resw 并添加名为“AppDisplayName”和值“Adventure Works Cycles”的新字符串资源。

  3. 将显示名称字符串文本替换为对刚刚创建的字符串资源标识符(“AppDisplayName”)的引用。 可以使用 ms-resource URI(统一资源标识符)方案执行此操作。

    Package.appxmanifest 文件的屏幕截图,其中显示了“应用程序”选项卡,其中显示名称设置为 M S 资源应用显示名称。

  4. 对清单中要本地化的每个字符串重复此过程。 例如,应用的短名称(可以配置为“开始”时在应用磁贴上显示)。 有关应用包清单中可本地化的所有项的列表,请参阅 可本地化的清单项

本地化字符串资源

  1. 为其他语言创建资源文件(.resw)副本。

    1. 在“字符串”下,为 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

    添加资源,德语

如果需要,可以重复步骤 1 和步骤 2 以获取其他语言。

Strings/fr-FR/Resources.resw

添加资源,法语

测试应用

测试应用的默认显示语言。 之后,可以在设置>时间和语言>区域和语言>语言中更改显示语言并重新测试应用。 查看 UI 和 shell 中的字符串,例如,标题栏(即显示名称)以及磁贴上的短名称。

注意

如果可以找到与显示语言设置匹配的文件夹名称,则会加载该文件夹中的资源文件。 否则,将进行回退,使用应用默认语言的资源。

将字符串分解为多个资源文件

可以将所有字符串保留在单个资源文件(resw)中,也可以将它们分解为多个资源文件。 例如,你可能想要将错误消息保存在一个资源文件中、应用包清单字符串在另一个资源文件中, UI 字符串在第三个资源文件中。 这就是文件夹结构在这种情况下的情形。

解决方案面板的屏幕截图,其中显示了 Adventure Works Cycles > Strings 文件夹,其中包含德语、美国英语和法语区域设置文件夹和文件。

若要限定对特定文件字符串资源标识符引用的范围,只需在标识符之前添加 /<resources-file-name>/。 下面的标记示例假定 ErrorMessages.resw 包含一个资源,其名称为“PasswordTooWeak.Text”,其值描述错误。

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

只需在资源文件以外的Resources.resw资源文件的字符串资源标识符之前添加/<resources-file-name>/。 这是因为“Resources.resw”是默认文件名,因此,如果省略文件名(如本主题前面的示例中所示),则假定为这种情况。

下面的代码示例假定 ErrorMessages.resw 包含名为“MismatchedPasswords”且其值描述错误的资源。

var resourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("ErrorMessages");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("MismatchedPasswords");

如果要将“AppDisplayName”资源移出 Resources.resw 并移入 ManifestResources.resw 中,则在应用包清单中,将 ms-resource:AppDisplayName 更改为 ms-resource:/ManifestResources/AppDisplayName

如果资源文件名已分段(包含“.”字符),请在引用时保留名称中的点。 请勿像引用资源名称时一样,将点替换为正斜杠(“/”)字符。

var resourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("Err.Msgs");

如有疑问,可以使用 MakePri.exe 转储应用的 PRI 文件。 每个资源的 uri 都显示在转储文件中。

<ResourceMapSubtree name="Err.Msgs"><NamedResource name="MismatchedPasswords" uri="ms-resource://<GUID>/Err.Msgs/MismatchedPasswords">...

加载特定语言或其他上下文的字符串

默认 ResourceContext (在创建 ResourceLoader 时获取)包含每个限定符名称的限定符值,表示默认运行时上下文(换句话说,当前用户和计算机的设置)。 根据该运行时上下文中的限定符值匹配资源文件 (.resw) - 基于其名称中的限定符。

但是,有时你可能希望你的应用替代系统设置,并在查找要加载的匹配资源文件时显式显示语言、缩放或其他限定符值。 例如,你可能希望用户能够为工具提示或错误消息选择替换语言。

为此,可以构造新的 ResourceContext,重写其值,然后在字符串查找中使用该上下文对象。

var resourceManager = new Microsoft.Windows.ApplicationModel.Resources.ResourceManager();
var resourceContext = resourceManager.CreateResourceContext();
resourceContext.QualifierValues["Language"] = "de-DE";
var resourceMap = resourceManager.MainResourceMap.GetSubtree("Resources");
this.myXAMLTextBlockElement.Text = resourceMap.GetValue("Farewell", resourceContext).ValueAsString;

如上面的代码示例所示,使用 QualifierValues 适用于任何限定符。 对于语言的特殊情况,也可以改为执行此操作。

resourceContext.Languages = new string[] { "de-DE" };

从类库加载字符串

引用的类库的字符串资源通常添加到包的子文件夹中,包的子文件夹在构建过程中包含这些资源。 此类字符串的资源标识符通常采用 LibraryName/ResourcesFileName/ResourceIdentifier 格式。

库可以为自己的资源获取 ResourceLoader。 例如,下面的代码说明了库或引用该库的应用如何为库的字符串资源获取 ResourceLoader

var resourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("ContosoControl/Resources");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("exampleResourceName");

如有关于路径的疑问,可以指定 MakePri.exe 命令行选项来转储组件或库的 PRI 文件。 每个资源的 uri 都显示在转储文件中。

<NamedResource name="exampleResourceName" uri="ms-resource://Contoso.Control/Contoso.Control/ReswFileName/exampleResourceName">...

从其他包加载字符串

应用包的资源通过包自身的顶级 ResourceMap(可从 ResourceManager 访问)进行管理和访问。 在每个包中,各种组件可以有自己的 ResourceMap 子树,可以通过 ResourceMap.GetSubtree 进行访问。

框架包可以使用绝对资源标识符 URI 访问自己的资源。 有关详细信息,请参阅 UWP 文档中的 URI 方案

在未打包应用程序中加载字符串

从 Windows 版本 1903(2019 年 5 月更新)开始,未打包应用程序也可以利用资源管理系统。

只需创建 Windows 应用 SDK 用户控件/库并将所有字符串存储在资源文件中。 然后,就可以引用 XAML 中的字符串资源标识符引用代码中的字符串资源标识符,或从类库加载字符串

若要在未打包应用程序中使用资源,应执行以下几项操作:

  1. 从代码解析资源时,请使用 ResourceManager 的重载构造函数传递应用的 .pri 文件的文件名,因为在未打包的场景中没有默认视图。
  2. 使用 MakePri.exe 手动生成应用的 resources.pri 文件。
    • makepri new /pr <PROJECTROOT> /cf <PRICONFIG> /of resources.pri运行
    • <PRICONFIG> 必须省略“<packaging>”节,以便将所有资源捆绑在一个 resources.pri 文件中。 如果使用 createconfig 创建的默认 MakePri.exe 配置文件,则需要在创建“<packaging>”节后手动删除该节。
    • <PRICONFIG> 必须包含将项目中的所有资源合并到单个 resources.pri 文件所需的所有相关索引器。 createconfig 创建的默认 MakePri.exe 配置文件包含所有索引器。
    • 如果不使用默认配置,请确保启用 PRI 索引器(查看默认配置,了解如何执行此操作),以合并从项目根目录下的项目引用、NuGet 引用等引用中找到的 PRI。

      注意

      通过省略 /IndexName,并且让项目没有应用清单,PRI 文件的 IndexName/根命名空间会自动设置为 Application,运行时可将其识别为未打包应用的 IndexName/根命名空间(这会删除以前对包 ID 的硬依赖)。 指定资源 URI 时,省略根命名空间的 ms-resource:/// 引用会将 Application 推断为未打包应用的根命名空间(或者可以像在 ms-resource://Application/ 中一样显式指定 Application)。

  3. 将 PRI 文件复制到 .exe 的生成输出目录
  4. 运行 .exe

    注意

    资源管理系统根据未打包应用中的语言解析资源时,使用系统显示语言而不是用户首选语言列表。 用户首选语言列表仅用于 Windows 应用 SDK 打包应用。

重要

每次修改资源时,都必须手动重新生成 PRI 文件。 建议使用生成后脚本来处理 MakePri.exe 命令并将 resources.pri 输出复制到 .exe 目录。

重要的 API

另请参阅