Создание многоязычного веб-приложения с помощью Nuxt 3 и Nuxt i18n

В настоящее время разработка веб-приложений, ориентированных на пользователей с разных языков, имеет важное значение, особенно если вы создаете крупномасштабные приложения. Разработка многоязычного приложения может быть сложной задачей, но Nuxt i18n упрощает работу с проектами Nuxt 3, упрощая перевод контента, обработку языковых стандартов и маршрутизацию, что обеспечивает более плавную работу для глобальной аудитории.

В этом руководстве вы узнаете, как создать многоязычное веб-приложение с использованием Nuxt 3 и Nuxt i18n. Вы научитесь настраивать Nuxt i18n, языковые стандарты и выполнять переводы. Мы создадим многоязычное приложение для электронной коммерции, которое будет отображать товары на трех языках, в зависимости от выбранного пользователем языка.

Чтобы следовать дальше, вам понадобится:

    На вашем компьютере установлен Nodejs версии 21 Общие сведения о Vue

Создание проекта Nuxt 3

Чтобы запустить Nuxt i18n, нам нужно настроить проект Nuxt 3. Перейдите в командную строку, перейдите в папку, в которой вы хотите настроить свой проект, и запустите приведенный ниже код:

npx nuxi init ecommmerceDemo

Приведенный выше код создает папку ecommmerceDemo и инициализирует приложение Nuxt внутри этой папки.

Выполните следующую команду, чтобы запустить ваше приложение:

cd ecommmerceDemo
npm run dev

Теперь ваше приложение Nuxt должно быть запущено в вашем браузере.

Настройка многоязычного приложения

Прежде чем мы сможем сделать наше приложение многоязычным, нам нужно сначала настроить его основные функции.

Давайте создадим папки, необходимые для организации нашего проекта. В корневой папке создайте три папки:

    страницы компонентов статичны

Нам также понадобится файл JSON для хранения наших данных. В папке static создайте файл JSON с именем products. Затем вставьте следующее:

[
    {
        "id": 1,
        "name": "Timberland boots",
        "description": "Leather boot crafted with your legs in mind",
        "price": 50
    },
    {
        "id": 2,
        "name": "Product B",
        "description": "This is Product B",
        "price": 75
    },
    {
        "id": 3,
        "name": "Product B",
        "description": "This is Product C",
        "price": 75
    },
    {
        "id": 4,
        "name": "Product B",
        "description": "This is Product C",
        "price": 75
    },
    {
        "id": 5,
        "name": "Product B",
        "description": "This is Product C",
        "price": 75
    }
]

Приведенный выше файл содержит информацию, которую мы будем отображать в нашем приложении.

Затем создайте файл с именем ProductCard.vue в папке components и вставьте приведенный ниже код:

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    price: {
      type: Number,
      required: true
    }
  }
};
</script>

<template>
  <div class="product-card">
    <h3>{{ item.name }}</h3>
    <p>{{ item.description }}</p>
    <p>Price: ${{ item.price }}</p>
    <button>Add to Cart</button>
  </div>
</template>

<style scoped>
.product-card {
  border: 1px solid #ddd;
  background-color: bisque;
  padding: 16px;
  margin: 8px;
  border-radius: 8px;
  text-align: center;
}

.product-button {
  border: 1px solid blueviolet;
  border-radius: 8px;
  padding:5px;
}
</style>

Мы только что создали компонент ProductCard, чтобы красиво отображать наши товары в нашем интернет-магазине.

Затем создайте файл index.vue в папке pages и вставьте следующий код для отображения компонента ProductCard:

<script>
import products from '~/static/products.json';
import ProductCard from '~/components/ProductCard.vue';

export default {
  components: {
    ProductCard,
  },
  data() {
    return {
      items: products,
    };
  },
};
</script>

<template>
  <div>
    <h1>Welcome to our e-commerce store!</h1>
    <div class="product-list">
      <ProductCard
        v-for="item in items"
        :key="item.id"
        :item="item"
      />
    </div>
  </div>
</template>

<style scoped>
.product-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  padding: 16px;
}

