国际化开发及配置
平台支持国际化(多语言),对于平台提供的应用,分别提供了中文简体、中文繁体和英文等三种语言。
中文简体界面
中文繁体界面
英文界面
开发多语言应用
开发多语言应用的步骤如下
- 正常开发应用
- 修改js文件,将中文替换为多语言函数
- 使用系统工具
- 检测并替换多语言表达式
- 扫描生成资源文件
- 填入语言资源
- 开启多语言
开启多语言
开启多语言,参考《开启多语言、设置当前语言》一节。开启多语言后,门户右上角会显示语言切换图标,系统默认显示三种语言,如需添加其它语言,在开启多语言配置中添加。用户登录后默认使用设置的语言,也可以通过门户右上角的语言切换图标切换语言。
一些常用内容,系统已经翻译,在语言资源文件中无需再翻译
在 JS 文件中使用多语言函数
JS 文件中使用的多语言函数是:this.i18n("中文内容",import.meta.url),替换的作用有两个
- 系统扫描 JS 文件时,会将多语言函数中的中文内容生成到资源文件中
- 运行时,将中文内容替换为资源文件中的语言内容
例如将“提示”替换为多语言函数,代码如下
title: '提示'
改为
title: this.i18n('提示',import.meta.url)
JS文件中通过请求获取多语言信息,平台请求request已集成语言设置,可直接使用。
let onButton2Click = async(event) => {
/**
* 特别注意:这里一定要使用平台自带的请求方法request。如果你用其他的请求方式,例如fetch,axios等,需要在请求头中新增accept-language用来定义请求语言
*/
let {data}=await $page.request({url:"$serviceName/main/i18n/getlanguageinfo"});
message.info(JSON.stringify(data));
}
如果要使用第三方请求方法,例如fetch,axios等,需要在请求头中新增“accept-language”来定义请求语言,以fetch为例
/**
* 使用第三方请求,获取多语言资源
* @param {*} event
* @returns
*/
let onThirdBtnClick = async(event) => {
const pageData=$page.comp("pageData")
let currentData=pageData.getCurrentRow();
if(!currentData.key||!currentData.language){
message.error("语言及语言key不能为空");
return;
}
const response=await fetch(`/main/i18n/test?key=${currentData.key}`,{headers:{"accept-language":currentData.language}});
let data=await response.text();
pageData.setValue("txt",data);
}
在 Java 文件中使用多语言函数
Java 后端资源文件需要按需新建(系统不会自动生成),统一放在到 "$$model/service/service-meta-info/src/main/resources/i18n" 目录下,语言资源路径规范:$model/service/service-meta-info/src/main/resources/i18n/语言/resource.json
在后端使用多语言需要引用 I18nResourceLoader 类,通过使用 i18n 方法进行内容翻译
I18nResourceLoader类常用方法
public String i18n(String key) throws ExecutionException
public String i18n(String key, String languageId) throws ExecutionException
描述:通过指定语言获取key对应的语言资源
参数:
key 语言请求内容
languageId 语言(zh-CN/en-US等),默认从请求(accept-language)中获取
返回:
指定语言对应的资源
后端获取语言相关信息,可以在 controller 上新增 Locale 参数,然后在具体服务中使用,也可以在服务类下直接使用 SpringWebUtil.getRequest().getLocale() 获取
public String getLanguageInfo(Locale locale) throws Exception {
JSONObject obj=new JSONObject();
obj.put("displayLanguage", locale.getDisplayLanguage());
obj.put("language", locale.getLanguage());
obj.put("displayCountry", locale.getDisplayCountry());
//从当前请求中获取Locale
Locale localeReq=SpringWebUtil.getRequest().getLocale();
//从当前请求中获取语言id
obj.put("languageId", SpringWebUtil.getRequest().getLocale().toLanguageTag());
return obj.toJSONString();
}
模型的多语言配置
在 IDE 中,点击右上角的齿轮图标,弹出下拉菜单。点击多语言配置菜单,打开多语言配置对话框。
系统默认三种语言,点击语言选项按钮,修改语言选项。
前端多语言配置
选择桌面端,依次点击检测并替换多语言表达式、扫描生成资源文件、开启多语言等三个按钮。系统自动扫描桌面端(UI2/pcx 目录)下的 w 和 js 文件,将其中的中文内容生成到资源文件中。
- 系统检查 w 文件时,对其中可作为语言资源的内容,增加多语言函数,例如 text="操作"被替换为 text="{$page.i18n('操作')}"
- 系统扫描 w 和 js 文件时,将其中多语言函数的第一个参数生成到语言资源文件中
生成后,展开左侧的资源树,可以看到系统扫描出的 w 和 js 文件,点击某个文件,切换语言,右侧表格中显示出该语言的语言资源。在“值”列中输入该语言资源,
可以通过点击新建键值按钮,添加新的键值。例如数据集的必填提示和约束提示,就需要手工添加相应的语言资源。
每个端每种语言对应一个资源文件,桌面端生成的语言资源文件为 UI2/pcx/i18n/语言/resource.json
后端多语言配置
选择后端,点击扫描生成资源文件按钮。系统自动扫描后端(service/main 目录)下的 data.m 文件,将其中的中文内容生成到资源文件中。
生成后,展开左侧的资源树,可以看到系统扫描出的数据集,点击某个数据集,切换语言,右侧表格中显示出该语言的语言资源。在“值”列中输入该语言资源,
每个端每种语言对应一个资源文件,后端生成的语言资源文件为 service/service-meta-info/src/main/resources/i18n/语言/resource.json
系统翻译规则
运行时语言资源经过一些处理,会合并为一个 JSON 对象,在浏览器的控制台中,输入 getCurrentReactPage().getCurrentLanguage() 即可看到
- 数据集(data.m)的资源会生成到服务名下
- 前端多语言函数 i18n 的查找顺序是,先通过精确路径查找,如果没找到,再找服务名下的资源,如果还没找到,直接找根下的资源
- 精确路径规则为:/服务名+/所在页面端访问路径+文件详细路径(支持.w 及.js 文件)
例如:控制台中的“租户管理”页面地址为:/pcx/tenants/adminTenants.w,对应的精确路径为:/consoleui/pcxapp/pcx/tenants/adminTenants.w,统一通用配置中的多语言配置如下:
{
"/consoleui": {
"/pcxapp": {
"/pcx": {
"/tenants": {
"/adminTenants.w": {
"添加租户": "添加空间",
"租户设置": "空间设置"
}
}
}
}
}
}
所在页面端访问路径可以在云 IDE 下高级,多模块多端配置下找到,pcx 端的访问路径是 pcxapp
- 后端服务只支持精确路径查找,路径规则:/服务名+/service+请求地址+":"+请求类型(默认类型为get)
例如:企业门户中的菜单请求服务 url 为:/manager/authorized/menus,对应的后端服务精确路径为:/entry/service/manager/authorized/menus:GET,统一通用配置中的多语言配置如下:
{
"/entry": {
"/service": {
"/manager": {
"/authorized": {
"/menus:GET": {
"title": {
"租户管理": "空间管理",
"租户统计": "空间统计",
"我的租户": "我的空间",
"租户申请": "空间申请",
"租户变更申请": "空间变更申请"
}
}
}
}
}
}
}
- 数据集(data.m)的资源建议定义在后端资源文件中,在所有使用到该数据集的 w 文件中都不用再定义
- 运行时,会将“键”里面的内容替换为“值”里面的内容进行显示。当“值”为空时,会显示“键”里面的内容
- 数据集的必填提示和约束提示,需要手工添加相应的语言资源
资源内容中不是静态的,需要显示上下文中的变量,做法如下
在资源内容中使用 {} 表示参数,例如下面的代码中使用了两个参数:{begin}和{end}
"确认将{begin}至{end} 期间已结束的任务归档?": "Confirm to archive the completed tasks from {begin} to {end}?",
- 在 js 文件中,先进行资源替换,再给参数赋值,代码如下
tipsTxt = this.i18n("确认将{begin}至{end}期间已结束的任务归档?",import.meta.url);
tipsTxt = wx.String.stringFormatByKey(tipsTxt, {"begin":begin,"end":end});
- 当资源内容中包括 > 和 : 等特殊字符,系统不能找到对应的语言资源时,需要对语言内容执行 md5(32位 小写),作为键的值。例如中文内容为:以 fn: 开头定义 js,语言资源应写成
"718e5376e126f3ebece6a3c083490da8": "Define JavaScript starting with fn:",
其中 718e5376e126f3ebece6a3c083490da8 为“以fn:开头定义js”md5 后的值
- 数据集组件提供了加载数据前事件,事件参数 event.data 是要加载的数据,此时可修改 event.data,最终数据集会将 event.data 加载到数据集中。可以使用此特性对一些需要翻译的数据进行翻译。步骤如下:
静态数据集 channelData 中 name 列里面的中文需要翻译
<wx:tableData id="channelData" idColumn="id" type="custom" >
<column id="default66" label="id" name="id" type="String"/>
<column id="default67" label="name" name="name" type="String"/>
<data id="default68" >[![CDATA[[{"id":"portal","name":"门户"},{"id":"email","name":"邮件"},{"id":"dingtalk","name":"钉钉"},{"id":"wx","name":"企业微信"},{"id":"sms","name":"短信"}]]]](!%5BCDATA%5B%5B%7B%22id%22:%22portal%22,%22name%22:%22%E9%97%A8%E6%88%B7%22%7D,%7B%22id%22:%22email%22,%22name%22:%22%E9%82%AE%E4%BB%B6%22%7D,%7B%22id%22:%22dingtalk%22,%22name%22:%22%E9%92%89%E9%92%89%22%7D,%7B%22id%22:%22wx%22,%22name%22:%22%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%22%7D,%7B%22id%22:%22sms%22,%22name%22:%22%E7%9F%AD%E4%BF%A1%22%7D%5D%5D%5D)</data>
(/wx:tableData)
在 channelData 的加载数据前事件中,调用 jsonI18n 方法翻译要加载的数据。注意为了使用当前 js 的语言资源,i18n 方法必须使用当前 js 里面的。js 代码如下
onChannelDataBeforeLoad = (event) => {
this.i18nFn = (key) => {
return this.i18n(key, import.meta.url);
}
wx.String.jsonI18n(event.data, ["name"], this.i18nFn);
}
如果页面上有多个数据集需要翻译,可以将 this.i18nFn 定义到 constructor 方法中,代码如下
constructor(props, context) {
super(props, context);
this.i18nFn = (key) => {
return this.i18n(key, import.meta.url);
}
}
服务的多语言配置
系统提供对服务返回结果和报错信息的翻译能力,例如门户功能树就是对服务返回结果的翻译。
翻译服务返回结果
- 定义一个服务,GET 请求,在服务中返回 JSON 字符串数据
public String returnInfo() throws Exception {
JSONObject ret = new JSONObject();
ret.put("message", "这是服务返回信息");
return ret.toJSONString();
}
- 在 js 中调用这个服务,获取服务返回的 JSON 数据
try{
let ret = await this.request({
url:"$serviceName/main/fuwu/returninfo"
})
message.info(ret.data.message);
}catch(e){
message.error(e.data.message);
}
- 在后端的语言资源文件中添加服务返回结果的语言资源
{
"$service": {
"/main": {
"/fuwu": {
"/returninfo:GET":{
"message":{
"这是服务返回信息": "This is service return info"
}
}
}
}
}
}
- 运行效果
翻译服务报错信息
- 定义一个服务,在服务中返回404
public String returnError() throws Exception {
throw new BaseRuntimeException(HttpStatus.NOT_FOUND.value(),"这是服务报错信息");
}
- 在 js 中调用这个服务,获取异常信息
try{
let ret = await this.request({
url:"$serviceName/main/fuwu/returnerror"
})
message.info(ret.data.message);
}catch(e){
message.error(e.data.message);
}
- 在后端的语言资源文件中添加服务报错信息的语言资源
{
"$service": {
"@error": {
"message": {
"这是服务报错信息": "This is service error info"
}
}
}
}
- 运行效果
功能树的多语言配置
上面配置的内容都是页面内的语言资源,对于显示到门户功能树上的菜单的语言资源,需要在统一通用配置中的多语言配置中配置,如下图所示。
其中/entry/manager/authorized/menus:GET 是获取菜单的请求
{
"/entry": {
"/service": {
"/manager": {
"/authorized": {
"/menus:GET": {
"title": {
"订单(多语言)": "Order(International)"
}
}
}
}
}
}
}
运行效果
开启多语言配置
系统默认不开启多语言,在企业门户中开启多语言。访问企业门户,打开统一通用配置,有三个多语言相关配置,分别是:开启多语言、当前语言、多语言配置。
开启多语言
开启多语言:在这里开启多语言和设置系统支持的语言
设置当前语言
当前语言:打开统一按组织配置,可以按组织设置当前语言
系统标题的多语言配置
打开统一通用配置,先设置系统名称和登录页标题,再设置语言资源。
- 在门户配置中设置系统名称
- 在登录配置中设置登录页标题
- 在移动端登录配置中设置登录页标题
- 在多语言配置中,配置某种语言的语言资源,一种语言对应一个配置项
其中 /entry/config/config/getconfig:GET 是获取统一通用配置的请求
{
"/entry": {
"/service": {
"/config": {
"/config": {
"/getconfig:GET":{
"loginTitle":{
"登录": "Login",
"欢迎": "Welcome"
},
"sysName":{
"系统": "System"
}
}
}
}
}
}
}
运行效果
页面文字的多语言配置
找出页面的路径
在浏览器中打开页面,地址栏里面会显示页面路径。例如打开组织管理页面后,地址栏里面的地址为
http://域名/entry/pcxapp/#/entry/pcxapp/pcx/index#/entry/opm-mobileapp/opm-mobile/org
第二个#后面的路径即为页面的路径:/entry/opm-mobileapp/opm-mobile/org 是桌面端页面,实际路径是:/entry/opm-pcxapp/opm-pcx/org.w 属于企业门户应用 entry,IDE 中的路径是:/UI2/opm-pcx/org.w
找到资源文件
打开企业门户应用的 IDE,找到 /UI2/opm-pcx/i18n 目录,这个目录下一般包括3个语言目录,中文简体:zh-CN、中文繁体:zh-TW、英语:en-US。在语言目录下是资源文件 resource.json。在资源文件中找到页面中资源的定义,如下图所示
添加多语言配置
在多语言配置中,逐级写出页面路径,在页面下写出语言资源,如下图所示
配置完成后,刷新页面查看配置效果,如下图所示
定义公共语言资源
如果多个页面,需要设置统一的语言资源,可以将语言资源直接定义到根下。下面以控制台门户将“租户”替换为“空间”为例说明
在多语言配置中,页面上统一使用的语言资源直接写在根下,后端服务的语言资源还是写到精确位置下,如下图所示
{
"租户名称或编码": "空间名称或编码",
"租户": "空间",
"租户名称": "空间名称",
"租户编码": "空间编码",
"租户编辑": "空间编辑",
"租户账号": "空间账号",
"查看租户账号": "查看空间账号",
"添加租户": "添加空间",
"租户设置": "空间设置",
"租户组织": "空间组织",
"/entry": {
"/service": {
"/manager": {
"/authorized": {
"/menus:GET": {
"title": {
"租户管理": "空间管理",
"租户统计": "空间统计",
"我的租户": "我的空间",
"租户申请": "空间申请",
"租户变更申请": "空间变更申请"
}
}
}
}
}
}
}
配置完成后,刷新页面查看配置效果,如下图所示
特别说明
- 前端多语言配置支持根节点及精确路径定义
- 后端服务只支持精确路径定义
总结,根据需要,页面的语言资源,即可以定义在页面的精确路径下,也可以定义在根下;后端请求的语言资源,必须定义在请求的精确路径下。示例代码如下
{
"租户名称或编码": "空间名称或编码",
"租户": "空间",
"租户名称": "空间名称",
"租户编码": "空间编码",
"租户编辑": "空间编辑",
"租户账号": "空间账号",
"查看租户账号": "查看空间账号",
"/consoleui": {
"/pcxapp": {
"/pcx": {
"/tenants": {
"/adminTenants.w": {
"添加租户": "添加空间",
"租户设置": "空间设置"
}
}
}
}
},
"/entry": {
"/service": {
"/manager": {
"/authorized": {
"/menus:GET": {
"title": {
"租户管理": "空间管理",
"租户统计": "空间统计",
"我的租户": "我的空间",
"租户申请": "空间申请",
"租户变更申请": "空间变更申请"
}
}
}
}
},
"/pcxapp": {
"/pcx": {
"/index.HeaderAvatar.js": {
"租户组织": "空间组织"
}
}
}
}
}