使用资源模型

学习目标

  • 使用可翻译文本对应用程序进行国际化

资源包

观看视频,了解如何通过资源模型实现语言特定的 UI。

视频:本节含 SAP 官方视频(视频 ID 1_cbjj47bc),需在 learning.sap.com 在线观看。

使用本地化文本

本地化文本示例,高亮显示 i18n 属性。

资源包文件存储在 SAPUI5 项目的 i18n 文件夹中,该文件夹位于 webapp 文件夹下。

图中 使用本地化文本 展示了一个基本名称为 i18n 的资源包,它由三个文件组成:i18n.propertiesi18n_en.propertiesi18n_de.properties。这三个文件都位于项目的 i18n 文件夹中。i18n_en.properties 文件包含两个键 cityLabelTextcountryLabelText 的英文文本 CityCountry。而 i18n_de.properties 文件则包含这些键的德文文本 StadtLand

借助资源模型,应用程序现在可以将 UI 上看到的标签文本绑定到资源包中的文本。为此,绑定使用与语言无关的键。相关细节将在下一节讨论。

如果应用程序现在以 en 作为语言代码/区域设置运行,则要显示的文本取自 i18n_en.properties 文件。反之,如果使用 de 作为语言代码/区域设置,则相应地显示德文文本。

资源模型

模型实例化

通过资源模型,本地化文本可以用于数据绑定。资源模型是资源包的包装器,它将本地化文本作为模型公开以用于数据绑定。您可以使用资源模型将控件属性的文本绑定到与语言相关的资源包属性。

示例资源模型,如文中所述。

资源模型通过 sap.ui.model.resource.ResourceModel 类实现。相应的模型实例既可以在 JavaScript 中调用该类的构造函数来创建,也可以通过应用程序描述符以声明方式创建。图中 实例化资源模型 展示了通过在 sap.ui5 命名空间的 models 属性中添加条目来实现的声明方式。

该条目创建一个资源模型,并以模型名称 i18n 为组件设置。包名称引用要使用的资源包的 .properties 基础文件。它以点号表示法指定为 SAPUI5 模块名称,并像普通 SAPUI5 模块一样解析为路径,然后附加 “.properties”。在示例中,指定的是 SAPUI5 项目 i18n 文件夹中的 i18n.properties 文件,因为项目的资源根被设置为 sap.training.exc

supportedLocalesfallbackLocale 这两个属性可用于控制资源包文件的加载,并按如下方式避免 “404 Not Found” 网络响应:假设 SAPUI5 确定 de_DE 为应用程序当前的语言代码/区域设置。在不使用这两个属性的情况下,示例中将使用以下回退链:要为所使用的键加载与语言相关的文本,首先会向服务器请求 i18n_de_DE.properties 文件。如果未找到该文件或其中不存在所使用的键,则接下来请求 i18n_de.properties 文件(不带地区后缀)。如果未找到该文件或其中不存在所使用的键,则接下来请求 i18n_en.properties 文件。如果通过该请求也无法确定该键的值,则最终向服务器请求原始文件 i18n.properties

通过 supportedLocales 可以指定区域设置列表以限制回退链。空字符串("")表示原始文件。fallbackLocale 属性可用于指定在所有派生区域设置都尝试失败之后、使用原始文件之前要使用的区域设置。该属性的默认值为 en。要防止通用回退,可使用空字符串("")。

因此,此处为 supportedLocales("")和 fallbackLocale("")所使用的值可确保浏览器仅请求原始文件,而不会执行回退。

数据绑定

资源模型实例化后,您就拥有了一个包含资源包文本作为数据的模型。

示例数据绑定代码,如以下文本所述。

与其他模型不同,资源模型的绑定路径不得以斜杠开头;它们默认是绝对路径,并且没有更深层的结构。基础资源包中的每个键都是有效的绑定路径。

在图中 数据绑定 所示的示例中,资源包中的键 cityLabelTextcountryLabelText 被用于为两个输入字段定义与语言相关的标签。由于该模型在应用程序描述符中声明时被赋予了名称 i18n,因此绑定路径必须相应地加上前缀 i18n>

使用 sap/base/strings/formatMessage 代码的示例代码,如以下文本所述。