h1 {
  text-align: center;
  margin-bottom: 24px;
}
</style>

Теперь обновите app.vue, чтобы добавить немного стиля:

<template>
  <div>
    <NuxtPage />
  </div>
</template>

<style>
body {
  background-color: #f0f0f0;
  display: grid;
  place-content: center;
  height: 100vh;
  text-align: center;
  font-family: sans-serif;
}

a,
a:visited {
  color: #fff;
  text-decoration: none;
  padding: 8px 10px;
  background-color: cadetblue;
  border-radius: 5px;
  font-size: 14px;
  display: block;
  margin-bottom: 50px;
}
a:hover {
  background-color: rgb(23, 61, 62);
}
</style>

Теперь давайте запустим наше приложение с помощью npm run dev:

Ecommerce Store In English

Наше приложение теперь работает!

Настройка Nuxt i18n

Nuxt i18n - это модуль интернационализации (i18n), который интегрирует Vue I18n в проекты Nuxt, оптимизируя производительность и SEO. Он автоматически добавляет префиксы языковых стандартов к URL-адресам, предоставляет настраиваемые функции для настройки SEO-метаданных на основе языковых стандартов и поддерживает отложенную загрузку выбранных языков, обеспечивая удобный многоязычный интерфейс.

Чтобы настроить Nuxt i18n, выполните следующие действия в вашем терминале:

npx nuxi@latest module add @nuxtjs/i18n@next

Приведенный выше код установит модуль Nuxt i18n для нашего проекта, но нам еще предстоит проделать некоторую работу, чтобы заставить Nuxti 18n работать в нашем проекте.

Откройте следующий файл config.ts и вставьте приведенный ниже код после модулей: ['@nuxtjs/i18n']:

 i18n: {
    /* module options */
    lazy: true,
    langDir: "locales",
    strategy: "prefix_except_default",
    locales: [
      {
        code: "en-US",
        iso: "en-US",
        name: "English(US)",
        file: "en-US.json",
      },
      {
        code: "es-ES",
        iso: "es-ES",
        name: "Español",
        file: "es-ES.json",
      },
      {
        code: "in-HI",
        iso: "en-HI",
        name: "हिंदी",
        file: "in-HI.json",
      },
    ],
    defaultLocale: "en-US",
  },

В приведенном выше коде мы определили свойства языковых стандартов Nuxt i18n, указав коды языков ISO: en для английского, es для испанского и hi для хинди. Мы также указали каталог для языкового перевода с помощью langDir: "locales" и включили оптимизированную загрузку файлов перевода с помощью lazy: true, которая указывает Nuxt 3 загружать файлы перевода только при необходимости. Мы также устанавливаем язык по умолчанию на английский с параметром defaultLocale: 'en'.

Добавление языков и перевод

Файлы перевода Nuxt i18n записаны в формате JSON. Чтобы добавить языки и переводы в наш проект, мы создадим папку i18n, а внутри нее - папку locale.

Для нашего приложения мы добавим следующие языки:

    Английский Хинди Испанский

Внутри папки locale мы создадим три файла:

    en-US.json es-ES.json в-ПРИВЕТ.json

В файл en-US.json вставьте следующий JSON-файл:

{
    "welcome": "Welcome to our e-commerce store!",
    "product_title": "Product Title",
    "product_price": "Price",
    "product_description": "Description",
    "add_to_cart": "Add to Cart",
    "product_a": "Timberland boots",
    "product_b": "Nike Snikers",
    "product_c": "Chelsea boots",
    "product_a_price": "200",
    "product_b_price": "250",
    "product_c_price": "300"
  }

В файл es-ES.json вставьте следующий JSON-файл:

{
  "welcome": "¡Bienvenido a nuestra tienda en línea!",
  "product_title": "Título del producto",
  "product_price": "Precio",
  "product_description": "Descripción",
  "add_to_cart": "Añadir a la cesta",
  "product_a": "Botas Timberland",
  "product_b": "Zapatos nike",
  "product_c": "Botas Chelsea",
  "product_a_price": "200",
  "product_b_price": "250",
  "product_c_price": "300"
}

