Vue project internationalization (using vue-i18n)

A recent high-priority task — global internationalization of the previous vue project. Although time was urgent and more efforts were made, due to lack of care, there were errors such as misspelling words and missing translations. The style problem caused by the difference in the length of English characters, the online effect is not ideal. Here is a record of the use of the vue-i18n internationalization language pack processing plugin.

vue-i18n official website document

Install

npm install vue-i18n --save

Configuration and use

Create a new i18n directory in the src directory, en.js is the English language pack, zh.js is the Chinese language pack

en.js file content

export default {
    common: {
      username: '用户名',
      password: '密码',
      save: '保存',
      edit: '编辑',
      update: '更新',
      delete: '删除',
      forever: '永久',
      expired: '过期'
    }
}

zh.js file content

export default {
    common: {
      username: 'username',
      password: 'password',
      save: 'Save',
      edit: 'Edit',
      update: 'Update',
      delete: 'Delete',
      forever: 'Forever',
      expired: 'Expired'
    }
}

 index.js file under i18n

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Cookies from 'js-cookie'
import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang导入Element的语言包 英文
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang g导入Element的语言包 中文
import enLocale from './en' // 导入项目中用到的英文语言包
import zhLocale from './zh'// 导入项目中用到的中文语言包
Vue.use(VueI18n)
const messages = {
  en: {
    ...enLocale,
    ...elementEnLocale
  },
  zh: {
    ...zhLocale,
    ...elementZhLocale,
  },

}

const i18n = new VueI18n({
  locale: localStorage.getItem('language') || 'zh', // 设置语种
  messages, // 设置全局当地语言包,
  fallbackLocale: 'zh',
  numberFormats:{ //设置 数字本地化
    'en': {
      currency: { //添加 $
        style: 'currency', currency: 'USD'
      }
    },
    'zh': {
      currency: { //添加 ¥
        style: 'currency', currency: 'JPY', currencyDisplay: 'symbol'
      }
    }
  },
    dateTimeFormats:{//设置 日期时间本地化
    'en': {
      short: { 
        year: 'numeric', month: 'short', day: 'numeric'
      },
      long: {
        year: 'numeric', month: 'short', day: 'numeric',
        weekday: 'short', hour: 'numeric', minute: 'numeric'
      }
    },
    'zh': {
      short: {
        year: 'numeric', month: 'short', day: 'numeric'
      },
      long: {
            year: 'numeric', month: 'short', day: 'numeric',
            weekday: 'short', hour: 'numeric', minute: 'numeric'  
      }
    }
  }
})

export default i18n

main.jsin the main entry file

import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//导入配置好的国际化语言包
import i18n from './i18n' // Internationalization

Vue.use(Element, {
  size: 'medium', // set element-ui default size设置元素默认大小
  i18n: (key, value) => i18n.t(key, value)// 在注册Element时设置i18n的处理方法
})
Vue.config.productionTip = false// 生产提示
new Vue({
  el: '#app',
  i18n, // 注入 配置好的国际化语言配置
})


this.$i18nAfter registering i18n in vue, we can get the configured i18n object in the component

Instantiate the imported VueI18none and pass in the configuration information in new VueI18n():

  • locale current language
  • fallbackLocale If the current language does not exist, the current language is set by default
  • messages locale ('en','zh'...)
  • numberFormats set number formatting
  • dateTimeFormats Set the time and date format and then introduce one by one:

Locale is mainly used to set the language package. How to switch locale?

//在组件中
import i18n from "@/i18n" //根据项目对应真实路径

i18n.locale="en" // 改变为中文
localStorage.setItem('language',"en")//在localStorage中存入设置

 messages 

Generally, the static language in the project will be divided into various languages ​​required by the product, including Chinese, English, French, etc... For example:


message:{
  zh: {
    common: {
      username: '用户名',
      password: '密码',
      save: '保存',
      edit: '编辑',
      update: '更新',
      delete: '删除',
      forever: '永久',
      expired: '过期'
    }

  },
  en: {
    common: {
      username: 'username',
      password: 'password',
      save: 'Save',
      edit: 'Edit',
      update: 'Update',
      delete: 'Delete',
      forever: 'Forever',
      expired: 'Expired'
    }
  }
}

