preface

Some of the components in the Air-UI component library also use some hints, in addition to allowing customization with passing parameters, there must be default values. For example, air-Select allows you to search,

If not, there is a default message: no match, which is one of the default message defaults for this component. And the default value is actually Chinese. Now let’s see how that works, okay?

Component access language files

Some components interact with default prompts, such as Select, data-picker, color-picker, and Messagebox. Let’s take the SELECT component as an example:

The select.vue code of the Element-UI component is not the same as that of the select.vue code. Air-ui is all introduced with relative paths), and pretty much everything else is the same

<script type="text/babel"> import Locale from '.. /.. /.. /.. /src/mixins/locale'; . import { t } from '.. /.. /.. /.. /src/locale'; . export default { ... computed: { ... emptyText() { if (this.loading) { return this.loadingText || this.t('air.select.loading'); } else { if (this.remote && this.query === '' && this.options.length === 0) return false; if (this.filterable && this.query && this.options.length > 0 && this.filteredOptionsCount === 0) { return this.noMatchText || this.t('air.select.noMatch'); } if (this.options.length === 0) { return this.noDataText || this.t('air.select.noData'); } } return null; }, } } </script>Copy the code

EmptyText: emptyText: emptyText: emptyText: emptyText: emptyText: emptyText: emptyText: emptyText: emptyText: emptyText

  • If loading is in the loading state, the loading prompt is displayed. If no loading parameter is passed, the default loading prompt is used:air.select.loading
  • If it is searchable, the option value is matched. If not, and there is no additional reference to the prompt, the default term is used:air.select.noMatch
  • If there is no option value and no additional reference is made to the prompt, the default entry is used:air.select.noData

We can see that the extraction of default values is handled by the t() method, which is defined in the SRC /mixins/local.js file (which is introduced above) :

import { t } from '.. /locale';

export default {
  methods: { t(... args) {return t.apply(this, args); }}};Copy the code

It returns a t method, and since it was introduced with mix, it can be used in this instance: this.t(XXX):

mixins: [..., Locale, ...] .Copy the code

The t method is exported from SRC /locale/index.js:

import defaultLang from '.. /lang/zh-CN';
import Vue from 'vue';
import deepmerge from 'deepmerge';
import Format from './format';

const format = Format(Vue);
let lang = defaultLang;
let merged = false;
let i18nHandler = function () {
  // If there is a vuE-i18N component, then merge the UI component's multilingual file into the corresponding language file of the I18N component. In this way, when we use the UI component's entry, we directly call the i18N component's method
  const vuei18n = Object.getPrototypeOf(this || Vue).$t;
  // If it is a vue-i18n component and has the vue. locale method, then it is directly compatible with the built-in, which is to overwrite and merge the lang object with the air-UI lang object
  if (typeof vuei18n === 'function'&&!!!!! Vue.locale) {if(! merged) { merged =true;
      Vue.locale(
        Vue.config.lang,
        deepmerge(lang, Vue.locale(Vue.config.lang) || {}, {clone: true})); }return vuei18n.apply(this.arguments); }};export const t = function (path, options) {
  // Select * from i18n; // Select * from i18n
  let value = i18nHandler.apply(this.arguments);
  if(value ! = =null&& value ! = =undefined) return value;

  const array = path.split('. ');
  let current = lang;

  for (let i = 0, j = array.length; i < j; i++) {
    const property = array[i];
    value = current[property];
    if (i === j - 1) return format(value, options);
    if(! value)return ' ';
    current = value;
  }
  return ' ';
};

export const use = function (l) {
  lang = l || lang;
};

export const i18n = function (fn) {
  i18nHandler = fn || i18nHandler;
};

export default {use, t, i18n};
Copy the code

The logic of this file is also simple:

  1. First import the default Chinese language package file, getlangThis map object
  2. Let’s look at method T, which is the method that passes the key, based on the multilingual key that’s passed ini18nHandlerThis method looks to see if it can find the corresponding value, if not, then from the default language packagelangThe map object gets the corresponding value and returns it.

SRC /lang/ zh-cn.js SRC /lang/ zh-cn.js

