404 Not Found

404 Not Found


nginx

Internationalization (i18n)

MegaShop wants to enter the Japanese and global markets, but all its pages are in Chinese only. Alice can't see prices in yen in Japan, and Japanese users can't find products by their Japanese names. Charlie needs i18n to enable MegaShop to support switching between Chinese, English, and Japanese, with prices automatically formatted according to the currency.

1. What You'll Learn


2. A True Story of an Architect

(1) Pain Point: Single-Language Limitations on Globalization

MegaShop's website is only in Chinese, so Japanese users can't understand it, and U.S. users can't find products by their English names. All prices are displayed in RMB, so when Alice in the U.S. sees "¥2,999," she doesn't know if it's in yen or RMB.

(2) The @nuxtjs/i18n Solution

The Nuxt i18n module automatically enables multilingual support for every page, and its URL strategy is SEO-friendly:

TEXT
/en/products/123  → English page, USD price
/ja/products/123  → Japanese page, JPY price
/zh/products/123  → Chinese page, CNY price

(3) Benefits: Global Market Coverage

Three months later, traffic from Japan increased by 200% and traffic from the U.S. increased by 150%; the hreflang tags enabled Google to correctly index each language version.


3. i18n Language Processing Workflow

(1) Language Detection → Loading → Rendering Workflow

100%
flowchart TB
    A[User Request] --> B{Detect Language}
    B -->|Cookie| C[Use saved locale]
    B -->|Browser Header| D[Match Accept-Language]
    B -->|Default| E[Use defaultLocale: en]
    C --> F[Load translation file]
    D --> F
    E --> F
    F --> G[Set URL prefix]
    G --> H[Render page with locale]
    H --> I[Generate hreflang tags]
    ```

---

## 4. @nuxtjs/i18n Configuration

### (1) Installation and Basic Configuration

```bash
npm install @nuxtjs/i18n

(1) ▶ Example: i18n Module Configuration

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/i18n'],

  i18n: {
    locales: [
      { code: 'en', name: 'English', file: 'en.json', currency: 'USD' },
      { code: 'zh', name: 'Chinese', file: 'zh.json', currency: 'CNY' },
      { code: 'ja', name: 'Japanese', file: 'ja.json', currency: 'JPY' }
    ],
    defaultLocale: 'en',
    lazy: true,
    langDir: 'locales/',
    strategy: 'prefix_except_default',  // / for en, /zh/..., /ja/...
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'i18n-locale',
      redirectOn: 'root'
    }
  }
})

Output:

TEXT
// Execution Successful

(2) Comparison of URL Policies

Strategy English URL Chinese URL SEO Effectiveness
prefix_except_default /products /zh/products ✅ Recommended
prefix /en/products /zh/products ✅ Match
prefix_and_default /en/products + /products /zh/products ⚠️ Duplicate
no_prefix /products /products ❌ Cannot distinguish

4. Translation File Management

(1) ▶ Example: Translation File Structure

TEXT
locales/
├── en.json    # English
├── zh.json    # Chinese
└── ja.json    # Japanese

Output:

TEXT
Execution Successful

(2) ▶ Example: English Translation Document

JSON
{
  "common": {
    "home": "Home",
    "products": "Products",
    "cart": "Cart",
    "search": "Search",
    "signIn": "Sign In",
    "signOut": "Sign Out"
  },
  "product": {
    "addToCart": "Add to Cart",
    "outOfStock": "Out of Stock",
    "reviews": "{count} reviews",
    "price": "Price: {amount} {currency}",
    "freeShipping": "Free shipping on orders over {amount} USD"
  },
  "cart": {
    "empty": "Your cart is empty",
    "total": "Total: {amount}",
    "checkout": "Proceed to Checkout",
    "items": "{count} items"
  }
}

Output:

JSON
{
  "common": {
    "home": "Home",
    "products": "Products",
    "cart": "Cart",
    "search": "Search",
    "signIn": "Sign In",
    "signOut": "Sign Out"
  },
  "product": {
    "addToCart": "Add to Cart",
    "outOfStock": "Out of Stock",
    "reviews": "{count} reviews",
    "price": "Price: {amount} {currency}",
    "freeShipping": "Free shipping on orders over {amount} USD"
  },
  "cart": {
    "empty": "Your cart is empty",
    "total": "Total: {amount}",
    "checkout": "Proceed to Ch

(3) ▶ Example: Chinese Translation File

JSON
{
  "common": {
    "home": "Home Page",
    "products": "Products",
    "cart": "Shopping Cart",
    "search": "Search",
    "signIn": "Sign In",
    "signOut": "Sign Out"
  },
  "product": {
    "addToCart": "Add to Cart",
    "outOfStock": "Out of stock",
    "reviews": "{count} reviews",
    "price": "Price: {amount} {currency}",
    "freeShipping": "Free shipping on orders of {amount} yuan or more"
  },
  "cart": {
    "empty": "Your cart is empty",
    "total": "Total: {amount}",
    "checkout": "Proceed to Checkout",
    "items": "{count} items"
  }
}

Output:

JSON
{
  "common": {
    "home": "Home Page",
    "products": "Products",
    "cart": "Shopping Cart",
    "search": "Search",
    "signIn": "Sign In",
    "signOut": "Sign Out"
  },
  "product": {
    "addToCart": "Add to Cart",
    "outOfStock": "Out of stock",
    "reviews": "{count} reviews",
    "price": "Price: {amount} {currency}",
    "freeShipping": "Free shipping on orders of {amount} yuan or more"
  },
  "cart": {
    "empty": "Your cart is empty",
    "total": "Total: {amount}",
    "checkout": "Proceed to Checkout",
    "items": "{count} items"
  }
}

5. Runtime API

(1) ▶ Example: Using useI18n in a component

VUE
<template>
  <div>
    <h1>{{ t('common.products') }}</h1>
    <button>{{ t('product.addToCart') }}</button>
    <p>{{ t('product.reviews', { count: 1200 }) }}</p>
    <p>{{ t('product.price', { amount: formattedPrice, currency: currentCurrency }) }}</p>
  </div>
</template>

<script setup lang="ts">
const { t, locale, locales } = useI18n()

// Get current currency based on locale
const currentCurrency = computed(() => {
  const current = locales.value.find(l => l.code === locale.value)
  return current?.currency || 'USD'
})

const formattedPrice = computed(() => {
  return new Intl.NumberFormat(locale.value, {
    style: 'currency',
    currency: currentCurrency.value
  }).format(299.99)
})
</script>

Output:

TEXT
// Execution Successful

(2) ▶ Example: Language Switch Navigation

VUE
<!-- components/LanguageSwitcher.vue -->
<template>
  <div class="language-switcher">
    <NuxtLink
      v-for="loc in availableLocales"
      :key="loc.code"
      :to="switchLocalePath(loc.code)"
      :class="{ active: loc.code === locale }"
    >
      {{ loc.name }}
    </NuxtLink>
  </div>
</template>

<script setup lang="ts">
const { locale, locales, t } = useI18n()
const switchLocalePath = useSwitchLocalePath()

const availableLocales = computed(() =>
  (locales.value as any[]).filter(l => l.code !== locale.value)
)
</script>

Output:

TEXT
// Execution Successful

(3) ▶ Example: localePath Route Translation

VUE
<template>
  <nav>
    <NuxtLink :to="localePath('/')">{{ t('common.home') }}</NuxtLink>
    <NuxtLink :to="localePath('/products')">{{ t('common.products') }}</NuxtLink>
    <NuxtLink :to="localePath('/cart')">{{ t('common.cart') }}</NuxtLink>
  </nav>
</template>

<script setup lang="ts">
const localePath = useLocalePath()
</script>

Output:

TEXT
// Execution Successful

6. SEO and i18n

(1) Automatic Generation of hreflang Tags

@nuxtjs/i18n automatically generates an hreflang tag for each page:

HTML
<!-- Auto-generated by i18n module -->
<link rel="alternate" hreflang="en" href="https://megashop.com/products/123" />
<link rel="alternate" hreflang="zh" href="https://megashop.com/zh/products/123" />
<link rel="alternate" hreflang="ja" href="https://megashop.com/ja/products/123" />
<link rel="alternate" hreflang="x-default" href="https://megashop.com/products/123" />

(1) ▶ Example: Multilingual Sitemap

TYPESCRIPT
// nuxt.config.ts - i18n + sitemap integration
export default defineNuxtConfig({
  modules: ['@nuxtjs/i18n', '@nuxtjs/sitemap'],

  i18n: {
    locales: [
      { code: 'en', name: 'English', file: 'en.json' },
      { code: 'zh', name: 'Chinese', file: 'zh.json' },
      { code: 'ja', name: 'Japanese', file: 'ja.json' }
    ],
    defaultLocale: 'en'
  },

  sitemap: {
    hostname: 'https://megashop.com',
    i18n: {
      locales: ['en', 'zh', 'ja'],
      defaultLocale: 'en'
    }
  }
})

Output:

TEXT
// Execution Successful

(2) i18n SEO Checklist

Check Item Requirement Verification Method
hreflang tag Cross-linking between language versions View source code
canonical URL Link to the current language version View source code
x-default Links to the default language View source code
URLs containing language prefixes /zh/ /ja/ Browser address bar
Translation Completion Rate > 95% Automated Check

7. Comprehensive Example: MegaShop—Multilingual and Multi-Currency

TYPESCRIPT
// composables/useLocalizedPrice.ts
export function useLocalizedPrice() {
  const { locale, locales } = useI18n()

  const currentCurrency = computed(() => {
    const current = (locales.value as any[]).find(l => l.code === locale.value)
    return current?.currency || 'USD'
  })

  function formatPrice(amount: number): string {
    return new Intl.NumberFormat(locale.value, {
      style: 'currency',
      currency: currentCurrency.value
    }).format(amount)
  }

  // Convert USD base price to local currency (simplified)
  const rates: Record<string, number> = { USD: 1, CNY: 7.25, JPY: 149.5 }

  function convertFromUSD(usdAmount: number): number {
    const rate = rates[currentCurrency.value] || 1
    return usdAmount * rate
  }

  function formatFromUSD(usdAmount: number): string {
    return formatPrice(convertFromUSD(usdAmount))
  }

  return { currentCurrency, formatPrice, convertFromUSD, formatFromUSD }
}
VUE
<!-- components/ProductCard.vue -->
<template>
  <div class="product-card">
    <img :src="product.image" :alt="product.name" />
    <h3>{{ product.name }}</h3>
    <p>{{ formatFromUSD(product.price) }}</p>
    <button>{{ t('product.addToCart') }}</button>
    <p>{{ t('product.reviews', { count: product.reviewCount }) }}</p>
  </div>
</template>

<script setup lang="ts">
const { t } = useI18n()
const { formatFromUSD } = useLocalizedPrice()

defineProps<{ product: any }>()
</script>

❓ FAQ

Q What is the difference between lazy: true and lazy: false?
A lazy: true loads translation files on demand (only when switching languages), reducing the size of the above-the-fold content. lazy: false loads all languages at once; switching is instantaneous, but the above-the-fold content loads more slowly. We recommend lazy: true.
Q Should I use JSON or YAML for translation files?
A JSON is the default format and offers the best compatibility. YAML is more readable but requires installing a parser. JSON is recommended for team collaboration because it supports nested structures.
Q Will the i18n strategy "prefix_except_default" result in the default language having no URL prefix?
A Yes, "/" is English, and "/zh/" is Chinese. This is the recommended SEO strategy—shorter URLs for the default language. If you need consistency, use the "prefix" strategy.
Q How is the language switch persisted at runtime?
A The i18n module includes built-in cookie persistence (detectBrowserLanguage.useCookie: true). You can also set it manually using setLocaleCookie().
Q How should multiple currencies be handled—does i18n handle only the translation?
A i18n handles language translation; currency must be handled separately. Use Intl.NumberFormat for formatting, and implement currency conversion in a Composable. MegaShop's useLocalizedPrice encapsulates both.
Q How are translations managed for a million product pages?
A Dynamic data such as product names and descriptions is stored in multiple languages in the database (in the ProductTranslation table); translation files only handle UI text. The API returns the corresponding translation based on the current language.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty: ⭐): Install @nuxtjs/i18n, configure support for Chinese and English, and implement basic UI translation
  2. Advanced Exercise (Difficulty: ⭐⭐): Add Japanese language support + language switcher + localePath route translation, and verify the hreflang tag
  3. Challenge (Difficulty: ⭐⭐⭐): Implement the useLocalizedPrice Composable to support automatic conversion and formatting for three currencies—USD, CNY, and JPY—and display prices in the corresponding currency on the product page based on the language.

---|

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