在任何前端框架中设置国际化(i18n)都可以通过使用不同的技术来完成。大多数企业级应用程序对页面的每个语言版本使用不同的url,而不是使用cookie、本地存储或浏览器设置来调整页面上的内容语言。搜索引擎(例如Google)也建议使用此方法。

例如,如果你打开一个像apple.com这样的网站,它会以默认语言加载(在这里是US English)。但是,如果您想将语言更改为法语,则您的偏好语言将显示在网站的URL中:
- English — apple.com
- French — apple.com/fr
- German — apple.com/de
- etc.
像这样的站点需要复杂的后端服务器设置,但是在它复杂的背后是简单的路由器配置。其基本思想是,路由器将检查URL的第一个参数是否是语言参数,如果是这样,它将为您提供该语言的内容(apple.com/fr/iphone)。但是,如果第一个参数与任何受支持的语言都不匹配,它将以默认语言(apple.com/iphone)为您提供内容。我们将尝试演示如何使用Vue路由器在Vue中实现这一目标。

在本文中,我们将介绍:
- Vue i18n的安装和配置
- 加载开发转换键(dev.json)
- 使用Router将语言设置为URL参数
- 使用Axios加载翻译文件(将JSON文件与Vue分离)
- 改变语言
- 使用Linguallo TMS管理翻译文件(l10n)
Vue i18n的安装和配置
为了帮助我们进行国际化,我们将使用Vue i18n插件。您可以使用以下方法安装插件
NPM:
npm install vue-i18n --save
Yarn:
yarn add vue-i18n
Vue CLI
vue add i18n
通过在i18n.js文件中设置配置来配置插件:
import Vue from 'vue'import VueI18n from 'vue-i18n'Vue.use(VueI18n)export default new VueI18n({ silentTranslationWarn: true, locale: 'en', fallbackLocale: 'dev', messages: { dev: { hello_world: 'Hello World!' } }})
然后,您将需要在main.js中注册插件:
import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'import i18n from './i18n'Vue.config.productionTip = falsenew Vue({ router, store, i18n, render: h => h(App)}).$mount('#app')
我们已经在Vue应用程序中设置了i18n!
加载开发转换键(dev.json)
您可能已经注意到,我们已经将地区locale为dev。在开发新特性、修复bug等时,拥有一个开发翻译文件(dev.json)是有帮助的。此文件主要在开发应用程序时使用,但也可以用作应用程序的默认后备语言。
在src文件夹中,创建区域设置文件夹并添加dev.json文件,然后在实例化VueI18n时加载该文件。您的i18n.js文件现在应该如下所示:
import Vue from 'vue'import VueI18n from 'vue-i18n'Vue.use(VueI18n)export default new VueI18n({ silentTranslationWarn: true, locale: 'en', fallbackLocale: 'dev', messages: { dev: require('./locales/dev.json') }})
使用Router将语言设置为URL参数
正如我们在开始时所提到的,我们的路由配置应该期望语言参数。如果第一个参数与任何支持的语言都不匹配,它将为您提供默认语言的内容。此外,如果URL与任何路由都不匹配,它将以英语(默认)语言加载404页。
首先,让我们用基本路径定义支持的语言。创建新的文件夹常量并添加文件locales.js:
export const SUPPORTED_LOCALES = [{ code: 'en', base: '', flag: 'us', name: 'English', translations: '/translations/en.json'}, { code: 'fr', base: '/fr', flag: 'fr', name: 'Français', translations: '/translations/fr.json'}]
现在,我们将仅使用code属性。在继续阅读本文时,我们将使用其余的内容。
接下来,我们将配置路由器,更新 src/router/index.js:
import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)import routes from './routes'import { SUPPORTED_LOCALES } from '../constants/locale'// Creates regex (en|fr)function getLocaleRegex() { let reg = '' SUPPORTED_LOCALES.forEach((locale, index) => { reg = `${reg}${locale.code}${index !== SUPPORTED_LOCALES.length - 1 ? '|' : ''}` }) return `(${reg})`}const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes: [{ path: `/:locale${getLocaleRegex()}?`, component: { template: '' }, children: routes }]});export default router
现在,我们的 src/router/router.js 文件应如下所示:
function load (component) { return () => import(/* webpackChunkName: "[request]" */ `@/views/${component}.vue`)}export default [{ path: 'about', name: 'About', component: load('About')},{ path: '', name: 'Home', component: load('Home')}, { path: '*', name: '404', component: load('404')}];
如果我们在路径中使用简单的动态参数,比如我们的父路由的 /:locale,路由器将无法轻松区分 /fr 和 /about URLs。用通俗易懂的术语来说,它将匹配两个URL。基于这个原因,我们决定使用基于我们支持的locale配置构建的高级模式:
/:locale(en|fr)?
在这里,:locale 代表我们的动态参数,(en | fr)表示参数param是en还是fr,则将匹配该参数,并设置语言环境param。如果第一个参数是其他参数,例如 /about,则路径仍将匹配,但不会设置语言环境参数(因为我们后面的问号?表示可选参数)。
以上所有内容都可以这样表示:

使用Axios加载翻译文件(将JSON文件与Vue分离)
由于我们已经成功地从URL中提取了语言环境参数,因此我们现在可以配置应用程序,加载翻译文件并设置消息。我们将在进入父级路线的守卫之前在内部进行此操作。这是接收3个参数的函数:
- to - 你想去的路由
- from - 你来自哪个
- next - 完成后要调用的回调函数
理想情况下,在企业应用程序中,翻译文件应该从Web应用程序外部化。这意味着文件应位于应用程序上下文之外,从而允许业务或IT部门更改翻译文件,而不必重新构建和部署前端应用程序。出于演示目的,我们将文件放在public/translations 文件夹中,并创建新的en.json和fr.json文件。
现在,我们的 src/router/index.js 文件将如下所示:
import Vue from 'vue'import VueRouter from 'vue-router'import store from '../store';import i18n from '../plugins/i18n';import axios from 'axios';Vue.use(VueRouter);import routes from './routes';import { SUPPORTED_LOCALES } from '../constants/locale';// Creates regex (en|fr)function getLocaleRegex() { let reg = ''; SUPPORTED_LOCALES.forEach((locale, index) => { reg = `${reg}${locale.code}${index !== SUPPORTED_LOCALES.length - 1 ? '|' : ''}`; }); return `(${reg})`;}// Returns locale configurationfunction getLocale(locale = 'en') { return SUPPORTED_LOCALES.find(loc => loc.code === locale);}const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes: [{ path: `/:locale${getLocaleRegex()}?`, component: { template: '' }, beforeEnter(to, from, next) { const locale = getLocale(to.params.locale); store.dispatch('setLocale', locale); axios.get(locale.translations).then(res => { i18n.setLocaleMessage(locale.code, res.data || {}); }).catch(() => { // TODO handle error }).finally(() => { i18n.locale = locale.code; next(); }); }, children: routes }]});export default router
让我们看看我们的新后卫正在发生什么:
- 我们正在使用 to.params.locale 读取语言环境参数
- 基于参数,我们将从 src/constants/locales.js 文件中定义的受支持的语言环境列表中获取配置,如果在 site/ 或 website/about 的示例中未设置语言环境,我们会将默认语言环境设置为 en。
- 在我们的Vuex store中设置区域设置配置,以进一步用于确定当前应用程序区域设置
- 根据语言环境,我们将使用Axios获取JSON文件
- 如果文件存在,我们将使用 i18n.setLocaleMessage() 设置翻译消息
- 在 finally 语句中,我们将为i18n插件设置语言环境并触发 next() 回调
改变语言
我们希望通过路由更改实现的是,当用户在特定语言中使用路由,但决定更改语言时,它会将用户重定向到新的首选语言的相同页面。
您可以在下图上看到它:

这可以通过将URL指向另一个语言路由来实现。通过将 href 设置为锚元素,我们可以通过编程或直接从html实现这一点。以前,我们已经在我们的store中设置了当前的地区配置,但是现在我们可以使用它来计算实际的子路由。我们可以通过在完整路径上执行 substring 并删除语言基路径来实现这一点。例如,如果我们当前的路线是 /fr/about,则我们的 beforeEnter 保护将配置设置为:
{ code: 'fr', base: '/fr', flag: 'fr', name: 'Français', translations: '/translations/fr.json'}
接下来,我们将从完整路径 /fr/about 中删除基本部分 /fr,并获得路由 /about。我们的新语言的最终URL将是前面示例中的新语言库+新URL。如果您想添加更多的语言,例如德语(/de),它将是 /de + /about = /de/about。在我们的例子中,它看起来像是 ‘’+ / about = / about。
逻辑可以在这里看到:
效果如下

使用Linguallo TMS管理翻译文件(l10n)
所示示例是一个仅包含几个翻译键的简单项目。但是,正如我们一开始提到的,大规模应用程序要复杂得多。它们不仅具有成千上万的键,而且它们都与语言数量成正比。因此,翻译的最终数量很可能是数十万。
此外,由于开发人员在开发新功能时会不断添加新键,因此复杂性会进一步增加。因此,现在您可以在这里看到一个重复的模式——每次添加翻译时向其发送新键并将它们同步回应用程序。这就形成了一个巨大的恶性循环,非常耗时。
解决方案是引入翻译管理系统(TMS),它将代表真理的唯一来源。
在我的整个职业生涯中,我熟悉了多种不同的TMS。其中价格最高的是Translator,它是Adobe Experience Manager(AEM)的一部分。但是,Adobe AEM的价格为数十万美元,仅保留给数量有限的公司。
在搜索和尝试几乎所有在线TMS时,我碰到了一个很棒的网站-Linguallo.com,它是SaaS,可以免费使用。免费计划包括无限数量的电子表格,其中每个电子表格可以在每个应用程序中使用,并且每个工作表有500个免费托管键,5种语言和3个用户可以在上面进行协作。以我的拙见,对于大多数公司来说,这是一个不错的选择。该工具与其他工具有什么区别:
- 它看起来像Excel,使用起来很直观,并且具有与Trello相似的角色库访问权限。
- 借助名为Publisher(免费)的工具,它具有完整的版本管理功能。该工具类似于Jenkins,可以创建构建并将其部署到 AWS S3 或 GitHub。
- 您可以直接以 Pull Request 的形式推翻译键,或者使用它们的 CLI 从系统中 pull 出翻译文件,这是同步来自多个开发人员的新翻译键的好方法。
最重要的是它允许连续本地化(Continuous Localization)的概念。

假设您已经安装了Linguallo CLI,添加新键很简单,只需在项目的工作区中键入以下内容:
translate push --input="./src/locales/dev.json"
我强烈建议您尝试一下,并在评论部分告诉我您的印象!
总结
在本文中,我们讨论了如何设置Vue应用程序的高级路由和国际化。我们还提到了如何管理,翻译和发布语言文件。
即使它是“三巨头”(Angular,React和Vue)中的最新产品,我也一定会在企业应用程序中尝试一下Vue,因为我已经在与团队进行讨论。多年来,我一直在Angular和React框架中进行开发,同时构建了世界上最大的旅行电子商务Web应用程序之一。
我认为,与React相比,Vue更容易学习。 Vue以Web开发人员已经习惯的方式分离关注点,将HTML,CSS和JavaScript分离。我认为Vue掌握了React和Angular的精髓。
原文:https://levelup.gitconnected.com/advanced-vue-js-internationalization-i18n-and-localization-l10n-using-vue-router-a94ecd83fecd
作者:Ivan Miletic
翻译:做工程师不做码农
本头条号聚焦大前端技术和程序员成长,如果对你有所启发和帮助,可以点个关注、收藏,也可以留言讨论,这是对作者的最大鼓励。
作者简介:Web前端工程师,全栈开发工程师、持续学习者。
#Vue.js#