404 Not Found

404 Not Found


nginx

Internacionalização (i18n)

O MegaShop quer entrar no mercado japonês e global, mas todas as suas páginas estão apenas em chinês. Alice não consegue ver preços em ienes no Japão, e usuários japoneses não conseguem encontrar produtos por seus nomes em japonês. Charlie precisa de i18n para permitir que o MegaShop suporte alternância entre chinês, inglês e japonês, com preços automaticamente formatados de acordo com a moeda.

1. O Que Você Vai Aprender


2. Uma História Real de um Arquiteto

(1) Ponto Crítico: Limitações de Idioma Único na Globalização

O site do MegaShop está apenas em chinês, então usuários japoneses não conseguem entender, e usuários americanos não conseguem encontrar produtos por seus nomes em inglês. Todos os preços são exibidos em RMB, então quando Alice nos EUA vê "¥2,999," ela não sabe se é em ienes ou RMB.

(2) Solução com @nuxtjs/i18n

O módulo i18n do Nuxt habilita automaticamente o suporte multilíngue para cada página, e sua estratégia de URL é amigável para SEO:

TEXT
/en/products/123  → Página em inglês, preço em USD
/ja/products/123  → Página em japonês, preço em JPY
/zh/products/123  → Página em chinês, preço em CNY

(3) Benefícios: Cobertura de Mercado Global

Três meses depois, o tráfego do Japão aumentou 200% e o tráfego dos EUA aumentou 150%; as tags hreflang permitiram que o Google indexasse corretamente cada versão de idioma.


3. Fluxo de Processamento de Idiomas do i18n

(1) Fluxo de Detecção → Carregamento → Renderização de Idiomas

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. Configuração do @nuxtjs/i18n

### (1) Instalação e Configuração Básica

```bash
npm install @nuxtjs/i18n

(1) ▶Exemplo: Configuração do Módulo i18n

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',  // / para en, /zh/..., /ja/...
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'i18n-locale',
      redirectOn: 'root'
    }
  }
})

Saída:

TEXT
// Execução Bem-sucedida

(2) Comparação de Políticas de URL

Estratégia URL em Inglês URL em Chinês Eficácia SEO
prefix_except_default /products /zh/products ✅ Recomendado
prefix /en/products /zh/products ✅ Consistente
prefix_and_default /en/products + /products /zh/products ⚠️ Duplicado
no_prefix /products /products ❌ Não distingue

4. Gerenciamento de Arquivos de Tradução

(1) ▶Exemplo: Estrutura de Arquivos de Tradução

TEXT
locales/
├── en.json    # Inglês
├── zh.json    # Chinês
└── ja.json    # Japonês

Saída:

TEXT
Execução Bem-sucedida

(2) ▶Exemplo: Documento de Tradução em Inglês

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"
  }
}

Saída:

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) ▶Exemplo: Arquivo de Tradução em Chinês

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"
  }
}

Saída:

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. API em Tempo de Execução

(1) ▶Exemplo: Usando useI18n em um componente

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()

// Obter moeda atual com base no 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>

Saída:

TEXT
// Execução Bem-sucedida

(2) ▶Exemplo: Navegação de Troca de Idioma

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>

Saída:

TEXT
// Execução Bem-sucedida

(3) ▶Exemplo: Tradução de Rotas localePath

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>

Saída:

TEXT
// Execução Bem-sucedida

6. SEO e i18n

(1) Geração Automática de Tags hreflang

O @nuxtjs/i18n gera automaticamente uma tag hreflang para cada página:

HTML
<!-- Gerado automaticamente pelo módulo i18n -->
<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) ▶Exemplo: Sitemap Multilíngue

TYPESCRIPT
// nuxt.config.ts - Integração i18n + sitemap
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'
    }
  }
})

Saída:

TEXT
// Execução Bem-sucedida

(2) Checklist de SEO i18n

Item de Verificação Requisito Método de Verificação
Tag hreflang Links cruzados entre versões de idiomas Ver código fonte
URL canônica Link para a versão do idioma atual Ver código fonte
x-default Links para o idioma padrão Ver código fonte
URLs contendo prefixos de idioma /zh/ /ja/ Barra de endereços do navegador
Taxa de Conclusão de Tradução > 95% Verificação Automatizada

7. Exemplo Completo: MegaShop — Multilíngue e Multi-moeda

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)
  }

  // Converter preço base em USD para moeda local (simplificado)
  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>

❓Perguntas Frequentes

P Qual é a diferença entre lazy: true e lazy: false?
R lazy: true carrega arquivos de tradução sob demanda (somente ao trocar de idioma), reduzindo o tamanho do conteúdo acima da dobra. lazy: false carrega todos os idiomas de uma vez; a troca é instantânea, mas o conteúdo acima da dobra carrega mais lentamente. Recomendamos lazy: true.
P Devo usar JSON ou YAML para arquivos de tradução?
R JSON é o formato padrão e oferece a melhor compatibilidade. YAML é mais legível, mas requer instalação de um parser. JSON é recomendado para colaboração em equipe porque suporta estruturas aninhadas.
P A estratégia i18n "prefix_except_default" fará com que o idioma padrão não tenha prefixo de URL?
R Sim, "/" é inglês, e "/zh/" é chinês. Esta é a estratégia SEO recomendada — URLs mais curtas para o idioma padrão. Se precisar de consistência, use a estratégia "prefix".
P Como a troca de idioma é persistida em tempo de execução?
R O módulo i18n inclui persistência de cookie embutida (detectBrowserLanguage.useCookie: true). Você também pode defini-la manualmente usando setLocaleCookie().
P Como lidar com múltiplas moedas — o i18n gerencia apenas a tradução?
R O i18n gerencia a tradução de idiomas; moeda deve ser tratada separadamente. Use Intl.NumberFormat para formatação, e implemente conversão de moeda em um Composable. O useLocalizedPrice do MegaShop encapsula ambos.
P Como as traduções são gerenciadas para um milhão de páginas de produtos?
R Dados dinâmicos como nomes e descrições de produtos são armazenados em múltiplos idiomas no banco de dados (na tabela ProductTranslation); arquivos de tradução gerenciam apenas texto de UI. A API retorna a tradução correspondente com base no idioma atual.

📖Resumo


📝Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Instale @nuxtjs/i18n, configure suporte para chinês e inglês, e implemente tradução básica de UI
  2. Exercício Avançado (Dificuldade: ⭐⭐): Adicione suporte ao idioma japonês + seletor de idioma + tradução de rotas localePath, e verifique a tag hreflang
  3. Desafio (Dificuldade: ⭐⭐⭐): Implemente o Composable useLocalizedPrice para suportar conversão e formatação automática para três moedas — USD, CNY e JPY — e exiba preços na moeda correspondente na página do produto com base no idioma.

---|

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%