export default {
  air: {
    colorpicker: {
      confirm: 'sure'.clear: 'empty'
    },
    datepicker: {
      now: 'the moment'.today: 'today'.cancel: 'cancel'.clear: 'empty'.confirm: 'sure'.selectDate: 'Select date'.selectTime: 'Choose time'.startDate: 'Start date'.startTime: 'Start time'.endDate: 'End Date'.endTime: 'End time'.prevYear: 'Previous year'.nextYear: 'The year after'.prevMonth: 'Last month'.nextMonth: 'Next month'.year: 'years'.month1: '1 month'.month2: '2 months'.month3: 'march'.month4: 'in April'.month5: '5 月'.month6: 'June'.month7: 'July'.month8: 'August'.month9: 'September'.month10: 'October'.month11: 'November'.month12: '12 months'.// week: 'week ',
      weeks: {
        sun: 'day'.mon: '一'.tue: '二'.wed: '三'.thu: 'four'.fri: 'five'.sat: '六'
      },
      months: {
        jan: '一月'.feb: '二月'.mar: 'march'.apr: 'in April'.may: 'may'.jun: 'June'.jul: 'July'.aug: 'August'.sep: 'September'.oct: 'October'.nov: November.dec: December}},select: {
      loading: 'Loading'.noMatch: 'No match data'.noData: 'No data'.placeholder: 'Please select'
    },
    cascader: {
      noMatch: 'No match data'.loading: 'Loading'.placeholder: 'Please select'.noData: 'No data at present'
    },
    pagination: {
      goto: '前往'.pagesize: 'Bar/page'.total: 'Total {total}'.pageClassifier: 'pages'
    },
    messagebox: {
      title: 'tip'.confirm: 'sure'.cancel: 'cancel'.error: 'The input data is illegal! '
    },
    upload: {
      deleteTip: 'Press delete key to delete'.delete: 'delete'.preview: 'View pictures'.continue: 'Continue uploading'
    },
    table: {
      emptyText: 'No data at present'.confirmFilter: 'screening'.resetFilter: 'reset'.clearFilter: 'all'.sumText: 'together'
    },
    tree: {
      emptyText: 'No data at present'
    },
    transfer: {
      noMatch: 'No match data'.noData: 'No data'.titles: [List of '1'.List of '2'].filterPlaceholder: 'Please enter search content'.noCheckedFormat: 'Total {total} item'.hasCheckedFormat: '{checked}/{total} items selected'
    },
    image: {
      error: 'Load failed'
    },
    pageHeader: {
      title: 'return'}}};Copy the code

So if the key is air.select.nomatch then it will find the key noMatch in the select object in the air object and get the value and return it. This allows you to use the language of the language pack.

Components use multiple languages

We already know how to insert language files into components and use language file entries. However, there is still a problem, is air-UI default load language file is Chinese, so how do I load other multilingual files? All multilingual files are stored in the SRC /lang directory.

This involves the use method in the SRC /locale/index.js file listed above:

export const use = function (l) {
  lang = l || lang;
};
Copy the code

We know that the method t gets the value of the key from the object lang, and when lang is initialized, it is assigned to it by the Chinese package object. So to use a package from another language, such as en, we simply export the en package and call the use method to override the lang object:

import locale from './locale/index'
import en from './lang/en'

locale.use(en)
Copy the code

In this case, the en language package will be used, screenshot below:

Combining to the air – the UI

We can use the syntax above to implement packages in other languages, but it is not elegant enough. We can embed this syntax in air-UI initialization, so we can change it to components/index.js and add:

import locale from '.. /.. /src/locale'

const install = function (Vue, opts = {}) {
  // Add language parameters that can be passed to other languages when the component is initializedlocale.use(opts.locale); locale.i18n(opts.i18n); . }module.exports = {
  locale: locale,
  i18n: locale.i18n, install, ... Other components... }Copy the code

You can see that in addition to introducing locale objects, two changes have been made:

  1. The install method adds handling for use and I18n. Then you can get the multilingual object passed in and the i18n method directly from the OPTS parameter
  2. When you export, you also export the LOCALE object and its i18N method separately, so that you can use multiple languages when you reference components separately later

So the reference will look something like this:

import AirUI from './components/index'
import enLng from './lang/en'

Vue.use(AirUI, {'locale': enLng})
Copy the code

It’s grammatically better.

Compatible with I18N plug-in

SRC /locale/index.js exports three methods:

  1. tGet the entry by key
  2. useReplace the new language package file
  3. i18nCustomize the method to get

We’ve already covered 1 and 2. The third method, i18n, is compatible with the existing i18N plug-in in the project or the custom method to obtain a multi-language value.

Sometimes a project has its own multilingual files, and then AIR-UI has its own multilingual files. If entries in air-UI’s own multilingual files need to be adjusted, then you need to maintain two multilingual files at the same time. And one of them is a multilingual file that comes with third-party libraries. That’s where it gets messy. Air-ui provides a way for you to customize the syntax and map of multiple languages by referencing air-UI. The logic code is as follows:

let i18nHandler = function () {
  // If there is a vuE-i18N component, then merge the UI component's multilingual file into the corresponding language file of the I18N component. In this way, when we use the UI component's entry, we directly call the i18N component's method
  const vuei18n = Object.getPrototypeOf(this || Vue).$t;
  // Merge the multilingual list of UI into the corresponding multilingual file of I18n
  if (typeof vuei18n === 'function'&&!!!!! Vue.locale) {if(! merged) { merged =true;
      Vue.locale(
        Vue.config.lang,
        deepmerge(lang, Vue.locale(Vue.config.lang) || {}, {clone: true})); }return vuei18n.apply(this.arguments); }};export const i18n = function (fn) {
  i18nHandler = fn || i18nHandler;
};
Copy the code

