Author:
    Creation:2025-11-01Last update:2026-09-27

    2025 рдореЗрдВ next-i18next рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ Next.js рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХреИрд╕реЗ рдХрд░реЗрдВ

    рд╕рд╛рдордЧреНрд░реА рд╕реВрдЪреА

    next-i18next рдХреНрдпрд╛ рд╣реИ?

    next-i18next Next.js рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рд▓реЛрдХрдкреНрд░рд┐рдп рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг (i18n) рд╕рдорд╛рдзрд╛рди рд╣реИред рдЬрдмрдХрд┐ рдореВрд▓ next-i18next рдкреИрдХреЗрдЬ рдкреЗрдЬреЗрд╕ рд░рд╛рдЙрдЯрд░ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдпрд╣ рдЧрд╛рдЗрдб рдЖрдкрдХреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдЖрдзреБрдирд┐рдХ App Router рдХреЗ рд╕рд╛рде i18next рдФрд░ react-i18next рдХрд╛ рд╕реАрдзреЗ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ i18next рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред

    рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде, рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

    • рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВ рдиреЗрдорд╕реНрдкреЗрд╕ (рдЬреИрд╕реЗ, common.json, about.json) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмреЗрд╣рддрд░ рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдПред
    • рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рд▓реЛрдб рдХрд░реЗрдВ рдХреЗрд╡рд▓ рдкреНрд░рддреНрдпреЗрдХ рдкреЗрдЬ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдиреЗрдорд╕реНрдкреЗрд╕ рд▓реЛрдб рдХрд░рдХреЗ, рдЬрд┐рд╕рд╕реЗ рдмрдВрдбрд▓ рдЖрдХрд╛рд░ рдХрдо рд╣реЛрддрд╛ рд╣реИред
    • рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рджреЛрдиреЛрдВ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВ рдЙрдЪрд┐рдд SSR рдФрд░ рд╣рд╛рдЗрдбреНрд░реЗрд╢рди рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдХреЗ рд╕рд╛рдеред
    • TypeScript рд╕рдорд░реНрдерди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдЯрд╛рдЗрдк-рд╕реЗрдл рд▓реЛрдХрд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдФрд░ рдЕрдиреБрд╡рд╛рдж рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рдеред
    • SEO рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░реЗрдВ рдЙрдЪрд┐рдд рдореЗрдЯрд╛рдбреЗрдЯрд╛, рд╕рд╛рдЗрдЯрдореИрдк, рдФрд░ robots.txt рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХреЗ рд╕рд╛рдеред
    рдПрдХ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ, рдЖрдк next-intl рдЧрд╛рдЗрдб рдХреЛ рднреА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рд╕реАрдзреЗ Intlayer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
    рддреБрд▓рдирд╛ рджреЗрдЦреЗрдВ next-i18next vs next-intl vs Intlayer рдореЗрдВред
    рдпреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╣рд╛рдБ рд╕реЗ рдЖрдИрдВ, рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП JavaScript i18n рдХрд╛ рдЗрддрд┐рд╣рд╛рд╕ рдкрдврд╝реЗрдВред

    Next.js рдкрд░ next-i18next рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ benchmark рдХреНрдпрд╛ рдХрд╣рддрд╛ рд╣реИ

    рд╕реЗрдЯрдЕрдк рдореЗрдВ рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдпрд╣ рд╕рдордЭрдирд╛ рдЬрд╝рд░реВрд░реА рд╣реИ рдХрд┐ рдЖрдкрдХреА i18n рд▓рд╛рдЗрдмреНрд░реЗрд░реА performance рдФрд░ bundle рдкрд░ рдХреНрдпрд╛ рдЕрд╕рд░ рдбрд╛рд▓рддреА рд╣реИред i18n benchmark рдПрдХ рд╣реА 10 рдкреЗрдЬ рдФрд░ 10 locale рд╡рд╛рд▓реЗ Next.js рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреНрд░рдореБрдЦ i18n рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд╕рд╛рде рдЪрд▓рд╛рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рдЕрд╕рд▓реА bundle рдЖрдХрд╛рд░, string leakage рдФрд░ hydration overhead рдХреЛ рдорд╛рдкрд╛ рдЬрд╛ рд╕рдХреЗред

    рдореАрдЯреНрд░рд┐рдХ

    рдбрд╛рдпрдирд╛рдорд┐рдХ JSON рд▓реЛрдбрд┐рдВрдЧ

    рд░рдирдЯрд╛рдЗрдо рдкрд░ рдЖрд▓рд╕реНрдп рд╕реЗ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ

    рд╕реНрдХреЛрдкреНрдб JSON (рдиреЗрдорд╕реНрдкреЗрд╕рд┐рдВрдЧ)

    рдкреНрд░рддрд┐-рдкреГрд╖реНрда рдЕрдиреБрд╡рд╛рдж рдиреЗрдорд╕реНрдкреЗрд╕

    рдпрд╣ рдореАрдЯреНрд░рд┐рдХ рдХреНрдпрд╛ рд╣реИ?

    рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдмрдВрдбрд▓ рдХрд╛ рдХреБрд▓ gzip-рд╕рдВрдкреАрдбрд╝рд┐рдд рдЖрдХрд╛рд░ред рдЗрд╕рдореЗрдВ рдХреЗрд╡рд▓ рдЯреНрд░реА-рд╢реЗрдХрд┐рдВрдЧ рдФрд░ рдорд┐рдирд┐рдлрд┐рдХреЗрд╢рди рдХреЗ рдмрд╛рдж рдкреНрд░рджрд╛рддрд╛ рдФрд░ рд╕рд╛рдордЧреНрд░реА рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рддрд░реНрдХ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред

    рдпрд╣ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХреНрдпреЛрдВ рд╣реИ?

    рдПрдХ рдЫреЛрдЯрд╛ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЖрдХрд╛рд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреЗрд▓реЛрдб рдХреЛ рдХрдо рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ рддреЗрдЬрд╝ рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп рд╣реЛрддрд╛ рд╣реИред

    рджреЗрдЦрдиреЗ рдХрд╛ рддрд░реАрдХрд╛

    Next.js рдкрд░ next-i18next рдХреЗ рдореБрдЦреНрдп рдЖрдВрдХрдбрд╝реЗ (gzip):

    рд╕реЗрдЯрдЕрдкрд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЖрдХрд╛рд░рдФрд╕рдд рдкреЗрдЬ JSрдЕрдиреНрдп locale leakрдЕрдиреНрдп рдкреЗрдЬ leak
    рдмреЗрд╕ (рдмрд┐рдирд╛ i18n)-141.0 KB0.0%0.0%
    next-i18next19.7 KB169.5 KB50.0%89.8%
    @intlayer/next-i18next (compat)9.4 KB150.7 KB0.0%0.0%
    next-intlayer (native Intlayer)5.5 KB141.3 KB0.0%0.0%

    рдореБрдЦреНрдп рдирд┐рд╖реНрдХрд░реНрд╖:

    • Namespace splitting рдЬрд╝рд░реВрд░реА рд╣реИ: рд╕рд╛рдзрд╛рд░рдг рд╕реЗрдЯрдЕрдк рдореЗрдВ, next-i18next рд╣рд░ namespace рдХреЛ рд╣рд░ рдкреЗрдЬ рдкрд░ рднреЗрдЬрддрд╛ рд╣реИ (~89.8% рдкреЗрдЬ leakage)ред Route рдХреЗ рдЕрдиреБрд╕рд╛рд░ namespaces рдмрд╛рдБрдЯрдХрд░ рдЙрдиреНрд╣реЗрдВ lazy load рдХрд░рдиреЗ рд╕реЗ рдкреЗрдЬ JS рдХрдо рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рд▓рд┐рдП рд╕рд╛рд╡рдзрд╛рдиреАрдкреВрд░реНрд╡рдХ рдореИрдиреНрдпреБрдЕрд▓ рд╡реНрдпрд╡рд╕реНрдерд╛ рдЪрд╛рд╣рд┐рдПред
    • Runtime рдХрд╛ рд╡рдЬрд╝рди: i18next рдХрд╛ client runtime рд╣рд░ рдкреЗрдЬ рдкрд░ ~19.7 KB gzip рд╣реЛрддрд╛ рд╣реИред рдореМрдЬреВрджрд╛ codebase рдХреЗ рд▓рд┐рдП, @intlayer/next-i18next compat adapter рд╡рд╣реА i18next API рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП runtime рдХреЛ 9.4 KB рддрдХ рдШрдЯрд╛рддрд╛ рд╣реИ рдФрд░ leakage рдЦрддреНрдо рдХрд░рддрд╛ рд╣реИред Native next-intlayer 5.5 KB рддрдХ рдЖ рдЬрд╛рддрд╛ рд╣реИред
    рдкреВрд░рд╛ рдбреЗрдЯрд╛ рджреЗрдЦреЗрдВ: Next.js benchmark рд░рд┐рдкреЛрд░реНрдЯ, рдФрд░ benchmark repositoryред

    Next.js рдкрд░ рдлреАрдЪрд░ рддреБрд▓рдирд╛

    рдПрдХ Next.js App Router рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛ рдЖрдо рддреМрд░ рдкрд░ рдЬрд┐рди рдлреАрдЪрд░реНрд╕ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реЛрддреА рд╣реИ, рдЙрди рдкрд░ next-i18next рдХреА рддреБрд▓рдирд╛ next-intl рдФрд░ Intlayer рд╕реЗ:

    рдлреАрдЪрд░next-intlayer (Intlayer)next-intlnext-i18next
    рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреЗ рдкрд╛рд╕ рдЕрдиреБрд╡рд╛рджтЬЕ рд╣рд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдВрдЯтЭМ рдХреЗрдВрджреНрд░реАрдХреГрдд JSONтЭМ рдХреЗрдВрджреНрд░реАрдХреГрдд JSON
    TypeScript рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рдитЬЕ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдмрдиреЗ strict typesтЬЕ рдЕрдЪреНрдЫрд╛, AppConfig augmentation рдХреЗ рдЬрд╝рд░рд┐рдПтЪая╕П рдмреБрдирд┐рдпрд╛рджреА
    рдЫреВрдЯреЗ рд╣реБрдП рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреА рдкрд╣рдЪрд╛рдитЬЕ TypeScript errors рдФрд░ build-time warningsтЪая╕П Runtime fallbackтЪая╕П Runtime fallback
    рд░рд┐рдЪ рдХрдВрдЯреЗрдВрдЯ (JSX, Markdown)тЬЕ рд╕реАрдзрд╛ рд╕рдкреЛрд░реНрдЯтЪая╕П t.rich рдХреЗ рдЬрд╝рд░рд┐рдП tags, Markdown рдирд╣реАрдВтЪая╕П <Trans> рдХреЗ рдЬрд╝рд░рд┐рдП tags
    AI рдЕрдиреБрд╡рд╛рджтЬЕ рдЖрдкрдХрд╛ рдЕрдкрдирд╛ provider рдФрд░ API key, рдРрдк рдХреЗ рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рдетЭМ рдирд╣реАрдВтЭМ рдирд╣реАрдВ
    рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░ / CMSтЬЕ рд▓реЛрдХрд▓ рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░ + рд╡реИрдХрд▓реНрдкрд┐рдХ CMSтЭМ рдмрд╛рд╣рд░реА рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рдЬрд╝рд░рд┐рдПтЭМ рдмрд╛рд╣рд░реА рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рдЬрд╝рд░рд┐рдП
    рд▓реЛрдХрд▓рд╛рдЗрдЬрд╝реНрдб рд░реВрдЯрд┐рдВрдЧтЬЕ рдмрд┐рд▓реНрдЯ-рдЗрди (Next.js рдФрд░ Vite)тЬЕ рдмрд┐рд▓реНрдЯ-рдЗрди [locale] segmentтЬЕ рдмрд┐рд▓реНрдЯ-рдЗрди
    рдмрд╣реБрд╡рдЪрди (Pluralization)тЬЕ Enumeration-рдЖрдзрд╛рд░рд┐рддтЬЕ ICUтЬЕ Suffix-рдЖрдзрд╛рд░рд┐рдд (_one, _other)
    рдлрд╝реЙрд░реНрдореЗрдЯрд┐рдВрдЧ (рддрд╛рд░реАрдЦ, рд╕рдВрдЦреНрдпрд╛, рдореБрджреНрд░рд╛)тЬЕ Intl-рдЖрдзрд╛рд░рд┐рдд formattersтЬЕ useFormatterтЬЕ Intl-рдЖрдзрд╛рд░рд┐рдд
    рдХрдВрдЯреЗрдВрдЯ рдлрд╝реЙрд░реНрдореЗрдЯтЬЕ .ts, .tsx, .js, .json, .md, .yamlтЬЕ .json, .js, .tsтЪая╕П .json
    ICU MessageFormatтЬЕ format: "icu" рдХреЗ рдЬрд╝рд░рд┐рдПтЬЕ NativeтЪая╕П i18next-icu рдХреЗ рдЬрд╝рд░рд┐рдП
    SEO helpers (hreflang, sitemap)тЬЕ Metadata, sitemap рдФрд░ robots.txt helpersтЬЕ рдЕрдЪреНрдЫрд╛тЬЕ рдЕрдЪреНрдЫрд╛
    Server ComponentsтЬЕ рдХрд┐рд╕реА рднреА Server Component рдореЗрдВ рд╕реАрдзрд╛ рдПрдХреНрд╕реЗрд╕тЪая╕П рд╣рд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдореЗрдВ t рдпрд╛ await getTranslations() рдкрд╛рд╕ рдХрд░реЗрдВтЪая╕П рдХрдВрдкреЛрдиреЗрдВрдЯ рдЯреНрд░реА рдореЗрдВ рдиреАрдЪреЗ t рдкрд╛рд╕ рдХрд░реЗрдВ
    рдкреНрд░рддрд┐-рдХрдВрдкреЛрдиреЗрдВрдЯ tree-shakingтЬЕ Build time рдкрд░ (Babel / SWC)тЪая╕П рдореИрдиреНрдпреБрдЕрд▓, рд╣рд░ route рдХреЗ рд▓рд┐рдП pick() рдХреЗ рд╕рд╛рдетЪая╕П рдореИрдиреНрдпреБрдЕрд▓, рд╣рд░ route рдХреЗ рд▓рд┐рдП namespaces рдХреЗ рд╕рд╛рде
    Lazy loadingтЬЕ рдкреНрд░рддрд┐ locale рдФрд░ рдкреНрд░рддрд┐ dictionaryтЬЕ рдкреНрд░рддрд┐ locale, namespaces рд╣рд╛рде рд╕реЗ рдореИрдиреЗрдЬтЬЕ рдкреНрд░рддрд┐ locale, namespaces рд╣рд╛рде рд╕реЗ рдореИрдиреЗрдЬ
    Runtime рдЖрдХрд╛рд░ (gzip, benchmark)4.9 KB14.7 KB19.7 KB
    CI рдореЗрдВ рдЫреВрдЯреЗ рд╣реБрдП рдЕрдиреБрд╡рд╛рджтЬЕ npx intlayer testтЪая╕П рдмрд┐рд▓реНрдЯ-рдЗрди рдирд╣реАрдВтЪая╕П рдмрд┐рд▓реНрдЯ-рдЗрди рдирд╣реАрдВ, runtime рдкрд░ saveMissing
    рдЗрдХреЛрд╕рд┐рд╕реНрдЯрдо / рдХрдореНрдпреБрдирд┐рдЯреАтЪая╕П рдЫреЛрдЯрд╛, рддреЗрдЬрд╝реА рд╕реЗ рдмрдврд╝ рд░рд╣рд╛тЬЕ рдмрдбрд╝рд╛тЬЕ рдмрд╣реБрдд рдмрдбрд╝рд╛
    Runtime рдЖрдХрд╛рд░ Next.js benchmark рд╕реЗ рд▓рд┐рдП рдЧрдП рд╣реИрдВред рд╡рд┐рд╕реНрддреГрдд рдЪрд░реНрдЪрд╛ рдХреЗ рд▓рд┐рдП, next-i18next vs next-intl vs Intlayer рдкрдврд╝реЗрдВред

    рдЖрдкрдХреЛ рдЬрд┐рди рдкреНрд░рдерд╛рдУрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП

    рдЗрдореНрдкреНрд▓реАрдореЗрдВрдЯреЗрд╢рди рдореЗрдВ рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдпрд╣рд╛рдВ рдХреБрдЫ рдкреНрд░рдерд╛рдПрдВ рд╣реИрдВ рдЬрд┐рдирдХрд╛ рдЖрдкрдХреЛ рдкрд╛рд▓рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:

    • HTML рдХреЗ lang рдФрд░ dir рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯ рд╕реЗрдЯ рдХрд░реЗрдВ
    • рдЕрдкрдиреЗ рд▓реЗрдЖрдЙрдЯ рдореЗрдВ, dir рдХреА рдЧрдгрдирд╛ getLocaleDirection(locale) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд░реЗрдВ рдФрд░ рдЙрдЪрд┐рдд рдкрд╣реБрдВрдЪ рдФрд░ SEO рдХреЗ рд▓рд┐рдП <html lang={locale} dir={dir}> рд╕реЗрдЯ рдХрд░реЗрдВред
    • рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ namespace рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ JSON рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ locale рдФрд░ namespace (рдЬреИрд╕реЗ, common.json, about.json) рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВ рддрд╛рдХрд┐ рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ рдЪреАрдЬрд╝реЗрдВ рд╣реА рд▓реЛрдб рд╣реЛрдВред
    • рдХреНрд▓рд╛рдЗрдВрдЯ рдкреЗрд▓реЛрдб рдХреЛ рдиреНрдпреВрдирддрдо рдХрд░реЗрдВ рдкреГрд╖реНрдареЛрдВ рдкрд░, рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ namespaces рдХреЛ NextIntlClientProvider рдХреЛ рднреЗрдЬреЗрдВ (рдЬреИрд╕реЗ, pick(messages, ['common', 'about']))ред
    • рд╕реНрдереИрддрд┐рдХ рдкреГрд╖реНрдареЛрдВ рдХреЛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреЗрдВ рдмреЗрд╣рддрд░ рдкреНрд░рджрд░реНрд╢рди рдФрд░ SEO рдХреЗ рд▓рд┐рдП рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рд╕реНрдереИрддрд┐рдХ рдкреГрд╖реНрдареЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
    • рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдореЗрдВ I18n рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕, рдЬреИрд╕реЗ рдкреГрд╖реНрда рдпрд╛ рд╕рднреА рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдЬреЛ client рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдирд╣реАрдВ рд╣реИрдВ, рд╕реНрдереИрддрд┐рдХ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдмрд┐рд▓реНрдб рд╕рдордп рдкрд░ рдкреНрд░реА-рд░реЗрдВрдбрд░ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЛ рдЙрдиреНрд╣реЗрдВ props рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
    • TypeScript рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдХрд░реЗрдВ
    • рдЖрдкрдХреЗ locales рдХреЗ рд▓рд┐рдП рдкреВрд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ type safety рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП TypeScript types рд╕реЗрдЯ рдХрд░реЗрдВред
    • рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рди рдХреЗ рд▓рд┐рдП рдкреНрд░реЙрдХреНрд╕реА locale рдкрд╣рдЪрд╛рди рдФрд░ рд░реВрдЯрд┐рдВрдЧ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЙрдХреНрд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЙрдЪрд┐рдд locale-рдкреНрд░рд┐рдлрд┐рдХреНрд╕реНрдб URL рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░реЗрдВред
    • рдЕрдкрдиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛, рд╕рд╛рдЗрдЯрдореИрдк, robots.txt рдХрд╛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг Next.js рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП generateMetadata рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛, рд╕рд╛рдЗрдЯрдореИрдк, robots.txt рдХрд╛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд░реЗрдВ рддрд╛рдХрд┐ рд╕рднреА locales рдореЗрдВ рд╕рд░реНрдЪ рдЗрдВрдЬрди рджреНрд╡рд╛рд░рд╛ рдмреЗрд╣рддрд░ рдЦреЛрдЬ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рд╣реЛ рд╕рдХреЗред
    • рд▓рд┐рдВрдХ рдХреЛ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдХрд░реЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЙрдЪрд┐рдд locale-рдкреНрд░рд┐рдлрд┐рдХреНрд╕реНрдб URL рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Link рдХрдВрдкреЛрдиреЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд┐рдВрдХ рдХреЛ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдХрд░реЗрдВред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рдкреГрд╖реНрда рд╕рднреА locales рдореЗрдВ рдЦреЛрдЬреЗ рдЬрд╛ рд╕рдХреЗрдВред
    • рдЯреЗрд╕реНрдЯ рдФрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░реЗрдВ рдЯреЗрд╕реНрдЯ рдФрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдирд╛ рдЖрдкрдХреЗ рдмрд╣реБрднрд╛рд╖реА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд░рдЦрд░рдЦрд╛рд╡ рдореЗрдВ рд╕рдордп рдХреА рдмрдЪрдд рдХрд░рддрд╛ рд╣реИред
    рд╣рдорд╛рд░реЗ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдХреЛ рджреЗрдЦреЗрдВ рдЬрд┐рд╕рдореЗрдВ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдФрд░ SEO рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрдкрдХреЛ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рд╕реВрдЪреАрдмрджреНрдз рд╣реИ: next-intl рдХреЗ рд╕рд╛рде рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг (i18n)ред

    Next.js рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ i18next рд╕реЗрдЯрдЕрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд░рдг-рджрд░-рдЪрд░рдг рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛

    ide.intlayer.org
    GitHub рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЯреЗрдореНрдкрд▓реЗрдЯ рджреЗрдЦреЗрдВред

    рдпрд╣рд╛рдБ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдмрдирд╛рдПрдВрдЧреЗ:

    bash
    .
    тФЬтФАтФА i18n.config.ts
    тФФтФАтФА src # Src рд╡реИрдХрд▓реНрдкрд┐рдХ рд╣реИ
        тФЬтФАтФА locales
        тФВ   тФЬтФАтФА en
        тФВ   тФВ  тФЬтФАтФА common.json
        тФВ   тФВ  тФФтФАтФА about.json
        тФВ   тФФтФАтФА fr
        тФВ      тФЬтФАтФА common.json
        тФВ      тФФтФАтФА about.json
        тФЬтФАтФА types
        тФВ   тФФтФАтФА i18next.d.ts
        тФЬтФАтФА app
        тФВ   тФЬтФАтФА proxy.ts
        тФВ   тФЬтФАтФА i18n
        тФВ   тФВ   тФФтФАтФА server.ts
        тФВ   тФФтФАтФА [locale]
        тФВ       тФЬтФАтФА layout.tsx
        тФВ       тФЬтФАтФА (home) # / (рд░реВрдЯ рдЧреНрд░реБрдк рддрд╛рдХрд┐ рд╣реЛрдо рд╕рдВрджреЗрд╢реЛрдВ рд╕реЗ рд╕рднреА рдкреГрд╖реНрда рдкреНрд░рджреВрд╖рд┐рдд рди рд╣реЛрдВ)
        тФВ       тФВ   тФЬтФАтФА layout.tsx
        тФВ       тФВ   тФФтФАтФА page.tsx
        тФВ       тФФтФАтФА about # /about
        тФВ           тФЬтФАтФА layout.tsx
        тФВ           тФФтФАтФА page.tsx
        тФФтФАтФА components
            тФЬтФАтФА I18nProvider.tsx
            тФЬтФАтФА ClientComponent.tsx
            тФФтФАтФА ServerComponent.tsx
    
    1. Dependencies рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ

      npm рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрд╡рд╢реНрдпрдХ рдкреИрдХреЗрдЬ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ:

      bash
      npm install i18next react-i18next i18next-resources-to-backend
      
      • i18next: рдореБрдЦреНрдп рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдлреНрд░реЗрдорд╡рд░реНрдХ рдЬреЛ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдбрд┐рдВрдЧ рдФрд░ рдкреНрд░рдмрдВрдзрди рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред
      • react-i18next: i18next рдХреЗ рд▓рд┐рдП React рдмрд╛рдЗрдВрдбрд┐рдВрдЧреНрд╕ рдЬреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП useTranslation рдЬреИрд╕реЗ рд╣реБрдХ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
      • i18next-resources-to-backend: рдПрдХ рдкреНрд▓рдЧрдЗрди рдЬреЛ рдЕрдиреБрд╡рд╛рдж рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдк рд╕реЗ рд▓реЛрдб рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдмрдирд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЖрдк рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ namespaces рдХреЛ рд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
    2. рдЕрдкрдиреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ

      рдПрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдЖрдкрдХреЗ рд╕рдорд░реНрдерд┐рдд рд▓реЛрдХрд▓, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХрд▓, рдФрд░ URL рд▓реЛрдХрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реЛрдВред рдпрд╣ рдлрд╝рд╛рдЗрд▓ рдЖрдкрдХреЗ i18n рд╕реЗрдЯрдЕрдк рдХреЗ рд▓рд┐рдП рдПрдХрдорд╛рддреНрд░ рд╕рддреНрдп рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддреА рд╣реИ рдФрд░ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЯрд╛рдЗрдк рд╕реБрд░рдХреНрд╖рд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИред

      рдЕрдкрдиреЗ рд▓реЛрдХрд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдХреЗрдВрджреНрд░реАрдХреГрдд рдХрд░рдиреЗ рд╕реЗ рдЕрд╕рдВрдЧрддрддрд╛рдУрдВ рд╕реЗ рдмрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рд▓реЛрдХрд▓ рдЬреЛрдбрд╝рдирд╛ рдпрд╛ рд╣рдЯрд╛рдирд╛ рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди SEO рдФрд░ рд░реВрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╕реБрд╕рдВрдЧрдд URL рдЬрдирд░реЗрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВред

      i18n.config.ts
      // рдЯрд╛рдЗрдк рд╕реБрд░рдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерд┐рдд рд▓реЛрдХрд▓ рдХреЛ const array рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ
      // 'as const' рдЕрд╕рд░реНрд╢рди TypeScript рдХреЛ string[] рдХреЗ рдмрдЬрд╛рдп literal types рдЕрдиреБрдорд╛рдирд┐рдд рдХрд░рдиреЗ рджреЗрддрд╛ рд╣реИ
      export const locales = ["en", "fr"] as const;
      
      // locales array рд╕реЗ Locale рдЯрд╛рдЗрдк рдирд┐рдХрд╛рд▓реЗрдВ
      // рдпрд╣ рдПрдХ рдпреВрдирд┐рдпрди рдЯрд╛рдЗрдк рдмрдирд╛рддрд╛ рд╣реИ: "en" | "fr"
      export type Locale = (typeof locales)[number];
      
      // рдЬрдм рдХреЛрдИ рд▓реЛрдХрд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реЛ рддреЛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдиреЗ рд╡рд╛рд▓рд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХрд▓ рд╕реЗрдЯ рдХрд░реЗрдВ
      export const defaultLocale: Locale = "en";
      
      // рджрд╛рдПрдВ рд╕реЗ рдмрд╛рдПрдВ рднрд╛рд╖рд╛рдПрдБ рдЬрд┐рдиреНрд╣реЗрдВ рд╡рд┐рд╢реЗрд╖ рдЯреЗрдХреНрд╕реНрдЯ рджрд┐рд╢рд╛ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ
      export const rtlLocales = ["ar", "he", "fa", "ur"] as const;
      
      // рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдХрд┐рд╕реА рд▓реЛрдХрд▓ рдХреЛ RTL (рджрд╛рдПрдВ рд╕реЗ рдмрд╛рдПрдВ) рдЯреЗрдХреНрд╕реНрдЯ рджрд┐рд╢рд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
      // рдЕрд░рдмреА, рд╣рд┐рдмреНрд░реВ, рдлрд╛рд░рд╕реА, рдФрд░ рдЙрд░реНрджреВ рдЬреИрд╕реА рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
      export const isRtl = (locale: string) =>
        (rtlLocales as readonly string[]).includes(locale);
      
      // рджрд┐рдП рдЧрдП рд▓реЛрдХрд▓ рдФрд░ рдкрде рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкрде рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ
      // рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХрд▓ рдкрдереЛрдВ рдореЗрдВ рдХреЛрдИ рдЙрдкрд╕рд░реНрдЧ рдирд╣реАрдВ рд╣реЛрддрд╛ (рдЬреИрд╕реЗ "/about" рдмрдЬрд╛рдп "/en/about")
      // рдЕрдиреНрдп рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рдЙрдкрд╕рд░реНрдЧ рд╣реЛрддрд╛ рд╣реИ (рдЬреИрд╕реЗ "/fr/about")
      export function localizedPath(locale: string, path: string) {
        return locale === defaultLocale ? path : `/${locale}${path}`;
      }
      
      // рдкреВрд░реНрдг URL рдХреЗ рд▓рд┐рдП рдмреЗрд╕ URL (рд╕рд╛рдЗрдЯрдореИрдк, рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдЖрджрд┐ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ)
      const ORIGIN = "https://example.com";
      
      // рд▓реЛрдХрд▓ рдкреНрд░реАрдлрд┐рдХреНрд╕ рдХреЗ рд╕рд╛рде рдкреВрд░реНрдг URL рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ
      // SEO рдореЗрдЯрд╛рдбреЗрдЯрд╛, рд╕рд╛рдЗрдЯрдореИрдкреНрд╕, рдФрд░ рдХреИрдиреЛрдирд┐рдХрд▓ URLs рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
      export function absoluteUrl(locale: string, path: string) {
        return `${ORIGIN}${localizedPath(locale, path)}`;
      }
      
      // рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рд▓реЛрдХрд▓ рдХреБрдХреА рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
      export function getCookie(locale: Locale) {
        return [
          `NEXT_LOCALE=${locale}`,
          "Path=/",
          `Max-Age=${60 * 60 * 24 * 365}`, // 1 рд╡рд░реНрд╖
          "SameSite=Lax",
        ].join("; ");
      }
      
    3. рдЕрдиреБрд╡рд╛рдж рдиреЗрдорд╕реНрдкреЗрд╕реЗрд╕ рдХреЛ рдХреЗрдВрджреНрд░реАрдХреГрдд рдХрд░реЗрдВ

      рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рджреНрд╡рд╛рд░рд╛ рдПрдХреНрд╕рдкреЛрдЬрд╝ рдХрд┐рдП рдЧрдП рдкреНрд░рддреНрдпреЗрдХ namespace рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд┐рдВрдЧрд▓ рд╕реЛрд░реНрд╕ рдСрдл рдЯреНрд░реВрде рдмрдирд╛рдПрдВред рдЗрд╕ рд╕реВрдЪреА рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рд╕рд░реНрд╡рд░, рдХреНрд▓рд╛рдЗрдВрдЯ, рдФрд░ рдЯреВрд▓рд┐рдВрдЧ рдХреЛрдб рдХреЛ рд╕рд┐рдВрдХ рдореЗрдВ рд░рдЦрддрд╛ рд╣реИ рдФрд░ рдЯреНрд░рд╛рдВрд╕рд▓реЗрд╢рди рд╣реЗрд▓реНрдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрдд рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХреЛ рдЕрдирд▓реЙрдХ рдХрд░рддрд╛ рд╣реИред

      src/i18n.namespaces.ts
      export const namespaces = ["common", "about"] as const;
      
      export type Namespace = (typeof namespaces)[number];
      
    4. TypeScript рдХреЗ рд╕рд╛рде рдЯреНрд░рд╛рдВрд╕рд▓реЗрд╢рди рдХреАрдЬрд╝ рдХреЛ рдордЬрдмреВрдд рдЯрд╛рдЗрдк рдХрд░реЗрдВ

      i18next рдХреЛ рдЕрдкрдиреЗ рдХреИрдиреЛрдирд┐рдХрд▓ рднрд╛рд╖рд╛ рдлрд╝рд╛рдЗрд▓реЛрдВ (рдЖрдорддреМрд░ рдкрд░ рдЕрдВрдЧреНрд░реЗрдЬрд╝реА) рдХреА рдУрд░ рдмрдврд╝рд╛рдПрдВред TypeScript рддрдм рдкреНрд░рддреНрдпреЗрдХ namespace рдХреЗ рд▓рд┐рдП рд╡реИрдз рдХреАрдЬрд╝ рдХрд╛ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП t() рдХреЙрд▓реНрд╕ рдХреЛ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдЪреЗрдХ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

      src/types/i18next.d.ts
      import "i18next";
      
      declare module "i18next" {
        interface CustomTypeOptions {
          defaultNS: "common";
          resources: {
            common: typeof import("@/locales/en/common.json");
            about: typeof import("@/locales/en/about.json");
          };
        }
      }
      
      рд╕реБрдЭрд╛рд╡: рдЗрд╕ рдШреЛрд╖рдгрд╛ рдХреЛ src/types рдХреЗ рдЕрдВрддрд░реНрдЧрдд рд╕реНрдЯреЛрд░ рдХрд░реЗрдВ (рдпрджрд┐ рдлрд╝реЛрд▓реНрдбрд░ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ рддреЛ рдмрдирд╛рдПрдВ)ред Next.js рдкрд╣рд▓реЗ рд╕реЗ рд╣реА tsconfig.json рдореЗрдВ src рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдСрдЧрдореЗрдВрдЯреЗрд╢рди рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдкрдХрдбрд╝ рд▓рд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдЕрдкрдиреЗ tsconfig.json рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝реЗрдВ:
      tsconfig.json
      {
        "include": ["src/types/**/*.ts"],
      }
      

      рдЗрд╕рдХреЗ рд╕рд╛рде рдЖрдк рдСрдЯреЛрдХрдВрдкреНрд▓реАрдЯ рдФрд░ рдХрдВрдкрд╛рдЗрд▓-рдЯрд╛рдЗрдо рдЪреЗрдХреНрд╕ рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

      tsx
      import { useTranslation, type TFunction } from "react-i18next";
      
      const { t } = useTranslation("about");
      
      // рдареАрдХ рд╣реИ, рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рдЧрдпрд╛: t("counter.increment")
      // рддреНрд░реБрдЯрд┐, рдХрдВрдкрд╛рдЗрд▓ рддреНрд░реБрдЯрд┐: t("doesNotExist")
      export type AboutTranslator = TFunction<"about">;
      
    5. рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб i18n рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рд╕реЗрдЯ рдХрд░реЗрдВ

      рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб i18n рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдПрдВ рдЬреЛ рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рд░реЗрдВрдбрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдмрдирд╛рддрд╛ рд╣реИ, рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реБрдП рдХрд┐ рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рд╣реЛ рдЬрд╛рдПрдВред

      рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдЪрд╛рд╣рд┐рдП рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рд╕реЗ рдЕрд▓рдЧ рд╕рдВрджрд░реНрдн рдореЗрдВ рдЪрд▓рддреЗ рд╣реИрдВред рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рдкреНрд░реАрд▓реЛрдб рдХрд░рдиреЗ рд╕реЗ рдЕрдиреБрд╡рд╛рджрд┐рдд рдирд╣реАрдВ рд╣реБрдП рдХрдВрдЯреЗрдВрдЯ рдХрд╛ рдлреНрд▓реИрд╢ рд░реЛрдХрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ SEO рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╕рд░реНрдЪ рдЗрдВрдЬрди рдЕрдиреБрд╡рд╛рджрд┐рдд рдХрдВрдЯреЗрдВрдЯ рджреЗрдЦ рдкрд╛рддреЗ рд╣реИрдВред

      src/app/i18n/server.ts
      import { createInstance } from "i18next";
      import { initReactI18next } from "react-i18next/initReactI18next";
      import resourcesToBackend from "i18next-resources-to-backend";
      import { defaultLocale } from "@/i18n.config";
      import { namespaces, type Namespace } from "@/i18n.namespaces";
      
      // i18next рдХреЗ рд▓рд┐рдП рдбрд╛рдпрдирд╛рдорд┐рдХ рд░рд┐рд╕реЛрд░реНрд╕ рд▓реЛрдбрд┐рдВрдЧ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ
      // рдпрд╣ рдлрд╝рдВрдХреНрд╢рди locale рдФрд░ namespace рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЕрдиреБрд╡рд╛рдж JSON рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдк рд╕реЗ рдЗрдореНрдкреЛрд░реНрдЯ рдХрд░рддрд╛ рд╣реИ
      // рдЙрджрд╛рд╣рд░рдг: locale="fr", namespace="about" -> "@/locales/fr/about.json" рдХреЛ рдЗрдореНрдкреЛрд░реНрдЯ рдХрд░рддрд╛ рд╣реИ
      const backend = resourcesToBackend(
        (locale: string, namespace: string) =>
          import(`@/locales/${locale}/${namespace}.json`)
      );
      
      const DEFAULT_NAMESPACES = [
        namespaces[0],
      ] as const satisfies readonly Namespace[];
      
      /**
       * рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рд░реЗрдВрдбрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ
       *
       * @returns рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реНрдб i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕
       */
      export async function initI18next(
        locale: string,
        ns: readonly Namespace[] = DEFAULT_NAMESPACES
      ) {
        // рдПрдХ рдирдпрд╛ i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдмрдирд╛рдПрдВ (рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдЗрдВрд╕реНрдЯреЗрдВрд╕ рд╕реЗ рдЕрд▓рдЧ)
        const i18n = createInstance();
      
        // React рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рди рдФрд░ рдмреИрдХрдПрдВрдб рд▓реЛрдбрд░ рдХреЗ рд╕рд╛рде рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ
        await i18n
          .use(initReactI18next) // React hooks рд╕рдкреЛрд░реНрдЯ рд╕рдХреНрд╖рдо рдХрд░реЗрдВ
          .use(backend) // рдбрд╛рдпрдирд╛рдорд┐рдХ рд░рд┐рд╕реЛрд░реНрд╕ рд▓реЛрдбрд┐рдВрдЧ рд╕рдХреНрд╖рдо рдХрд░реЗрдВ
          .init({
            lng: locale,
            fallbackLng: defaultLocale,
            ns, // рдмреЗрд╣рддрд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ namespaces рд▓реЛрдб рдХрд░реЗрдВ
            defaultNS: "common", // рдЬрдм рдХреЛрдИ namespace рдирд┐рд░реНрджрд┐рд╖реНрдЯ рди рд╣реЛ рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ namespace
            interpolation: { escapeValue: false }, // HTML рдХреЛ escape рди рдХрд░реЗрдВ (React XSS рд╕реБрд░рдХреНрд╖рд╛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ)
            react: { useSuspense: false }, // SSR рд╕рдВрдЧрддрддрд╛ рдХреЗ рд▓рд┐рдП Suspense рдЕрдХреНрд╖рдо рдХрд░реЗрдВ
            returnNull: false, // рдЧрд╛рдпрдм keys рдХреЗ рд▓рд┐рдП null рдХреА рдмрдЬрд╛рдп рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рд▓реМрдЯрд╛рдПрдВ
            initImmediate: false, // рд╕рдВрд╕рд╛рдзрди рд▓реЛрдб рд╣реЛрдиреЗ рддрдХ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рд╕реНрдердЧрд┐рдд рдХрд░реЗрдВ (рддреЗрдЬрд╝ SSR)
          });
        return i18n;
      }
      
    6. рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб i18n рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдмрдирд╛рдПрдВ

      рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯ рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдмрдирд╛рдПрдВ рдЬреЛ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ i18next рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рд▓рдкреЗрдЯрддрд╛ рд╣реИред рдпрд╣ рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рд╕рд░реНрд╡рд░ рд╕реЗ рдкрд╣рд▓реЗ рд╕реЗ рд▓реЛрдб рдХреА рдЧрдИ рдЕрдиреБрд╡рд╛рдж рд╕рд╛рдордЧреНрд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдЕрдиреБрд╡рд╛рджрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЗ рдлреНрд▓реИрд╢ (FOUC) рдХреЛ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХреЗ рдФрд░ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдлреЗрдЪрд┐рдВрдЧ рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХреЗред

      рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ i18next рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдЪрд╛рд╣рд┐рдП рдЬреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЪрд▓рддрд╛ рд╣реИред рд╕рд░реНрд╡рд░ рд╕реЗ рдкрд╣рд▓реЗ рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдЧрдП рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдХреЗ, рд╣рдо рдирд┐рд░реНрдмрд╛рдз рд╣рд╛рдЗрдбреНрд░реЗрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╕рд╛рдордЧреНрд░реА рдХреЗ рдлреНрд▓реИрд╢рд┐рдВрдЧ рдХреЛ рд░реЛрдХрддреЗ рд╣реИрдВред рдпрд╣ рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рд╕реНрдерд╛рдиреАрдп рднрд╛рд╖рд╛ рдкрд░рд┐рд╡рд░реНрддрди рдФрд░ рдиреЗрдорд╕реНрдкреЗрд╕ рд▓реЛрдбрд┐рдВрдЧ рдХреЛ рднреА рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рддрд╛ рд╣реИред

      src/components/I18nProvider.tsx
      "use client";
      
      import { useEffect, useState } from "react";
      import { I18nextProvider } from "react-i18next";
      import { createInstance, type ResourceLanguage } from "i18next";
      import { initReactI18next } from "react-i18next/initReactI18next";
      import resourcesToBackend from "i18next-resources-to-backend";
      import { defaultLocale } from "@/i18n.config";
      import { namespaces as allNamespaces, type Namespace } from "@/i18n.namespaces";
      
      // рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдХреЗ рд▓рд┐рдП рдбрд╛рдпрдирд╛рдорд┐рдХ рд░рд┐рд╕реЛрд░реНрд╕ рд▓реЛрдбрд┐рдВрдЧ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ
      // рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдХреЗ рд╕рдорд╛рди рдкреИрдЯрд░реНрди, рд▓реЗрдХрд┐рди рдпрд╣ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЪрд▓рддрд╛ рд╣реИ
      const backend = resourcesToBackend(
        (locale: string, namespace: string) =>
          import(`@/locales/${locale}/${namespace}.json`)
      );
      
      type Props = {
        locale: string;
        namespaces?: readonly Namespace[];
        // рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░реА-рд▓реЛрдбреЗрдб рд╕рдВрд╕рд╛рдзрди (FOUC - рдЕрдиреБрд╡рд╛рджрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЗ рдлреНрд▓реИрд╢ рдХреЛ рд░реЛрдХрддрд╛ рд╣реИ)
        // рдкреНрд░рд╛рд░реВрдк: { namespace: translationBundle }
        resources?: Record<Namespace, ResourceLanguage>;
        children: React.ReactNode;
      };
      
      /**
       * рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб i18n рдкреНрд░рджрд╛рддрд╛ рдЬреЛ рдРрдк рдХреЛ i18next рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рд▓рдкреЗрдЯрддрд╛ рд╣реИ
       * рд╕рд░реНрд╡рд░ рд╕реЗ рдкрд╣рд▓реЗ рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдЧрдП рд╕рдВрд╕рд╛рдзрди рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХреЗ
       */
      export default function I18nProvider({
        locale,
        namespaces = [allNamespaces[0]] as const,
        resources,
        children,
      }: Props) {
        // useState рд▓реЗрдЬрд╝реА рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ i18n рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдмрдирд╛рдПрдВ
        // рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдмрдирд╛рдпрд╛ рдЬрд╛рдП, рд╣рд░ рд░реЗрдВрдбрд░ рдкрд░ рдирд╣реАрдВ
        const [i18n] = useState(() => {
          const i18nInstance = createInstance();
      
          i18nInstance
            .use(initReactI18next)
            .use(backend)
            .init({
              lng: locale,
              fallbackLng: defaultLocale,
              ns: namespaces,
              // рдпрджрд┐ рд╕рдВрд╕рд╛рдзрди (рд╕рд░реНрд╡рд░ рд╕реЗ) рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рд╣реИрдВ, рддреЛ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╕реЗ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрддрд┐ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
              // рдпрд╣ FOUC рдХреЛ рд░реЛрдХрддрд╛ рд╣реИ рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд▓реЛрдб рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рддрд╛ рд╣реИ
              resources: resources ? { [locale]: resources } : undefined,
              defaultNS: "common",
              interpolation: { escapeValue: false },
              react: { useSuspense: false },
              returnNull: false, // рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рдорд╛рди рд▓реМрдЯрдиреЗ рд╕реЗ рд░реЛрдХреЗрдВ
            });
      
          return i18nInstance;
        });
      
        // рдЬрдм locale prop рдмрджрд▓рддрд╛ рд╣реИ рддреЛ рднрд╛рд╖рд╛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ
        useEffect(() => {
          i18n.changeLanguage(locale);
        }, [locale, i18n]);
      
        // рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ namespaces рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдкрд░ рд▓реЛрдб рд╣реЛрдВ
        // рд╕рд╣реА рдврдВрдЧ рд╕реЗ arrays рдХреА рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП join("|") рдХреЛ dependency рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
        useEffect(() => {
          i18n.loadNamespaces(namespaces);
        }, [namespaces.join("|"), i18n]);
      
        // React context рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рднреА child components рдХреЛ i18n instance рдкреНрд░рджрд╛рди рдХрд░реЗрдВ
        return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
      }
      
    7. рдбрд╛рдпрдирд╛рдорд┐рдХ рд▓реЛрдХрд▓ рд░реВрдЯреНрд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ

      рдЕрдкрдиреЗ рдРрдк рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ [locale] рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рдмрдирд╛рдХрд░ рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдЯрд┐рдВрдЧ рд╕реЗрдЯ рдХрд░реЗрдВред рдЗрд╕рд╕реЗ Next.js рд▓реЛрдХрд▓-рдЖрдзрд╛рд░рд┐рдд рд░реВрдЯрд┐рдВрдЧ рдХреЛ рд╕рдВрднрд╛рд▓ рд╕рдХрддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХрд▓ URL рд╕реЗрдЧрдореЗрдВрдЯ рдмрди рдЬрд╛рддрд╛ рд╣реИ (рдЬреИрд╕реЗ, /en/about, /fr/about)ред

      рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдЯреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ Next.js рдмрд┐рд▓реНрдб рд╕рдордп рдкрд░ рд╕рднреА рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рд╕реНрдереИрддрд┐рдХ рдкреЗрдЬ рдЬреЗрдирд░реЗрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдкреНрд░рджрд░реНрд╢рди рдФрд░ SEO рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реЛрддрд╛ рд╣реИред рд▓реЗрдЖрдЙрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯ HTML рдХреЗ lang рдФрд░ dir рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯреНрд╕ рдХреЛ рд▓реЛрдХрд▓ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдкрд╣реБрдВрдЪ рдФрд░ рд╕рд░реНрдЪ рдЗрдВрдЬрди рдХреА рд╕рдордЭ рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

      src/app/[locale]/layout.tsx
      import type { ReactNode } from "react";
      import { locales, defaultLocale, isRtl, type Locale } from "@/i18n.config";
      
      // рдбрд╛рдпрдирд╛рдорд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рдЕрдХреНрд╖рдо рдХрд░реЗрдВ - рд╕рднреА рд▓реЛрдХрд▓реНрд╕ рдХреЛ рдмрд┐рд▓реНрдб рд╕рдордп рдкрд░ рдЬрд╛рдирд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП
      // рдпрд╣ рд╕рднреА рд▓реЛрдХрд▓ рд░реВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рд╕реНрдереИрддрд┐рдХ рдЬреЗрдирд░реЗрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ
      export const dynamicParams = false;
      
      /**
       * рдмрд┐рд▓реНрдб рд╕рдордп рдкрд░ рд╕рднреА рд▓реЛрдХрд▓реНрд╕ рдХреЗ рд▓рд┐рдП рд╕реНрдереИрддрд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░ рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ
       * Next.js рдпрд╣рд╛рдВ рд▓реМрдЯрд╛рдП рдЧрдП рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рдкреЗрдЬ рдкреНрд░реА-рд░реЗрдВрдбрд░ рдХрд░реЗрдЧрд╛
       * рдЙрджрд╛рд╣рд░рдг: [{ locale: "en" }, { locale: "fr" }]
       */
      export function generateStaticParams() {
        return locales.map((locale) => ({ locale }));
      }
      
      /**
       * рд░реВрдЯ рд▓реЗрдЖрдЙрдЯ рдХреЙрдореНрдкреЛрдиреЗрдВрдЯ рдЬреЛ рд▓реЛрдХрд▓-рд╡рд┐рд╢рд┐рд╖реНрдЯ HTML рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯреНрд╕ рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ
       * рд▓реЛрдХрд▓ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ lang рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯ рдФрд░ рдЯреЗрдХреНрд╕реНрдЯ рджрд┐рд╢рд╛ (ltr/rtl) рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ
       */
      export default function LocaleLayout({
        children,
        params,
      }: {
        children: ReactNode;
        params: { locale: string };
      }) {
        /// URL рдкреИрд░рд╛рдореАрдЯрд░ рд╕реЗ locale рдХреЛ рдорд╛рдиреНрдп рдХрд░реЗрдВ
        // рдпрджрд┐ рдЕрдорд╛рдиреНрдп locale рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ locale рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ
        const locale: Locale = (locales as readonly string[]).includes(params.locale)
          ? params.locale
          : defaultLocale;
      
        // locale рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЯреЗрдХреНрд╕реНрдЯ рджрд┐рд╢рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ
        // рдЕрд░рдмреА рдЬреИрд╕реА RTL рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рд╣реА рдЯреЗрдХреНрд╕реНрдЯ рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╣реЗрддреБ dir="rtl" рдЖрд╡рд╢реНрдпрдХ рд╣реИ
        const dir = isRtl(locale) ? "rtl" : "ltr";
      
        return (
          <html lang={locale} dir={dir}>
            <body>{children}</body>
          </html>
        );
      }
      
    8. рдЕрдкрдиреА рдЕрдиреБрд╡рд╛рдж рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдПрдВ

      рдкреНрд░рддреНрдпреЗрдХ locale рдФрд░ namespace рдХреЗ рд▓рд┐рдП JSON рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдПрдВред рдпрд╣ рд╕рдВрд░рдЪрдирд╛ рдЖрдкрдХреЛ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рддрд╛рд░реНрдХрд┐рдХ рд░реВрдк рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдФрд░ рдХреЗрд╡рд▓ рдЙрд╕ рдкреГрд╖реНрда рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред

      рдирд╛рдорд╕реНрдерд╛рди (namespace) рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдирд╛ (рдЬреИрд╕реЗ, common.json, about.json) рдХреЛрдб рд╕реНрдкреНрд▓рд┐рдЯрд┐рдВрдЧ рдХреЛ рд╕рдХреНрд╖рдо рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдмрдВрдбрд▓ рдХрд╛ рдЖрдХрд╛рд░ рдХрдо рдХрд░рддрд╛ рд╣реИред рдЖрдк рдХреЗрд╡рд▓ рдЙрди рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ рдкреЗрдЬ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реЛрддрд╛ рд╣реИред

      src/locales/en/common.json
      {
        "appTitle": "Next.js i18n App",
        "appDescription": "Example Next.js application with internationalization using i18next"
      }
      
      src/locales/fr/common.json
      {
        "appTitle": "Application Next.js i18n",
        "appDescription": "Exemple d'application Next.js avec internationalisation utilisant i18next"
      }
      
      src/locales/en/home.json
      {
        "title": "Home",
        "description": "Home page description",
        "welcome": "Welcome",
        "greeting": "Hello, world!",
        "aboutPage": "About Page",
        "documentation": "Documentation"
      }
      
      src/locales/fr/home.json
      {
        "title": "Accueil",
        "description": "Description de la page d'accueil",
        "welcome": "Bienvenue",
        "greeting": "Bonjour le monde!",
        "aboutPage": "Page ├А propos",
        "documentation": "Documentation"
      }
      
      src/locales/en/about.json
      {
        "title": "About",
        "description": "About page description",
        "counter": {
          "label": "Counter",
          "increment": "Increment",
          "description": "Click the button to increase the counter"
        }
      }
      
      src/locales/fr/about.json
      {
        "title": "├А propos",
        "description": "Description de la page ├А propos",
        "counter": {
          "label": "Compteur",
          "increment": "Incr├йmenter",
          "description": "Cliquez sur le bouton pour augmenter le compteur"
        }
      }
      
    9. рдЕрдкрдиреЗ рдкреГрд╖реНрдареЛрдВ рдореЗрдВ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

      рдПрдХ рдкреЗрдЬ рдХреЙрдореНрдкреЛрдиреЗрдВрдЯ рдмрдирд╛рдПрдВ рдЬреЛ рд╕рд░реНрд╡рд░ рдкрд░ i18next рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рджреЛрдиреЛрдВ рдХреЙрдореНрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЕрдиреБрд╡рд╛рдж рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╕реЗ рдкрд╣рд▓реЗ рд▓реЛрдб рд╣реЛ рдЬрд╛рдПрдВ рдФрд░ рдХрдВрдЯреЗрдВрдЯ рдлреНрд▓реИрд╢рд┐рдВрдЧ рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХреЗред

      рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдкреЗрдЬ рдХреЗ рд░реЗрдВрдбрд░ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ SEO рдмреЗрд╣рддрд░ рд╣реЛрддрд╛ рд╣реИ рдФрд░ FOUC (рдлреНрд▓реИрд╢ рдСрдл рдЕрдирд╕реНрдЯрд╛рдЗрд▓реНрдб рдХрдВрдЯреЗрдВрдЯ) рд╕реЗ рдмрдЪрд╛рд╡ рд╣реЛрддрд╛ рд╣реИред рдкреНрд░реАрд▓реЛрдбреЗрдб рд░рд┐рд╕реЛрд░реНрд╕реЗрдЬ рдХреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдХреЛ рдкрд╛рд╕ рдХрд░рдХреЗ, рд╣рдо рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдлреЗрдЪрд┐рдВрдЧ рд╕реЗ рдмрдЪрддреЗ рд╣реИрдВ рдФрд░ рд╕реНрдореВрде рд╣рд╛рдЗрдбреНрд░реЗрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВред

      src/app/[locale]/about/index.tsx
      import I18nProvider from "@/components/I18nProvider";
      import { initI18next } from "@/app/i18n/server";
      import type { Locale } from "@/i18n.config";
      import { namespaces as allNamespaces, type Namespace } from "@/i18n.namespaces";
      import type { ResourceLanguage } from "i18next";
      import ClientComponent from "@/components/ClientComponent";
      import ServerComponent from "@/components/ServerComponent";
      
      /**
       * рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдкреЗрдЬ рдЬреЛ i18n рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ
       * рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рдкреНрд░реА-рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИ
       */
      export default async function AboutPage({
        params: { locale },
      }: {
        params: { locale: Locale };
      }) {
        // рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЗрд╕ рдкреЗрдЬ рдХреЛ рдХреМрди рд╕реЗ рдЕрдиреБрд╡рд╛рдж рдиреЗрдорд╕реНрдкреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
        // рдЯрд╛рдЗрдк рд╕реБрд░рдХреНрд╖рд╛ рдФрд░ рдСрдЯреЛрдХрдВрдкреНрд▓реАрдЯ рдХреЗ рд▓рд┐рдП рдХреЗрдВрджреНрд░реАрдХреГрдд рд╕реВрдЪреА рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
        const pageNamespaces = allNamespaces;
      
        // рдЖрд╡рд╢реНрдпрдХ рдиреЗрдорд╕реНрдкреЗрд╕ рдХреЗ рд╕рд╛рде рд╕рд░реНрд╡рд░ рдкрд░ i18next рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ
        // рдпрд╣ рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдЕрдиреБрд╡рд╛рдж JSON рдлрд╝рд╛рдЗрд▓реЗрдВ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ
        const i18n = await initI18next(locale, pageNamespaces);
      
        // "about" namespace рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдерд┐рд░ рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
        // getFixedT namespace рдХреЛ рд▓реЙрдХ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП t("title") рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдмрдЬрд╛рдп t("about:title") рдХреЗ
        const tAbout = i18n.getFixedT(locale, "about");
      
        // i18n instance рд╕реЗ рдЕрдиреБрд╡рд╛рдж рдмрдВрдбрд▓ рдирд┐рдХрд╛рд▓реЗрдВ
        // рдпрд╣ рдбреЗрдЯрд╛ I18nProvider рдХреЛ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб i18n рдХреЛ рд╣рд╛рдЗрдбреНрд░реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ
        // FOUC (Flash of Untranslated Content) рдХреЛ рд░реЛрдХрддрд╛ рд╣реИ рдФрд░ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ fetching рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИ
        const resources = Object.fromEntries(
          pageNamespaces.map((ns) => [ns, i18n.getResourceBundle(locale, ns)])
        ) satisfies Record<Namespace, ResourceLanguage>;
      
        return (
          <I18nProvider
            locale={locale}
            namespaces={pageNamespaces}
            resources={resources}
          >
            <main>
              <h1>{tAbout("title")}</h1>
      
              <ClientComponent />
              <ServerComponent t={tAbout} locale={locale} count={0} />
            </main>
          </I18nProvider>
        );
      }
      
    10. рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

      рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдЕрдиреБрд╡рд╛рджреЛрдВ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП useTranslation рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рд╣реБрдХ рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рди рдФрд░ i18n рдЗрдВрд╕реНрдЯреЗрдВрд╕ рддрдХ рдкрд╣реБрдБрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЖрдк рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд▓реЛрдХрд▓ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

      рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рдЕрдиреБрд╡рд╛рджреЛрдВ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП React рд╣реБрдХреНрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред useTranslation рд╣реБрдХ i18next рдХреЗ рд╕рд╛рде рд╕рд╣рдЬрддрд╛ рд╕реЗ рдПрдХреАрдХреГрдд рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдЬрдм рд▓реЛрдХрд▓ рдмрджрд▓рддрд╛ рд╣реИ рддреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдЕрдкрдбреЗрдЯ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

      рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдкреЗрдЬ/рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдореЗрдВ рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ namespaces рд╢рд╛рдорд┐рд▓ рд╣реЛрдВ (рдЬреИрд╕реЗ, about)ред
      рдпрджрд┐ рдЖрдк React < 19 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рднрд╛рд░реА рдлреЙрд░реНрдореЗрдЯрд░реНрд╕ рдЬреИрд╕реЗ Intl.NumberFormat рдХреЛ рдореЗрдореЛрдЬрд╝ рдХрд░реЗрдВред

      src/components/ClientComponent.tsx
      "use client";
      
      import { useState } from "react";
      import { useTranslation } from "react-i18next";
      
      /**
       * рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯ рдЙрджрд╛рд╣рд░рдг рдЬреЛ React hooks рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЗ рд▓рд┐рдП
       * useState, useEffect, рдФрд░ useTranslation рдЬреИрд╕реЗ hooks рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ
       */
      const ClientComponent = () => {
        // useTranslation hook рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рди рдФрд░ i18n рдЗрдВрд╕реНрдЯреЗрдВрд╕ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ
        // рдХреЗрд╡рд▓ "about" namespace рдХреЗ рдЕрдиреБрд╡рд╛рдж рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП namespace рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ
        const { t, i18n } = useTranslation("about");
        const [count, setCount] = useState(0);
      
        // locale-рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рд╕рдВрдЦреНрдпрд╛ рд╕реНрд╡рд░реВрдкрдХ рдмрдирд╛рдПрдБ
        // i18n.language рд╡рд░реНрддрдорд╛рди locale рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ (рдЬреИрд╕реЗ, "en", "fr")
        // Intl.NumberFormat рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ locale рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕реНрд╡рд░реВрдкрд┐рдд рдХрд░рддрд╛ рд╣реИ
        const numberFormat = new Intl.NumberFormat(i18n.language);
      
        return (
          <div className="flex flex-col items-center gap-4">
            {/* рд╕реНрдерд╛рдиреАрдп-рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реНрд╡рд░реВрдкрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдВрдЦреНрдпрд╛ рд╕реНрд╡рд░реВрдкрд┐рдд рдХрд░реЗрдВ */}
            <p className="text-5xl font-bold text-white m-0">
              {numberFormat.format(count)}
            </p>
            <button
              type="button"
              className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
              aria-label={t("counter.label")}
              onClick={() => setCount((c) => c + 1)}
            >
              {t("counter.increment")}
            </button>
          </div>
        );
      };
      
      export default ClientComponent;
      
    11. рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдореЗрдВ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

      рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ React hooks рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╡реЗ рдЕрдкрдиреЗ рдкреИрд░реЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рд╕реЗ props рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рддрд░реАрдХрд╛ рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ synchronous рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЗ рдЕрдВрджрд░ рдиреЗрд╕реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

      рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдЬреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдмрд╛рдЙрдВрдбреНрд░реАрдЬрд╝ рдХреЗ рдЕрдВрддрд░реНрдЧрдд рдиреЗрд╕реНрдЯ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ synchronous рд╣реЛрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЕрдиреБрд╡рд╛рджрд┐рдд рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдФрд░ locale рдЬрд╛рдирдХрд╛рд░реА рдХреЛ props рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░рдХреЗ, рд╣рдо async рдСрдкрд░реЗрд╢рдВрд╕ рд╕реЗ рдмрдЪрддреЗ рд╣реИрдВ рдФрд░ рд╕рд╣реА рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВред

      src/components/ServerComponent.tsx
      import type { TFunction } from "i18next";
      
      type ServerComponentProps = {
        // рдкреИрд░реЗрдВрдЯ рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рд╕реЗ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рди
        // рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ hooks рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рдЗрд╕рд▓рд┐рдП рдЕрдиреБрд╡рд╛рдж props рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрддреЗ рд╣реИрдВ
        t: TFunction<"about">;
        locale: string;
        count: number;
      };
      
      /**
       * рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдЙрджрд╛рд╣рд░рдг - рдЕрдиреБрд╡рд╛рдж props рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ
       * рдХреНрд▓рд╛рдЗрдВрдЯ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ (async рд╕рд░реНрд╡рд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕) рдХреЗ рдЕрдВрджрд░ рдиреЗрд╕реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
       * React hooks рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛, рдЗрд╕рд▓рд┐рдП рд╕рднреА рдбреЗрдЯрд╛ props рдпрд╛ async рдСрдкрд░реЗрд╢рдВрд╕ рд╕реЗ рдЖрдирд╛ рдЪрд╛рд╣рд┐рдП
       */
      const ServerComponent = ({ t, locale, count }: ServerComponentProps) => {
        // locale рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдирдВрдмрд░ рдлреЙрд░реНрдореЗрдЯ рдХрд░реЗрдВ
        // рдпрд╣ SSR рдХреЗ рджреМрд░рд╛рди рд╕рд░реНрд╡рд░ рдкрд░ рдЪрд▓рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдкреЗрдЬ рд▓реЛрдб рдмреЗрд╣рддрд░ рд╣реЛрддрд╛ рд╣реИ
        const formatted = new Intl.NumberFormat(locale).format(count);
      
        return (
          <div className="flex flex-col items-center gap-4">
            <p className="text-5xl font-bold text-white m-0">{formatted}</p>
            {/* prop рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд┐рдП рдЧрдП рдЕрдиреБрд╡рд╛рдж рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ */}
            <div className="flex flex-col items-center gap-2">
              <span className="text-xl font-semibold text-white">
                {t("counter.label")}
              </span>
              <span className="text-sm opacity-80 italic">
                {t("counter.description")}
              </span>
            </div>
          </div>
        );
      };
      
      export default ServerComponent;
      
    12. рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдХреА рднрд╛рд╖рд╛ рдмрджрд▓реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      Next.js рдореЗрдВ рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдХреА рднрд╛рд╖рд╛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдиреБрд╢рдВрд╕рд┐рдд рддрд░реАрдХрд╛ рд╣реИ locale-рдкреВрд░реНрд╡рд╕рд░реНрдЧ рд╡рд╛рд▓реЗ URL рдФрд░ Next.js рд▓рд┐рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред рдиреАрдЪреЗ рджрд┐рдпрд╛ рдЧрдпрд╛ рдЙрджрд╛рд╣рд░рдг рд╡рд░реНрддрдорд╛рди locale рдХреЛ route рд╕реЗ рдкрдврд╝рддрд╛ рд╣реИ, pathname рд╕реЗ рдЗрд╕реЗ рд╣рдЯрд╛рддрд╛ рд╣реИ, рдФрд░ рдЙрдкрд▓рдмреНрдз рдкреНрд░рддреНрдпреЗрдХ locale рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рд░реЗрдВрдбрд░ рдХрд░рддрд╛ рд╣реИред

      src/components/LocaleSwitcher.tsx
      "use client";
      
      import Link from "next/link";
      import { useParams, usePathname } from "next/navigation";
      import { useMemo } from "react";
      import { defaultLocale, getCookie, type Locale, locales } from "@/i18n.config";
      
      export default function LocaleSwitcher() {
        const params = useParams();
        const pathname = usePathname();
      
        const activeLocale = (params?.locale as Locale | undefined) ?? defaultLocale;
      
        const getLocaleLabel = (locale: Locale): string => {
          try {
            const displayNames = new Intl.DisplayNames([locale], {
              type: "language",
            });
            return displayNames.of(locale) ?? locale.toUpperCase();
          } catch {
            return locale.toUpperCase();
          }
        };
      
        const basePath = useMemo(() => {
          if (!pathname) return "/";
      
          const segments = pathname.split("/").filter(Boolean);
      
          if (segments.length === 0) return "/";
      
          const maybeLocale = segments[0] as Locale;
      
          if ((locales as readonly string[]).includes(maybeLocale)) {
            const rest = segments.slice(1).join("/");
            return rest ? `/${rest}` : "/";
          }
      
          return pathname;
        }, [pathname]);
      
        return (
          <nav aria-label="рднрд╛рд╖рд╛ рдЪрдпрдирдХрд░реНрддрд╛">
            {(locales as readonly Locale[]).map((locale) => {
              const isActive = locale === activeLocale;
      
              const href =
                locale === defaultLocale ? basePath : `/${locale}${basePath}`;
      
              return (
                <Link
                  key={locale}
                  href={href}
                  aria-current={isActive ? "рдкреГрд╖реНрда" : undefined}
                  onClick={() => {
                    document.cookie = getCookie(locale);
                  }}
                >
                  {getLocaleLabel(locale)}
                </Link>
              );
            })}
          </nav>
        );
      }
      
    13. рд╡реИрдХрд▓реНрдкрд┐рдХ

      рдЕрдкрдиреЗ рдРрдк рдореЗрдВ рд╕реНрдерд╛рдиреАрдпрдХреГрдд URLs рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЛ рд╕реБрд╕рдВрдЧрдд рдФрд░ SEO-рдЕрдиреБрдХреВрд▓ рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИред next/link рдХреЛ рдПрдХ рдЫреЛрдЯреЗ рд╣реЗрд▓реНрдкрд░ рдореЗрдВ рд▓рдкреЗрдЯреЗрдВ рдЬреЛ рдЖрдВрддрд░рд┐рдХ рд░реВрдЯреНрд╕ рдХреЗ рд╕рд╛рдордиреЗ рд╕рдХреНрд░рд┐рдп locale рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдЬрдмрдХрд┐ рдмрд╛рд╣рд░реА URLs рдХреЛ рдЕрдкрд░рд┐рд╡рд░реНрддрд┐рдд рдЫреЛрдбрд╝рддрд╛ рд╣реИред

      src/components/LocalizedLink.tsx
      "use client";
      
      import NextLink, { type LinkProps } from "next/link";
      import { useParams } from "next/navigation";
      import type { ComponentProps, PropsWithChildren } from "react";
      import {
        defaultLocale,
        type Locale,
        locales,
        localizedPath,
      } from "@/i18n.config";
      
      const isExternal = (href: string) => /^https?:\/\//.test(href);
      
      type LocalizedLinkProps = PropsWithChildren<
        Omit<LinkProps, "href"> &
          Omit<ComponentProps<"a">, "href"> & { href: string; locale?: Locale }
      >;
      
      export default function LocalizedLink({
        href,
        locale,
        children,
        ...props
      }: LocalizedLinkProps) {
        const params = useParams();
        const fallback = (params?.locale as Locale | undefined) ?? defaultLocale;
        const normalizedLocale = (locales as readonly string[]).includes(fallback)
          ? ((locale ?? fallback) as Locale)
          : defaultLocale;
      
        const normalizedPath = href.startsWith("/") ? href : `/${href}`;
        const localizedHref = isExternal(href)
          ? href
          : localizedPath(normalizedLocale, normalizedPath);
      
        return (
          <NextLink href={localizedHref} {...props}>
            {children}
          </NextLink>
        );
      }
      
      рд╕реБрдЭрд╛рд╡: рдХреНрдпреЛрдВрдХрд┐ LocalizedLink рдПрдХ рдбреНрд░реЙрдк-рдЗрди рд░рд┐рдкреНрд▓реЗрд╕рдореЗрдВрдЯ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдпрд╛рддреЛрдВ рдХреЛ рдзреАрд░реЗ-рдзреАрд░реЗ рдмрджрд▓рдХрд░ рдФрд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреЛ locale-рд╡рд┐рд╢рд┐рд╖реНрдЯ URLs рд╕рдВрднрд╛рд▓рдиреЗ рджреЗрдВ, рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдорд╛рдЗрдЧреНрд░реЗрдЯ рдХрд░реЗрдВред
    14. рд╕рд░реНрд╡рд░ рдПрдХреНрд╢рдиреНрд╕ рдХреЗ рдЕрдВрджрд░ рд╕рдХреНрд░рд┐рдп locale рддрдХ рдкрд╣реБрдБрдЪреЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      рд╕рд░реНрд╡рд░ рдПрдХреНрд╢рдиреНрд╕ рдХреЛ рдЕрдХреНрд╕рд░ рдИрдореЗрд▓, рд▓реЙрдЧрд┐рдВрдЧ, рдпрд╛ рдерд░реНрдб-рдкрд╛рд░реНрдЯреА рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рд╡рд░реНрддрдорд╛рди locale рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЕрдкрдиреЗ рдкреНрд░реЙрдХреНрд╕реА рджреНрд╡рд╛рд░рд╛ рд╕реЗрдЯ рдХрд┐рдП рдЧрдП locale рдХреБрдХреА рдХреЛ Accept-Language рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдлреЙрд▓рдмреИрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░реЗрдВред

      src/app/actions/get-current-locale.ts
      "use server";
      
      import { cookies, headers } from "next/headers";
      import { defaultLocale, locales, type Locale } from "@/i18n.config";
      
      const KNOWN_LOCALES = new Set(locales as readonly string[]);
      
      const normalize = (value: string | undefined): Locale | undefined => {
        if (!value) return undefined;
        const base = value.toLowerCase().split("-")[0];
        return KNOWN_LOCALES.has(base) ? (base as Locale) : undefined;
      };
      
      export async function getCurrentLocale(): Promise<Locale> {
        const cookieLocale = normalize(cookies().get("NEXT_LOCALE")?.value);
      
        if (cookieLocale) return cookieLocale;
      
        const headerLocale = normalize(headers().get("accept-language"));
        return headerLocale ?? defaultLocale;
      }
      
      // рд╡рд░реНрддрдорд╛рди locale рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реА рд╕рд░реНрд╡рд░ рдХреНрд░рд┐рдпрд╛ рдХрд╛ рдЙрджрд╛рд╣рд░рдг
      export async function stuffFromServer(formData: FormData) {
        const locale = await getCurrentLocale();
      
        // рд╕реНрдерд╛рдиреАрдпрдХреГрдд рд╕рд╛рдЗрдб рдЗрдлреЗрдХреНрдЯреНрд╕ (рдИрдореЗрд▓, CRM, рдЖрджрд┐) рдХреЗ рд▓рд┐рдП locale рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
        console.log(`Stuff from server with locale ${locale}`);
      }
      
      рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣реЗрд▓реНрдкрд░ Next.js рдХреБрдХреАрдЬрд╝ рдФрд░ рд╣реЗрдбрд░реНрд╕ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ, рдпрд╣ Route Handlers, Server Actions, рдФрд░ рдЕрдиреНрдп рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░-рд╕рдВрджрд░реНрднреЛрдВ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
    15. рдЕрдкрдиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХрд╛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд░реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдЖрдкрдХреА рд╡реЗрдмрд╕рд╛рдЗрдЯ рдХреЛ рджреБрдирд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рджреГрд╢реНрдпрдиреАрдп рдмрдирд╛рдирд╛ рд╣реИред I18n рдЖрдкрдХреА рд╡реЗрдмрд╕рд╛рдЗрдЯ рдХреА рджреГрд╢реНрдпрддрд╛ рдХреЛ рдЙрдЪрд┐рдд SEO рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрджреНрднреБрдд рд╕рд╛рдзрди рд╣реИред

      рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХреГрдд рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдЦреЛрдЬ рдЗрдВрдЬрди рдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреА рдкреГрд╖реНрдареЛрдВ рдкрд░ рдХреМрди-рдХреМрди рд╕реА рднрд╛рд╖рд╛рдПрдБ рдЙрдкрд▓рдмреНрдз рд╣реИрдВред рдЗрд╕рдореЗрдВ hreflang рдореЗрдЯрд╛ рдЯреИрдЧ рд╕реЗрдЯ рдХрд░рдирд╛, рд╢реАрд░реНрд╖рдХ рдФрд░ рд╡рд┐рд╡рд░рдгреЛрдВ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рдирд╛, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рдХреИрдиреЛрдирд┐рдХрд▓ URL рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕реЗрдЯ рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

      рдпрд╣рд╛рдБ рдмрд╣реБрднрд╛рд╖реА SEO рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдХреБрдЫ рдЕрдЪреНрдЫреА рдкреНрд░рдерд╛рдУрдВ рдХреА рд╕реВрдЪреА рд╣реИ:

      • <head> рдЯреИрдЧ рдореЗрдВ hreflang рдореЗрдЯрд╛ рдЯреИрдЧ рд╕реЗрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рд╕рд░реНрдЪ рдЗрдВрдЬрди рд╕рдордЭ рд╕рдХреЗрдВ рдХрд┐ рдкреЗрдЬ рдкрд░ рдХреМрди-рдХреМрди рд╕реА рднрд╛рд╖рд╛рдПрдБ рдЙрдкрд▓рдмреНрдз рд╣реИрдВ
      • sitemap.xml рдореЗрдВ рд╕рднреА рдкреЗрдЬ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ http://www.w3.org/1999/xhtml XML рд╕реНрдХреАрдорд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗрдВ
      • robots.txt рд╕реЗ рдкреНрд░реАрдлрд┐рдХреНрд╕ рд╡рд╛рд▓реЗ рдкреЗрдЬреЛрдВ рдХреЛ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓рдирд╛ рди рднреВрд▓реЗрдВ (рдЬреИрд╕реЗ, /dashboard, /fr/dashboard, /es/dashboard)
      • рд╕рдмрд╕реЗ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкреЗрдЬ рдкрд░ рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╕реНрдЯрдо Link рдХрдВрдкреЛрдиреЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ (рдЬреИрд╕реЗ, рдлреНрд░реЗрдВрдЪ рдореЗрдВ <a href="/fr/about">├А propos</a>)

      рдбреЗрд╡рд▓рдкрд░реНрд╕ рдЕрдХреНрд╕рд░ рдЕрдкрдиреЗ рдкреЗрдЬреЛрдВ рдХреЛ рд╡рд┐рднрд┐рдиреНрди рд▓реЛрдХрд▓реНрд╕ рдореЗрдВ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдирд╛ рднреВрд▓ рдЬрд╛рддреЗ рд╣реИрдВред рдЖрдЗрдП рдЗрд╕реЗ рдареАрдХ рдХрд░реЗрдВ:

      src/app/[locale]/about/layout.tsx
      import type { Metadata } from "next";
      import {
        locales,
        defaultLocale,
        localizedPath,
        absoluteUrl,
      } from "@/i18n.config";
      
      /**
       * рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП SEO рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ
       * рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рддреНрдпреЗрдХ locale рдХреЗ рд▓рд┐рдП build рд╕рдордп рдкрд░ рдЪрд▓рддрд╛ рд╣реИ
       */
      export async function generateMetadata({
        params,
      }: {
        params: { locale: string };
      }): Promise<Metadata> {
        const { locale } = params;
      
        // рдЗрд╕ locale рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд╛рдж рдлрд╝рд╛рдЗрд▓ рдХреЛ рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдк рд╕реЗ рдЗрдореНрдкреЛрд░реНрдЯ рдХрд░реЗрдВ
        // рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд╛рджрд┐рдд рд╢реАрд░реНрд╖рдХ рдФрд░ рд╡рд┐рд╡рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
        const messages = (await import(`@/locales/${locale}/about.json`)).default;
      
        // рд╕рднреА locales рдХреЗ рд▓рд┐рдП hreflang рдореИрдкрд┐рдВрдЧ рдмрдирд╛рдПрдВ
        // рдЦреЛрдЬ рдЗрдВрдЬрди рдХреЛ рднрд╛рд╖рд╛ рд╡рд┐рдХрд▓реНрдк рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ
        // рдкреНрд░рд╛рд░реВрдк: { "en": "/about", "fr": "/fr/about" }
        const languages = Object.fromEntries(
          locales.map((locale) => [locale, localizedPath(locale, "/about")])
        );
      
        return {
          title: messages.title,
          description: messages.description,
          alternates: {
            // рдЗрд╕ рд▓реЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдХреИрдиреЛрдирд┐рдХрд▓ URL
            canonical: absoluteUrl(locale, "/about"),
            // SEO рдХреЗ рд▓рд┐рдП рднрд╛рд╖рд╛ рд╡рд┐рдХрд▓реНрдк (hreflang рдЯреИрдЧреНрд╕)
            // "x-default" рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ
            languages: {
              ...languages,
              "x-default": absoluteUrl(defaultLocale, "/about"),
            },
          },
        };
      }
      
      export default async function AboutPage() {
        return <h1>About</h1>;
      }
      
    16. рдЕрдкрдиреЗ рд╕рд╛рдЗрдЯрдореИрдк рдХреЛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХреГрдд рдХрд░реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      рдПрдХ рд╕рд╛рдЗрдЯрдореИрдк рдмрдирд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдЖрдкрдХреЗ рдкреГрд╖реНрдареЛрдВ рдХреЗ рд╕рднреА рд▓реЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдг рд╢рд╛рдорд┐рд▓ рд╣реЛрдВред рдпрд╣ рд╕рд░реНрдЪ рдЗрдВрдЬрди рдХреЛ рдЖрдкрдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рднреА рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдФрд░ рдЗрдВрдбреЗрдХреНрд╕ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред

      рдПрдХ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХреГрдд рд╕рд╛рдЗрдЯрдореИрдк рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕рд░реНрдЪ рдЗрдВрдЬрди рдЖрдкрдХреЗ рдкреГрд╖реНрдареЛрдВ рдХреЗ рд╕рднреА рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рдЦреЛрдЬ рдФрд░ рдЗрдВрдбреЗрдХреНрд╕ рдХрд░ рд╕рдХреЗред рдЗрд╕рд╕реЗ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдп рдЦреЛрдЬ рдкрд░рд┐рдгрд╛рдореЛрдВ рдореЗрдВ рджреГрд╢реНрдпрддрд╛ рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реЛрддрд╛ рд╣реИред

      src/app/sitemap.ts
      import type { MetadataRoute } from "next";
      import { defaultLocale, locales } from "@/i18n";
      
      const origin = "https://example.com";
      
      // рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкрде рд╕реНрд╡рд░реВрдкрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдлрд╝рдВрдХреНрд╢рди
      const formatterLocalizedPath = (locale: string, path: string) =>
        locale === defaultLocale ? `${origin}${path}` : `${origin}/${locale}${path}`;
      
      /**
       * рд╕рднреА рд╕реНрдерд╛рдиреАрдп рднрд╛рд╖рд╛рдУрдВ рдФрд░ рдЙрдирдХреЗ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкрдереЛрдВ рдХрд╛ рдорд╛рдирдЪрд┐рддреНрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
       *
       * рдЙрджрд╛рд╣рд░рдг рдЖрдЙрдЯрдкреБрдЯ:
       * {
       *   "en": "https://example.com",
       *   "fr": "https://example.com/fr",
       *   "es": "https://example.com/es",
       *   "x-default": "https://example.com"
       * }
       */
      const getLocalizedMap = (path: string) =>
        Object.fromEntries([
          ...locales.map((locale) => [locale, formatterLocalizedPath(locale, path)]),
          ["x-default", formatterLocalizedPath(defaultLocale, path)],
        ]);
      
      ts fileName="src/app/sitemap.ts"
      // рдмреЗрд╣рддрд░ SEO рдХреЗ рд▓рд┐рдП рд╕рднреА locale рд╡реЗрд░рд┐рдПрдВрдЯреНрд╕ рдХреЗ рд╕рд╛рде рд╕рд╛рдЗрдЯрдореИрдк рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ
      // alternates рдлрд╝реАрд▓реНрдб рд╕рд░реНрдЪ рдЗрдВрдЬрдиреЛрдВ рдХреЛ рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ
      export default function sitemap(): MetadataRoute.Sitemap {
        return [
          {
            url: formatterLocalizedPath(defaultLocale, "/"),
            lastModified: new Date(),
            changeFrequency: "monthly",
            priority: 1.0,
            alternates: { languages: getLocalizedMap("/") },
          },
          {
            url: formatterLocalizedPath(defaultLocale, "/about"),
            lastModified: new Date(),
            changeFrequency: "monthly",
            priority: 0.7,
            alternates: { languages: getLocalizedMap("/about") },
          },
        ];
      }
      
    17. рдЕрдкрдиреЗ robots.txt рдХреЛ рдЕрдВрддрд░рд░рд╛рд╖реНрдЯреНрд░реАрдпрдХреГрдд рдХрд░реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      рдЕрдкрдиреЗ рд╕рдВрд░рдХреНрд╖рд┐рдд рд░реВрдЯреНрд╕ рдХреЗ рд╕рднреА рд▓реЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ robots.txt рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕рд░реНрдЪ рдЗрдВрдЬрди рдХрд┐рд╕реА рднреА рднрд╛рд╖рд╛ рдореЗрдВ рдПрдбрдорд┐рди рдпрд╛ рдбреИрд╢рдмреЛрд░реНрдб рдкреЗрдЬреЛрдВ рдХреЛ рдЗрдВрдбреЗрдХреНрд╕ рди рдХрд░реЗрдВред

      рд╕рднреА рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП robots.txt рдХреЛ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рд╕реЗ рд╕рд░реНрдЪ рдЗрдВрдЬрди рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдкреГрд╖реНрдареЛрдВ рдХреЛ рдХрд┐рд╕реА рднреА рднрд╛рд╖рд╛ рдореЗрдВ рдЗрдВрдбреЗрдХреНрд╕ рдХрд░рдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рд╣реИред рдпрд╣ рд╕реБрд░рдХреНрд╖рд╛ рдФрд░ рдЧреЛрдкрдиреАрдпрддрд╛ рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

      src/app/robots.ts
      import type { MetadataRoute } from "next";
      import { defaultLocale, locales } from "@/i18n";
      
      const origin = "https://example.com";
      
      // рд╕рднреА рд▓реЛрдХрд▓ рдХреЗ рд▓рд┐рдП рдкрде рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ (рдЬреИрд╕реЗ, /admin, /fr/admin, /es/admin)
      const withAllLocales = (path: string) => [
        path,
        ...locales
          .filter((locale) => locale !== defaultLocale)
          .map((locale) => `/${locale}${path}`),
      ];
      
      const disallow = [...withAllLocales("/dashboard"), ...withAllLocales("/admin")];
      
      export default function robots(): MetadataRoute.Robots {
        return {
          rules: { userAgent: "*", allow: ["/"], disallow },
          host: origin,
          sitemap: `${origin}/sitemap.xml`,
        };
      }
      
    18. рд▓реЛрдХрд▓ рд░реВрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдорд┐рдбрд▓рд╡реЗрдпрд░ рд╕реЗрдЯ рдХрд░реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      рдПрдХ рдкреНрд░реЙрдХреНрд╕реА рдмрдирд╛рдПрдВ рдЬреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдкрд╕рдВрджреАрджрд╛ рднрд╛рд╖рд╛ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдП рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЙрдкрдпреБрдХреНрдд рд▓реЛрдХрд▓-рдкреНрд░рд┐рдлрд┐рдХреНрд╕реНрдб URL рдкрд░ рдкреБрдирдГ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░реЗред рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╕рд╛рдордЧреНрд░реА рдЙрдирдХреА рдкрд╕рдВрджреАрджрд╛ рднрд╛рд╖рд╛ рдореЗрдВ рджрд┐рдЦрд╛рдИ рдЬрд╛рддреА рд╣реИред

      рдорд┐рдбрд▓рд╡реЗрдпрд░ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЖрдкрдХреА рд╕рд╛рдЗрдЯ рдкрд░ рдЖрддреЗ рд╣реИрдВ рддреЛ рдЙрдиреНрд╣реЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдирдХреА рдкрд╕рдВрджреАрджрд╛ рднрд╛рд╖рд╛ рдореЗрдВ рдкреБрдирдГ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред рдпрд╣ рднрд╡рд┐рд╖реНрдп рдХреА рдпрд╛рддреНрд░рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдкрд╕рдВрдж рдХреЛ рдХреБрдХреА рдореЗрдВ рднреА рд╕рд╣реЗрдЬрддрд╛ рд╣реИред

      src/proxy.ts
      import { NextResponse, type NextRequest } from "next/server";
      import { defaultLocale, locales } from "@/i18n.config";
      
      // рдПрдХреНрд╕рдЯреЗрдВрд╢рдиреНрд╕ рд╡рд╛рд▓реЗ рдлрд╛рдЗрд▓реЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП Regex (рдЬреИрд╕реЗ .js, .css, .png)
      // рд▓реЛрдХрд▓ рд░реВрдЯрд┐рдВрдЧ рд╕реЗ рд╕реНрдЯреИрдЯрд┐рдХ рдПрд╕реЗрдЯреНрд╕ рдХреЛ рдмрд╛рд╣рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
      const PUBLIC_FILE = /\.[^/]+$/;
      
      /**
       * Accept-Language рд╣реЗрдбрд░ рд╕реЗ рд▓реЛрдХрд▓ рдирд┐рдХрд╛рд▓рдирд╛
       * "fr-CA", "en-US" рдЬреИрд╕реЗ рдлреЙрд░реНрдореЗрдЯреНрд╕ рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ
       * рдЕрдЧрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рднрд╛рд╖рд╛ рд╕рдорд░реНрдерд┐рдд рдирд╣реАрдВ рд╣реИ рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХрд▓ рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рддрд╛ рд╣реИ
       */
      const pickLocale = (accept: string | null) => {
        // рдкрд╣рд▓реА рднрд╛рд╖рд╛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ (рдЬреИрд╕реЗ "fr-CA" рд╕реЗ "fr-CA,en-US;q=0.9")
        const raw = accept?.split(",")[0] ?? defaultLocale;
        // рдмреЗрд╕ рднрд╛рд╖рд╛ рдХреЛрдб рдирд┐рдХрд╛рд▓реЗрдВ (рдЬреИрд╕реЗ "fr" рд╕реЗ "fr-CA")
        const base = raw.toLowerCase().split("-")[0];
        // рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдЗрд╕ рд▓реЛрдХрд▓ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВ, рдЕрдиреНрдпрдерд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
        return (locales as readonly string[]).includes(base) ? base : defaultLocale;
      };
      
      /**
       * Next.js рдХреЗ рд▓рд┐рдП locale рдкрд╣рдЪрд╛рди рдФрд░ рд░реВрдЯрд┐рдВрдЧ рдХрд╛ рдкреНрд░реЙрдХреНрд╕реА
       * рдкреЗрдЬ рд░реЗрдВрдбрд░ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╣рд░ рдЕрдиреБрд░реЛрдз рдкрд░ рдЪрд▓рддрд╛ рд╣реИ
       * рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдиреЗ рдкрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ locale-рдкреВрд░реНрд╡рд╕рд░реНрдЧ рд╡рд╛рд▓реЗ URL рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ
       */
      export function proxy(request: NextRequest) {
        const { pathname } = request.nextUrl;
      
        // Next.js рдХреЗ рдЖрдВрддрд░рд┐рдХ рд╣рд┐рд╕реНрд╕реЛрдВ, API рд░реВрдЯреНрд╕, рдФрд░ рд╕реНрдереИрддрд┐рдХ рдлрд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░реЙрдХреНрд╕реА рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ
        // рдЗрдиреНрд╣реЗрдВ locale-рдкреВрд░реНрд╡рд╕рд░реНрдЧ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
        if (
          pathname.startsWith("/_next") ||
          pathname.startsWith("/api") ||
          pathname.startsWith("/static") ||
          PUBLIC_FILE.test(pathname)
        ) {
          return;
        }
      
        // рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ URL рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА locale рдкреВрд░реНрд╡рд╕рд░реНрдЧ рд╣реИ рдпрд╛ рдирд╣реАрдВ
        // рдЙрджрд╛рд╣рд░рдг: "/fr/about" рдпрд╛ "/en" рд╕рд╣реА рд▓реМрдЯрд╛рдПрдЧрд╛
        const hasLocale = (locales as readonly string[]).some(
          (locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`)
        );
      
        // рдпрджрд┐ рдХреЛрдИ locale рдЙрдкрд╕рд░реНрдЧ рдирд╣реАрдВ рд╣реИ, рддреЛ locale рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВ рдФрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░реЗрдВ
        if (!hasLocale) {
          // рдкрд╣рд▓реЗ рдХреБрдХреА рд╕реЗ locale рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ (рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛)
          const cookieLocale = request.cookies.get("NEXT_LOCALE")?.value;
      
          // рдпрджрд┐ рдХреБрдХреА locale рдорд╛рдиреНрдп рд╣реИ рддреЛ рдЙрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рдЕрдиреНрдпрдерд╛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╣реЗрдбрд░ рд╕реЗ рдкрддрд╛ рд▓рдЧрд╛рдПрдВ
          const locale =
            cookieLocale && (locales as readonly string[]).includes(cookieLocale)
              ? cookieLocale
              : pickLocale(request.headers.get("accept-language"));
      
          // pathname рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП URL рдХреНрд▓реЛрди рдХрд░реЗрдВ
          const url = request.nextUrl.clone();
          // pathname рдореЗрдВ locale рдЙрдкрд╕рд░реНрдЧ рдЬреЛрдбрд╝реЗрдВ
          // рдбрдмрд▓ рд╕реНрд▓реИрд╢ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд░реВрдЯ рдкрде рдХреЛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓реЗрдВ
          url.pathname = `/${locale}${pathname === "/" ? "" : pathname}`;
      
          // рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдмрдирд╛рдПрдВ рдФрд░ locale рдХреБрдХреА рд╕реЗрдЯ рдХрд░реЗрдВ
          const res = NextResponse.redirect(url);
          res.cookies.set("NEXT_LOCALE", locale, { path: "/" });
          return res;
        }
      }
      
      export const config = {
        matcher: [
          // рд╕рднреА рдкрдереЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рдПрдВ рд╕рд┐рд╡рд╛рдп:
          // - API рд░реВрдЯреНрд╕ (/api/*)
          // - Next.js рдЖрдВрддрд░рд┐рдХ (/_next/*)
          // - рд╕реНрдереИрддрд┐рдХ рдлрд╛рдЗрд▓реЗрдВ (/static/*)
          // - рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд╛рд▓реА рдлрд╛рдЗрд▓реЗрдВ (.*\\..*)
          "/((?!api|_next|static|.*\\..*).*)",
        ],
      };
      
    19. Intlayer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░реЗрдВ

      рд╡реИрдХрд▓реНрдкрд┐рдХ

      Intlayer рдПрдХ рдореБрдлреНрдд рдФрд░ рдУрдкрди-рд╕реЛрд░реНрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╣реИ рдЬреЛ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╕рд╣рд╛рдпрддрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХреА рдЧрдИ рд╣реИред рдЬрдмрдХрд┐ i18next рдЕрдиреБрд╡рд╛рдж рд▓реЛрдбрд┐рдВрдЧ рдФрд░ рдкреНрд░рдмрдВрдзрди рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ, Intlayer рдЕрдиреБрд╡рд╛рдж рдХрд╛рд░реНрдпрдкреНрд░рд╡рд╛рд╣ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред

      рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХрд░рдирд╛ рд╕рдордп рд▓реЗрдиреЗ рд╡рд╛рд▓рд╛ рдФрд░ рддреНрд░реБрдЯрд┐рдкреВрд░реНрдг рд╣реЛ рд╕рдХрддрд╛ рд╣реИред Intlayer рдЕрдиреБрд╡рд╛рдж рдкрд░реАрдХреНрд╖рдг, рдирд┐рд░реНрдорд╛рдг, рдФрд░ рдкреНрд░рдмрдВрдзрди рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЖрдкрдХрд╛ рд╕рдордп рдмрдЪрддрд╛ рд╣реИ рдФрд░ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рд╕реНрдерд┐рд░рддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рд╣реЛрддреА рд╣реИред

      Intlayer рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реБрд╡рд┐рдзрд╛рдПрдБ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:

      • рдЕрдкрдиреЗ рдХреЛрдбрдмреЗрд╕ рдореЗрдВ рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдЬрд╣рд╛рдБ рдЪрд╛рд╣реЗрдВ рдШреЛрд╖рд┐рдд рдХрд░реЗрдВ Intlayer рдЖрдкрдХреЛ .content.{ts|js|json} рдлрд╛рдЗрд▓реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдЕрдкрдиреЗ рдХреЛрдбрдмреЗрд╕ рдореЗрдВ рдЬрд╣рд╛рдБ рдЪрд╛рд╣реЗрдВ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдпрд╣ рдЖрдкрдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рдмреЗрд╣рддрд░ рд╕рдВрдЧрдарди рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рдЬрд┐рд╕рд╕реЗ рдЖрдкрдХреЗ рдХреЛрдбрдмреЗрд╕ рдХреА рдкрдардиреАрдпрддрд╛ рдФрд░ рд░рдЦрд░рдЦрд╛рд╡ рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реЛрдЧрд╛ред

      • рд▓рд╛рдкрддрд╛ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ Intlayer рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдк рдЕрдкрдиреА CI/CD рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдпрд╛ рдЕрдкрдиреА рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВ testing your translationsред

      • рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░реЗрдВ, Intlayer рдЖрдкрдХреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ CLI рдФрд░ VSCode рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕реЗ рдЖрдкрдХреЗ CI/CD рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВред рдЖрдк рдЕрдкрдиреА рдЕрдкрдиреА API рдХреБрдВрдЬреА рдФрд░ рдЕрдкрдиреА рдкрд╕рдВрдж рдХреЗ AI рдкреНрд░рджрд╛рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рд╕рдВрджрд░реНрдн-рд╕рдЪреЗрдд рдЕрдиреБрд╡рд╛рдж рднреА рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рджреЗрдЦреЗрдВ рд╕рд╛рдордЧреНрд░реА рднрд░реЗрдВред

      • рдмрд╛рд╣рд░реА рд╕рд╛рдордЧреНрд░реА рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ
        Intlayer рдЖрдкрдХреЛ рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдПрдХ рдмрд╛рд╣рд░реА рдХрдВрдЯреЗрдВрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯ рд╕рд┐рд╕реНрдЯрдо (CMS) рд╕реЗ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕реЗ рдПрдХ рдЕрдиреБрдХреВрд▓рд┐рдд рддрд░реАрдХреЗ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдЕрдкрдиреА JSON рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдмрд╛рд╣рд░реА рд╕рд╛рдордЧреНрд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВред

      • рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░
        Intlayer рдПрдХ рдореБрдлреНрдд рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рд╕реЗ рдЖрдк рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рд╡рд┐рдЬрд╝реБрдЕрд▓ рд╕рдВрдкрд╛рджрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВред

      рдФрд░ рднреА рдмрд╣реБрдд рдХреБрдЫред Intlayer рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХреА рдЧрдИ рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП, рдХреГрдкрдпрд╛ Intlayer рдХреЗ рдорд╣рддреНрд╡ рдХреА рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рджреЗрдЦреЗрдВред

      рд╡рд┐рд╕реНрддреГрдд performance benchmarks рдФрд░ рддреБрд▓рдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВ:

    рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

    рдЕрднреА рддрдХ рдХреЛрдИ рдЯрд┐рдкреНрдкрдгреА рдирд╣реАрдВред рдЕрдкрдиреЗ рд╡рд┐рдЪрд╛рд░ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкрд╣рд▓реЗ рд╡реНрдпрдХреНрддрд┐ рдмрдиреЗрдВред

    рд╕рдВрдмрдВрдзрд┐рдд рдкреЛрд╕реНрдЯ

    рдирд╡реАрдирддрдо рдкреЛрд╕реНрдЯ