⼩程序-国际化(miniprogram-i18n)
前情提要
最近维护了⼀个⼩程序的⽼项⽬,维护的其中⼀项是添加国际化。由于踩了蛮多坑,所以就有了这篇⽂档miniprogram-i18n
对除⼩程序外的其他框架开发做过国际化的朋友来说i18n这⼏个字母应该不陌⽣,i18n之所以叫i18n是因为次单词长度为20,以i开头以n结束,i和n之间间隔18位。
国际化全流程及踩坑
⾸先,在⼩程序项⽬中引⼊依赖。官⽅⽂档上有依赖安装位置及⽂件关系,详情可点击查看,简单理解为,在⼩程序根⽬录下使⽤命令⾏安装依赖
npm i -D gulp @miniprogram-i18n/gulp-i18n-locales @miniprogram-i18n/gulp-i18n-wxml
这⼀步做了什么呢?
安装了gulp、和miniprogram-i18n的gulp插件。
为什么要安装这些呢?
为了打包⽣成翻译⽂件以及编译`.wxml`⽂件。
为什么要打包呢?
这就是⼀个需要了解国际化原理的问题了,我将其理解为:在打包之前,我们写的语⾔翻译配置⽂件与页⾯还没有真正地联系起来,打包之后会⽣成⼀个`locales.js`和`locales.wxs`⽂件,配合`gulp-i18n-xml`插件将`.wxs`引⼊到每⼀个页⾯中,这样才能真正的实现页⾯翻译。
为什么要⽤`gulp-i18n-xml`打包`.wxml`⽂件呢?
因为按照官⽅时使⽤指南,我们在页⾯的使⽤中直接是`{{t('key')}}`这样的⽅式进⾏⽂本翻译的,然⽽真正实现国际化的`.xml`写法的语句是`<wxs src="⽣成的locale.wxs⽂件路径" module="i18n"/> <view>{{i18n.t('key', $_locale)}}</view>`这样的。也就是说,使⽤此插件可以⾃动为`.wxml`引⼊`.wxs`并且将翻译的⽂本转换为实现所需要的格式,如此可以减少开发者的代码编写数量。
⼀定要使⽤`gulp-i18n-xml`才能实现翻译吗?
不是。如上所说,此插件实际上只是减少开发者的代码编写数量,如果开发者⼿动引⼊⽂件,并在使⽤时以`i18n.t('key', $_locale)`这样的形式实现⽂本翻译时,即可不⽤此插件。
顺便⼀说,如果要直接使⽤此插件⽣成翻译⽂件,那⼏乎是将现有⽂件完全⽣成⼀份新的到⽬标⽂件夹下,项⽬发布时,直接发布打包后的⽂件到⽣产。这对于从0开始的项⽬来说这并没有什么影响甚⾄能减少开发者⼯作量(也许),但如果是维护⽼项⽬的话,此举可能并不是明智的。
如果使⽤`i18n.t('key', $_locale)`的形式实现,引⼊的⽂件从哪⾥获得呢?
前⾯说过,打包之后会⽣成⼀个`locales.js`和`locales.wxs`⽂件,引⼊的就是此`locales.wxs`⽂件。
完全交由gulp⼯具打包需要注意什么呢?
如果是维护⽼项⽬,那么⽬录结构⼀般都是`pages、app.js、app.json、app.wxss、otherFolders/页⾯⽂件(夹),此时打包需要注意将同级⽬录每⼀个需要的⽂件都copy⼀份到⽬标⽂件夹下,并注意路径。如果是新项⽬可以将需要打包的⽂件全部放置于⼀个src⽂件夹内(注意:需要的⽂件多半还包括package.json,也就是src⽂件夹内外部可能都需要⼀个package.json⽂件,可参照官⽅example的⽬录结构搭建)。
注意:如果没有将`node_modules`或`miniprogram_npm`打包到⽬标⽂件夹下,需要在⽬标⽂件夹下执⾏`npm i`和`构建npm`
根据官⽅⽂档和example可以发现,官⽅打包前的⽂件⽬录结构是app.js/json/wxs以及page、i18n、
静态资源⽂件夹等都由⼀个src⽂件夹包裹着,中将i18n交由`gulp-i18n-locale`处理,wxml⽂件交由`gulp-i18n-xml`处理,src⽬录下的其他⽂件全部copy到⽬标⽬标⽣成⽂件夹下。
上⼀步我们已经往安装了依赖,现在需要在⼩程序中使⽤⼯具构建npm,如此才能在⼩程序js⽂件中成功引⽤依赖。
`⼯具`->`构建npm`
构建npm出错?
可能的原因是:未成功安装依赖,可以先卸载依赖再安装;当前构建npm的位置没有package.json⽂件;
上⼀步我们已经往⼩程序中注⼊了依赖,接下来就是如何使⽤的问题。通过官⽅⽂档可以直到需要在i18n⽂件夹内新建语⾔配置的json⽂件(⽐如en-US、zh-CN)
// en
{
"hello": "Hello"
}
// zh
{
"hello": "你好"
}
然后在需要使⽤国际化的页⾯的js中
...
import { I18n } from '@miniprogram-i18n/core';
Component({
behaviores: [I18n]
})
页⾯使⽤
<view>{{t('hello')}}</view>
必须要⽤Component吗?
我们在⼩程序官⽅⽂档发现`behaviors`是Component构造器所有的,那么如果当前是Page怎么办呢?国际化官⽅⽂档中建议都使⽤Component构造器定义,否则就需要引⼊I18nPage代替Page构造器。然⽽在实践中发现直接在Page构造器中直接使⽤`behaviors`并不会报错,i18n也能被正确引⼊(直到2022/01/19)。当然这只是针对维护⽼项⽬⽽⾔,也许这样做存在系列潜在风险,出于安全考虑,在使⽤Component构造器或者I18nPage都⽅便的前提下,最好还是不要尝试以上的⽅法。
为什么照官⽅⽂档做了,还是不能正常翻译?
实际上,到这⼀步⽆法正常翻译才是正确的结果,甚⾄在控制台可能会看到这样的报错:
根据以上报错,提⽰我们在使⽤I18n之前确保在app.js⽂件中运⾏了initI18n()。回顾我们之前的操作,没见过也没有运⾏过这⼀函数。不必惊慌,导致这⼀错误并不完全是我们的问题,因为官⽅的快速开始⽂档⾥确实没有对这⼀步的相关描述(不过在⾥有描述)。
按照控制台报错,我们在app.js中执⾏InitI18n()
...
import { initI18n } from '@miniprogram-i18n/core'
initI18n('en-US')
App({
...
})
再检查页⾯,此时翻译⽂本就正常显⽰了,并且控制台不再有出现上⾯描述的错误
为什么官⽅的select,我不能成功使⽤?
截⽌2022/01/19,本⼈尚未成功使⽤过select。根据⽂档,我想⽂档中特性部分的`⽬前 miniprogram-i18n 仅⽀持纯⽂本及⽂本插值,后续会对其他i18n 特性进⾏⽀持。`这句话也许是答案。
如何在js中使⽤i18n?
截⽌2022/01/19,本⼈也尚未成功在js中成功使⽤i18n(官⽅的example可以),不过项⽬与官⽅example不同的地⽅是:使⽤Page构造器,并且没有使⽤I18nPage代替;国际化是通过将gulp⽣成的两个国际化⽂件copy出来⼿动引⼊实现的。(事实上,更改Page,和⾃动⽣成.wxml⽂件,也依旧没有成功)。
在官⽅给出的样本中,是能够在js⽂件中使⽤i18n的,只是同步渲染存在⼀点⼩问题(也就是通过js⽂件处理展⽰在页⾯上的国际化⽂本,在语⾔切换后,在不进⾏任何其他函数处理的前提下,不会同步转换为当前语⾔的⽂本)。
什么时候build呢?
每当翻译配置⽂件有内容修改时。如果是⼿动引⼊locales.wxs,每当翻译配置⽂件有内容修改时,都需要build⽣成新的⽂件。
每当涉及国际化的⽂件有变动时。如果是⾃动build实现locales.wxs⽂件引⼊,每当wxml有国际化相关内容变动、翻译配置⽂件有内容修改时,都需要build重新⽣成。
本⼈项⽬参考
前提了解:维护⽼项⽬,没有⼀个⽤于包裹pages、utils、assets、app.*等⽂件(夹)的src⽂件夹。
安装依赖
构建npm
新建语⾔配置⽂件
在根⽬录下(与app.*⽂件同级)新建i18n⽂件夹,⽂件夹内新建两个json⽂件,分别是`en-US.json`与`zh-CN` {
"index": "⾸页",
"hello": "你好{name}, 欢迎!"
...
}
{
"index": "Index",
"hello": "Hello {name}, Welcome!"代码转换
...
}
gulp配置
在根⽬录下(与app.*⽂件同级)新建gulpfile.js⽂件
1 const { src, dest, series } = require('gulp')
2 const gulpI18nWxml = require('@miniprogram-i18n/gulp-i18n-wxml')
3 const gulpI18nLocales = require('@miniprogram-i18n/gulp-i18n-locales')
4
5 function mergeAndGenerateLocales() {
6 return src('i18n/*.json')
7 .pipe(gulpI18nLocales({ defaultLocale: 'zh-CN', fallbackLocale: 'zh-CN' }))
8 .pipe(dest('dist/src/i18n/'))
9 }
10 export.default = series(mergeAndGenerateLocales)
package.json⽂件"script"配置
{
...
"script": {
"build": "gulp",
...
},
...
}
i18n初始化
在app.js⽂件中
...
import { initI18n, getI18nInstance } from '@miniprogram-i18n/core'
initI18n("en-US")
App({
onLaunch: function() {
/** 获得本地语⾔ */
const lang = wx.getAppBaseInfo().language
const i18n = getI18nInstance()
/
** 根据本地语⾔设置⼩程序语⾔ */
i18n.LowerCase().includes('zh') ? 'zh-CN' : 'en-US')
}
})
在需要使⽤到国际化翻译页⾯的js⽂件引⼊I18n
...
const { I18n } = require('@miniproogram-i18n/core')
Page({
behabiors: [I18n],
...
})
打包⽣成locale.*⽂件
在gulpfile.js⽂件所在⽂件夹,⽤命令⾏运⾏
npm run build
从dist/src/i18n⽂件夹下,将⽣成的`locales.js`及`locales.wxs`拷贝到任意位置(我的位置是utils/i18n/)
在需要使⽤到国际化翻译页⾯的wxml⽂件中引⼊并书写翻译⽂本
<wxs src="../../utils/i18n/locales.wxs" module="i18n"></wxs>
<view class="warpper">
<view>{{ i18n.t('index', $_locale) }}</view>
<text>{{ i18n.t('hello', { name: 'Jone' }, $_locale) }}</text>
</view>
当翻译配置⽂件有变动的时候,重新build并更新utils/i18n/⽂件夹下的两个⽂件
官⽅样本
在社区看到不少朋友有⽆法顺利打开官⽅提供的example的困扰,在这⾥也单独说⼀下。
先从glthub将下载到本地,此时可以先不在开发者⼯具中打开此项⽬,即使打开页⾯也不会正常显⽰,因为根⽂件夹下没有app.*⽂件。
在gulpfile.js所在的⽂件位置,命令⾏运⾏。
此时会有⼀个新的`dist`⽂件夹,进⼊dist⽂件夹。
命令⾏依次运⾏。
npm install
npm run build
在开发者⼯具中导⼊dist⽂件夹这个项⽬(注意是dist)。
点击`⼯具`->`构建npm`
此时页⾯应该已经加载在模拟器中了,如果没有,可以点击`预览`(Windows系统也可以使⽤Ctrl+B快捷键)。
下载下来的example不能直接打开的可能原因⼀是:没有依赖。⼆是:根⽬录下没有`app.*`⽂件。
example就是典型的将所有都交给gulp打包的案例,我们编辑的⽂件只是为了⽤于⽣成dist⽂件夹中的内容,⽽真正查看效果以及上传到版本的是dist内的⽣成的⽂件。
个⼈遗留问题
1. 在Page构造器中使⽤`behaviors`有没有/有哪些副作⽤?
2. 为什么不能在js⽂件中使⽤I18n?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论