zhIt represents the Chinese version of the static language, enand the English version of the static language. Generally en, , zhis divided into two modules—— en.jszh.js. This not only makes the project structure more concise and clear, but also saves a lot of time in the maintenance and development phase.

Use of $t (formatting)

To put it simply, it is to get messagesa certain data, and the parameter is a string, representing a certain piece of data to be obtained

Notice:

 The internationalization of static data placed in data needs to be placed in computed, so that it will be responsive when switching;

 When translating some constants defined in consts, use i18n.t to translate and then use the function to return, and call the function in computed when the page is used, and then there will be responsiveness when switching;

  easy to use

//template 需要使用 {
   
   {}} 将 name包装起来
{
   
   {$t('save')}}

// js
this.$t('save')

[name formatting]

const messages = {
  en: {
    message: {
      title: 'hello, {name}'
    }
  }
}
//组件中使用
<p>{
   
   { $t('message.title', { name: 'Kite' }) }}</p>

//输出
<p>hello, Kite</p>

This is called named formatting , and it can format information regionally. In this case, $tthe second parameter is an object, which represents all the content that needs to be dynamically added. Note that all messagethe variables that need to be dynamically added in are in the second parameter.

1. The second parameter is not passed

const message = {
  en: {
    message: {
      title: '{a}{b}哈哈'
    }
  }
}
//组件中使用1
<p>{
   
   { $t('message.title') }}</p>
//输出
<p>{a}{b}哈哈</p>

