前情提要

  最近维护了一个微信小程序的老项目,维护的其中一项是添加国际化。由于踩了蛮多坑,所以就有了这篇文档!!!

miniprogram-i18n

  对除小程序外的其他框架开发做过国际化的朋友来说i18n这几个字母应该不陌生,i18n之所以叫i18n是因为次单词长度为20,以i开头以n结束,i和n之间间隔18位。

国际化全流程及踩坑

  • 首先,在小程序项目中引入依赖。官方文档上有依赖安装位置及文件关系,详情可点击miniprogram-i18n查看,简单理解为,在小程序根目录下使用命令行安装依赖
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文件夹包裹着,gulp配置文件中将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.setLocale(lang.toLowerCase().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将example下载到本地,此时可以先不在开发者工具中打开此项目,即使打开页面也不会正常显示,因为根文件夹下没有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?

微信小程序-国际化(miniprogram-i18n)的更多相关文章

  1. 微信小程序国际化

    微信小程序国际化 现状 小程序国际化官方没有支持,也没有现成的插件. 网上有人做了国际化的尝试.但是只能替换静态文本,就是简单的键值匹配. vue-i18n 由于是基于html 和 vue, 不同于w ...

  2. 微信公众号菜单添加小程序,miniprogram,pagepath参数详解,php开发公众号

    随着微信小程序功能的开发, 已经可以跟公众号打通了, 主要有两种方式: 1) 在公众号文章中插入小程序 2) 在公众号菜单中添加小程序 第一种方式, 子恒老师在前面的课程已经详细介绍过, 今天来讲第二 ...

  3. 微信小程序web-view之wx.miniProgram.redirectTo

    17年微信小程序官方提供了web-view组件. 官方描述:web-view组件是一个可以用来承载网页的容器,会自动铺满整个小程序页面.个人类型与海外类型的小程序暂不支持使用. 这段时间研究了一下小程 ...

  4. 微信小程序的坑之wx.miniProgram.postMessage

    工作中有个需求是小程序的网页在关闭的时候,需要回传给小程序一个参数 查阅小程序官方文档,有这样一个接口 wx.miniProgram.postMessage ,可以用来从网页向小程序发送消息,然后通过 ...

  5. 微信小程序导航:官方工具+精品教程+DEMO集合(1月7更新)

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=14764346784612:简易教程:https://mp.weixin.qq.com/debug ...

  6. 官方问答--微信小程序常见FAQ (17.8.21-17.8.27)

    给提问的开发者的建议:提问之前先查询 文档.通过社区右上角搜索搜索已经存在的问题. 写一个简明扼要的标题,并且正文描述清楚你的问题. 提交 BUG:需要带上基础库版本号,设备信息(iOS, Andro ...

  7. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  8. 微信小程序 发现之旅(一)—— 项目搭建与页面跳转

    开发微信小程序需要注册一个小程序账号,具体流程可以参照官方教程: https://mp.weixin.qq.com/debug/wxadoc/dev/index.html 开通账户之后,在 “开发设置 ...

  9. 微信小程序开发笔记

    前言: 因为前段时间一直在做关于微信小程序方面的项目,作为一名后端的攻城狮而言做一些简单的前端页面数据操作和管理还是比较容易快上手的,当然前提是要理解微信小程序的基本语法和请求原理.该篇博客主要记录的 ...

随机推荐

  1. 如何获取网管MTU

    在本机打开dos窗口,执行: ping -f -l 1472 192.168.0.1 其中192.168.0.1是网关IP地址,1472是数据包的长度.请注意,上面的参数是"-l" ...

  2. LeetCode Top 100 Liked 点赞最高的 100 道算法题

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:刷题顺序,刷题路径,好题,top100,怎么刷题,Leet ...

  3. 第一篇CSDN博客,大家好!

    大家好,我是负雪明烛! 我这昵称的来源是喜欢一句很有意蕴的古诗--苍山负雪,明烛天南. 我喜欢这句诗,很多的账号都用了这个"负雪明烛"的昵称,如果大家在其他地方看到叫这个名字的人, ...

  4. 【LeetCode】716. Max Stack 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双栈 日期 题目地址:https://leetcode ...

  5. 【LeetCode】688. Knight Probability in Chessboard 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址:https://leetcode.com/problems/knight-pr ...

  6. 1198 - Karate Competition

    1198 - Karate Competition    PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 ...

  7. Codeforces 872B:Maximum of Maximums of Minimums(思维)

    B. Maximum of Maximums of Minimums You are given an array a1, a2, ..., an consisting of n integers, ...

  8. 防止 jar 包被反编译

    1.隔离Java程序 最简单的方法就是让用户不能够访问到Java Class程序,这种方法是最根本的方法,具体实现有多种方式.例如,开发人员可以将关键的Java Class放在服务器端,客户端通过访问 ...

  9. 【Java笔记】Java分包问题

    这个图讲的很清晰,转自-http://www.bubuko.com/infodetail-2219664.html

  10. [c++]关于指针的一些问题记录

    const char* 和char* 之间的转换 const char*是指向常量的指针,而不是指针本身为常量,可以不被初始化.该指针可以指向常量也可以指向变量,只是从该指针的角度而言,它所指向的是常 ...