前端国际化
最近做国外项目,需要实现项目的的国际化,这里大致捋一下思路、实现方式。项目技术栈是 vue + antd + java,我大致将需要翻译的内容划分为如下5个部分,接下来会一个一个的说明为何这么区分、如何实现翻译。这里强调一下,很负责的说,目前国际化,就是开发者写对象,一个key关联若干语种的翻译,纯手工翻译,目前不存在任何一下代码包可以一键智能翻译(因为翻译的不准)。ps:包括翻译表格表头,表头和表格体同时翻译都会说明
一、目录:
1、菜单等静态文本的国际化(I18n的使用,及其和antd的一些问题)
2、ui框架+其他外部依赖包的国际化
3、图片的国际化
4、服务端返回的国际化(接口反馈+维护数据)
5、登录页等无用户登录信息的国际化
二、菜单等静态文本的国际化
这些基本的静态信息的国际化,我采用 vue-i18n 这个包来实现的(详细用法请查npm),指令: npm i vue-i18n ;用法很简单,不过在触发翻译的机制上会有一些蛋疼的地方,待会具体写一下。
1、引入、配置
import Vue from 'vue'; import VueI18n from 'vue-i18n' Vue.use(VueI18n) const i18n = new VueI18n({ //定义默认语言 locale: 'zh', messages:{ 'zh': require('@/constants/lang/zh'), // 语言配置文件的路径 'us': require('@/constants/lang/us') } }) new Vue({ i18n, router render: (h) => h(App) }).$mount('#app')
module.exports = { // 公共 common: { // 按钮类 search: '查询', reset: '重置', collapse: '展开', add: '新增', delete: '删除', edit: '编辑', deleteMany: '批量删除', import: '导入', export: '导出', yes: '是', no: '否', confirm: '确认', cancel: '取消', changeLanguage: '切换语言', // 表格信息类 createName: '创建人员', createTime: '创建时间', updateName: '维护人员', updateTime: '维护时间', operation: '操作', // 提示类 requireRule: '该项为必填项', dataImport: '数据导入', }, // 提示信息 message: { text: '简体中文', delete: '确定要删除吗?', exportExcel: '正在导出Excel...', updateBom: '正在更新bom数据...', numberAndletter: '仅允许输入数字和字母,并以英文逗号分隔' }, // 文本提示 placeholder: { input: '请输入', select: '请选择', rangePicker: '开始日期 ~ 结束日期' } }
引入后需要做一个全局配置,目前我仅支持了中英,有需要的加不同语言配置文件即可。注意每个文本的分类,通常按照功能分类, 比如 一个一级菜单、通用按钮、提示信息等等。
2、具体使用
// 在HTML中使用 <span>{{ $t(message.delete) }}</span> // 在js中使用 this.$t(`message.exportExcel`) // 切换语言 changeLanguage() { let lang = this.$store.state.app.language === 'zh' ? 'us' : 'zh'; this.$i18n.locale = lang; this.$store.commit('CHANGE_LANGUAGE', lang ) },
语言属于用户属性,存储在数据库,登陆成功后我将语言存储在vuex中,只要是登陆的都可以保持语种状态。
3、遇到的坑
基础使用,自然没问题,但是和别的包配合使用就遇到问题了,大致如下:
(1)antd 的table,翻译他的表头
这个不能直接在js中翻译columns,因为不会触发自动转换,需要表头采用插槽的方式,如果是操作列需要翻译表格体也是同理,具体看代码
const columns = [ { // 只翻译表头 dataIndex: 'area', key: 'area', widtd: 120, align: 'center', slotName: 'calendar.area', scopedSlots: { title: 'calendar.area' } }, { // 操作类,翻译表格体,比如翻译 编辑 删除 操作 key: 'operation', fixed: 'right', widtd: 120, align: 'center', slotName: 'common.operation', scopedSlots: { title: 'common.operation', customRender: 'operationContent' }, }, ]; <a-table rowKey="id" :columns="columns" > // 翻译表头 <template v-for="(item, index) in columns" :slot="item.slotName"> <span :key="index">{{ $t(item.slotName) }}</span> </template> // 操作类,翻译表格体,比如翻译 编辑 删除 操 <span slot="operationContent" slot-scope="text,record"> <a @click="edit(record)"> {{ $t('common.edit') }}</a> </span> </a-table>
(2)路由数据的翻译,因为 router 和 I18n 的引入是同时的,所以无法直接翻译路由数据,只能在渲染菜单的时候进行翻译,这个具体要看项目架构了。目前我的处理方式是路由配置价格国际化字段,渲染之前根据字段去判断。
new Vue({ store, i18n, router, created () { bootstrap() }, render: (h) => h(App) }).$mount('#app')
三、ui框架+其他外部依赖包的国际化
1、antd 是有国际化组件的,也是监听vuex中语种字段,很简单就实现的 I18n 和 a-locale-provider 的同步。具体使用如下:
<template> <a-locale-provider :locale="locale"> <div id="app"> <router-view/> </div> </a-locale-provider> </template> <script> import { mapState } from 'vuex' import en_GB from 'ant-design-vue/lib/locale-provider/en_GB' import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN' import { AppDeviceEnquire } from '@/utils/mixin' export default { mixins: [AppDeviceEnquire], data () { return {} }, computed: mapState({ locale: state => state.app.language === 'zh' ? zhCN : en_GB, }) } </script>
2、其他包,比如 moment 等等,这个就得具体分析了,有的包根本就不支持,有的都是基于数据输入的可以做。选包需慎重。
四、图片的国际化
图片这种也分,如果像新闻这种每天更换的,直接服务端做区分,如果是固定的,就得做好几套,一般直接存储到不同语言目录下,监听全局的 language 变量展示不同路径图片即可
五、服务端返回的国际化(接口反馈+维护数据)
服务端的国际化主要是2块,一是:接口反馈信息,比如成功 失败的提示信息,需要直接返回指定语言的,前端不做任何处理,直接展示; 二是: 配置信息,比如某个下拉列表的信息是需要放在服务端的,就需要服务端按照语言返回。前端当然也能做,但是有些场景不允许前端写死,这类数据需要放在服务端。通常做法是数据加语种字段,用的时候筛选出来即可。
六、登录页等无用户登录信息的国际化
我们通常会将语言信息写到浏览器的 ocalstorage 中,如果涉及到没有用户信息的时候优先读取 ocalstorage ,比如 登录页。这样二次登录的用户是没问题的。如果 ocalstorage 没有,比如首次登陆、清楚本地缓存的情况,服务端会判断其IP的地区,根据当前我们的语种支持范围,选择一个可能性最大的,比如,目前我们项目,除了欧美、中南亚用户全部展示英文,中国展示中文。注意这个只是一个只能推荐,我们只考虑现实,VPN这种不考虑。另外建议登录页不要放太多文本类型的内容。
小结:
好了,这就是我对项目国际化的一些总结,一方面自己做记录,另一方面也希望能对大家有用吧。