Работать с Vue.js одно удовольствие. Элегантный дизайн, а надежные сторонние дополнения, которые можно сочетать, превращают создание браузерных приложений в удовольствие.

Самым известным плагином i18n для прогрессивного JavaScript-фреймворка Vue.js, вероятно, является Vue I18n.

Казуя, спасибо за этот замечательный плагин для i18n!

новые версии

Помимо шаблонов, директив, привязки данных, обработки событий и т. д., в v3 Vue.js теперь также представляет Composition API, Teleport, Fragments… и Suspense.
Соответствующая версия для Vue. js v3 для Vue I18n — v9.

Так как же выглядит базовая установка vue-i18n?

Давайте углубимся в это…

Предпосылки

Убедитесь, что у вас установлены Node.js и npm. Лучше всего, если у вас есть некоторый опыт работы с простым HTML, JavaScript и базовым Vue.js, прежде чем переходить к vue-i18n.

Начиная

Возьмите свой собственный проект Vue.js или создайте новый, то есть с помощью команды vue create cli.

npx @vue/cli create vue-starter-project
# select vue 3 preset

Давайте установим зависимость vue-i18n:

npm install vue-i18n@9

Подготовим файл main.js:

import { createApp } from 'vue'
import { createI18n } from 'vue-i18n';
import App from './App.vue'
export const i18n = createI18n({
  locale: 'en', // set locale
  fallbackLocale: 'en', // set fallback locale
  messages: {
    en: {
      message: {
        welcome: 'Welcome to Your Vue.js App'
      }
    },
    de: {
      message: {
        welcome: 'Willkommen zu Deiner Vue.js App'
      }
    }
  }
  // If you need to specify other options, you can set other options
  // ...
})
createApp(App).use(i18n).mount('#app')

Теперь давайте создадим первый компонент TranslationShowCase.vue:

<template>
  <div class="hello">
    <h1>{{ $t("welcome") }}</h1>
  </div>
</template>
<script>
export default {
  name: 'TranslationShowCase'
}
</script>

