微信小程序-國際化(miniprogram-i18n)


前情提要

  最近維護了一個微信小程序的老項目,維護的其中一項是添加國際化。由於踩了蠻多坑,所以就有了這篇文檔!!!

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>
<view>{{t('day', {day: '12'})}}</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?

  先說結果: this.t('hello') || this.t('day', {day : this.data.day}) // 文本插值語法

  我在最初編寫這篇博文的時候,是沒有成功在自己的js中成功使用js的,盡管官方的example成功了,我幾番比對都沒有發現自己漏掉了哪一步。直到前天突然靈光一閃,會不會是js中使用i18n的機制問題。結果我將原本單獨存放locale.*文件的i18n文件夾與國際化配置文件的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文件。(從配置會在第一次build時,在i18n文件夾下生成locales.js和locales.wxs文件,之后每一次build這兩個文件都會隨着配置文件的更新而更新

 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('i18n/'))
 9 }
10 export.default = series(mergeAndGenerateLocales)
  • package.json文件"script"配置
{
  ...
  "script": {
    "build": "gulp",
    ...
  },
 ...
}
  •  i18n初始化

  在app.js文件中

...
import { initI18n, getI18nInstance } from '@miniprogram-i18n/core'
const i18n = getI18nInstance() initI18n("en-US") App({ onLaunch: function() { /** 獲得本地語言 */ const lang = wx.getAppBaseInfo().language /** 根據本地語言設置小程序語言 */ i18n.setLocale(lang.toLowerCase().includes('zh') ? 'zh-CN' : 'en-US') } })
  • 在需要使用到國際化翻譯頁面的js文件引入I18n
...
const { I18n } = require('@miniproogram-i18n/core')
Component({
  behabiors: [I18n],
  ...
})
// 或者
...
const { I18nPage } = require('@miniprogram-i18n/core')
I18nPage({
...
})
  • 打包生成locale.*文件

  在gulpfile.js文件所在文件夾,用命令行運行

npm run build
  • 在需要使用到國際化翻譯頁面的wxml文件中引入並書寫翻譯文本
<wxs src="../..i18n/locales.wxs" module="i18n"></wxs>
<view class="warpper">
  <view>{{ i18n.t('index', $_locale) }}</view>
  <text>{{ i18n.t('hello', { name: 'Jone' }, $_locale) }}</text>
</view>
  • 在需要使用到國際化翻譯的js文件中
import { I18n } from "@miniprogram-i18n/core"
Component({
    behaviors: [I18n]
    data: {name: 'Developer'}
    methods: {
        OnLoad: function () {
            console.log(this.t('index'), this.t('hello', {name: this.data.name})
        }
    }
})
//或者
import { I18nPage } from "@miniprogram-i18n/core"
I18nPage({
    data: {name: 'Lii'} OnLoad: function () { console.log(this.t('index'), this.t('hello', {name: this.data.name}) } })
  • 當翻譯配置文件有變動的時候,重新build並更新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`有沒有/有哪些副作用?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM