# i18n Lokalizacja: konfiguracja locali dla Payload, negocjacja języka (cookie / Accept-Language / default), budowanie ścieżek locale-aware, przełączanie języka bez 404. ## Config (payload.config.ts) ```ts ipalKit({ i18n: { defaultLocale: 'pl', locales: [ { code: 'pl', label: 'Polski' }, { code: 'en', label: 'English' }, // { code: 'ar', label: 'العربية', rtl: true }, ], // fallback: true, // domyślnie true }, }) ``` Plugin ustawia `config.localization` z tego. Walidacja jest eager (fail-fast przy starcie): pusta lista, duplikaty kodów, `defaultLocale` spoza listy, zły format kodu → błąd `[ipal] i18n: ...`. ## Front — helpery Wszystkie helpery są czyste (przyjmują config jako argument). Trzymaj swój `i18nConfig` w jednym miejscu i importuj gdzie trzeba. ```ts import { getLocaleCodes, getDefaultLocale, isValidLocale, getLocaleDefinition, negotiateLocale, buildLocalizedPath, switchLocalePath, getLocalizedSlugs, LOCALE_COOKIE_NAME, } from '@intecion/ipal-kit' const config = { defaultLocale: 'pl', locales: [{code:'pl',label:'Polski'},{code:'en',label:'English'}] } getLocaleCodes(config) // ['pl', 'en'] isValidLocale('de', config) // false ``` ### Budowanie ścieżek ```ts // dokument pobrany z locale:'all' → slug to mapa { pl, en } const doc = await payload.findByID({ collection: 'pages', id, locale: 'all' }) const slugs = getLocalizedSlugs({ slugField: doc.slug, config }) // { pl: 'o-nas', en: 'about' } buildLocalizedPath({ slugs, locale: 'en', config }) // '/en/about' // home slug ('home') zwija się do roota: buildLocalizedPath({ slugs: { en: 'home' }, locale: 'en', config }) // '/en' ``` ### Przełącznik języka (bez 404) ```ts // /pl/strona-glowna → klik EN → /en/home (albo /en jeśli brak tłumaczenia) const href = switchLocalePath({ slugs, targetLocale: 'en', config }) router.push(href) ``` `switchLocalePath` nigdy nie zwraca undefined — brak slug w danym locale → fallback na `/{locale}` (root), zamiast dead-endu na 404. ## Middleware — patrz osobno Negocjacja locale + redirect na wejściu (`domena.com` → `/pl`) jest w `@intecion/ipal-kit/next/middleware`. Zobacz [middleware w tej sekcji](#middleware) niżej. ## Middleware ```ts // middleware.ts (projekt klienta) — jedyna logika to podłączenie import { NextResponse } from 'next/server' import { createLocaleMiddleware, DEFAULT_MIDDLEWARE_MATCHER } from '@intecion/ipal-kit/next/middleware' const i18nConfig = { defaultLocale: 'pl', locales: [{ code: 'pl', label: 'Polski' }, { code: 'en', label: 'English' }], } const localeMiddleware = createLocaleMiddleware({ config: i18nConfig }) export function middleware(req) { const r = localeMiddleware(req) if (r.type === 'next') return NextResponse.next() const res = NextResponse.redirect(r.location) res.cookies.set(r.cookie.name, r.cookie.value) return res } export const config = { matcher: DEFAULT_MIDDLEWARE_MATCHER } ``` Zachowanie: - ścieżka z locale (`/pl/...`) → przepuść - root albo ścieżka bez locale (`/`, `/o-nas`) → redirect na `/{locale}...`, locale z: cookie → Accept-Language → default - wybrany locale zapisany w cookie (`LOCALE_COOKIE_NAME`) `DEFAULT_MIDDLEWARE_MATCHER` wyklucza `api`, `admin`, `_next`, pliki statyczne.