更新记录

102(2023-12-20)

1、使用文档更新

101(2023-12-20)

1、程序优化 2、使用说明优化

100(2023-12-20)

1、uniapp国际化应用与示例

查看更多

平台兼容性

Vue2 Vue3
×
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.98 app-vue app-nvue × × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari

前言

实际上uni官网关于国际化应用的文档写的已经很详细了,因近期公司项目应用到国际化,在使用的过程中,也遇到了一些问题,特梳理了记录下~

国际化配置

main.js引入并初始化VueI18n

import App from './App'
import Vue from 'vue'
import VueI18n from 'vue-i18n'

// 多语言
import {
    langMessage
} from '@/locale/index'

let i18nConfig = {
    locale: uni.getLocale() || systemInfo.language || 'zh-Hant',
    fallbackLocale: "zh-Hant",
    silentTranslationWarn: true, // 去除国际化警告
    messages: langMessage()
}

Vue.use(VueI18n)
const i18n = new VueI18n(i18nConfig)

Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
    i18n,
    ...App
})
app.$mount()

细心的同学肯定会发现,为啥这边引入多语言内容的方式与官网示例有点不同。

官网是直接引用多语言的json文件,考虑到json文件不好进行模块拆分,把项目中所有的多语言都配置在同一个文件,会导致后期维护麻烦,本项目示例中按模块进行拆分。具体的可查看@/common/i18n/(业务中使用的国际化语言包)。

当然,别忘了把数据格式转换成uniapp支持的格式,在main.js引用前,数据进行转换,原码路径@/locale/index

import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
import {
    messages
} from '@/common/i18n/index.js'

/**
 * 多语言数据格式转换
 * @param {Object} messages
 * @param {Object} key
 */
function dataFormatting(messages, key) {
    let map = {};

    function objParse(holder, key, lastKey) {
        if (holder && typeof holder === "object") {
            if (key !== '') {
                lastKey += key + "."
            }
            // 对象遍历
            for (let k in holder) {
                objParse(holder[k], k, lastKey);
            }
        } else {
            lastKey += key
            map[lastKey] = holder
        }
    }

    objParse(messages[key], "", "")

    return map;
}

let i18nMessage = {}
export function langMessage() {
    // 缓存,防止多次转化
    if (Object.keys(i18nMessage).length === 0) {
        i18nMessage = {
            'en': {
                ...en,
                ...dataFormatting(messages, "en")
            },
            'zh-Hans': {
                ...zhHans,
                ...dataFormatting(messages, "zh-Hans")
            },
            'zh-Hant': {
                ...zhHant,
                ...dataFormatting(messages, "zh-Hant")
            }
        }

        // compareDiff(i18nMessage)
    }

    return i18nMessage
}

@/locale/index中,提供了各语言包之间的比对,方便快速定位哪些国际化key漏配。

基本用法(vue或js)

在vue或js中,使用与web方案很相近,页面模板中使用 $t() 获取,并传递国际文件中定义的key,js中使用 this.$t(''),具体使用示例见index.vue

<template>
    <view class="content">
        <image class="logo" src="/static/logo.png"></image>
        <view class="vue">
            <view class="vue__title">{{$t('index.title')}}</view>
            <view class="vue__desc">{{$t('index.desc')}}</view>
            <u--text mode="link" :text="$t('index.link')"
                href="https://uniapp.dcloud.net.cn/tutorial/i18n.html"></u--text>
        </view>
        <u-button :text="$t('index.button.clickMe')" type="success" @click="tip"></u-button>
    </view>
</template>

<script>
    export default {
        methods: {
            tip(){
                uni.showToast({
                    icon: 'none',
                    title: this.$t('index.tip.msg'),
                    duration: 3000
                });
            }
        }
    }
</script>

nvue页面国际化

nvue目前的国际化方案需要在每个页面单独引入uni-i18n,官网说后期会抹平差异,具体时间待定。

具体实现见nvue页面,考虑到项目可能会有多个nvue页面,把nvue页面需要引入的uni-i18n提成一个js,方便公用。

// @/common/util/i18n.js
import {
    initVueI18n
} from '@dcloudio/uni-i18n'

import {
    langMessage
} from '@/locale/index'

const {
    t
} = initVueI18n(langMessage())

export const i18n = {
    t
}
  • nvue页面国际化示例
<template>
    <view class="nvue">
        <text class="nvue__title">{{i18n.t('nvue.title')}}</text>
        <text class="nvue__desc">{{i18n.t('nvue.desc')}}</text>
        <text class="nvue__text">{{i18n.t('nvue.text')}}</text>
        <u--text mode="link" :text="i18n.t('nvue.link')" href="https://uniapp.dcloud.net.cn/tutorial/nvue-outline.html"></u--text>
    </view>
</template>

<script>
    import {
        i18n
    } from '@/common/util/i18n.js'
    export default {
        data() {
            return {
                i18n
            };
        }
    }
</script>

pages.json国际化

pages.json不属于vue页面,其中的原生tabbar和原生导航栏里也有文字内容。这部分国际化要特别注意,只能写在项目根目录的locale目录下配置语言json文件,我尝试过写在common/i18n,发现并没有生效,细想也能理解,因为这些内容的国际化在项目加载之前就生成了

