使用 Gem 的国际化模块,你可以很迅速的为你的应用添加多语言支持。
import { I18n } from '@mantou/gem/helper/i18n';
const en = {
title: 'This is I18n',
};
const i18n = new I18n({
fallbackLanguage: 'en',
resources: {
en,
zh: 'data:text/plain;base64,eyJ0aXRsZSI6Iui/meaYr0kxOG4ifQ==',
},
});
console.log(i18n.get('title'));实例化 I18n 对象时会自动根据浏览器设置选择适当的语言。语言包支持远端读取,以实现按需加载。
TIP
建议使用 Crowdin,Pontoon 类似的服务来维护你的语言包
在元素中可以直接使用 i18n.get('title') 来读取语言包中的值。
@customElement('app-root')
class App extends GemElement {
render = () => {
return html`
<button @click=${() => i18n.setLanguage('zh')}>zh</button>
<p>${i18n.get('title')}</p>
`;
}
}用户选择语言或者远端语言包都可以进行缓存,在用户下次进入 App 时直接使用,使用 cache 指定,缓存数据将保存到 localStorage。
const i18n = new I18n({
cache: true,
fallbackLanguage: 'en',
resources: {
en,
zh: 'data:text/plain;base64,eyJ0aXRsZSI6Iui/meaYr0kxOG4ifQ==',
},
});在多语言项目中,常常有变量嵌入的情况,例如:
html`Hello, ${username}`;使用 Gem 时,你可以使用 $ 标记变量,例如:
const i18n = new I18n({
fallbackLanguage: 'en',
resources: {
en: {
hello: 'Hello, $1! $2=> $1, Hello!',
},
},
});
html`${i18n.get('hello', 'World', 'reverse')}`;
// Hello, World! reverse=> World, Hello!变量也可以是一个自定义渲染函数,它能将语言模版中提供的内容进行自定义渲染,下面的例子就是将语言条目中指定的单词 detail 渲染成链接:
const i18n = new I18n({
fallbackLanguage: 'en',
resources: {
en: {
detail: 'See $1<detail>, $1<detail2>',
},
},
});
html`${i18n.get('detail', (s) => html`<a href="#">${s}</a>`)}`;一般会为不同的语言生成唯一的 URL,因为这样能让搜索引擎进行准确的索引。I18n 在实例化时根据 urlParamsType 检查 URL,它支持:
path:根路径,例如 /zh/home
querystring:查询字符串,名称使用 urlParamsName 指定
ccTLD:子域名,例如 jp.website.com
gTLD:顶级域名,例如 website.jp
const i18n = new I18n({
fallbackLanguage: 'en',
urlParamsType: 'ccTLD',
resources: {
en: {
title: 'This is I18n',
},
},
});TIP
当 urlParamsType 为 path 或者 querystring,
页面中的链接、history 路由切换都需要修改。
例如,urlParamsType 为 path 时可以通过设置 history.basePath 来全局定义此操作:
new I18n({
urlParamsType: 'path',
fallbackLanguage: 'zh-CN',
resources: {
'zh-CN': zhCN,
},
onChange(lang) {
if (!history.basePath) {
history.basePath = '/' + lang;
const { path, query, hash } = history.getParams();
history.replace({ path, query, hash });
} else {
const { path, query, hash } = history.getParams();
history.basePath = '/' + lang;
history.replace({ path, query, hash });
}
},
});
I18n.createSubModule 创建子模块,你可以按路由分割语言包,加快首屏渲染速度。
可以使用 <gem-route> 根据不同语言渲染不同的内容,只需要将 trigger 指定为 i18n 即可,例如:
const localizeRoutes = [
{
pattern: 'zh-*',
async getContent() {
import('...');
return html`other element`;
},
},
];
html`<gem-route .trigger=${i18n} .routes=${localizeRoutes}></gem-route>`;
import { customElement, GemElement, html, render } from '@mantou/gem';
import { I18n } from '@mantou/gem/helper/i18n';
import type { RouteItem } from 'duoyun-ui/elements/route';
import 'duoyun-ui/elements/route';
import '../elements/layout';
const en = {
title: 'This is I18n',
hello: 'Hello, $1! $2=> $1, Hello!',
detail: 'See $1<detail>, $1<detail2>',
};
const i18n = new I18n<typeof en>({
cache: true,
fallbackLanguage: 'en',
resources: {
en,
de: {
title: 'Das ist I18n',
},
zh: 'data:text/plain;base64,eyJ0aXRsZSI6Iui/meaYr0kxOG4ifQ==',
},
onChange: console.log,
});
const i18nModule = i18n.createSubModule<typeof en>('test', {
en,
de: {
title: 'Das ist I18n',
},
zh: 'data:text/plain;base64,eyJ0aXRsZSI6Iui/meaYr0kxOG4ifQ==',
});
const localizeRoutes: RouteItem[] = [
{
pattern: 'en',
getContent() {
return html`en element`;
},
},
{
pattern: 'de',
getContent() {
return html`de element`;
},
},
{
pattern: '*',
getContent() {
return html`other element`;
},
},
];
@customElement('app-root')
export class App extends GemElement {
render() {
return html`
<button @click=${() => i18n.setLanguage('de')}>de</button>
<button @click=${() => i18n.setLanguage('zh')}>zh</button>
<button @click=${() => i18n.setLanguage('en')}>en</button>
<button @click=${() => i18n.resetLanguage()}>reset</button>
<p>Current language: ${i18n.currentLanguage}</p>
<p>${i18n.get('title')}</p>
<p>${i18n.get('hello', 'World', 'reverse')}</p>
<p>${i18n.get('detail', (s) => html`<a href="#">${s}</a>`)}</p>
<h2>sub module</h2>
<p>${i18nModule.get('title')}</p>
<p>${i18nModule.get('hello', 'World', 'reverse')}</p>
<p>${i18nModule.get('detail', (s) => html`<a href="#">${s}</a>`)}</p>
<h2>localize content</h2>
<dy-route .trigger=${i18n} .routes=${localizeRoutes}></dy-route>
`;
}
}
render(
html`
<gem-examples-layout>
<app-root></app-root>
</gem-examples-layout>
`,
document.body,
);