---
title: Mitmekeelsus (i18n)
description: Lisab Next.js projektile täieliku mitmekeelsuse tugi next-intl abil.
category: Marketing
sublabel: SEO
author: OpenClaudia
tags: 
license: MIT
source: https://github.com/OpenClaudia/openclaudia-skills
---

# Rahvusvahelista Next.js projekt

Lisa Next.js (App Router) projektile täielik rahvusvahelistamine, kasutades **next-intl v4**. See oskus käsitleb marsruutimist, tõlkefaile, saidikaardi hreflangi ja hulgitõlget kõigisse lokaadidesse.

## Samm 1: Hinda projekt

1. Kontrolli Next.js versiooni (`package.json`) — peab olema 13+ App Routeriga
2. Kontrolli, kas i18n on juba osaliselt seadistatud (otsi `next-intl`, `next-i18next`, `[locale]` marsruute)
3. Tuvasta kõik lehed/marsruudid, mis vajavad tõlget
4. Tuvasta kõik kasutajale nähtavad stringid (kõvakodeeritud tekst komponentides)
5. Küsi kasutajalt, milliseid lokaade toetada (vaikimisi soovitus: en, es, fr, de, pt, ja, ar, zh, zh-tw, id, vi, ms, ru, hi)

## Samm 2: Installi sõltuvused

```bash
npm install next-intl
```


## Samm 3: Loo i18n konfiguratsioonifailid

Loo 4 faili kataloogi `src/i18n/` alla:

### `src/i18n/config.ts`
```typescript
export const locales = ['en', 'es', 'fr', 'de', 'pt', 'ja', 'ar', 'zh', 'zh-tw', 'id', 'vi', 'ms', 'ru', 'hi'] as const

export type Locale = (typeof locales)[number]
export const defaultLocale: Locale = 'en'

export const localeNames: Record<Locale, string> = {
  en: 'English',
  es: 'Espanol',
  fr: 'Francais',
  de: 'Deutsch',
  pt: 'Portugues',
  ja: '日本語',
  ar: 'العربية',
  zh: '简体中文',
  'zh-tw': '繁體中文',
  id: 'Bahasa Indonesia',
  vi: 'Tieng Viet',
  ms: 'Bahasa Melayu',
  ru: 'Русский',
  hi: 'हिन्दी',
}

export const rtlLocales: Locale[] = ['ar']
```


### `src/i18n/routing.ts`
```typescript
import { defineRouting } from 'next-intl/routing'
import { defaultLocale, locales } from './config'

export const routing = defineRouting({
  locales,
  defaultLocale,
  localePrefix: 'as-needed', // English URLs stay clean, other locales get /es/, /fr/, etc.
})
```


### `src/i18n/navigation.ts`
```typescript
import { createNavigation } from 'next-intl/navigation'
import { routing } from './routing'

export const { Link, redirect, usePathname, useRouter } = createNavigation(routing)
```


### `src/i18n/request.ts`
```typescript
import { getRequestConfig } from 'next-intl/server'
import { routing } from './routing'

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale
  if (!locale || !routing.locales.includes(locale as any)) {
    locale = routing.defaultLocale
  }
  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default,
  }
})
```


## Samm 4: Loo middleware

Loo `src/middleware.ts`:
```typescript
import createMiddleware from 'next-intl/middleware'
import { routing } from '@/i18n/routing'

export default createMiddleware({
  ...routing,
  localeDetection: false, // Don't auto-redirect based on Accept-Language
})

export const config = {
  matcher: ['/((?!_next|api|images|fonts|favicon|sitemap|robots).*)'],
}
```


**Võtmeotsus**: `localeDetection: false` takistab kasutajate automaatset ümbersuunamist brauserikeele põhjal. See hoiab ingliskeelsed URL-id SEO jaoks stabiilsena. Kasutajad saavad keelt käsitsi vahetada keelevalija kaudu.

## Samm 5: Uuenda next.config

Mässi olemasolev konfiguratsioon `createNextIntlPlugin` abil:

```typescript
import createNextIntlPlugin from 'next-intl/plugin'
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts')

// ... existing config ...
export default withNextIntl(nextConfig)
```


## Samm 6: Lisa `[locale]` dünaamiline marsruut

Liiguta kogu lehesisu `src/app/[locale]/` alla:

1. Loo `src/app/[locale]/layout.tsx` koos:
   - `generateStaticParams()`, mis tagastab kõik lokaadid
   - `setRequestLocale(locale)` kutsega
   - `<NextIntlClientProvider>` laste ümber
   - `<html lang={locale} dir={rtlLocales.includes(locale) ? 'rtl' : 'ltr'}>`
   - Hreflangi `<link>` märgendid `<head>`-is kõigile lokaadidele + `x-default`

2. Liiguta olemasolevad lehed `src/app/[locale]/` alla
3. Iga leht peaks staatilise genereerimise jaoks kutsuma `setRequestLocale(locale)`

## Samm 7: Ekstrakti stringid tõlkefailidesse

1. Loo `src/messages/en.json` kõigi kasutajale nähtavate stringidega, organiseeritud sektsiooni järgi:
      ```json
   {
     "common": { "signIn": "Sign In", ... },
     "tools": { "tool-slug": { "title": "...", "description": "..." } },
     "faq": { "tool-slug": [{ "question": "...", "answer": "..." }] }
   }
   ```


2. Asenda kõik kõvakodeeritud stringid komponentides `useTranslations()` abil:
      ```typescript
   const t = useTranslations('common')
   return <button>{t('signIn')}</button>
   ```


3. Serverikomponentide jaoks kasuta `getTranslations()`:
      ```typescript
   const t = await getTranslations('common')
   ```