资源包中使用的文本可能包含 {integer} 形式的占位符。此类占位符可以在数据绑定中使用 sap/base/strings/formatMessage 函数替换。

sap/base/strings/formatMessage 函数期望第一个参数是带占位符的模式字符串。第二个参数是一个数组,包含用于替代占位符的值。每次出现 {0} 都会被数组索引位置 0 处的值替换,每次出现 {1} 都会被数组索引位置 1 处的值替换,依此类推。该函数返回相应格式化后的字符串作为结果。

图中 替换占位符 展示了一个示例,说明如何在数据绑定中使用 sap/base/strings/formatMessage 函数来替换占位符。所示的 i18n.properties 资源包文件包含键 dialogText 的语言相关文本,其中使用了占位符 {0}

该文本将使用 Text UI 元素显示,其中占位符要替换为客户名称。

为此,在 <Text> 标签中使用 core:require 属性以确保加载 sap/base/strings/formatMessage 模块(core 是先前定义的 sap.ui.core 命名空间的别名)。加载的模块被赋予别名 formatMessage

一个绑定对象被传递给 Text UI 元素的 text 属性。在那里,加载的函数通过其被赋予的别名设置为该绑定的格式化函数。parts 数组用于通过 i18n>dialogText 路径传递模式字符串,并通过 customer>/CustomerName 路径传递占位符的值。所传递的占位符值是名为 customer 的模型的 CustomerName 属性内容。

formatMessage 函数确保资源包中的文本在插入客户名称后显示在 UI 上。

模块 sap/base/i18n/ResourceBundle

SAPUI5 提供两种在应用程序中访问本地化文本的方式:除了通过资源模型进行数据绑定外,还可以使用 sap/base/i18n/ResourceBundle 模块。该模块提供了一个 API,用于访问资源包中包含的本地化文本。

使用 sap/base/i18n/ResourceBundle 的示例代码。

使用该模块的 create 方法创建 sap/base/i18n/ResourceBundle 的实例。该方法的 url 参数可用于传递指向资源包基础 .properties 文件的 URL。

create 方法在异步请求资源包时,要么返回 sap/base/i18n/ResourceBundle 的实例,要么返回该资源包的 promise。要异步加载资源包,必须将 create 方法的 async 参数传递为值 true

与资源模型的构造函数类似,create 方法也具有 supportedLocalesfallbackLocale 参数。有关详细信息,请参阅 Demo Kit 中的 API 参考。

资源模型底层的资源包也可以直接从资源模型访问,而不必使用 sap/base/i18n/ResourceBundle 模块的 create 方法。为此,资源模型提供了 getResourceBundle 方法。该方法返回模型底层的资源包(sap/base/i18n/ResourceBundle 的实例),在异步情况下返回以它解决的 promise。要通过资源模型异步加载资源包,在实例化资源模型时必须将构造函数的 async 参数传递为值 true。

资源包的 getText 方法返回给定键的区域设置特定字符串值。该方法有一个可选的第二参数,可用于传递数组。如果传递了这样的数组,则在找到的区域设置特定字符串值中,任何 {n} 形式(n 为整数)的占位符都会被数组中索引为 n 的对应值替换。

图中 Using sap/base/i18n/ResourceBundle 展示了如何使用该模块的示例。在所示的 classText 方法中,通过其 create 方法创建了该模块的实例,并指定 i18n/i18n.properties 作为资源包的基础文件。然后调用 getText 方法从资源包中检索键 flightClassC 的区域设置特定文本。

使用可翻译文本

业务场景

在之前的练习中,您将 UI 上显示的所有文本都硬编码在相应的文件中。在本练习中,您现在将把 Overview 视图、格式化函数以及 XML 片段中的这些文本移到资源包文件中,以便可以通过资源模型访问它们。通过这一国际化过程,这些文本可以被翻译成其他语言。*模板:*Git 仓库:https://github.com/SAP-samples/sapui5-development-learning-journey.git,分支:*sol/18_device_adaptation模型解决方案:*Git 仓库:https://github.com/SAP-samples/sapui5-development-learning-journey.git,分支:sol/19_resource_model

任务 1:为组件添加资源模型

步骤

  1. 在编辑器中打开 *webapp* 文件夹中的 *manifest.json* 应用程序描述符。

  2. 在应用程序描述符中,查找 sap.ui5 命名空间下 models 属性中包含的以下条目:

