README
简介
@volcengine/i18n
是针对node、web等泛前端场景推出的国际化运行时sdk,可帮助解决远程拉取国际化翻译平台数据并在运行时实时进行文案替换,快速接入翻译平台帮助应用国际化
使用场景
该 sdk 默认使用 i18next 框架为底座并基于开源社区进行功能扩展,实现多个场景下的国际化能力。如需更多的能力可查询官方网站进行判断
并且多种场景下只需安装一次,默认情况下是React
npm install @volcengine/i18n
以下多场景中 backend 参数一致,统一说明
字段名称 | 必填 | 类型 | 默认值 | 说明 |
---|---|---|---|---|
namespace | 是 | number|number[] | - | 国际化翻译平台空间 id |
apiKey | 是 | string | - | 国际化翻译平台apikey,用于鉴权 |
projectId | 是 | number | - | 国际化翻译平台项目 id,用于鉴权 |
operatorId | 是 | number | - | 国际化翻译平台用户id,必须是主账号,用户鉴权 |
mode | 否 | 'normal' | 'gray' | 'test' | normal | 选择拉取文案的环境,支持正式,测试,灰度环境。normal: 拉取正式环境 test: 拉取测试环境 gray: 拉取灰度环境 |
host | 否 | string | https://starling-public.snssdk.com | 文案数据获取的域名,默认国内 |
fallbackLangs | 否 | string[] | [] | 文案拉取兜底语种 |
version | 否 | string|string[] | [] | 按版本获取文案,与namespace一一对应 |
expiredTime | 否 | number | 60 * 1000 | 本地缓存过期时间,默认一分钟 |
timeout | 否 | number | 10000 | 接口请求超时时间,默认10s |
retry | 否 | number | 5 | 失败后重试次数,每隔1s重试一次,默认5次 |
enableWatch | 否 | boolean | false | 针对node,开启自动定时更新本地缓存 |
cron | 否 | string | */20 * * * * * | 针对node,每隔20分钟刷新一次,格式参考:https://crontab.guru/ |
React
React 场景下基于 react-i18next 进行处理,api一致,如需更多功能可查询官方网站
新建 i18n.js
import reactI18n from '@volcengine/i18n'
reactI18n.init({
lng: 'zh',
backend: {
namespace: 3174,
operatorId: 210041130,
apiKey: '704dbe7057f510ec8e4aedf71dc34d4f',
projectId: 4168,
}
})
export default reactI18n
入口index.js
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './i18n';
ReactDOM.render(
<Suspense fallback="Loading...">
<App />
</Suspense>,
document.getElementById('root')
);
页面使用-类组件
import React, { Component } from 'react';
import { withTranslation, Trans } from '@volcengine/i18n';
class Page extends Component {
render() {
const { t, i18n } = this.props;
const changeLanguage = (lng) => {
i18n.changeLanguage(lng);
};
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<button onClick={() => changeLanguage('zh')}>zh</button>
<button onClick={() => changeLanguage('en')}>en</button>
</div>
<h1>文案</h1>
<div>{t('normal')}</div>
<h1>文案,带插值</h1>
<div>{t('placeholder', { name: 'xx' })}</div>
<h1>文案,富文本</h1>
<Trans i18nKey="richText">
To get started, edit <code>src/App.js</code> and save to reload.
</Trans>
<h1>文案,带富文本插值 </h1>
<Trans
i18nKey="Welcome, <0>{name}</0>!"
components={[<code>src/App.js</code>]}
values={{ name: 3232 }}
/>
</div>
);
}
}
const PageWithTranslation = withTranslation('translations')(Page);
export default PageWithTranslation
页面使用-函数组件
import React, { Component } from 'react';
import { useTranslation, Trans } from '@volcengine/i18n';
function Page() {
const { t, i18n } = useTranslation();
const changeLanguage = (lng) => {
i18n.changeLanguage(lng);
};
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<button onClick={() => changeLanguage('zh')}>zh</button>
<button onClick={() => changeLanguage('en')}>en</button>
</div>
<h1>文案</h1>
<div>{t('normal')}</div>
<h1>文案,带插值</h1>
<div>{t('placeholder', { name: 'xx' })}</div>
<h1>文案,富文本</h1>
<Trans i18nKey="richText">
To get started, edit <code>src/App.js</code> and save to reload.
</Trans>
<h1>文案,带富文本插值 </h1>
<Trans
i18nKey="Welcome, <0>{name}</0>!"
components={[<code>src/App.js</code>]}
values={{ name: 3232 }}
/>
</div>
);
}
export default Page
Vue
vue 场景下基于 vue-i18next 进行处理,api一致,如需更多功能可查询官方网站
入口main.js
import Vue from 'vue'
import App from './App.vue'
import vueI18n from '@volcengine/i18n/dist/vue';
const i18n = vueI18n.use(ICU).init({
lng: 'en',
backend: {
namespace: 39174,
operatorId: 2100041130,
apiKey: '704dbe7057f511ec8e4aedf71dc34d4f',
projectId: 4568,
}
}, Vue)
new Vue({
render: h => h(App),
i18n: i18n
}).$mount('#app')
使用
// 当注入语言如下
const locales = {
en: {
tos: "Term of Service",
term: "I accept {{0}}. {{1}}.",
promise: "I promise",
hello: "Hello {{name}}"
}
};
<template>
<div id="app">
<h1>文案</h1>
{{$t('tos')}}
<h1>文案带插值</h1>
<p ref="text" v-t="{ path: 'hello', args: { name: 'Hans' } }"></p>
<h1>文案带富文本</h1>
<i18next path="term" tag="label">
<a href="#" target="_blank">{{ $t("tos") }}</a>
<strong>{{ $t("promise") }}</strong>
</i18next>
</div>
</template>
node
node端如果有使用koa之类的框架,可以直接写一个中间件进行扩展:
const nodeI18n = require('@volcengine/i18n/dist/node')
module.exports = (options) => {
const i18n = nodeI18n.init({
lng: 'en',
backend: {
namespace: 3174,
operatorId: 210041130,
apiKey: '704dbe7057f510ec8e4aedf71dc34d4f',
projectId: 4168,
enableWatch: true
}
})
return async (ctx, next) => {
ctx.t = i18n.t
await next()
}
}
然后在代码中直接 ctx.t 进行调用
扩展功能
扩展功能都是基于i18next的生态,如想继续扩展可以在 i18next 插件自行寻找
浏览器语言检测
import LanguageDetector from 'i18next-browser-languagedetector';
import reactI18n from '@volcengine/i18n';
reactI18n.use(LanguageDetector).init({
...
})
ICU
文档:https://github.com/i18next/i18next-icu
import ICU from 'i18next-icu';
import reactI18n from '@volcengine/i18n';
reactI18n.use(ICU).init({
...
})
文案拉取
如果使用的不是 i18next 框架,但依旧要用到我们的国际化平台托管文案,我们也支持单独的文案拉取功能
web端
import WebBackend from '@volcengine/i18n/dist/backend/web'
// 这里的options同顶部backend参数
const web = new WebBackend({...})
web.load('zh', (err, data) => {
// data 数据结构:{ key: value }
})
// 然后注入到对应的intl框架中
node端
import NodeBackend from '@volcengine/i18n/dist/backend/node'
// 这里的options同顶部backend参数
const node = new WebBackend({...})
node.load('zh', (err, data) => {
// data 数据结构:{ key: value }
})
// 然后注入到对应的intl框架中
自定义场景扩展
自定义扩展必须实现以下四个方法
auth
获取签名接口
method: POST
参数
参数名 | 描述 |
---|---|
url | 鉴权文案接口地址 |
callback | (err, data) => void,有错误传err,正常请求传data,data结构: string |
fetch
拉取文案核心方案
method: GET
参数
参数名 | 描述 |
---|---|
url | 拉取文案接口地址 |
headers | 主要是 { Authorization: '' } 用于接口鉴权,需要放于请求头中 |
callback | (err, data) => void,有错误传err,正常请求传data,data结构: { key: value } |
setCache
保存文案进本地缓存,可以同时存入一个过期时间
参数
参数名 | 描述 |
---|---|
key | 缓存key |
value | value结构: { key: value } |
getCache
获取本地缓存
参数
参数名 | 描述 |
---|---|
key | 缓存key |
callback | (err, data) => void,有错误传err,正常请求传data,data结构: { key: value } |
import BaseBackend from '@volcengine/i18n/dist/backend/base'
class OtherBackend extends BaseBackend {
fetch(url, headers, callback) {
throw new StarlingError('fetch() needs to be implemented.')
}
auth(url, callback) {
throw new StarlingError('auth() needs to be implemented.')
}
getCache(key: string, callback) {
try {
const { expiredTime, value } = JSON.parse(localStorage.getItem(key) || '{}')
if (Date.now() - expiredTime < this.options.expiredTime && Object.keys(value).length) {
return callback(null, value)
}
callback(null, undefined)
} catch (error) {
callback(error, undefined)
}
}
setCache(key, value) {
try {
const data = { expiredTime: Date.now(), value }
localStorage.setItem(key, JSON.stringify(data))
} catch (error) {
//
}
}
}