// pages.json
{
    "pages": [
        {
            "path": "pages/index/index",
            "style": {
                "navigationBarTitleText": "%navigationBarTitleText.index%" // locale目录下 语言地区代码.json 文件中定义的 key,使用 %% 占位
            }
        },
        {
            "path" : "pages/nvue/nvue",
            "style" : 
            {
                "navigationBarTitleText" : "%navigationBarTitleText.nvue%",
                "enablePullDownRefresh" : false
            }
        },
        {
            "path" : "pages/setting/setting",
            "style" : 
            {
                "navigationBarTitleText" : "%navigationBarTitleText.setting%",
                "enablePullDownRefresh" : false
            }
        }
    ],
    "tabBar": {
        "borderStyle": "white",
        "color": "#999999",
        "selectedColor": "#4bb1ff",
        "backgroundColor": "#FFFFFF",
        "list": [{
                "text": "%tabbar.index%",
                "pagePath": "pages/index/index",
                "iconPath": "/static/images/tabbar/index.png",
                "selectedIconPath": "/static/images/tabbar/indexSelect.png"
            },
            {
                "text": "%tabbar.nvue%",
                "pagePath": "pages/nvue/nvue",
                "iconPath": "/static/images/tabbar/nvue.png",
                "selectedIconPath": "/static/images/tabbar/nvueSelect.png"
            },
            {
                "text": "%tabbar.setting%",
                "pagePath": "pages/setting/setting",
                "iconPath": "/static/images/tabbar/setting.png",
                "selectedIconPath": "/static/images/tabbar/settingSelect.png"
            }
        ]
    }
}

pages.json 支持以下属性配置国际化信息

navigationBarTitleText titleNView->titleText titleNView->searchInput->placeholder tabBar->list->text 注:小程序下不支持这种国际化方案,也可以使用设置tabbar和navigationbar的API来设置文字。或者废弃原生tabbar和navigationbar,使用自定义方式。

应用名称及iOS隐私提示语的国际化

"locales" : {
            "en" : {
                // 英文  
                "name" : "uni-i18n", // 应用名称  
                "ios" : {
                    "privacyDescription" : {
                        "NSPhotoLibraryUsageDescription" : "Get the user album content permission to manually select and upload photos from the album when changing avatar information. Is it allowed to read album content",
                        "NSCameraUsageDescription" : "Get the user camera permission to take photos and upload photos when changing avatar information. Is it allowed to use the camera"
                    }
                }
            },
            "zh" : {
                // 中文(简体)  
                "name" : "uni-国际化",
                "ios" : {
                    "privacyDescription" : {
                        //iOS平台隐私访问描述信息  
                        "NSPhotoLibraryUsageDescription" : "获取用户相册内容权限,用于更改头像信息时手动选择上传相册内的照片,是否允许读取相册内容",
                        "NSCameraUsageDescription" : "获取用户摄像头权限,用于更改头像信息时拍照上传照片,是否允许使用摄像头"
                    }
                }
            },
            "zh-TW" : {
                // 中文(繁体)
                "name" : "uni-國際化",
                "ios" : {
                    "privacyDescription" : {
                        //iOS平台隐私访问描述信息
                        "NSPhotoLibraryUsageDescription" : "獲取用戶相册內容許可權,用於更改頭像資訊時手動選擇上傳相册內的照片,是否允許讀取相册內容",
                        "NSCameraUsageDescription" : "獲取用戶監視器許可權,用於更改頭像資訊時拍照上傳照片,是否允許使用監視器"
                    }
                }
            }
        }

详细用法见应用云端打包国际化处理

应用名国际时,慎用以下方式,我遇到在本地调试时,经常提示异常。异常现象pages.json一致,在项目根目录增加locale/uni-app.语言地区代码.json文件,然后在 manifest.json 中使用%%占位

{
  "name" : "%app.name%",
}

遇到问题

  • 如何将语言包按模块拆分,方便后期维护

官网是直接引用多语言的json文件,考虑到json文件不好进行模块拆分,把项目中所有的多语言都配置在同一个文件,会导致后期维护麻烦,本项目示例中按模块进行拆分。具体的可查看@/common/i18n/(业务中使用的国际化语言包)。

  • nvue页面国际化问题

考虑到项目可能会有多个nvue页面,把nvue页面需要引入的uni-i18n提成一个js,方便公用,后续调用与vue页面类似

  • mainfest.json应用名称国际化后,自定义基座运行后提示异常

按照官网提示的示例,在项目根目录增加 locale/uni-app.语言地区代码.json 文件,然后在 manifest.json 中使用 %% 占位,自定义基座运行时,会提示如下异常,正式包打包应用名又能正常显示。

14:22:33.184 应用【%app.name%】已启动
14:22:34.197 error
14:22:34.197 请求的页面无法打开:file:///storage/emulated/0/Android/data/uni.UNIC0CCBD4/apps/__UNI__C0CCBD4/www/__uniappview.html at file:///android_asset/data/dcloud_error.html:41

具体的解决方案参考应用名称及iOS隐私提示语的国际化

当然,看再多的文档,不如亲身去体验~赶紧下载试试,如果有什么建议,欢迎指导交流~

原码地址

您可以前往gite下载,uni-i18n 也可以在插件市场下载uniapp国际化应用与示例

特别感谢

本项目使用的UI框架,界面风格大气,上手简单 uView

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问