"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "<...>"
}
}

注意

此声明会为组件自动实例化一个名为 i18n 的资源模型。

  1. 通过将 bundleName 属性的 "<...>" 替换为 "sap.training.exc.i18n.i18n",指定要用于资源模型的资源包。

注意

该包名称现在指向项目中已存在的 i18n 文件夹中的 i18n.properties 文件。

结果

资源模型的声明现在应如下所示: JSON 文件,高亮显示 bundleName 属性。 4. 除 bundleName 属性外,再将以下两个属性添加到 settings 属性中:

"supportedLocales": [""],
"fallbackLocale": ""

注意

为简单起见,本练习场景仅使用 i18n.properties 文件。除该原始文件外,不会额外创建其他语言特定的 i18n_*.properties 文件。因此,此处为 supportedLocales 和 fallbackLocale 设置的值可确保浏览器仅请求原始文件,而不会执行任何回退。

结果

资源模型的声明现在应如下所示:

JSON 代码,高亮显示 supported Locales 和 fallbackLocale 属性。

任务 2:将 Overview 视图上硬编码的文本替换为可翻译文本

步骤

  1. 在编辑器中打开 *i18n* 文件夹中的 *i18n.properties* 资源包文件。

  2. 对于 Overview 视图上使用的硬编码文本,将以下键值对添加到资源包文件中:

# Overview View
overviewPageTitle=Flight Customers
customerPanelHeader=New Customer
newCustomerButtonText=Create Customer
generalDataFormContainerTitle=General Data
addressDataFormContainerTitle=Address Data
contactDataFormContainerTitle=Contact Data
formLabelText=Form
nameLabelText=Customer Name
discountLabelText=Discount
streetLabelText=Street
postcodeLabelText=Post Code
cityLabelText=City
countryLabelText=Country
emailLabelText=Email
phoneLabelText=Telephone
customerTableHeader=Customers
bookingTableHeader=Bookings
airlineColumnHeader=Airline ID
connectionColumnHeader=Connection Number
fldateColumnHeader=Flight Date
classColumnHeader=Class
paymentColumnHeader=Foreign Currency Payment
cancellationColumnHeader=Cancellation Status
cancelledTooltip=cancelled
notCancelledTooltip=not cancelled

注意

在接下来的步骤中,您将使用此处定义的键从资源模型替换 Overview 视图上硬编码的文本。

结果

以下 i18n.properties 资源包文件现在应如下所示: Overview View 代码被高亮显示。 3. 在编辑器中打开 *webapp/view* 文件夹中的 *Overview.view.xml* 文件。 4. 现在将 <Page> 标签中 title 属性的值替换为 {i18n>overviewPageTitle}

注意

在新值中,i18n 是应用程序描述符中为资源模型指定的名称,而 overviewPageTitle 是资源包文件中的键。

结果

以下 标签现在应如下所示: XML 文件,高亮显示 title 属性。 5. 将 <Panel> 标签中 headerText 属性的值替换为 {i18n>customerPanelHeader}

结果

以下 标签现在应如下所示: XML 文件,高亮显示 headerText 属性。 6. 将 <Button> 标签中 text 属性的值替换为 {i18n>newCustomerButtonText}

结果

以下

结果

表单现在应如下所示: XML 文件,高亮显示 text 属性。 8. 按下表所示,替换客户表中硬编码的文本:

Old

New Attribute Value

<Title text="Customers"/>

i18n>customerTableHeader

<Text text="Customer Name"/>

i18n>nameLabelText

<Text text="Street"/>

i18n>streetLabelText

<Text text="Post Code"/>

i18n>postcodeLabelText

<Text text="City"/>

i18n>cityLabelText

<Text text="Country"/>

i18n>countryLabelText

<Text text="Email"/>

i18n>emailLabelText

结果

客户表现在应如下所示: XML 文件,高亮显示 text 属性。 9. 最后,按下表所示,替换预订表中硬编码的文本:

Old

New Attribute Value

<Table headerText="Bookings" ...>

i18n>bookingTableHeader

<Text text="Airline ID"/>

i18n>airlineColumnHeader

<Text text="Connection Number"/>

i18n>connectionColumnHeader

