# 自製簡易版 I18N in Vue
###### tags: `w3HexSchool` . `vue` . `i18n`
> 這篇文章主要說明如何在 Vue 中實現網頁上的 i18n,先備知識必須要已經基本會使用 Vue。
## 建立 Vue 專案
我們直接用 vue-cli 的初始頁面來做練習:
![](https://i.imgur.com/zLiglLQ.png)
直接透過 vue-cli 建立 Vue 專案:
```bash=
$ vue create vue-i18n-sandbox
$ cd vue-i18n-sandbox
$ npm start
```
## 定義多語系字典檔
這時候就可以先定義這個字典檔。首先在 `./src` 資料夾內再新增一個 `i18n` 的資料夾,裡面分別放入 `en.json`, `ja.json`, `ko.json`, `tw.json`:
![](https://i.imgur.com/KA2k7ce.png)
```json=
// ./src/i18n/en.json
{
"app": {
"hello": "Hello , ${name}"
}
}
```
```json=
// ./src/i18n/ja.json
{
"app": {
"hello": "こんにちは , ${name}"
}
}
```
```json=
// ./src/i18n/ko.json
{
"app": {
"hello": "환영합니다 , ${name}"
}
}
```
```json=
// ./src/i18n/tw.json
{
"app": {
"hello": "歡迎 , ${name}"
}
}
```
## 建立 i18n 工具檔案 ( I18nUtil.js )
在 `./src` 資料夾內新增一個 `utils` 的資料夾,並建立 `I18nUtil.js`:
```javascript=
// ./src/utils/I18nUtil.js
import _ from 'lodash';
import TwProperty from "../i18n/tw.json";
import EnProperty from "../i18n/en.json";
import JaProperty from "../i18n/ja.json";
import KoProperty from "../i18n/ko.json";
// util
import StrFillTemplate from './StrFillTemplate.js';
// the translations
const resources = {
tw: {
translation: TwProperty
},
en: {
translation: EnProperty
},
ja: {
translation: JaProperty
},
ko: {
translation: KoProperty
}
};
let defaultLanguage = 'tw';
export const translate = (key) => _.get(resources[defaultLanguage].translation, key);
export const translateWithParams = (key, params = {}) => StrFillTemplate(_.get(resources[defaultLanguage].translation, key), params);
export const setDefaultLanguage = (language) => defaultLanguage = language;
export const getDefaultLanguage = () => defaultLanguage;
```
## StrFillTemplate.js - 讓 `name` 參數在 `runtime` 可以被取代
在 `./src/utils` 資料夾內建立 `StrFillTemplate.js`:
```javascript=
// ./src/utils/StrFillTemplate.js
/**
* 將 模板字串 塞入 參數值.
* https://stackoverflow.com/questions/30003353/can-es6-template-literals-be-substituted-at-runtime-or-reused#answer-37217166
* @constructor
* @param {string} templateString - template literals .
* @param {object} [templateVars={}] - 參數名稱 .
*/
export default (templateString, templateVars = {}) => {
const args = '{' + Object.keys(templateVars).join(',') + '}'; // args = '{ name , value }'
const body = "return `" + templateString + "`;";
// new Function 學習 : https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function
return new Function(args, body).call(null, templateVars); // call 教學 : https://ithelp.ithome.com.tw/articles/10195896
};
```
## 撰寫切換語言的功能
在 `HelloWorld.vue` 的地方,撰寫四個按鈕可以來切換 `locale`:
```javascript=
// ./src/components/HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div class="container">
<!-- 建立四顆按鈕可以切換 "locale" -->
<button @click="changeLocale('en')">English</button>
<button @click="changeLocale('tw')">中文</button>
<button @click="changeLocale('ja')">日本語</button>
<button @click="changeLocale('ko')">한국어</button>
</div>
</div>
</template>
<script>
import {translateWithParams as t, setDefaultLanguage} from "../utils/I18nUtil";
export default {
name: 'HelloWorld',
beforeCreate: function () {
this.msg = t('app.hello', {name: '小明'});
},
methods: {
changeLocale: function (locale) {
setDefaultLanguage(locale);
this.msg = t('app.hello', {name: '小明'});
}
},
data: function () {
return {
msg: this.msg
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.container {
display: flex;
justify-content: center;
}
button {
height: 30px;
}
</style>
```
這時候的畫面會像這樣:
<iframe
src="https://codesandbox.io/embed/vue-i18n-sandbox-0i1i9?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="vue-i18n-sandbox"
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
></iframe>
## 參考資料
- [[筆記] 使用 react-intl 在 React 實作多語系功能 i18n, internationalization](https://pjchender.blogspot.com/2019/07/react-intl-react-i18n.html)
- [Vue I18n 實作多國語系 by Lynn](https://clhuang224.github.io/TechBlog/2020/03/15/20200315-vue-i18n/)
- [vue-i18n-sandbox](https://github.com/kuanhsuh/vue-i18n-sandbox)
## 其他套件
[vue-i18n](http://kazupon.github.io/vue-i18n/introduction.html)