…и использовать этот компонент в App.vue:

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <TranslationShowCase />
</template>
<script>
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
  name: 'App',
  components: {
    TranslationShowCase
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Теперь вы должны увидеть что-то вроде этого:

Переключатель языков

Теперь мы создадим переключатель языка, чтобы содержимое менялось между разными языками.

<template>
  <div class="hello">
    <h1>{{ $t("welcome") }}</h1>
  </div>
  <hr />
  <div>
    <div>
      <a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
      <strong v-if="$i18n.locale === 'de'">DE</strong>
      &nbsp;|&nbsp;
      <a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
      <strong v-if="$i18n.locale === 'en'">EN</strong>
    </div>
  </div>
</template>
<script>
export default {
  name: 'TranslationShowCase',
  methods: {
    changeLanguage(lang) {
      this.$i18n.locale = lang
    }
  }
}
</script>

🥳 Отлично, вы только что создали свой первый переключатель языков!

Компонентная интерполяция и директива

Теперь попробуем компонентную интерполяцию и директиву перевода:

<template>
  <div class="hello">
    <h1>{{ $t("welcome") }}</h1>
  </div>
  <p>
    <i18n-t keypath="descr" tag="label" for="doc">
      <a href="https://cli.vuejs.org" target="_blank">{{ $t('doc') }}</a>
    </i18n-t>
  </p>
  <div>
    <div>
      <span v-t="{path:'end'}" /> <!-- can also be written like: <i v-t="'end'" /> -->
    </div>
  </div>
  <hr />
  <div>
    <div>
      <a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
      <strong v-if="$i18n.locale === 'de'">DE</strong>
      &nbsp;|&nbsp;
      <a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
      <strong v-if="$i18n.locale === 'en'">EN</strong>
    </div>
  </div>
</template>
<script>
export default {
  name: 'TranslationShowCase',
  methods: {
    changeLanguage(lang) {
      this.$i18n.locale = lang
    }
  }
}
</script>

…и добавьте новые ключи к вашим переводам:

import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'
export const i18n = createI18n({
  locale: 'en', // set locale
  fallbackLocale: 'en', // set fallback locale
  messages: {
    en: {
      message: {
        welcome: 'Welcome to Your Vue.js App',
        descr: 'For a guide and recipes on how to configure / customize this project, check out the {0}.',
        doc: 'vue-cli documentation',
        end: 'have fun!'
      }
    },
    de: {
      message: {
        welcome: 'Willkommen zu Deiner Vue.js App',
        descr: 'Eine Anleitung und Rezepte für das Konfigurieren / Anpassen dieses Projekts findest du in der {0}.',
        doc: 'vue-cli Dokumentation',
        end: 'habe Spass!'
      }
    }
  }
  // If you need to specify other options, you can set other options
  // ...
})
createApp(App).use(i18n).mount('#app')

Это должно быть результатом:

Где дополнительные сверхспособности?

Знакомимся с locizer

locizer — это легкий модуль для доступа к данным из вашего проекта locize и использования их внутри вашего приложения.

Что такое локация?

Как это выглядит?

Сначала нужно зарегистрироваться в locize и войти.
Затем создать новый проект в locize и добавить свои переводы. Вы можете добавить свои переводы либо путем импорта отдельных файлов json, либо через API, либо с помощью CLI.

Наличие переводов в вашем файле кода работает, но не совсем подходит для работы с переводчиками.
Использование locize отделяет переводы от кода.

Импорт всех переводов должен выглядеть так:

Сделав это, мы собираемся установить locizer.

npm install locizer

Давайте создадим специальный файл i18n.js:

import { createI18n } from 'vue-i18n'
import locizer from 'locizer'
const namespace = 'messages' // your namespace name added in locize
locizer.init({
  projectId: 'your-locize-project-id'
})
export const i18n = createI18n({
  locale: locizer.lng, // locizer.lng is the language detected in your browser.
  fallbackLocale: 'en' // set fallback locale
  // If you need to specify other options, you can set other options
  // ...
})
// called from within setup hook in App.vue
export const loadMessagesPromise = new Promise((resolve, reject) => {
  locizer.loadAll(namespace, (err, messages) => {
    if (err) return reject(err);
    Object.keys(messages).forEach((l) => {
      i18n.global.setLocaleMessage(l, messages[l])
    })
    resolve(messages)
  })
})

Переводы теперь загружаются асинхронно, поэтому мы экспортируем loadMessagesPromise и используем его в вашем App.vue:

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <TranslationShowCase />
</template>
<script>
import { loadMessagesPromise } from './i18n'
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
  name: 'App',
  components: {
    TranslationShowCase
  },
  // used in combination with Suspense.
  // useful when translations are not in-memory...
  async setup() {
    await loadMessagesPromise
    return {}
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Кроме того, мы используем новую функцию Приостановка Vue.js.
Давайте создадим новый файл: например, Suspenser.vue:

<template>
  <Suspense>
    <template #default>
      <App />
    </template>
    <template #fallback>
      <span>Loading...</span>
    </template>
  </Suspense>
</template>
<script>
import App from './App.vue'
export default {
  name: 'Suspenser',
  components: {
    App
  }
}
</script>

И используйте это в своем файле main.js:

import { createApp } from 'vue'
import { i18n } from './i18n'
import App from './Suspenser.vue'
createApp(App).use(i18n).mount('#app')

Теперь, пока ваши переводы загружены, вы увидите резервный шаблон:

Если ваш браузер настроен на немецкий язык, вы, возможно, заметили, что по умолчанию язык был автоматически установлен на немецкий. Это связано с функцией определения языка locizer. Вы можете настроить определение языка с помощью других параметров
По умолчанию определение языка также ищет параметр запроса lng, поэтому вы также можете ввести этот URL-адрес, чтобы проверить это: http://localhost:8080/? lng=de

сохранить недостающие переводы

Я хочу, чтобы новые ключи, добавленные в код, автоматически сохранялись для локализации.

Ваше желание – моя команда!

Расширьте файл i18n.js с помощью locize api-key и функции handleMissing:

import { createI18n } from 'vue-i18n'
import locizer from 'locizer'
const namespace = 'messages' // your namespace name added in locize
const apiKey = 'my-api-key' // used for handleMissing functionality, do not add your api-key in a production build
locizer.init({
  projectId: 'your-locize-project-id',
  apiKey
})
export const i18n = createI18n({
  locale: locizer.lng, // locizer.lng is the language detected in your browser.
  fallbackLocale: 'en' // set fallback locale
  // If you need to specify other options, you can set other options
  // ...
})
// called from within setup hook in App.vue
export const loadMessagesPromise = new Promise((resolve, reject) => {
  locizer.loadAll(namespace, (err, messages) => {
    if (err) return reject(err);
    Object.keys(messages).forEach((l) => {
      i18n.global.setLocaleMessage(l, messages[l])
    })
    resolve(messages)
  })
})
export function handleMissing (locale, key) {
  if (!apiKey) return
  if (locale !== locizer.referenceLng) return
  locizer.add(namespace, key, key)
}

И используйте его в компоненте:

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <TranslationShowCase />
</template>
<script>
import { useI18n } from 'vue-i18n'
import { loadMessagesPromise, handleMissing } from './i18n'
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
  name: 'App',
  components: {
    TranslationShowCase
  },
  // used in combination with Suspense.
  // useful when translations are not in-memory...
  async setup() {
    useI18n().setMissingHandler(handleMissing)
    await loadMessagesPromise
    return {}
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Теперь, если вы добавите новый ключ в свои шаблоны, <h2>{{ $t("How are you?") }}</h2>:

<template>
  <div class="hello">
    <h1>{{ $t("welcome") }}</h1>
    <h2>{{ $t("How are you?") }}</h2>
  </div>
  <p>
    <i18n-t keypath="descr" tag="label" for="doc">
      <a href="https://cli.vuejs.org" target="_blank">{{ $t('doc') }}</a>
    </i18n-t>
  </p>
  <div>
    <div>
      <span v-t="{path:'end'}" /> <!-- can also be written like: <i v-t="'end'" /> -->
    </div>
  </div>
  <hr />
  <div>
    <div>
      <a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
      <strong v-if="$i18n.locale === 'de'">DE</strong>
      &nbsp;|&nbsp;
      <a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
      <strong v-if="$i18n.locale === 'en'">EN</strong>
    </div>
  </div>
</template>
<script>
export default {
  name: 'TranslationShowCase',
  methods: {
    changeLanguage(lang) {
      this.$i18n.locale = lang
    }
  }
}
</script>

Он автоматически сохраняется для определения местоположения:

Наконец, с помощью рабочего процесса автоматического машинного перевода новые ключи не только добавляются для автоматической локализации при разработке приложения, но также автоматически переводятся на целевые языки с помощью машинного перевода:

👀 но есть еще…

Кэширование:

Объединение версий:

🧑‍💻 Код можно найти здесь.

🎉🥳 Поздравляем 🎊🎁

Надеюсь, вы узнали что-то новое о локализации Vue.js и современных рабочих процессах локализации.

Так что, если вы хотите вывести свою тему i18n на новый уровень, стоит попробовать locize.

👍