Because in the t method, it will first obtain the value through i18nHandler method, and only when it cannot obtain the value, it will use its own language package to deal with it. So all we need to do is assign to the i18nHandler method to get a custom multilanguage method, like this:

const customLangMap = {
  'air.select.noMatch': 'Custom not found'
}
Vue.use(AirUI, {
  i18n: key= > customLangMap[key]
});
Copy the code

The effect is that when we call t, we will use our custom i18n method, and then get the value, and only when the return value is null or undefined, we will get it again in the original way. So here’s the result:

It’s also very convenient.

Compatible with vuE-I18N plug-in

The above method can be customized by customizing i18N method. But in fact, the most used I18N components in VUE projects still belong to VUE-18N, so AIR-UI is compatible with different versions of I18N to varying degrees

[email protected]

Locale is available if you are using version 5.0.3 of VUE-I18N. There is less need to customize the i18N method. Because we have built-in compatibility with this version in the i18nHandler method:

let i18nHandler = function () {
  // If there is a vuE-i18N component, then merge the UI component's multilingual file into the corresponding language file of the I18N component. In this way, when we use the UI component's entry, we directly call the i18N component's method
  const vuei18n = Object.getPrototypeOf(this || Vue).$t;
  // If it is a vue-i18n component and has the vue. locale method, then it is directly compatible with the built-in, which is to overwrite and merge the lang object with the air-UI lang object
  if (typeof vuei18n === 'function'&&!!!!! Vue.locale) {if(! merged) { merged =true;
      Vue.locale(
        Vue.config.lang,
        deepmerge(lang, Vue.locale(Vue.config.lang) || {}, {clone: true})); }return vuei18n.apply(this.arguments); }};Copy the code

So the call looks like this:

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import AirUI from 'air-ui'
import enLocale from 'air-ui/lib/lang/en'
import zhLocale from 'air-ui/lib/lang/zh-CN'

Vue.use(VueI18n)
Vue.use(AirUI)

Vue.config.lang = 'zh-cn'
Vue.locale('zh-cn', zhLocale)
Vue.locale('en', enLocale)
Copy the code

[email protected]

If it is the latest version of 6.x, then it is incompatible, still need to call i18n to customize, for example:

import Vue from 'vue'
import AirUI from 'air-ui'
import VueI18n from 'vue-i18n'
import enLocale from 'air-ui/lib/lang/en'
import zhLocale from 'air-ui/lib/lang/zh-CN'

Vue.use(VueI18n)

const messages = {
  en: {
    message: 'hello'. enLocale// Or use object. assign({message: 'hello'}, enLocale)
  },
  zh: {
    message: 'hello'. zhLocale// Or use object. assign({message: 'hello'}, zhLocale)}}// Create VueI18n instance with options
const i18n = new VueI18n({
  locale: 'en'.// set locale
  messages, // set locale messages
})

Vue.use(AirUI, {
  i18n: (key, value) = > i18n.t(key, value)
})

new Vue({ i18n }).$mount('#app')
Copy the code

conclusion

This section is mainly about how air-UI access to i18N multilingual mechanism. But there are still the following problems:

  1. We now have a default introductionzh-CN.jsThis file, this will cause us to pack out laterair-ui.common.jsAs the volume increases, how do we pull it out?
  2. If components are packaged separately, how can they be integrated into multiple languages when introduced?

This will be addressed in the next section.


Series of articles:

  • Air-ui (1) — Why do I need to build an Element UI component
  • Self-built VUE component AIR-UI (2) — Take a look at the Element UI project
  • Self-built VUE component AIR-UI (3) – CSS development specification
  • Air-ui (4) — Air-UI environment setup and directory structure
  • Air-ui (5) — Create the first vUE component, Button
  • Self-built VUE component AIR-UI (6) – Creates built-in service components
  • Build vUE component AIR-UI (7) – Create command component
  • Self-built VUE component AIR-UI (8) — Implementation part introduces components
  • Build your own VUE component air-UI (9) — document with Vuepress
  • Air-ui (10) — Vuepress Documentation (Advanced version)
  • Vue Component Air-UI (11) — Vuepress Documentation (Crawl version)
  • Self-built VUE component AIR-UI (12) — Internationalization mechanism
  • Self-built VUE Component AIR-UI (13) — Internationalization Mechanism (Advanced Version)
  • Self-built VUE component AIR-UI (14) — Packaged Build (Dev and Dist)
  • Self-built VUE component AIR-UI (15) — Theme customization
  • Self-built VUE component AIR-UI (16) – Packages to build pub tasks
  • Build your own VUE component AIR-UI (17) – Develop a pit crawl and summary