我们当前正处于一个全球化的世界,所以我们开发的 App
也会有很大的概率,需要满足国际化多语言的需求。今天刚好看到有个小伙伴遇到了这个需求需要实现,这里就借此机会,简单讲解一下,在 YonBuilder移动开发
技术中,如果去实现一个支持国际化多语言的 App
应用开发。
多语言国际化,说白了就是将页面的文字内容显示为指定的国家语音。根据这个核心诉求,我们可以将整体功能拆分成以下的几个功能点需求:
这个是物料基础,用于切换到对应的语言后,可以正确的显示对应内容
可以使用vue、react或者doT等模板渲染框架,目的是一旦切换了系统语言后,页面可以动态的进行快速切换
包括获取当前多语言版本、设置多语言版本、读取多语言版本、读取多语言内容、页面实时渲染等逻辑
PS: 还未学习创建的新手同学,可跳转【2023最新】超详细图文保姆级教程:App开发新手入门(1),进行基础学习后再回来继续。
创建一个应用,并在本地使用 YonStudio
开发工具打开
我们直接修改 ./html/main.html
页面,下面仅讲解涉及的主要功能代码,全部代码可去我的gitee仓库:https://gitee.com/T0T/yonbuilder-app-demos下载。
说明:本页面的数据绑定实现方式是通过引用 vue
框架来实现的,将最新的 vue.js
代码下载到本地j进行保存, 本次演示引用的是 vue3
框架代码
https://unpkg.com/vue@3.4.14/dist/vue.global.prod.js
PS: 通过 src
直接引用 cdn
链接也是可以的,不过在实际开发中,因为网络网速的原因,还是放在本地直接引用的方式,运行效率会更好。
页面内通过 script
标签引用 vue
文件
<head>
<script src="../script/vue.global.prod.js"></script>
<style>
html,body {
height: 100%;
width: 100%;
}
....代码省略
</style>
</head>
编写页面内容,对于需要做国际化的文字内容,使用模板变量来进行标识,及 下面代码块中的 {{ }}
,这些是vue的基本语法规则,这里就不多说了。
<body id="app">
<div class="panel">
<div class="title">{{ title }}</div>
<div class="row">
<span class="row-label">{{ nameLabel }}:</span>
<span class="row-content">{{ name }}</span>
</div>
<div class="row">
<span class="row-label">{{ ageLabel }}:</span>
<span class="row-content">{{ age }}</span>
</div>
</div>
<div class="panel" style="margin-top: 50px;">
<div class="title">多语言切换操作</div>
<div class="flex-row">
<div class="btn" tapmode="cilck-active" :class="{active: i18nKey==='zh-CN'}" @click="handleSetI18n('zh-CN')">中文</div>
<div class="btn" :class="{active: i18nKey==='en-US'}" tapmode="cilck-active" @click="handleSetI18n('en-US')">英文</div>
</div>
</div>
</body>
在运行逻辑部分,我们先初始化 vue
示例对象,然后在 生命周期事件 mounted
方法内,调用内部的 initPageWithVue()
方法进行页面的初始化逻辑操作。
// 页面内容国际化
addI18nChangeListener(this.parsePageWithI18n);
this.parsePageWithI18n();
上面代码实现了2个业务功能
addI18nChangeListener
方法是添加了国际化语音切换的事件监听,当在其他页面切换语言后,当前页面通过该监听获取该事件,然后即可调用 parsePageWithI18n
方法,进行页面内容的国际化切换。
该方法是封装在 i18n.js
文件内,当前页面通过 script
脚本方式引入,具体的内容,等后面我们讲解 i18n.js
文件时再展开。
<script type="text/javascript" src="../script/i18n.js"></script>
parsePageWithI18n
方法,主要逻辑是负责将当前页面的内容,转化成当前正在使用的国际化语言内容。
对当前页面的文本内容进行初始变量值的国际化处理,可以看到在 parsePageWithI18n
方法中,我们通过调用 parseWord
函数,对文本内容进行国际化内容转换。这个 parseWord
函数也是我们自己编写后封装在 i18n.js
文件中的,后面我们会做详细介绍。
parsePageWithI18n() {
this.i18nKey = getI18n();
this.title = parseWord('人物简介');
this.nameLabel = parseWord('姓名');
this.name = parseWord('张三');
this.ageLabel = parseWord('年龄');
}
当前页面我们还设置了一个切换国际化语音的方法 handleSetI18n
,用于模拟实际业务中的国际化语音切换。
handleSetI18n(i18nSign){
if(!i18nSign) return;
setI18n(i18nSign);
}
在实际业务中,根据产品需求,有可能在 App
应用中,显示的提供语言切换按钮,像本次 App
这样。也有可能直接获取手机操作系统的本地语言,然后 App
进行动态的适配。原来大致都是一样的,获取操作系统的本地语言,可以使用引擎提供的 api.language
方法
我们需要根据页面中需要进行国际化的语言内容,进行整理,然后编写一个最终版本的 国际化资源文件。当然此方法并不是唯一的实现逻辑,我们也可以根据需要,将文件内容按不同的维度拆分成多个文件进行相应的读取处理,这里我们主要讲解基本的实现思路,就不进行过多的扩展了。
我们实际 demo
应用中的 ./script/i18n.js
文件,就是我们最终封装的国际化多语言服务脚本。其中我们主要定义了以下几个主要的功能逻辑。
根据实际业务需要,我们可以增加自己的多语言适配版本。
PS: 当前使用中文内容作为 map
中的 key
,主要是为了方便在具体的引用页面中,可以直观的了解当前的文本内容的含义。开发者也可以使用英文或其他文本内容作为标识,这个并不强制唯一。
var i18nMapData = {
'多语言国际化示例': {
'zh-CN': '多语言国际化示例',
'en-US': 'i18n Demo'
},
'人物简介': {
'zh-CN': '人物简介',
'en-US': 'profile'
},
'姓名': {
'zh-CN': '姓名',
'en-US': 'name'
},
'张三': {
'zh-CN': '张三',
'en-US': 'three'
},
'年龄': {
'zh-CN': '年龄',
'en-US': 'age'
},
}
PS: 数据的本地化存储有多重方式,本处代码中,使用 api.setPrefs
、api.getPrefs
函数方法进行数据的本地化存储读取的主要原因是 api.getPrefs
函数方法支持同步读取(及下面代码的 sync: true
),大多数的本地读取是异步的,如果开发者经验不足,容易产生一些不必要的逻辑错误。
/**
* 读取国际化语言的判断标识(采用同步策略)
* @returns
*/
function getI18n() {
var i18nStr = api.getPrefs({
sync: true,
key: 'i18n'
});
if(!i18nStr) {
i18nStr = api.language;
setI18n(i18nStr);
}
return i18nStr;
}
这里我们在进行本地设置的同时,向外部发送了一个 i18nChange
的消息事件,主要的目的帮助已经加载完毕的页面,通过监听该事件,实现页面内容的动态国际化切换。
/**
* 存储国际化语言的判断标识
* @param {String} i18nSign
*/
function setI18n(i18nSign) {
// 新的系统语言标识
var i18nStr = i18nSign ? i18nSign : api.language;
// 本地缓存
api.setPrefs({
key: 'i18n',
value: i18nStr
});
// 发送同步通知,用于一些已经初始化的页面进行动态切换(按业务需要,非必须)
api.sendEvent({
name:'i18nChange',
extra: {
i18nSign: i18nStr
}
})
}
需要国际化的页面,通过调用本方法,即添加了事件监听。页面通过将自己内部的国际化处理函数传入当前方法,当事件触发时,通过回调机制触发函数执行,从而实现了自动化的国际化内容处理。
/**
* 添加i18n改变的页面监听
* @param {Function} callBack 触发事件后的回调函数
*/
function addI18nChangeListener(callBack) {
api.addEventListener({
name:'i18nChange'
}, function(ret){
if(typeof callBack === 'function') {
callBack(ret.value);
}
})
}
以上只是一个简单的多语言Demo
,意在示范整体的实现思路逻辑,在实际的应用开发中,开发者需要根据实际的业务逻辑进行相应的变通修改。
比如上面只是展示了页面内的静态内容的替换,那么对于一些交互的提示信息等动态内容并未展示。其实他们的内在逻辑是一样的,就是在内容展示的前一个周期内,将需要展示的文字内容动态替换为对应的语言内容即可。
另外我们在实际开发中,会向后端服务器发送请求,接收服务端的响应数据,并根据业务逻辑进行展示(正确的提示或者错误的提示等)。如果客户端展示的内容是由服务端提供的,那么这里有2种实现方式。
一种是前端将当前系统语音版本信息发送给服务端,由服务端负责返回对应的多语言内容;
另一种是将服务端返回的提示信息整理成固定的多语言版本文件,然后存储到前端应用中,由前端自行完成语言切换;
这两种方法都OK,具体实践中可以由前后端的开发人员一起沟通确定即可。
其他的比如切换系统语言后,如何实现页面的实时刷新,这里我们可以使用 事件监听或者跨页面执行脚本等支持消息传递的方法去实现事件触发即可。
注意事项: 因为各语种同一个意思的文字长度不相同,有的会很长,所以在实现了内容文字的动态国际化功能后,建议去每一个页面都去进行实际的切换,对于某些文字超出限定范围的情况,需要单独的定制化的去优化样式,达到最佳效果。
提醒: 通常我们进行国际化,只需要国际化我们开发负责实现的那些固定的文字内容即可,这里有两个关键词:开发负责实现、固定内容。进一步的解释就是,系统功能面板(比如由操作系统提供的一些显示亣内容,不需要我们开发处理,通常会跟随操作系统的语言进行动态切换的。另外相对于固定内容,动态内容通常是由服务端返回,并且大部分内容很难在开发阶段预判,所以尽量返回内容的国际化的工作由服务端负责,或者就不需要支持动态内容的国际化。
PS: 在代码编写过程中,我使用了 var
等老式的原生js语法编写,当前市场上虽然大部分手机系统都已经支持了 ES6
的新语法,但还存在一定量的手机系统的浏览器引擎并不支持,所以如果我们进行商业应用开发的话,这一点还是要注意的。另外,本次 demo
使用的是 html
混合方式进行的页面开发,如果使用 AVM
框架进行开发,则没有这方面的问题,因为 AVM
框架本身含有 build
的编译过程,可以对 ES6
等新语法进行兼容性处理。
道阻且长,祝顺利!加油 -~~!