Author:
    Creation:2026-09-26Last update:2026-09-26

    2026 рдореЗрдВ Paraglide JS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ TanStack Start рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХреИрд╕реЗ рдХрд░реЗрдВ

    рд╡рд┐рд╖рдп рд╕реВрдЪреА

    Paraglide JS рдХреНрдпрд╛ рд╣реИ?

    Paraglide JS (inlang рджреНрд╡рд╛рд░рд╛) рдПрдХ рдХрдВрдкрд╛рдЗрд▓рд░-рдЖрдзрд╛рд░рд┐рдд (compiler-based) i18n рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╣реИред рдХрд┐рд╕реА JSON рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдХреАрдЬрд╝ (keys) рдЦреЛрдЬрдиреЗ рд╡рд╛рд▓реЗ рд░рдирдЯрд╛рдЗрдо рдХреЛ рднреЗрдЬрдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдпрд╣ рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдХреЛ рдПрдХ рдЯрд╛рдЗрдкреНрдб рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдлрд╝рдВрдХреНрд╢рди (m.about_title()) рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд (compile) рдХрд░рддрд╛ рд╣реИред рдЕрдкреНрд░рдпреБрдХреНрдд рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рдмрдВрдбрд▓рд░ рджреНрд╡рд╛рд░рд╛ рд╣рдЯрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдХрд┐рд╕реА рдХреА (key) рдореЗрдВ рдЯрд╛рдЗрдкреЛ рд╣реЛрдирд╛ рдПрдХ рдХрдВрдкрд╛рдЗрд▓ рддреНрд░реБрдЯрд┐ (compile error) рдмрди рдЬрд╛рддрд╛ рд╣реИред

    Paraglide рдЖрдзрд┐рдХрд╛рд░рд┐рдХ TanStack Router рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдиреЗ рд╡рд╛рд▓рд╛ i18n рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИ, рдФрд░ рдпрд╣ рддреАрди рднрд╛рдЧреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ TanStack Start рдХреЗ рд╕рд╛рде рдПрдХреАрдХреГрдд рд╣реЛрддрд╛ рд╣реИ:

    • рдПрдХ Vite рдкреНрд▓рдЧрдЗрди рдЬреЛ рд╕рдВрджреЗрд╢реЛрдВ рдФрд░ рд░рдирдЯрд╛рдЗрдо рдХреЛ src/paraglide рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХрд░рддрд╛ рд╣реИ;
    • рдПрдХ рд╕рд░реНрд╡рд░ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓реЛрдХреЗрд▓ рдХреЛ рд╣рд▓ (resolve) рдХрд░рддрд╛ рд╣реИ;
    • рдПрдХ рд░рд╛рдЙрдЯрд░ рд░реАрд░рд╛рдЗрдЯ (router rewrite) рдЬреЛ рд╕реНрдерд╛рдиреАрдпрдХреГрдд URL (/fr/about) рдХреЛ рдЖрдкрдХреЗ рд░реВрдЯ рдЯреНрд░реА (/about) рдореЗрдВ рдореИрдк рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ $locale рд╕реЗрдЧрдореЗрдВрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред

    рдпрд╣ рдЧрд╛рдЗрдб рдЗрди рддреАрдиреЛрдВ рдХреЛ рд╕реЗрдЯ рдЕрдк рдХрд░рддреА рд╣реИ, рдлрд┐рд░ рдЙрди рд╕рднреА рдЪреАрдЬрд╝реЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░рддреА рд╣реИ рдЬреЛ Paraglide рдЖрдк рдкрд░ рдЫреЛрдбрд╝рддрд╛ рд╣реИ: lang рдФрд░ dir, рд▓реЛрдХреЗрд▓ рд╕реНрд╡рд┐рдЪрд░, рдЕрдиреБрд╡рд╛рджрд┐рдд рдореЗрдЯрд╛рдбреЗрдЯрд╛, canonical, x-default рдХреЗ рд╕рд╛рде hreflang, Open Graph, JSON-LD, рд╕рд╛рдЗрдЯрдореИрдк, robots.txt, рдкреНрд░реА-рд░реЗрдВрдбрд░рд┐рдВрдЧ рдФрд░ рд╕реНрдерд╛рдиреАрдпрдХреГрдд 404 рдкреЗрдЬред

    рдХреНрдпрд╛ рдЖрдк рдХрд┐рд╕реА рдЕрдиреНрдп рд╕реНрдЯреИрдХ рдХреА рддрд▓рд╛рд╢ рдореЗрдВ рд╣реИрдВ? TanStack Start + use-intl рдЧрд╛рдЗрдб, TanStack Start + Lingui рдЧрд╛рдЗрдб, рдпрд╛ TanStack Start + Intlayer рдЧрд╛рдЗрдб рджреЗрдЦреЗрдВред
    рджреЛ рдХрдВрдкрд╛рдЗрд▓рд░-рдЖрдзрд╛рд░рд┐рдд рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ? рдХреНрдпрд╛ Intlayer, Paraglide рд╕реЗ рд╣рд▓реНрдХрд╛ рд╣реИ? рдкрдврд╝реЗрдВред

    TanStack Start рдкрд░ Paraglide рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХреНрдпрд╛ рдХрд╣рддрд╛ рд╣реИ

    i18n рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд╣рд░ рдкреНрд░рдореБрдЦ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд╕рд╛рде рд╕рдорд╛рди 10-рдкреЗрдЬ, 10-рд▓реЛрдХреЗрд▓ TanStack Start рдРрдк рдЪрд▓рд╛рддрд╛ рд╣реИ рдФрд░ рдорд╛рдкрддрд╛ рд╣реИ рдХрд┐ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рддрд╛ рд╣реИред

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

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

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

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

    I18n рдкреНрд░рджрд░реНрд╢рди рдмреЗрдВрдЪрдорд╛рд░реНрдХ

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

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

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

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

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

    @inlang/paraglide-js@2.15.1 рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдЖрдВрдХрдбрд╝реЗ, 2026-09-26 рдХреЛ рдорд╛рдкреЗ рдЧрдП (gzip):

    рд╕реЗрдЯрдЕрдкрд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЖрдХрд╛рд░рдкреНрд░рддрд┐ рдкреЗрдЬ JSрдЕрдиреНрдп рд▓реЛрдХреЗрд▓ рд▓реАрдХрдЕрдиреНрдп рдкреЗрдЬ рд▓реАрдХрдкреЗрдЬ рд▓реЛрдб
    рдХреЛрдИ i18n рдирд╣реАрдВ (рдмреЗрд╕ рдРрдк)-111.0 KB0%0%15.7 ms
    Paraglide JS1.8 KB125.1 KB49.7%0%22.1 ms
    react-intlayer4.5 KB126.8 KB0%0%14.8 ms
    use-intl75.9 KB128.7 KB0%0%17.4 ms
    Lingui56.7 KB120.2 KB8.6%0%21.9 ms

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

    • рд░рдирдЯрд╛рдЗрдо рдмрд╣реБрдд рдЫреЛрдЯрд╛ рд╣реИ, рдФрд░ рдкреЗрдЬ рд▓реАрдХ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред рд░рдирдЯрд╛рдЗрдо рдЖрдкрдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдЬреЗрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╡рд╣реАрдВ рдЖрдпрд╛рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реЛрддрд╛ рд╣реИред
    • рд▓реЛрдХреЗрд▓реНрд╕ рд▓реАрдХ рд╣реЛрддреЗ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕рднреА рд▓реЛрдХреЗрд▓реНрд╕ рд╣реЛрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХрд┐рд╕реА рдкреЗрдЬ рдкрд░ рднреЗрдЬреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрд╡рд╛рджрд┐рдд рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХрд╛ рд▓рдЧрднрдЧ рдЖрдзрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдЙрди рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╣реЛрддрд╛ рд╣реИ рдЬрд┐рдирдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд┐рдЬрд╝рд┐рдЯрд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЖрдк рдЬрд┐рддрдиреЗ рдЕрдзрд┐рдХ рд▓реЛрдХреЗрд▓реНрд╕ рдЬреЛрдбрд╝реЗрдВрдЧреЗ, рдпрд╣ рд╣рд┐рд╕реНрд╕рд╛ рдЙрддрдирд╛ рд╣реА рдмрдбрд╝рд╛ рд╣реЛрддрд╛ рдЬрд╛рдПрдЧрд╛ред
    • рдкреЗрдЬ рд▓реЛрдб рд╕рдореВрд╣ рдореЗрдВ рд╕рдмрд╕реЗ рдзреАрдорд╛ рд╣реИ, рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдЗрд╕рд▓рд┐рдП рдХреНрдпреЛрдВрдХрд┐ рд▓реЛрдХреЗрд▓ рдХреЛ React рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рд╕реЗ рдкрдврд╝рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдкрд░ рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
    рдкреВрд░рд╛ рдбреЗрдЯрд╛ рджреЗрдЦреЗрдВ: TanStack Start рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд░рд┐рдкреЛрд░реНрдЯ, рдФрд░ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реАред

    TanStack Start рдкрд░ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреА рддреБрд▓рдирд╛

    TanStack Start рдкрд░ рдЖрдорддреМрд░ рдкрд░ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдЕрдиреНрдп рд▓рд╛рдЗрдмреНрд░реЗрд░реАрдЬрд╝ рдХреЗ рд╕рд╛рде Paraglide JS рдХреА рддреБрд▓рдирд╛:

    рд╕реБрд╡рд┐рдзрд╛react-intlayer (Intlayer)use-intlParaglide JSLingui
    рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЗ рдкрд╛рд╕ рдЕрдиреБрд╡рд╛рджтЬЕ Co-locatedтЭМ рдХреЗрдВрджреНрд░реАрдХреГрдд JSONтЭМ рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдПрдХ JSON рдлрд╝рд╛рдЗрд▓тЪая╕П рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдореЗрдВ рд╕реНрд░реЛрдд рдЯреЗрдХреНрд╕реНрдЯ
    TypeScript рдПрдХреАрдХрд░рдгтЬЕ рд╕реНрд╡рддрдГ рдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рдкреНрд░рдХрд╛рд░тЬЕ AppConfig рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗтЬЕ рдЯрд╛рдЗрдкреНрдб рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рдитЪая╕П рдХреЗрд╡рд▓ Macros
    рдЕрдиреБрдкрд▓рдмреНрдз рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛тЬЕ рдкреНрд░рдХрд╛рд░ рддреНрд░реБрдЯрд┐рдпрд╛рдБ рдФрд░ рдмрд┐рд▓реНрдб рдЪреЗрддрд╛рд╡рдирд┐рдпрд╛рдБтЪая╕П рд░рдирдЯрд╛рдЗрдо рдлрд╝реЙрд▓рдмреИрдХтЪая╕П рдмреЗрд╕ рд▓реЛрдХреЗрд▓ рдкрд░ рдлрд╝реЙрд▓рдмреИрдХтЪая╕П рд╕реНрд░реЛрдд рдЯреЗрдХреНрд╕реНрдЯ рдкрд░ рдлрд╝реЙрд▓рдмреИрдХ
    рд░рд┐рдЪ рдХрдВрдЯреЗрдВрдЯ (JSX, Markdown)тЬЕ рд╕реАрдзрд╛ рд╕рдорд░реНрдердитЪая╕П t.rich рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЯреИрдЧтЪая╕П рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕тЬЕ <Trans> рдХреЗ рдЕрдВрджрд░ JSX
    рд╕реНрдерд╛рдиреАрдпрдХреГрдд рд░реВрдЯрд┐рдВрдЧтЬЕ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд (Built-in)тЭМ рдореИрдиреНрдпреБрдЕрд▓ {-$locale}тЬЕ urlPatterns + router rewriteтЭМ рдореИрдиреНрдпреБрдЕрд▓ {-$locale}
    рд░реАрд▓реЛрдб рдХреЗ рдмрд┐рдирд╛ рд▓реЛрдХреЗрд▓ рд╕реНрд╡рд┐рдЪтЬЕ рд╣рд╛рдБтЬЕ рд╣рд╛рдБтЭМ рдкреВрд░реНрдг рдкреЗрдЬ рд░реАрд▓реЛрдбтЬЕ рд╣рд╛рдБ
    рдмрд╣реБрд╡рдЪрди (Pluralization)тЬЕ рдЧрдгрдирд╛-рдЖрдзрд╛рд░рд┐рддтЬЕ ICUтЬЕ рд╡реИрд░рд┐рдПрдВрдЯреНрд╕ (Variants)тЬЕ ICU
    ICU MessageFormatтЬЕ format: "icu" рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗтЬЕ рдиреЗрдЯрд┐рд╡тЪая╕П inlang рдкреНрд▓рдЧрдЗрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗтЬЕ рдиреЗрдЯрд┐рд╡
    рдХрдВрдЯреЗрдВрдЯ рдкреНрд░рд╛рд░реВрдктЬЕ .ts, .json, .md, .yaml...тЪая╕П .jsonтЪая╕П inlang JSONтЬЕ PO, JSON, CSV
    AI рдЕрдиреБрд╡рд╛рджтЬЕ рдЖрдкрдХрд╛ рдЕрдкрдирд╛ рдкреНрд░рджрд╛рддрд╛ рдФрд░ API рдХреАтЭМ рдирд╣реАрдВтЭМ рдирд╣реАрдВтЭМ рдирд╣реАрдВ
    рд╡рд┐рдЬрд╝реБрдЕрд▓ рдПрдбрд┐рдЯрд░ / CMSтЬЕ рд╕реНрдерд╛рдиреАрдп рд╕рдВрдкрд╛рджрдХ + рд╡реИрдХрд▓реНрдкрд┐рдХ CMSтЭМ рдмрд╛рд╣рд░реА рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдотЪая╕П inlang рдЗрдХреЛрд╕рд┐рд╕реНрдЯрдо рдРрдкреНрд╕тЭМ рдмрд╛рд╣рд░реА рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо
    SEO рд╕рд╣рд╛рдпрдХ (hreflang, sitemap)тЬЕ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рддтЭМ рдореИрдиреНрдпреБрдЕрд▓тЪая╕П рд╕реНрдерд╛рдиреАрдпрдХреГрдд URL, рдмрд╛рдХреА рдореИрдиреНрдпреБрдЕрд▓тЭМ рдореИрдиреНрдпреБрдЕрд▓
    рд░рдирдЯрд╛рдЗрдо рдЖрдХрд╛рд░ (gzip, рдмреЗрдВрдЪрдорд╛рд░реНрдХ)4.5 KB75.9 KB1.8 KB56.7 KB
    рд▓реАрдХ, рд╕рд░реНрд╡рд╢реНрд░реЗрд╖реНрда рд╕реЗрдЯрдЕрдк (рд▓реЛрдХреЗрд▓ / рдкреЗрдЬ)0% / 0%0% / 0%49.7% / 0%8.6% / 0%
    CI рдореЗрдВ рдЫреВрдЯреЗ рд╣реБрдП рдЕрдиреБрд╡рд╛рджтЬЕ npx intlayer testтЪая╕П рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдирд╣реАрдВтЪая╕П рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдирд╣реАрдВтЬЕ lingui compile --strict
    рд░рдирдЯрд╛рдЗрдо рдЖрдХрд╛рд░ рдФрд░ рд▓реАрдХ рдХреЗ рдЖрдВрдХрдбрд╝реЗ TanStack Start рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд╕реЗ рд▓рд┐рдП рдЧрдП рд╣реИрдВред рд▓реАрдХ рдХреЛ рдкреНрд░рддреНрдпреЗрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд╕рд░реНрд╡реЛрддреНрддрдо рд╕реЗрдЯрдЕрдк рдкрд░ рдорд╛рдкрд╛ рдЧрдпрд╛ рд╣реИред
    рдЕрдиреНрдп TanStack Start рдЧрд╛рдЗрдб: Lingui, use-intl, рдФрд░ Intlayerред

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

    • рд╕рд░реНрд╡рд░ рдкрд░ рд╣рд▓ рдХрд┐рдП рдЧрдП рд▓реЛрдХреЗрд▓ рд╕реЗ <html> рдкрд░ lang рдФрд░ dir рд╕реЗрдЯ рдХрд░реЗрдВред
    • рдПрдХ рдкреНрд░реАрдлрд╝рд┐рдХреНрд╕ рд░рдгрдиреАрддрд┐ (/fr/about) рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдПрдХ URL рд░рдЦреЗрдВ, рддрд╛рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдг рдЕрдиреБрдХреНрд░рдорд┐рдд (indexable) рд╣реЛ рд╕рдХреЗред
    • рдЕрдкрдиреА рд▓реЛрдХреЗрд▓ рд░рдгрдиреАрддрд┐ рдореЗрдВ url рдХреЛ рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд░рдЦреЗрдВ, рддрд╛рдХрд┐ URL рд╕рддреНрдп рдХрд╛ рд╕реНрд░реЛрдд (source of truth) рдмрдирд╛ рд░рд╣реЗ, рдФрд░ рдХреНрд░реЙрд▓рд░реНрд╕ рдХреЛ рд╡рд╣реА рдкреЗрдЬ рдорд┐рд▓реЗ рдЬрд┐рд╕рдХрд╛ рдЙрдиреНрд╣реЛрдВрдиреЗ рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдерд╛ред
    • рдлреНрд▓реИрдЯ, рд╡рд░реНрдгрдирд╛рддреНрдордХ рд╕рдВрджреЗрд╢ рдХреБрдВрдЬрд┐рдпреЛрдВ (keys) (about_title) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдЬреЛ рдлрд╝рдВрдХреНрд╢рди рдирд╛рдореЛрдВ рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдореИрдк рд╣реЛрддреА рд╣реИрдВред
    • рдЕрдкрдиреА messages/*.json рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдХрдорд┐рдЯ рдХрд░реЗрдВ, рди рдХрд┐ рдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП src/paraglide рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ, рддрд╛рдХрд┐ рдЬрдирд░реЗрдЯ рдХреА рдЧрдИ рдлрд╝рд╛рдЗрд▓реЛрдВ рдкрд░ рдорд░реНрдЬ рд╡рд┐рд░реЛрдз (merge conflicts) рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХреЗред
    • рдЕрдкрдиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░реЗрдВ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдкреЗрдЬ рдкрд░ canonical, hreflang рдФрд░ x-default рдШреЛрд╖рд┐рдд рдХрд░реЗрдВред
    • рдПрдХ рдмрд╣реБрднрд╛рд╖реА рд╕рд╛рдЗрдЯрдореИрдк рдФрд░ robots.txt рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХреЗрд▓ рдХреЛ рдкреНрд░реА-рд░реЗрдВрдбрд░ рдХрд░реЗрдВред
    • рд▓реЛрдХреЗрд▓ рд╕реНрд╡рд┐рдЪрд░ рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓рд┐рдВрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рддрд╛рдХрд┐ рдХреНрд░реЙрд▓рд░реНрд╕ рд╣рд░ рднрд╛рд╖рд╛ рдХреЛ рдЦреЛрдЬ рд╕рдХреЗрдВред
    рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдФрд░ SEO рдФрд░ hreflang рдЧрд╛рдЗрдб рдкрд░ рд╣рдорд╛рд░реА рдЧрд╛рдЗрдб рджреЗрдЦреЗрдВред

    TanStack Start рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ Paraglide JS рд╕реЗрдЯ рдЕрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд░рдг-рджрд░-рдЪрд░рдг рдЧрд╛рдЗрдб

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

    bash
    .
    тФЬтФАтФА project.inlang
    тФВ   тФФтФАтФА settings.json          # Locales and message format
    тФЬтФАтФА messages
    тФВ   тФЬтФАтФА en.json
    тФВ   тФЬтФАтФА fr.json
    тФВ   тФФтФАтФА es.json
    тФЬтФАтФА vite.config.ts
    тФФтФАтФА src
        тФЬтФАтФА paraglide              # Generated, git-ignored
        тФЬтФАтФА server.ts              # Paraglide middleware
        тФЬтФАтФА router.tsx             # URL rewrite
        тФЬтФАтФА i18n
        тФВ   тФЬтФАтФА config.ts          # Site URL, helpers
        тФВ   тФФтФАтФА seo.ts             # head() builder
        тФЬтФАтФА components
        тФВ   тФФтФАтФА LocaleSwitcher.tsx
        тФФтФАтФА routes
            тФЬтФАтФА __root.tsx
            тФЬтФАтФА index.tsx          # / and /fr
            тФЬтФАтФА about.tsx          # /about and /fr/about
            тФЬтФАтФА $.tsx              # Localized 404
            тФЬтФАтФА sitemap[.]xml.ts
            тФФтФАтФА robots[.]txt.ts
    

    рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣рд╛рдБ рдХреЛрдИ $locale рдлрд╝реЛрд▓реНрдбрд░ рдирд╣реАрдВ рд╣реИ: рд░реВрдЯ рдорд┐рд▓рд╛рди (route matching) рд╕реЗ рдкрд╣рд▓реЗ рд░рд╛рдЙрдЯрд░ рд░реАрд░рд╛рдЗрдЯ рдкреНрд░реАрдлрд╝рд┐рдХреНрд╕ рдХреЛ рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИред

    1. рдирд┐рд░реНрднрд░рддрд╛рдПрдБ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ

      TanStack Start рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕реЗ рд╢реБрд░реБрдЖрдд рдХрд░реЗрдВ, рдлрд┐рд░ Paraglide рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВред init рдХрдорд╛рдВрдб project.inlang/settings.json, рдПрдХ рдкрд╣рд▓реА messages/en.json рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдкреИрдХреЗрдЬ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рддрд╛ рд╣реИред

      bash
      npm create @tanstack/start@latest
      npx @inlang/paraglide-js@latest init
      
      • @inlang/paraglide-js: рдХрдВрдкрд╛рдЗрд▓рд░ рдФрд░ рдЗрд╕рдХрд╛ Vite рдкреНрд▓рдЧрдЗрдиред рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд░рдирдЯрд╛рдЗрдо рдкреИрдХреЗрдЬ рдирд╣реАрдВ рд╣реИ: рд░рдирдЯрд╛рдЗрдо рдЖрдкрдХреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рд╣реА рдЬрдирд░реЗрдЯ рд╣реЛрддрд╛ рд╣реИред
    2. рдЕрдкрдиреЗ рд▓реЛрдХреЗрд▓реНрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ

      project.inlang/settings.json рд▓реЛрдХреЗрд▓реНрд╕ рдХреЗ рд▓рд┐рдП рд╕рддреНрдп рдХрд╛ рдПрдХрдорд╛рддреНрд░ рд╕реНрд░реЛрдд рд╣реИред рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рд░реВрдк рдкреНрд▓рдЧрдЗрди рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдПрдХ JSON рдлрд╝рд╛рдЗрд▓ рдкрдврд╝рддрд╛ рд╣реИред

      project.inlang/settings.json
      {
        "$schema": "https://inlang.com/schema/project-settings",
        "baseLocale": "en",
        "locales": ["en", "fr", "es"],
        "modules": [
          "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
          "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
        ],
        "plugin.inlang.messageFormat": {
          "pathPattern": "./messages/{locale}.json"
        }
      }
      
    3. Vite рдкреНрд▓рдЧрдЗрди рдФрд░ URL рд░рдгрдиреАрддрд┐ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ

      рдкреНрд▓рдЧрдЗрди рд╣рд░ рдмрджрд▓рд╛рд╡ рдкрд░ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рддрд╛ рд╣реИред TanStack Start рдХреЗ рд▓рд┐рдП рддреАрди рд╡рд┐рдХрд▓реНрдк рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИрдВ:

      • strategy: рд▓реЛрдХреЗрд▓ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреЛрдВ рдХреА рдХреНрд░рдорд┐рдд рд╕реВрдЪреАред url рдкрд╣рд▓реЗ рд╣реЛрдиреЗ рд╕реЗ URL рд╕рддреНрдп рдХрд╛ рд╕реНрд░реЛрдд рдмрди рдЬрд╛рддрд╛ рд╣реИред cookie рдФрд░ preferredLanguage рдХрд╛ рдЙрдкрдпреЛрдЧ рдорд┐рдбрд▓рд╡реЗрдпрд░ рджреНрд╡рд╛рд░рд╛ рддрдм рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм URL рдирд┐рд░реНрдгрдп рдирд╣реАрдВ рд▓реЗрддрд╛ рд╣реИред
      • urlPatterns: рдПрдХ рд▓реЛрдХреЗрд▓ URL рдкрд░ рдХреИрд╕реЗ рдореИрдк рд╣реЛрддрд╛ рд╣реИред рдЧреИрд░-рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХреЗрд▓реНрд╕ рдкрд╣рд▓реЗ рд╕реВрдЪреАрдмрджреНрдз рд╣реЛрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдкрд╣рд▓рд╛ рдореЗрд▓ рдЦрд╛рдиреЗ рд╡рд╛рд▓рд╛ рдкреИрдЯрд░реНрди рдЬреАрддрддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЛрдХреЗрд▓ рдмрд┐рдирд╛ рдкреНрд░реАрдлрд╝рд┐рдХреНрд╕ (/about) рд░рд╣рддрд╛ рд╣реИ, рдФрд░ рдЕрдиреНрдп рд▓реЛрдХреЗрд▓реНрд╕ рдкреНрд░реАрдлрд╝рд┐рдХреНрд╕ (/fr/about) рдХреЗ рд╕рд╛рде рд╣реЛрддреЗ рд╣реИрдВред
      • outputStructure: "message-modules": рдкреНрд░рддрд┐ рд╕рдВрджреЗрд╢ рдПрдХ рдореЙрдбреНрдпреВрд▓, рдЬреЛ рдмрдВрдбрд▓рд░ рдХреЛ рдЙрди рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдХреЛрдИ рдкреЗрдЬ рдЖрдпрд╛рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
      vite.config.ts
      import { paraglideVitePlugin } from "@inlang/paraglide-js";
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";
      import viteReact from "@vitejs/plugin-react";
      import { defineConfig } from "vite";
      
      export default defineConfig({
        plugins: [
          paraglideVitePlugin({
            project: "./project.inlang",
            outdir: "./src/paraglide",
            outputStructure: "message-modules",
            cookieName: "PARAGLIDE_LOCALE",
            strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
            urlPatterns: [
              {
                pattern: "/:path(.*)?",
                localized: [
                  ["fr", "/fr/:path(.*)?"],
                  ["es", "/es/:path(.*)?"],
                  // Default locale last: it matches every remaining URL
                  ["en", "/:path(.*)?"],
                ],
              },
            ],
          }),
          tanstackStart(),
          viteReact(),
        ],
      });
      

      рдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ .gitignore рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред рдпрд╣ dev рдФрд░ build рдкрд░ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:

      .gitignore
      src/paraglide
      
    4. рдЕрдкрдиреА рдЕрдиреБрд╡рд╛рдж рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдПрдВ

      рдкреНрд░рддреНрдпреЗрдХ рдХреА (key) src/paraglide/messages рд╕реЗ рдирд┐рд░реНрдпрд╛рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдмрди рдЬрд╛рддреА рд╣реИред рдлреНрд▓реИрдЯ, snake_case рдХреБрдВрдЬрд┐рдпрд╛рдБ рд╕рдмрд╕реЗ рд╕рд╛рдл рдлрд╝рдВрдХреНрд╢рди рдирд╛рдо рджреЗрддреА рд╣реИрдВред рд╡реЗрд░рд┐рдПрдмрд▓реНрд╕ {name} рдкреНрд▓реЗрд╕рд╣реЛрд▓реНрдбрд░реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред

      messages/en.json
      {
        "$schema": "https://inlang.com/schema/inlang-message-format",
        "nav_home": "Home",
        "nav_about": "About",
        "locale_switcher_label": "Change language",
        "home_meta_title": "Welcome",
        "home_meta_description": "A multilingual TanStack Start application.",
        "home_title": "Hello {name}!",
        "about_meta_title": "About us",
        "about_meta_description": "Learn who we are and why we built this application.",
        "about_title": "About us",
        "not_found_title": "Page not found",
        "not_found_back_home": "Back to home"
      }
      
      messages/fr.json
      {
        "$schema": "https://inlang.com/schema/inlang-message-format",
        "nav_home": "Accueil",
        "nav_about": "├А propos",
        "locale_switcher_label": "Changer de langue",
        "home_meta_title": "Bienvenue",
        "home_meta_description": "Une application TanStack Start multilingue.",
        "home_title": "Bonjour {name} !",
        "about_meta_title": "├А propos",
        "about_meta_description": "D├йcouvrez qui nous sommes et pourquoi nous avons cr├й├й cette application.",
        "about_title": "├А propos",
        "not_found_title": "Page introuvable",
        "not_found_back_home": "Retour ├а l'accueil"
      }
      

      рдмрд╣реБрд╡рдЪрди inlang рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд╡реИрд░рд┐рдПрдВрдЯреНрд╕ (variants) рд╕рд┐рдВрдЯреИрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:

      messages/en.json
      {
        "cart_items": [
          {
            "declarations": ["input count", "local countPlural = count: plural"],
            "selectors": ["countPlural"],
            "match": {
              "countPlural=one": "{count} item",
              "countPlural=other": "{count} items"
            }
          }
        ]
      }
      
    5. рд╕рд░реНрд╡рд░ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдЬреЛрдбрд╝реЗрдВ

      рдорд┐рдбрд▓рд╡реЗрдпрд░ рдЖрдкрдХреА рд░рдгрдиреАрддрд┐ рдХреЗ рд╕рд╛рде рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓реЛрдХреЗрд▓ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕реЗ рдПрдХ AsyncLocalStorage рд╕реНрдХреЛрдк рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреВрд░реЗ рд╕рд░реНрд╡рд░ рд░реЗрдВрдбрд░ рдХреЗ рд▓рд┐рдП getLocale() рдкрд░ рдЙрдкрд▓рдмреНрдз рдХрд░рд╛рддрд╛ рд╣реИред рдпрд╣реА рд╡рд┐рднрд┐рдиреНрди рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╕рдорд╡рд░реНрддреА (concurrent) рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реБрд░рдХреНрд╖рд┐рдд рдмрдирд╛рддрд╛ рд╣реИред

      TanStack Start рдореЗрдВ, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рд░реНрд╡рд░ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ (server entry) рдХреЛ рд▓рдкреЗрдЯреЗрдВ:

      src/server.ts
      import handler from "@tanstack/react-start/server-entry";
      import { paraglideMiddleware } from "./paraglide/server";
      
      export default {
        fetch(request: Request): Promise<Response> {
          return paraglideMiddleware(request, () => handler.fetch(request));
        },
      };
      
    6. рд░рд╛рдЙрдЯрд░ рдореЗрдВ рд╕реНрдерд╛рдиреАрдпрдХреГрдд URL рд░реАрд░рд╛рдЗрдЯ рдХрд░реЗрдВ

      TanStack Router рдХрд╛ rewrite рд╡рд┐рдХрд▓реНрдк рд░рд╛рдЙрдЯрд░ рдХреА рд╕реАрдорд╛ рдкрд░ URL рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рддрд╛ рд╣реИ:

      • input: рд░реВрдЯ рдорд┐рд▓рд╛рди рд╕реЗ рдкрд╣рд▓реЗ /fr/about рдХреЛ /about рдореЗрдВ рдбреА-рд▓реЛрдХрд▓рд╛рдЗрдЬрд╝ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рдПрдХ рд╣реА about.tsx рд░реВрдЯ рд╣рд░ рднрд╛рд╖рд╛ рдХреЛ рд╕реЗрд╡рд╛ рджреЗ рд╕рдХреЗ;
      • output: рдкреНрд░рддреНрдпреЗрдХ рдЬрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ href (рд▓рд┐рдВрдХреНрд╕, рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯреНрд╕, рдиреЗрд╡рд┐рдЧреЗрд╢рди) рд╕рдХреНрд░рд┐рдп рд▓реЛрдХреЗрд▓ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреАрдпрдХреГрдд рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП <Link to="/about"> рдПрдХ рдлрд╝реНрд░реЗрдВрдЪ рдкреЗрдЬ рдкрд░ /fr/about рд░реЗрдВрдбрд░ рдХрд░рддрд╛ рд╣реИред
      src/router.tsx
      import { createRouter } from "@tanstack/react-router";
      import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime";
      import { routeTree } from "./routeTree.gen";
      
      export const getRouter = () =>
        createRouter({
          routeTree,
          scrollRestoration: true,
          rewrite: {
            input: ({ url }) => deLocalizeUrl(url),
            output: ({ url }) => localizeUrl(url),
          },
        });
      
      declare module "@tanstack/react-router" {
        interface Register {
          router: ReturnType<typeof getRouter>;
        }
      }
      
      рдХреНрдпреЛрдВрдХрд┐ рд▓рд┐рдВрдХ рд░реАрд░рд╛рдЗрдЯ рджреНрд╡рд╛рд░рд╛ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рд╣реЛрддреЗ рд╣реИрдВ, рдЖрдкрдХреЛ рдХрд╕реНрдЯрдо LocalizedLink рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ: рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣ TanStack Router рдХреЗ Link рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
    7. рд░реВрдЯ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдмрдирд╛рдПрдВ

      getLocale() рд╕рд░реНрд╡рд░ рдкрд░ рдорд┐рдбрд▓рд╡реЗрдпрд░ рджреНрд╡рд╛рд░рд╛ рд╣рд▓ рдХрд┐рдП рдЧрдП рд▓реЛрдХреЗрд▓ рдХреЛ рдФрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ URL рд╕реЗ рд▓реЛрдХреЗрд▓ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕рд░реНрд╡рд░ HTML рдФрд░ рд╣рд╛рдЗрдбреНрд░реЗрд╢рди рдХреЗ рдмрд╛рдж lang рдФрд░ dir рд╕рдорд╛рди рд╣реЛрддреЗ рд╣реИрдВред

      src/i18n/config.ts
      import { baseLocale, type Locale, localizeUrl } from "@/paraglide/runtime";
      
      /** Public origin, used for canonical URLs, hreflang and the sitemap. */
      export const siteUrl = "https://example.com";
      
      /** Open Graph expects `language_TERRITORY` codes. */
      export const openGraphLocales: Record<Locale, string> = {
        en: "en_US",
        fr: "fr_FR",
        es: "es_ES",
      };
      
      const rightToLeftLanguages = new Set(["ar", "fa", "he", "ur", "ps", "yi"]);
      
      export const getTextDirection = (locale: string): "ltr" | "rtl" =>
        rightToLeftLanguages.has(new Intl.Locale(locale).language) ? "rtl" : "ltr";
      
      /** `getAbsoluteUrl("/about", "fr")` тЖТ `https://example.com/fr/about` */
      export const getAbsoluteUrl = (path: string, locale: Locale): string =>
        localizeUrl(new URL(path, siteUrl), { locale }).href;
      
      export const getLocaleName = (locale: Locale): string =>
        new Intl.DisplayNames([locale], { type: "language" }).of(locale) ?? locale;
      
      export { baseLocale };
      
      src/routes/__root.tsx
      import {
        createRootRoute,
        HeadContent,
        Link,
        Outlet,
        Scripts,
      } from "@tanstack/react-router";
      import type { ReactNode } from "react";
      import { LocaleSwitcher } from "@/components/LocaleSwitcher";
      import { NotFound } from "@/components/NotFound";
      import { getTextDirection } from "@/i18n/config";
      import { m } from "@/paraglide/messages";
      import { getLocale } from "@/paraglide/runtime";
      
      export const Route = createRootRoute({
        head: () => ({
          meta: [
            { charSet: "utf-8" },
            { name: "viewport", content: "width=device-width, initial-scale=1" },
          ],
        }),
        shellComponent: RootDocument,
        component: RootLayout,
        notFoundComponent: NotFound,
      });
      
      function RootDocument({ children }: { children: ReactNode }) {
        const locale = getLocale();
      
        return (
          <html lang={locale} dir={getTextDirection(locale)}>
            <head>
              <HeadContent />
            </head>
            <body>
              {children}
              <Scripts />
            </body>
          </html>
        );
      }
      
      function RootLayout() {
        return (
          <>
            <header>
              <nav>
                <Link to="/">{m.nav_home()}</Link>
                <Link to="/about">{m.nav_about()}</Link>
              </nav>
              <LocaleSwitcher />
            </header>
            <main>
              <Outlet />
            </main>
          </>
        );
      }
      
    8. рдЕрдкрдиреЗ рдкреЗрдЬреЛрдВ рдореЗрдВ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

      рд╕рдВрджреЗрд╢ рд╕рд╛рдорд╛рдиреНрдп рдлрд╝рдВрдХреНрд╢рди рд╣реЛрддреЗ рд╣реИрдВ: m рдЖрдпрд╛рдд рдХрд░реЗрдВ, рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ, рд╡реЗрд░рд┐рдПрдмрд▓реНрд╕ рдХреЛ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░реЗрдВред рд╡реЗрд░рд┐рдПрдмрд▓реНрд╕ рд╕рд╣рд┐рдд рд╕рдм рдХреБрдЫ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЯрд╛рдЗрдкреНрдб рд╣реИред

      src/routes/index.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import { buildLocalizedHead } from "@/i18n/seo";
      import { m } from "@/paraglide/messages";
      import { getLocale } from "@/paraglide/runtime";
      
      export const Route = createFileRoute("/")({
        head: () =>
          buildLocalizedHead({
            path: "/",
            locale: getLocale(),
            title: m.home_meta_title(),
            description: m.home_meta_description(),
          }),
        component: HomePage,
      });
      
      function HomePage() {
        return <h1>{m.home_title({ name: "TanStack" })}</h1>;
      }
      
      src/routes/about.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import { buildLocalizedHead } from "@/i18n/seo";
      import { m } from "@/paraglide/messages";
      import { getLocale } from "@/paraglide/runtime";
      
      export const Route = createFileRoute("/about")({
        head: () =>
          buildLocalizedHead({
            path: "/about",
            locale: getLocale(),
            title: m.about_meta_title(),
            description: m.about_meta_description(),
          }),
        component: AboutPage,
      });
      
      function AboutPage() {
        return <h1>{m.about_title()}</h1>;
      }
      
      рдПрдХ рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдПрдХ рд╕реНрдкрд╖реНрдЯ рд▓реЛрдХреЗрд▓ рднреА рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ: m.about_title({}, { locale: "fr" })ред рдпрд╣ рд╕рд░реНрд╡рд░ рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧреА рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдЕрдиреБрд░реЛрдз рдХреА рднрд╛рд╖рд╛ рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рднрд╛рд╖рд╛ рдХреЛ рд░реЗрдВрдбрд░ рдХрд░рддрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдИрдореЗрд▓ред
    9. рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдХреА рднрд╛рд╖рд╛ рдмрджрд▓реЗрдВ

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

      рд╕реНрд╡рд┐рдЪрд░ рдХреЛ localizeHref рдХреЗ рд╕рд╛рде рд▓рд┐рдВрдХреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рд░реЗрдВрдбрд░ рдХрд░реЗрдВ, рддрд╛рдХрд┐ рдХреНрд░реЙрд▓рд░реНрд╕ рд╣рд░ рднрд╛рд╖рд╛ рдХреЛ рдЦреЛрдЬ рд╕рдХреЗрдВред setLocale рдкрд╕рдВрдж рдХреЛ рдХреБрдХреА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдирдИ рднрд╛рд╖рд╛ рдореЗрдВ рдкреЗрдЬ рдХреЛ рдкреБрдирдГ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ: рдПрдХ рдкреВрд░реНрдг рд░реАрд▓реЛрдб рдЕрдкреЗрдХреНрд╖рд┐рдд Paraglide рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди React рд╕реНрдерд┐рддрд┐ рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдиреЗ рдХреЗ рдмрдЬрд╛рдп рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдкрд░ рд▓реЛрдХреЗрд▓ рдкрдврд╝рддреЗ рд╣реИрдВред

      src/components/LocaleSwitcher.tsx
      import { useLocation } from "@tanstack/react-router";
      import { getLocaleName } from "@/i18n/config";
      import { m } from "@/paraglide/messages";
      import {
        getLocale,
        type Locale,
        locales,
        localizeHref,
        setLocale,
      } from "@/paraglide/runtime";
      
      export const LocaleSwitcher = () => {
        // Router pathname, already de-localized by the rewrite: "/about"
        const { pathname } = useLocation();
        const activeLocale = getLocale();
      
        const handleClick = (event: React.MouseEvent, locale: Locale) => {
          event.preventDefault();
          setLocale(locale); // Sets the cookie and reloads on the localized URL
        };
      
        return (
          <nav aria-label={m.locale_switcher_label()}>
            <ul>
              {locales.map((locale) => (
                <li key={locale}>
                  <a
                    href={localizeHref(pathname, { locale })}
                    hrefLang={locale}
                    lang={locale}
                    aria-current={locale === activeLocale ? "page" : undefined}
                    onClick={(event) => handleClick(event, locale)}
                  >
                    {getLocaleName(locale)}
                  </a>
                </li>
              ))}
            </ul>
          </nav>
        );
      };
      
    10. рдЕрдкрдиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХрд╛ рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд░реЗрдВ

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

      рдкреНрд░рддреНрдпреЗрдХ рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдг рдЕрдкрдиреЗ рджрдо рдкрд░ рд░реИрдВрдХ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдмрд╢рд░реНрддреЗ рдкреНрд░рддреНрдпреЗрдХ рдкреЗрдЬ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗ:

      • рдПрдХ рдЕрдиреБрд╡рд╛рджрд┐рдд <title> рдФрд░ description;
      • рд╕реНрд╡рдпрдВ рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ canonical URL;
      • рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдПрдХ hreflang alternate, рд╕рд╛рде рд╣реА x-default;
      • Open Graph og:locale, og:locale:alternate рдФрд░ og:url;
      • inLanguage рдХреЗ рд╕рд╛рде JSON-LDред

      Paraglide рдХрд╛ localizeUrl рдЖрдкрдХреЗ urlPatterns рд╕реЗ рд╡реИрдХрд▓реНрдкрд┐рдХ URL рдмрдирд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╡реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд░реВрдЯрд┐рдВрдЧ рд╕реЗ рдХрднреА рднрдЯрдХ рдирд╣реАрдВ рд╕рдХрддреЗ:

      src/i18n/seo.ts
      import { baseLocale, type Locale, locales } from "@/paraglide/runtime";
      import { getAbsoluteUrl, openGraphLocales } from "./config";
      
      type LocalizedHeadOptions = {
        /** De-localized path, e.g. "/about" */
        path: string;
        locale: Locale;
        title: string;
        description: string;
      };
      
      export const buildLocalizedHead = ({
        path,
        locale,
        title,
        description,
      }: LocalizedHeadOptions) => {
        const url = getAbsoluteUrl(path, locale);
      
        return {
          meta: [
            { title },
            { name: "description", content: description },
            { property: "og:type", content: "website" },
            { property: "og:title", content: title },
            { property: "og:description", content: description },
            { property: "og:url", content: url },
            { property: "og:locale", content: openGraphLocales[locale] },
            ...locales
              .filter((alternateLocale) => alternateLocale !== locale)
              .map((alternateLocale) => ({
                property: "og:locale:alternate",
                content: openGraphLocales[alternateLocale],
              })),
          ],
          links: [
            { rel: "canonical", href: url },
            ...locales.map((alternateLocale) => ({
              rel: "alternate",
              hrefLang: alternateLocale,
              href: getAbsoluteUrl(path, alternateLocale),
            })),
            {
              rel: "alternate",
              hrefLang: "x-default",
              href: getAbsoluteUrl(path, baseLocale),
            },
          ],
          scripts: [
            {
              type: "application/ld+json",
              children: JSON.stringify({
                "@context": "https://schema.org",
                "@type": "WebPage",
                name: title,
                description,
                url,
                inLanguage: locale,
              }),
            },
          ],
        };
      };
      
    11. рдЕрдкрдиреЗ рд╕рд╛рдЗрдЯрдореИрдк рдХрд╛ рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд░реЗрдВ

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

      рдПрдХ рдмрд╣реБрднрд╛рд╖реА рд╕рд╛рдЗрдЯрдореИрдк рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХреЗрд▓ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ URL рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ xhtml:link рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ рд╕рднреА рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреА рд╣реИ:

      src/routes/sitemap[.]xml.ts
      import { createFileRoute } from "@tanstack/react-router";
      import { getAbsoluteUrl } from "@/i18n/config";
      import { baseLocale, locales } from "@/paraglide/runtime";
      
      type SitemapPage = {
        path: string;
        changeFrequency: "daily" | "weekly" | "monthly";
        priority: number;
      };
      
      export const sitemapPages: SitemapPage[] = [
        { path: "/", changeFrequency: "daily", priority: 1.0 },
        { path: "/about", changeFrequency: "monthly", priority: 0.8 },
      ];
      
      const buildAlternateLinks = (path: string): string =>
        [
          ...locales.map(
            (locale) =>
              `<xhtml:link rel="alternate" hreflang="${locale}" href="${getAbsoluteUrl(path, locale)}"/>`
          ),
          `<xhtml:link rel="alternate" hreflang="x-default" href="${getAbsoluteUrl(path, baseLocale)}"/>`,
        ].join("");
      
      const buildSitemap = (): string => {
        const urls = sitemapPages.flatMap((page) =>
          locales.map(
            (locale) =>
              `<url><loc>${getAbsoluteUrl(page.path, locale)}</loc>${buildAlternateLinks(page.path)}<changefreq>${page.changeFrequency}</changefreq><priority>${page.priority}</priority></url>`
          )
        );
      
        return `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">${urls.join("")}</urlset>`;
      };
      
      export const Route = createFileRoute("/sitemap.xml")({
        server: {
          handlers: {
            GET: () =>
              new Response(buildSitemap(), {
                headers: { "Content-Type": "application/xml; charset=utf-8" },
              }),
          },
        },
      });
      
    12. рдЕрдкрдиреЗ robots.txt рдХрд╛ рдЕрдВрддрд░реНрд░рд╛рд╖реНрдЯреНрд░реАрдпрдХрд░рдг рдХрд░реЗрдВ

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

      рдирд┐рдЬреА рд░реВрдЯреНрд╕ (Private routes) рд╣рд░ рднрд╛рд╖рд╛ рдореЗрдВ рдореМрдЬреВрдж рд╣реЛрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП Disallow рдирд┐рдпрдореЛрдВ рдореЗрдВ рд╣рд░ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкрде рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рд╕реНрдЯрд╛рд░реНрдЯрд░ рдиреЗ public/robots.txt рдмрдирд╛рдпрд╛ рд╣реИ рддреЛ рдЙрд╕реЗ рд╣рдЯрд╛ рджреЗрдВ, рдлрд┐рд░ рдЗрд╕реЗ рдПрдХ рд░реВрдЯ рд╕реЗ рд╕рд░реНрд╡ рдХрд░реЗрдВ:

      src/routes/robots[.]txt.ts
      import { createFileRoute } from "@tanstack/react-router";
      import { siteUrl } from "@/i18n/config";
      import { locales, localizeHref } from "@/paraglide/runtime";
      
      const privatePaths = ["/dashboard", "/admin"];
      
      const buildRobots = (): string => {
        // /dashboard, /fr/dashboard, /es/dashboard...
        const disallowRules = privatePaths.flatMap((path) =>
          locales.map((locale) => `Disallow: ${localizeHref(path, { locale })}`)
        );
      
        return [
          "User-agent: *",
          "Allow: /",
          ...disallowRules,
          "",
          `Sitemap: ${siteUrl}/sitemap.xml`,
        ].join("\n");
      };
      
      export const Route = createFileRoute("/robots.txt")({
        server: {
          handlers: {
            GET: () =>
              new Response(buildRobots(), {
                headers: { "Content-Type": "text/plain; charset=utf-8" },
              }),
          },
        },
      });
      
    13. рдкреНрд░рддреНрдпреЗрдХ рд▓реЛрдХреЗрд▓ рдХреЛ рдкреНрд░реА-рд░реЗрдВрдбрд░ рдХрд░реЗрдВ

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

      рдкреНрд░рддреНрдпреЗрдХ рдкреЗрдЬ рдХреЗ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдкрде рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗрдВ рддрд╛рдХрд┐ TanStack Start рд╕рднреА рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рдкреНрд░реА-рд░реЗрдВрдбрд░ рдХрд░ рд╕рдХреЗред localizeHref рдмрд┐рдирд╛ рдХрд┐рд╕реА рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдирд┐рд░реНрднрд░рддрд╛ рд╡рд╛рд▓рд╛ рдЬрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдХреЛрдб рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ vite.config.ts рдореЗрдВ рдЪрд▓ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд╝рд╛рдЗрд▓ рдХреЗрд╡рд▓ рдкрд╣рд▓реЗ рд╕рдВрдХрд▓рди рдХреЗ рдмрд╛рдж рд╣реА рдореМрдЬреВрдж рд╣реЛрддреА рд╣реИред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЕрдиреБрд╕рд╛рд░ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдкрдереЛрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдирд╛ рдЙрд╕ рдХреНрд░рдо рдирд┐рд░реНрдзрд╛рд░рдг рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИ:

      vite.config.ts
      import { paraglideVitePlugin } from "@inlang/paraglide-js";
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";
      import viteReact from "@vitejs/plugin-react";
      import { defineConfig } from "vite";
      
      const prefixedLocales = ["fr", "es"]; // Default locale "en" is unprefixed
      const pagePaths = ["/", "/about"];
      
      const localizedPages = pagePaths.flatMap((path) => [
        path,
        ...prefixedLocales.map((locale) =>
          path === "/" ? `/${locale}` : `/${locale}${path}`
        ),
      ]);
      
      export default defineConfig({
        plugins: [
          paraglideVitePlugin({
            // ... same options as step 3
            project: "./project.inlang",
            outdir: "./src/paraglide",
          }),
          tanstackStart({
            prerender: { enabled: true, crawlLinks: true },
            pages: [
              ...localizedPages.map((path) => ({
                path,
                prerender: { enabled: true },
              })),
              { path: "/sitemap.xml", prerender: { enabled: true } },
              { path: "/robots.txt", prerender: { enabled: true } },
            ],
          }),
          viteReact(),
        ],
      });
      

      рдЪреВрдБрдХрд┐ рд╕реНрд╡рд┐рдЪрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓рд┐рдВрдХреНрд╕ рд░реЗрдВрдбрд░ рдХрд░рддрд╛ рд╣реИ, crawlLinks: true рдЙрди рдкреЗрдЬреЛрдВ рдХреЛ рднреА рдЦреЛрдЬ рд▓реЗрддрд╛ рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдк рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдирд╛ рднреВрд▓ рдЧрдП рдереЗред

    14. рд╕реНрдерд╛рдиреАрдпрдХреГрдд 404 рдкреЗрдЬреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓реЗрдВ

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

      рд░реАрд░рд╛рдЗрдЯ рдХреЗ рд╕рд╛рде, /fr/does-not-exist рдХрд╛ рдорд┐рд▓рд╛рди /does-not-exist рдХреЗ рд░реВрдк рдореЗрдВ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ getLocale() рдЕрднреА рднреА fr рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЪрд░рдг 7 рдХрд╛ рд░реВрдЯ notFoundComponent рдлрд╝реНрд░реЗрдВрдЪ рдореЗрдВ рд░реЗрдВрдбрд░ рд╣реЛрддрд╛ рд╣реИред рдПрдХ рдХреИрдЪ-рдСрд▓ рд░реВрдЯ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЧрд╣рд░реЗ рдкрде рднреА рдЗрд╕ рддрдХ рдкрд╣реБрдВрдЪреЗрдВред рдкреЗрдЬ рдХреЛ noindex рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВ: React 19 <meta> рдХреЛ <head> рдореЗрдВ рдлрд╣рд░рд╛рддрд╛ (hoist) рд╣реИред

      src/components/NotFound.tsx
      import { Link } from "@tanstack/react-router";
      import { m } from "@/paraglide/messages";
      
      export const NotFound = () => (
        <div>
          <meta name="robots" content="noindex" />
          <h1>{m.not_found_title()}</h1>
          <Link to="/">{m.not_found_back_home()}</Link>
        </div>
      );
      
      src/routes/$.tsx
      import { createFileRoute, notFound } from "@tanstack/react-router";
      
      export const Route = createFileRoute("/$")({
        beforeLoad: () => {
          throw notFound();
        },
      });
      
    15. рд╕рд░реНрд╡рд░ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдореЗрдВ рд▓реЛрдХреЗрд▓ рддрдХ рдкрд╣реБрдБрдЪреЗрдВ

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

      рд╕рд░реНрд╡рд░ рдлрд╝рдВрдХреНрд╢рдВрд╕ Paraglide рдорд┐рдбрд▓рд╡реЗрдпрд░ рд╕реНрдХреЛрдк рдХреЗ рдЕрдВрджрд░ рдЪрд▓рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП getLocale() рд╡рд╣рд╛рдБ рднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:

      src/server/sendWelcomeEmail.ts
      import { createServerFn } from "@tanstack/react-start";
      import { m } from "@/paraglide/messages";
      import { getLocale } from "@/paraglide/runtime";
      
      export const sendWelcomeEmail = createServerFn({ method: "POST" })
        .inputValidator((email: string) => email)
        .handler(async ({ data: email }) => {
          const locale = getLocale();
          const subject = m.home_meta_title({}, { locale });
      
          // await mailer.send({ to: email, subject, locale });
          return { email, subject, locale };
        });
      
    16. Intlayer рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░реЗрдВ

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

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

      • рд▓реЛрдХреЗрд▓реНрд╕: Intlayer рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдЧрддрд┐рд╢реАрд▓ рд╢рдмреНрджрдХреЛрд╢ (dynamic dictionaries) рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ (рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ 0% рд▓реЛрдХреЗрд▓ рд▓реАрдХ), рдЬрдмрдХрд┐ рдкреНрд░рддреНрдпреЗрдХ Paraglide рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕рднреА рд▓реЛрдХреЗрд▓реНрд╕ рд╣реЛрддреЗ рд╣реИрдВ (49.7%)ред
      • рд╕рд╛рдордЧреНрд░реА рд╕рдВрдЧрдарди: рд╕рд╛рдордЧреНрд░реА рдкреНрд░рддреНрдпреЗрдХ рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреЗ рдмрдЧрд▓ рдореЗрдВ .content.ts рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ, рдпрд╛ рдХреЗрдВрджреНрд░реАрдХреГрдд рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рд░рд╣ рд╕рдХрддреА рд╣реИред рджреЗрдЦреЗрдВ рдкреНрд░рддрд┐-рдХрдВрдкреЛрдиреЗрдВрдЯ рдмрдирд╛рдо рдХреЗрдВрджреНрд░реАрдХреГрдд i18nред
      • рд▓реЛрдХреЗрд▓ рд╕реНрд╡рд┐рдЪ: рд╕рд╛рдордЧреНрд░реА рдХреЛ React рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рд╕реЗ рдкрдврд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд▓реЛрдХреЗрд▓ рдмрджрд▓рдиреЗ рдкрд░ рдмрд┐рдирд╛ рд░реАрд▓реЛрдб рдХреЗ рд░реА-рд░реЗрдВрдбрд░ рд╣реЛрддрд╛ рд╣реИред
      • рдЬрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдХреЛрдб: src рдХреЗ рдЕрдВрджрд░ рдХреБрдЫ рднреА рдЬрдирд░реЗрдЯ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХрдорд┐рдЯ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлрд┐рд░ рд╕реЗ рдЬрдирд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИред

      рдпрджрд┐ рдЖрдк Paraglide рдХреЗ рдмрдЬрд╛рдп рдХрд┐рд╕реА рдЕрдиреНрдп рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдЖрддреЗ рд╣реИрдВ, рддреЛ рд╕рдВрдЧрддрддрд╛ рдПрдбреЗрдкреНрдЯрд░ (compat adapters) use-intl, next-intl, react-i18next, react-intl рдпрд╛ Lingui API рдХреЛ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реИрдВ рдФрд░ рд░рдирдЯрд╛рдЗрдо рдХреА рдЕрджрд▓рд╛-рдмрджрд▓реА рдХрд░рддреЗ рд╣реИрдВред

      рджреЗрдЦреЗрдВ рдХреНрдпрд╛ Intlayer, Paraglide рд╕реЗ рд╣рд▓реНрдХрд╛ рд╣реИ? рдФрд░ Intlayer TanStack Start рдЧрд╛рдЗрдбред

    17. Intlayer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░реЗрдВ

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

      Paraglide рдЕрдиреБрд╡рд╛рдж рд░реЗрдВрдбрд░ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЙрдиреНрд╣реЗрдВ рдмрдирд╛рдиреЗ (produce) рдореЗрдВ рдЖрдкрдХреА рдорджрдж рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред Intlayer рдореБрдлрд╝реНрдд рдФрд░ рдУрдкрди рд╕реЛрд░реНрд╕ рд╣реИ, рдФрд░ рдЗрд╕рдХреЗ рдЯреВрд▓реНрд╕ Paraglide рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдкрд░ рднреА рдорджрдж рдХрд░рддреЗ рд╣реИрдВ:

      • рдЕрдкрдиреА рдЦреБрдж рдХреА API рдХреА рдФрд░ рдкреНрд░рджрд╛рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ AI рдХреЗ рд╕рд╛рде рдЕрдиреБрд╡рд╛рдж рдХрд░реЗрдВред рджреЗрдЦреЗрдВ рдСрдЯреЛ рдлрд╝рд┐рд▓ рдФрд░ CLIред
      • sync JSON рдкреНрд▓рдЧрдЗрди рдХреЗ рд╕рд╛рде рдЕрдкрдиреА JSON рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕рддреНрдп рдХреЗ рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рд░рдЦреЗрдВред
      • CI рдореЗрдВ рдЕрдиреБрдкрд▓рдмреНрдз рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВред рджреЗрдЦреЗрдВ рдЕрдкрдиреЗ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ред
      • scan рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рде рдЫреВрдЯреЗ рд╣реБрдП hreflang, рдЧрд▓рдд canocinals рдФрд░ рд▓реЛрдХреЗрд▓ рд▓реАрдХ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреА рдкрд░рд┐рдирд┐рдпреЛрдЬрд┐рдд (deployed) рд╕рд╛рдЗрдЯ рдХреЛ рд╕реНрдХреИрди рдХрд░реЗрдВред

    рдЕрдХреНрд╕рд░ рдкреВрдЫреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рд╢реНрди

    рдпрд╣ рдПрдХ рдордЬрдмреВрдд рд╡рд┐рдХрд▓реНрдк рд╣реИ: рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ TanStack Router рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рд░рдирдЯрд╛рдЗрдо рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ рд╕рдмрд╕реЗ рдЫреЛрдЯрд╛ рд╣реИ (~1.8 KB gzip), рдФрд░ рд╕рдВрджреЗрд╢ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЯрд╛рдЗрдкреНрдб рд╣реИрдВред рдЗрд╕рдХреЗ рдиреБрдХрд╕рд╛рди рдпрд╣ рд╣реИрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕рднреА рд▓реЛрдХреЗрд▓реНрд╕ рд╣реЛрддреЗ рд╣реИрдВ, рдЬреЛ рдЕрдиреНрдп рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд╡рд┐рдЬрд╝рд┐рдЯрд░реНрд╕ рдХреЛ рдЕрдиреБрд╡рд╛рджрд┐рдд рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХрд╛ рд▓рдЧрднрдЧ рдЖрдзрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд▓реАрдХ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд▓реЛрдХреЗрд▓ рдмрджрд▓рдиреЗ рдкрд░ рдкреЗрдЬ рд░реАрд▓реЛрдб рд╣реЛрддрд╛ рд╣реИред

    рдирд╣реАрдВред рд░рд╛рдЙрдЯрд░ рдХрд╛ rewrite рд░реВрдЯ рдорд┐рд▓рд╛рди рд╕реЗ рдкрд╣рд▓реЗ рд▓реЛрдХреЗрд▓ рдкреНрд░реАрдлрд╝рд┐рдХреНрд╕ рдХреЛ рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рд▓рд┐рдВрдХреНрд╕ рдореЗрдВ рдЗрд╕реЗ рд╡рд╛рдкрд╕ рдЬреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдПрдХ рд╣реА about.tsx рдлрд╝рд╛рдЗрд▓ /about, /fr/about рдФрд░ /es/about рдХреЛ рд╕реЗрд╡рд╛ рджреЗрддреА рд╣реИред

    рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓ рдХрд┐рдП рдЬрд╛рдиреЗ рдкрд░ рд▓реЛрдХреЗрд▓ рдкрдврд╝рддреЗ рд╣реИрдВ, рд╡реЗ React рд╕реНрдЯреЗрдЯ рдХреА рд╕рджрд╕реНрдпрддрд╛ рдирд╣реАрдВ рд▓реЗрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП setLocale рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкреЗрдЬ рдХреЛ рдкреБрдирдГ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдирдИ рднрд╛рд╖рд╛ рдореЗрдВ рдлрд┐рд░ рд╕реЗ рд░реЗрдВрдбрд░ рд╣реЛ рд╕рдХреЗред рдЖрдк { reload: false } рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рдЖрдкрдХреЛ рдЯреНрд░реА рдХреЛ рд╕реНрд╡рдпрдВ рдлрд┐рд░ рд╕реЗ рд░реЗрдВрдбрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

    рдмреЗрд╣рддрд░ рд╣реЛрдЧрд╛ рдХрд┐ рдРрд╕рд╛ рди рдХрд░реЗрдВред рдпрд╣ рдлрд╝реЛрд▓реНрдбрд░ рд╣рд░ dev рдФрд░ build рдкрд░ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕реЗ рдХрдорд┐рдЯ рдХрд░рдиреЗ рд╕реЗ рдЬрдирд░реЗрдЯ рдХреА рдЧрдИ рдлрд╝рд╛рдЗрд▓реЛрдВ рдкрд░ рдорд░реНрдЬ рд╡рд┐рд░реЛрдз (merge conflicts) рд╣реЛрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп messages/*.json рдФрд░ project.inlang/settings.json рдХреЛ рдХрдорд┐рдЯ рдХрд░реЗрдВред

    рд░реВрдЯ head() рдореЗрдВ рдкреНрд░рддрд┐ рд▓реЛрдХреЗрд▓ рдПрдХ рдкреВрд░реНрдг (absolute) URL рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП localizeUrl рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рдФрд░ рдмреЗрд╕ рд▓реЛрдХреЗрд▓ рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рддреЗ рд╣реБрдП рдПрдХ x-default рдЬреЛрдбрд╝реЗрдВред рдЪрд░рдг 10 рдПрдХ рдкреБрди: рдкреНрд░рдпреЛрдЬреНрдп (reusable) рд╣реЗрд▓реНрдкрд░ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЪрд░рдг 11 рд╕рд╛рдЗрдЯрдореИрдк рдореЗрдВ рд╡рд╣реА рд╡рд┐рдХрд▓реНрдк рдЬреЛрдбрд╝рддрд╛ рд╣реИред

    рдЬрдм рдЖрдк outputStructure: "message-modules" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЕрдкреНрд░рдпреБрдХреНрдд рд╕рдВрджреЗрд╢реЛрдВ (messages) рдХреЛ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЕрдиреНрдп рдкреЗрдЬреЛрдВ рдХреА рд╕рд╛рдордЧреНрд░реА рд▓реАрдХ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рдЕрдкреНрд░рдпреБрдХреНрдд рд▓реЛрдХреЗрд▓реНрд╕ рдирд╣реАрдВ рд╣рдЯрд╛рдП рдЬрд╛рддреЗ: рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕рднреА рдЕрдиреБрд╡рд╛рдж рд╣реЛрддреЗ рд╣реИрдВ, рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдмреЗрдВрдЪрдорд╛рд░реНрдХ 49.7% рд▓реЛрдХреЗрд▓ рд▓реАрдХ рдорд╛рдкрддрд╛ рд╣реИред

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

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

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

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

    рдХреНрдпрд╛ Intlayer, Paraglide рд╕реЗ рд╣рд▓реНрдХрд╛ рд╣реИ?

    Paraglide i18n рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ рд▓рдЧрднрдЧ рд╢реВрдиреНрдп рднрд╛рд░ рд╡рд╛рд▓рд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдХреЛрдб рд╕реАрдзреЗ рдЖрдкрдХреЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдЬреЗрдирд░реЗрдЯ рд╣реЛрддрд╛ рд╣реИред рдЬрд╛рдирд┐рдП рдпрд╣ рд╡рдЬрди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд╣рд╛рдБ рдЬрд╛рддрд╛ рд╣реИ, рдкреНрд░рддрд┐-рдиреЛрдб рд▓реЛрдХреЗрд▓ рдкрдврд╝рдирд╛ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ Intlayer рдХрд╛ рдбрд╛рдпрдирд╛рдорд┐рдХ рд▓реЛрдбрд┐рдВрдЧ рд╕рднреА рдХреЗ рдмрдЬрд╛рдп рдХреЗрд╡рд▓ рдПрдХ рд▓реЛрдХреЗрд▓ рдХреИрд╕реЗ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИред

    Aymeric PINEAU