<Text text="Flight Date"/>

i18n>fldateColumnHeader

<Text text="Class"/>

i18n>classColumnHeader

<Text text="Foreign Currency Payment"/>

i18n>paymentColumnHeader

<Text text="Cancellation Status"/>

i18n>cancellationColumnHeader

<core:Icon tooltip="{= ${IsCancelled} === 'X' ? 'cancelled' : 'not cancelled' }" .../>

${IsCancelled} === 'X' ? ${i18n>cancelledTooltip} : ${i18n>notCancelledTooltip}

结果

预订表现在应如下所示:

XML 文件,高亮显示 headerText、text 和 tooltip 属性。

任务 3:将格式化函数中硬编码的文本替换为可翻译文本

步骤

  1. 在前一个练习中创建的 classText 格式化函数会根据 Class 模型属性的内容返回文本 Business ClassEconomy ClassFirst Class。 将以下键值对添加到 *i18n.properties* 文件,使这些文本可翻译:

# Formatter
flightClassC=Business Class
flightClassY=Economy Class
flightClassF=First Class

结果

以下 i18n.properties 资源包文件现在应如下所示: i18n 文件,高亮显示格式化函数。 2. 在编辑器中打开 *webapp/model* 文件夹中的 *formatter.js* 文件。 3. 将 sap/base/i18n/ResourceBundle 模块添加到 formatter 模块的依赖数组中,并向工厂函数添加一个名为 ResourceBundle 的对应参数。

注意

下一步将使用 ResourceBundle 模块加载资源包并访问上面创建的文本。

结果

以下 formatter 模块现在应如下所示: formatter.js 文件,高亮显示 sap/base/i18n/ResourceBundle 属性。 4. 按如下方式修改 classText 格式化函数的实现,以加载资源包并通过各自的键从中访问上面创建的文本:

classText: function (sClass) {
var oResourceBundle = ResourceBundle.create({ url: "i18n/i18n.properties" });
switch (sClass) {
case "C":
return oResourceBundle.getText("flightClassC");
case "Y":
return oResourceBundle.getText("flightClassY");
case "F":
return oResourceBundle.getText("flightClassF");
default:
return sClass;
}
}

结果

classText 格式化函数现在应如下所示:

Formatter.js 文件,高亮显示 classText 函数。

任务 4:将弹出窗口上硬编码的信息文本替换为可翻译文本

步骤

  1. 最后,应将弹出窗口上通过 *Dialog.fragment.xml* 文件在前一个练习中实现的以下文本变为可翻译的:

<Text
text="Customer {customer>/CustomerName} is later saved via an OData service."/>

为此,请将以下键值对添加到 i18n.properties 文件:

# Fragment
dialogText=Customer {0} is later saved via an OData service.

注意

在接下来的步骤中,您将通过资源模型在弹出窗口上显示此文本,并将{0}占位符替换为当前客户名称。

结果

以下 i18n.properties 资源包文件现在应如下所示: i18n.properties 文件,高亮显示 #Fragment 行。 2. 在编辑器中打开 *webapp/view* 文件夹中的 *Dialog.fragment.xml* 文件。 3. 按如下方式修改弹出窗口上的 Text UI 元素,以使用您刚创建的资源模型中的文本进行显示,并将 {0} 占位符替换为当前客户名称:

<Text
core:require="{formatMessage: 'sap/base/strings/formatMessage'}"
text="{
parts: [
{path: 'i18n>dialogText'},
{path: 'customer>/CustomerName'} ],
formatter: 'formatMessage' }"/>

结果

弹出窗口的实现现在应如下所示: XML 文件,高亮显示 Text 标签。 4. 从 SAP Business Application Studio 启动应用程序以进行测试运行。 请确保从用户角度看 UI 与上一个练习相比没有变化:Overview 视图上的所有文本(包括预订表中的航班舱位)以及弹出窗口上的文本都应显示不变。不过,这些文本现在来自资源包,并且是可翻译的。

  1. 右键单击 sapui5-development-learning-journey 项目中的任意子文件夹,然后从出现的上下文菜单中选择 Preview Application

  2. 在出现的对话框中选择名为 start-noflp 的 npm 脚本。

  3. 在打开的应用程序中,检查组件是否按预期工作。