## Samm 8: Tõlgi kõikidesse lokaadidesse

Iga mitte-inglise lokaadi jaoks loo `src/messages/{locale}.json` sama struktuuriga nagu `en.json`.

### Tõlkestrateegia

Kasuta **paralleelseid Codex agente** `codex-tasks` oskuse kaudu, et säästa Claude krediite:

1. Käivita üks Codex ülesanne lokaadi kohta (kuni 7 paralleelselt) käsuga `/codex-tasks`
2. Iga ülesanne loeb `en.json`, tõlgib kõik stringid, kirjutab `{locale}.json`
3. Codex päring peaks sisaldama:
   - Täielikku `en.json` sisu (või teed selle lugemiseks)
   - Sihtkeele nime ja lokaadikoodi
   - Juhiseid:
     - Tõlgi loomulikult, mitte sõnasõnaliselt
     - Hoia tehnilised terminid inglise keeles (PowerPoint, PDF, API jne)
     - Säilita JSON-struktuur täpselt (samad võtmed, sama pesastumine)
     - Säilita interpolatsioonimuutujad nagu `{count}`, `{name}` muutumatuna
     - Kirjuta tulemus faili `src/messages/{locale}.json`
4. Pärast Codex ülesannete lõppu **kontrolli tulemusi** alloleva kontrolliskriptiga — Codexi väljundi kvaliteet varieerub ja seda peab kontrollima

### Kontrollimine

Pärast tõlget käivita kontrolliskript, et probleeme kinni püüda:

```python
import json

locales = ['es', 'fr', 'de', 'pt', 'ja', 'ar', 'zh', 'zh-tw', 'id', 'vi', 'ms', 'ru', 'hi']
english_words = ['the ', 'and ', 'you ', 'your ', 'our ', 'this ', 'that ', 'with ', 'from ', 'will ']

with open('src/messages/en.json') as f:
    en = json.load(f)

for loc in locales:
    with open(f'src/messages/{loc}.json') as f:
        data = json.load(f)

    # Check: missing sections
    missing = [s for s in en if s not in data]

    # Check: residual English content
    eng_count = 0
    def check(d):
        nonlocal eng_count  # won't work in inline script; use list trick
        if isinstance(d, dict):
            for v in d.values(): check(v)
        elif isinstance(d, str):
            if sum(1 for w in english_words if w in d.lower()) >= 3:
                eng_count += 1
    check(data)

    status = 'OK' if not missing and eng_count == 0 else 'ISSUES'
    print(f'{loc}: {status} (missing={len(missing)}, english={eng_count})')
```


## Samm 9: Uuenda saidikaarti hreflangiga

Uuenda `src/app/sitemap.ts`, et kaasata hreflangi alternates:

```typescript
import { MetadataRoute } from 'next'
import { locales } from '@/i18n/config'

const baseUrl = 'https://www.example.com'

function buildAlternates(path: string): Record<string, string> {
  const alternates: Record<string, string> = {}
  for (const locale of locales) {
    const prefix = locale === 'en' ? '' : `/${locale}`
    alternates[locale] = `${baseUrl}${prefix}${path}`
  }
  return alternates
}

export default function sitemap(): MetadataRoute.Sitemap {
  return pages.map((path) => ({
    url: `${baseUrl}${path}`,
    lastModified: new Date(),
    alternates: { languages: buildAlternates(path) },
  }))
}
```


**Oluline**: Genereeri üks kanooniline URL lehe kohta hreflangi alternates’idega, MITTE üks URL lokaadi kohta. See takistab duplikaatsisu otsingutulemustes.

## Samm 10: Lisa keelevalija (valikuline)

Lisa keelevahetaja komponent, mis kasutab `useRouter` ja `usePathname` moodulist `@/i18n/navigation`, et vahetada lokaade, säilitades praeguse tee.

## Samm 11: Kontrolli

1. Ehita projekt: `npm run build` — kontrolli, et kõik staatilised lehed genereeruvad õigesti
2. Testi, et ingliskeelsed URL-id on ilma eesliiteta: `https://example.com/tools`
3. Testi, et lokaadi URL-idel on eesliide: `https://example.com/es/tools`
4. Kontrolli, et saidikaardil on hreflangi alternates
5. Kontrolli RTL renderdust araabia keele jaoks
6. Käivita tõlke kontrolliskript sammust 8

## Levinud lõksud

- **`public/sitemap.xml`** konfliktib dünaamilise `src/app/sitemap.ts`-iga arendusrežiimis — kustuta staatiline või nimeta ümber
- **Middleware matcher** peab välistama `_next`, `api`, `sitemap`, `robots` ja staatiliste varade teed
- **`localePrefix: 'as-needed'`** on kriitiline — see hoiab vaikimisi lokaadi URL-id SEO järjepidevuse jaoks puhtana
- **`localeDetection: false`** takistab soovimatuid ümbersuunamisi, mis murravad SEO-d ja ajavad kasutajaid segadusse
- **Suured tõlkefailid** (5000+ rida lokaadi kohta) võivad git push’id ebaõnnestuda — kasuta `git config http.postBuffer 524288000`
- **Kontrolli tõlkeid põhjalikult** — automatiseeritud tõlge annab sageli segakeelset väljundit; kontrolli alati ingliskeelsete sõnade tuvastamise skriptiga pärast Codex ülesannete lõppu

## Lokaadide arvu viide

- 14 lokaati × N lehte = 14N staatilist lehte ehitusajal
- Iga lokaadi JSON-fail on tavaliselt 2–5× en.json suurusest (CJK märgid, sõnarikkad keeled)
- Ehitusaeg kasvab lineaarselt lokaadide arvuga