В файл in-HI.json вставьте следующий JSON-файл:

{
  "welcome": "हमारे ई-कॉमर्स स्टोर में आपका स्वागत है!",
  "product_title": "उत्पाद का शीर्षक",
  "product_price": "कीमत",
  "product_description": "विवरण",
  "add_to_cart": "कार्ट में जोड़ें",
  "product_a": "टिम्बरलैंड बूट्स",
  "product_b": "नाइक स्नीकर्स",
  "product_c": "चेल्सी बूट्स",
  "product_a_price": "200",
  "product_b_price": "250",
  "product_c_price": "300"
}

Мы только что создали файлы перевода для нашего приложения.

Реализация компонента переключения языков

В этом разделе мы реализуем переключатель языков, чтобы использовать созданные файлы перевода для отображения продуктов на выбранном языке и обновления текущей локали.

Чтобы наш код был хорошо организован, создайте файл LanguageSwitcher.vue в папке component и добавьте приведенный ниже код:

<template>
  <div class="language-switcher">
    <select v-model="selectedLocale" @change="changeLocale">
      <option v-for="locale in $i18n.locales" :key="locale.code" :value="locale.code">
        {{ locale.name }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selectedLocale: this.$i18n.locale, // Set initial locale
    };
  },
  methods: {
    changeLocale() {
      this.$i18n.setLocale(this.selectedLocale); // Dynamically change locale
    },
  },
};
</script>

<style scoped>
.language-switcher {
  margin: 16px 0;
}

select {
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
}
</style>

Исходя из приведенного выше кода, когда пользователь выбирает любой параметр из тега select HTML, событие @change запускает функцию SwitchLanguage, которая обновляет языковой стандарт приложения, используя файлы JSON в нашей папке locales.

Управление переводами на страницах Nuxt

Теперь давайте обновим код для нашего файла pages/index.vue, чтобы перевод заработал:

<script>
import products from '~/static/products.json';
import ProductCard from '../components/ProductCard.vue';
import LanguageSwitcher from '../components/LanguageSwitcher.vue';

export default {
  components: { ProductCard, LanguageSwitcher },
  data() {
    return {
      items: products
    };
  }
};
</script>

<template>
  <div>
    <LanguageSwitcher />
    <h1>{{ $t('welcome') }}</h1>
    <div class="product-list">
      <ProductCard :title="$t('product_a')" :price="$t('product_a_price')"/>
      <ProductCard :title="$t('product_b')" :price="$t('product_b_price')"/>
      <ProductCard :title="$t('product_c')" :price="$t('product_c_price')"/>
    </div>
  </div>
</template>

<style scoped>
.product-list {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
</style>

Вот как теперь должно выглядеть наше приложение:

Ecommerce Store In Spanish

Настройка SEO для многоязычных приложений Nuxt

@nuxtjs/i18n добавляет некоторые метаданные для улучшения SEO-оптимизации вашей страницы, используя компонуемые функции useLocaleHead и definePageMeta().

Модуль позволяет проводить несколько СЕО-оптимизаций, в том числе:

    Установка атрибута lang для тега <html> Создание альтернативных ссылок на hreflang для улучшения многоязычной навигации Добавление тегов языка OpenGraph для улучшения обмена информацией в социальных сетях Создание канонических ссылок, чтобы избежать проблем с дублированием контента

Чтобы настроить SEO для нашего приложения, давайте сначала настроим параметр locals в nuxt.config.ts, добавив параметр language в теги locale language для каждого объекта следующим образом:

export default defineNuxtConfig({
  ...
  i18n: {
    locales: [
      {
        code: "en-US",
        iso: "en-US",
        language: "en-US",
        name: "English(US)",
        file: "en-US.json",
      },
      {
        code: "es-ES",
        iso: "es-ES",
        language: "es-ES",
        name: "Español",
        file: "es-ES.json",
      },
      {
        code: "in-HI",
        iso: "en-HI",
        language: "en-HI",
        name: "हिंदी",
        file: "in-HI.json",
      },
    ],
  },
});

Затем установите для параметра baseUrl значение рабочий домен, чтобы полностью указать альтернативные URL-адреса:

export default defineNuxtConfig({
  ...
  i18n: {
    ...
    baseUrl: '<https://my-nuxt-app.com>',
  },
});

Теперь мы можем вызывать составные функции в следующих местах проекта Nuxt:

    app.vue Компоненты Vue в каталоге pages Компоненты Vue в каталоге layouts

Чтобы включить метаданные SEO глобально, установите мета-компоненты в компонентах Vue в каталоге макетов следующим образом:

<script setup>
const route = useRoute()
const { t } = useI18n()
const head = useLocaleHead()
const title = computed(() => t(route.meta.title ?? 'TBD', t('layouts.title'))
);
</script>

<template>
  <div>
    <Html :lang="head.htmlAttrs.lang" :dir="head.htmlAttrs.dir">
      <Head>
        <Title>{{ title }}</Title>
        <template v-for="link in head.link" :key="link.id">
          <Link :id="link.id" :rel="link.rel" :href="link.href" :hreflang="link.hreflang" />
        </template>
        <template v-for="meta in head.meta" :key="meta.id">
          <Meta :id="meta.id" :property="meta.property" :content="meta.content" />
        </template>
      </Head>
      <Body>
        <slot />
      </Body>
    </Html>
  </div>
</template>

Функция useRoute извлекает текущий объект маршрута, включая метаданные, такие как заголовок страницы, указанный в конфигурации маршрута. Функция t из useI18n переводит ключи на язык активного региона, обеспечивая локализацию. Тем временем useLocaleHead генерирует локализованные метаданные, такие как атрибуты lang, ссылки на hreflang и другие теги, связанные с SEO, для текущего языкового стандарта.

Чтобы переопределить глобальные метаданные SEO, используйте функцию definePageMeta() в компонентах Vue в каталоге pages следующим образом:

<script setup>
definePageMeta({
  title: 'pages.title.top' // set resource key
})

const { locale, locales, t } = useI18n()
const switchLocalePath = useSwitchLocalePath()

const availableLocales = computed(() => {
  return locales.value.filter(i => i.code !== locale.value)
})
</script>

<template>
  <div>
    <p>{{ t('pages.top.description') }}</p>
    <p>{{ t('pages.top.languages') }}</p>
    <nav>
      <template v-for="(locale, index) in availableLocales" :key="locale.code">
        <span v-if="index"> | </span>
        <NuxtLink :to="switchLocalePath(locale.code)">
          {{ locale.name ?? locale.code }}
        </NuxtLink>
      </template>
    </nav>
  </div>
</template>

Функция definePageMeta устанавливает метаданные страницы, используя ключ (pages.title.top), соответствующий локализованному ресурсу с заголовками, который автоматически переводится на активный язык. Функция useSwitchLocalePath генерирует пути для переключения между языками, обеспечивая правильную маршрутизацию для каждой локали. Вычисляемое свойство availableLocales исключает текущую локаль из списка всех поддерживаемых языков, отображая только параметры, доступные для переключения.

Вы также можете вызвать функцию useHead() в компонентах Vue в каталоге pages, чтобы добавить дополнительные метаданные. Функция useHead() объединит дополнительные метаданные с глобальными метаданными:

<script setup>
definePageMeta({
  title: 'pages.title.about'
})

useHead({
  meta: [{ property: 'og:title', content: 'this is og title for about page' }]
})
</script>

<template>
  <h2>{{ $t('pages.about.description') }}</h2>
</template>

Стратегии маршрутизации Nuxt

Nuxt i18n предоставляет возможность добавлять префиксы языковых стандартов к URL-адресам с помощью стратегий маршрутизации. Он поставляется с четырьмя стратегиями маршрутизации:

    no_prefix префикс_except_default префикс prefix_and_default

Чтобы продемонстрировать, как работает каждая из этих стратегий маршрутизации в нашем приложении, давайте вернемся к нашему файлу nuxtconfig.ts. Мы будем корректировать стратегию "prefix_except_default" на стратегию "no_prefix".

В следующем примере к URL-адресу не добавляется префикс, зависящий от языкового стандарта:

No Locale Specified In Our Ecommerce Store

Теперь измените strategy на strategy: "prefix_except_default". Это добавляет префикс, зависящий от локали, к URL-адресу для языков, не используемых по умолчанию, но язык по умолчанию не имеет префикса:

Locale-Specific Prefix For Non-Default Language In Our Ecommerce Store

Если вы измените язык на английский, вы заметите, что к URL-адресу не добавлен префикс URL, поскольку английский является языком по умолчанию.

Теперь измените strategy на strategy: "префикс". Это добавит к URL-адресу префикс, зависящий от локали, для всех языков, включая используемый по умолчанию:

Locale-Specific Prefix For All Language In Our Ecommerce Store

Теперь измените стратегию на strategy: "prefix_and_default". Это объединяет все вышеперечисленные стратегии с дополнительным преимуществом, заключающимся в том, что вы получите URL-адреса с префиксом и без префикса для языка по умолчанию.

Оптимизация производительности с помощью Nuxt i18n Micro

Nuxt i18n Micro - это эффективный модуль интернационализации для Nuxt. Он разработан для обеспечения высочайшей производительности даже в крупномасштабных проектах, обеспечивая более высокую производительность по сравнению с традиционными опциями, такими как @nuxtjs/i18n.

Разработанный с учетом высокой скорости, Nuxt i18n Micro помогает сократить время сборки, снизить требования к серверу и сохранить небольшие размеры пакетов.

Запустить Nuxt i18n Micro в вашем проекте очень просто. Запустите следующий код в своем терминале:

npm install nuxt-i18n-micro

Затем добавьте его в свой файл nuxt.config.ts:

export default defineNuxtConfig({
  modules: [
    'nuxt-i18n-micro',
  ],
  i18n: {
    locales: [
      { code: 'en', iso: 'en-US', dir: 'ltr' },
      { code: 'fr', iso: 'fr-FR', dir: 'ltr' },
      { code: 'ar', iso: 'ar-SA', dir: 'rtl' },
    ],
    defaultLocale: 'en',
    translationDir: 'locales',
    meta: true,
  },
})

Теперь вы готовы использовать Nuxt i18n Micro в своем проекте и сравнить его скорость с Nuxt i18n. Ознакомьтесь с документацией Nuxt, чтобы узнать больше о Nuxt i18n Micro.

Nuxt i18n против Nuxt i18n Micro

Критерии эффективности

Тесты проводились в идентичных условиях, чтобы продемонстрировать эффективность Nuxt I18n Micro. Оба модуля были протестированы с использованием файла перевода объемом 10 МБ на одном и том же оборудовании, чтобы обеспечить справедливый контроль.

Время сборки и потребление ресурсов

Производительность сервера

Эти результаты демонстрируют, что Nuxt i18n Micro значительно превосходит оригинальный модуль во всех критических областях.

SEO-оптимизация

Когда дело доходит до SEO-оптимизации для многоязычных сайтов, Nuxt i18n Micro упрощает процесс, автоматически генерируя необходимые мета-теги и атрибуты, которые информируют поисковые системы о структуре и содержании вашего сайта с помощью единого флага.

Чтобы включить автоматическое управление поисковой оптимизацией, убедитесь, что для параметра meta в вашем файле nuxt.config.ts установлено значение true:

export default defineNuxtConfig({
  modules: ['nuxt-i18n-micro'],
  i18n: {
    meta: true,
  },
})

Вывод

Nuxt i18n предлагает простой и эффективный способ создания многоязычных приложений Nuxt, ориентированных на людей, говорящих на разных языках. В этом руководстве мы рассмотрели, как Nuxt i18n можно использовать для интернационализации приложений, а также, в частности, как настроить Nuxt i18n, добавить языковые файлы и переключатель языков в Nuxt i18n при создании нашего многоязычного приложения для электронной коммерции. Наконец, мы сравнили Nuxt i18n с Nuxt i18n Micro, подчеркнув преимущества последнего модуля в производительности.