//组件中使用2, 
<p>{
   
   { $t('message.title',{a:1,b:2) }}</p>
//输出
<p>12哈哈</p>

As shown in the above example, if the second parameter is not passed, it will be displayed as a string.


2. Different Naming Types

const messages = {
  en: {
    message: {
      title: '{a}{b}哈哈'
    }
  }
}
//组件中使用  数值型与字符串类型 1
<p>{
   
   { $t('message.title',{a:1,b:"2") }}</p>
//输出
<p>12哈哈</p>

//组件中使用2 对象类型
<p>{
   
   { $t('message.title',{a:{},b:"2") }}</p>
//输出
<p>[object Object]2哈哈</p>

//组件中使用3 数组类型(内含布尔,对象类型)
<p>{
   
   { $t('message.title',{a:[1,2,3,true,{}],b:"2") }}</p>
//输出
<p>123true[object Object]2哈哈</p>
  • The object object type will be output directly  [object Object]
  • boolean Boolean type will be output as a string  true-->"true"/false-->"false"
  • In the array array type, if each item is a value or a string, then output it directly, otherwise it will be displayed as above

 [list format]

const message = {
  en: {
    message: {
      sing: '{0}{1}{2}忘了想念'
    }
  }
}
// 组件内使用 1 列表格式
<p>{
   
   { $t('message.sing', ['我','以','为']) }}</p>
//输出
<p>我以为忘了想念</p>


// 组件内使用 2 类似命名格式的方式
<p>{
   
   { $t('message.sing', { '0':"我",'1':'以','2':'为' }) }}</p>
//输出
<p>我以为忘了想念</p>

Use of $tc (plural)

const messages = {
  en: {
    apple: 'no apples | one apple | {count} apples',
    banana: 'no bananas | {n} banana | {n} bananas'
  }
}

One thing to note here: you must define the locale with the pipe  | separator and define the plural in the pipe separator

//在组件内使用
<p>{
   
   { $tc('apple', 10, { count: 10 }) }}</p>
<p>{
   
   { $tc('apple', 10) }}</p>

<p>{
   
   { $tc('banana', 1, { n: 1 }) }}</p>
<p>{
   
   { $tc('banana', 1) }}</p>
<p>{
   
   { $tc('banana', 100, { n: 'too many' }) }}</p>

//输出
<p>10 apples</p>
<p>10 apples</p>

<p>1 banana</p>
<p>1 banana</p>
<p>too many bananas</p>

1. When defining plurals, it is necessary to use |the pipe character to separate them.

2. When |there is 1 pipe symbol, the index starts from 1, and the maximum index is 2; when there are more than 1 pipe symbols, the index starts from 0 (similar to an array), and the maximum index is the number of pipe symbols

3. $tc(“复数”,index)Obtain the corresponding language text by using


 dateTimeFormats date time format

dateTimeFormats:{//设置 日期时间本地化
    'en': {
  short: { //显示英文 年月日
    year: 'numeric', month: 'short', day: 'numeric'
  },
  long: { //显示英文 年月日 星期 小时 分钟
    year: 'numeric', month: 'short', day: 'numeric',
    weekday: 'short', hour: 'numeric', minute: 'numeric'
 }
    },
    'zh': {
  short: {
    year: 'numeric', month: 'short', day: 'numeric'
  },
  long: {
    year: 'numeric', month: 'short', day: 'numeric',
    weekday: 'short', hour: 'numeric', minute: 'numeric'  
  }
    }
  }

There are methods for dealing with numbers $n, and there are corresponding methods for date and time formatting——$d

//在组件中使用
<div id="app">
  <p>{
   
   { $d(new Date(), 'short') }}</p>
   <p>{
   
   { $d(new Date(), 'long') }}</p>
    <p>{
   
   { $d(new Date(), 'short','zh') }}</p>
  <p>{
   
   { $d(new Date(), 'long', 'zh') }}</p>
</div>

//输出
Jul 31, 2022
Sat, Jul 31, 2022, 5:55 PM

2022年07月23日
2018年07月23日 周六 下午5:55

numberFormats set number formatting including currency type etc.

numberFormats:{ 
    'en': {
  currency: { //添加 $
   style: 'currency', currency: 'USD'
  }
    },
    'zh': {
  currency: { //添加 ¥
    style: 'currency', currency: 'JPY', currencyDisplay: 'symbol'
  }
    }
  },

$n (numeric localization)

For how to use number formatting in components, as in the $tsame way, it also provides the corresponding method $n.

//组件中使用
  <p>{
   
   { $n(100, 'currency') }}</p>
  <p>{
   
   { $n(100, 'currency', 'zh') }}</p>

//输出
  <p>$100.00</p>
  <p>¥100</p>

$n(number,'path','locale')method, three parameters:

number The user must pass in the number
path The format scheme of the call must be passed
locale The language used, the default is the current this.$i18n.locale

New in 8.10+ : $n The method returns a result string with a fully formatted number that can only be used as a whole. $n is not sufficient in cases where certain parts of the formatted number, such as decimal places, need to be formatted . In this case, <i18n-n> functional components will help.

With a minimal set of properties, <i18n-n> the output produced is  $n identical to and wrapped into configured DOM elements.

<i18n-n :value="1234" :format="{ key: 'currency', currency: 'EUR' }">
  <span v-slot:currency="slotProps" styles="color: green">{
   
   { slotProps.currency }}</span>
  <span v-slot:integer="slotProps" styles="font-weight: bold">{
   
   { slotProps.integer }}</span>
  <span v-slot:group="slotProps" styles="font-weight: bold">{
   
   { slotProps.group }}</span>
  <span v-slot:fraction="slotProps" styles="font-size: small">{
   
   { slotProps.fraction }}</span>
</i18n-n>


// 结果
<span>
  <span styles="color: green">€</span>
  <span styles="font-weight: bold">1</span>
  <span styles="font-weight: bold">,</span>
  <span styles="font-weight: bold">234</span>
  <span styles="font-size: small">00</span>
</span>

 common method

getLocaleMessage

this.i18n.getLocaleMessage('key'), this method is used to obtain the language pack of a certain language in the global language pack, for example:

 this.i18n.getLocaleMessage('en')//获取英文的语言包 返回的同样是一个对象

mergeLocaleMessage

this.i18n.mergeLocaleMessage('key',localeData), this is the method used to add local language packs to the 'key' language, often in a sub-component, we will merge a certain regional language pack into the global language pack of the corresponding language

this.$i18n.mergeLocaleMessage('zh', local.zh)//向全局中文语言包中补充内容

v-t

Custom instruction v-t. It $thas the same function as getting a piece of data in the language pack, but there are big differences

v-tusage of

//locale='en'
const messages = {
  en: {
    message: {
      title: hello'
    }
  },
  zh:{
   message: {
      title: '哈哈{name}'
    }
  }
}
//组件中使用1 字符串用法
 <p v-t="'message.title'"></p>
 //输出
 hello
 
 //组件中使用2 对象用法
<p v-t="{ path: 'message.title', locale: 'zh', args: { name: 'cfz' } }"></p>
 //输出
 哈哈cfz

The difference between vt and $t

$t is the extended Vue instance method

[Advantages] You   can flexibly use mustache syntax (mustash) syntax { {}} in templates , and you can also flexibly use calculation props and methods in Vue instances.

[ Disadvantage ] Executed every time you re-render, so it is more performance-intensive.

vt is a custom directive

[ Advantages$t ] When translated once, has better performance than methods due to its use of custom directives for caching .

[ Disadvantages ] vt cannot flexibly use $t, because it is quite complicated. The translated content vt will be inserted into the textContent element.

There are some other usages, please refer to the official documentation for details


insert component

If you encounter such a scene, how to deal with it?

<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>

My first reaction is to divide it into two fields . The a tag does not belong to the content of translation, as long as it is written as:

<p>{
   
   { $t('xx1') }}<a href="/term">{
   
   { $t('xx2') }}</a></p>

After reading the introduction on the official website, I said that this kind of processing is too clumsy, and it can be processed by components .

Two variables are used to store information to tagproduce labels, pathand to formulate the content of labels

// 这里使用了i18n 组件
<i18n path="term" tag="p" for="tos">
    <a :href="url" target="_blank">{
   
   { $t('tos') }}</a>
</i18n>

const messages = {
  en: {
    tos: 'Term of Service',
    term: 'I accept xxx {0}.'
  }
}

new Vue({
  el: '#app',
  i18n,
  data: {
    url: '/term'
  }
})

For more advanced usage, you can control the insertion position of the html element , by placespecifying the position where it appears in the html.

<i18n path="info" tag="p">
    <span place="limit">{
   
   { changeLimit }}</span>
    <a place="action" :href="changeUrl">{
   
   { $t('change') }}</a>
</i18n>

const messages = {
  en: {
    info: 'You can {action} until {limit} minutes from departure.',
    change: 'change your flight',
    refund: 'refund the ticket'
  }
}

const i18n = new VueI18n({
  locale: 'en',
  messages
})
new Vue({
  i18n,
  data: {
    changeUrl: '/change',
    refundUrl: '/refund',
    changeLimit: 15,
    refundLimit: 30
  }
}).$mount('#app')

// result
<p>
    You can <a href="/change">change your flight</a> until <span>15</span> minutes from departure.
</p>

Dynamically load language packs

It is not necessary to load all the language packs at once, especially when the language packs have been used. I also raised this problem before and found that the official website gave a solution.

//i18n-setup.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import messages from '@/i18n' // 语言包的地址,随项目本身设置修改
import axios from 'axios' // 根据项目中使用api请求模块去设置,不一定是axios

Vue.use(VueI18n)

export const i18n = new VueI18n({
  locale: 'en', // set locale
  fallbackLocale: 'en', // 默认语言设置,当其他语言没有的情况下,使用en作为默认语言
  messages // set locale messages
})

const loadedLanguages = ['en'] // our default language that is prelaoded 

function setI18nLanguage (lang) {
  i18n.locale = lang
  axios.defaults.headers.common['Accept-Language'] = lang // 设置请求头部
  document.querySelector('html').setAttribute('lang', lang) // 根元素增加lang属性
  return lang
}

export function loadLanguageAsync (lang) {
  if (i18n.locale !== lang) {
    if (!loadedLanguages.includes(lang)) {
      return import(/* webpackChunkName: "lang-[request]" */ `@/lang/${lang}`).then(msgs => {
        i18n.setLocaleMessage(lang, msgs.default)
        loadedLanguages.push(lang)
        return setI18nLanguage(lang)
      })
    } 
    return Promise.resolve(setI18nLanguage(lang))
  }
  return Promise.resolve(lang)
}


// 在vue-router的beforeEach的全局钩子处理
router.beforeEach((to, from, next) => {
  const lang = to.params.lang
  loadLanguageAsync(lang).then(() => next())
})

Guess you like

Origin blog.csdn.net/qq_44376306/article/details/125949595