Автор:
    Дата створення:2025-03-25Останнє оновлення:2026-08-25

    Перекладіть свій вебсайт Tanstack Start + Solid.js за допомогою Intlayer | Інтернаціоналізація (i18n)

    Зміст

    Цей посібник демонструє, як інтегрувати Intlayer для безперешкодної інтернаціоналізації в проектах Tanstack Start із Solid.js, маршрутизацією з урахуванням локалі, підтримкою TypeScript та сучасними практиками розробки.

    Чому варто обрати Intlayer, а не альтернативи?

    Порівняно з основними рішеннями, такими як react-i18next або i18next, Intlayer пропонує рішення, яке має такі інтегровані оптимізації, як:

    Intlayer оптимізовано для ідеальної роботи з TanStack Start і Solid, пропонуючи багатомовну маршрутизацію, карту сайту та всі функції, необхідні для масштабування інтернаціоналізації (i18n).

    Замість того, щоб завантажувати великі файли JSON на свої сторінки, завантажуйте лише необхідний вміст. Intlayer допомагає зменшити розмір бандлу і сторінок до 50%.

    Організація вмісту за окремими областями (scoping) полегшує технічне обслуговування великомасштабних програм. Ви можете скопіювати або видалити окрему папку функцій без розумового навантаження перегляду всієї кодової бази вмісту. Крім того, Intlayer повністю типізований (fully typed), щоб забезпечити точність вашого вмісту.

    Спільне розміщення вмісту зменшує контекст, необхідний для великих мовних моделей (LLM). Intlayer також постачається з набором інструментів, наприклад CLI для перевірки відсутніх перекладів,LSP, MCP і agent skills, щоб зробити роботу розробника (DX) ще зручнішою для агентів ШІ.

    Використовуйте автоматизацію для перекладу в конвеєрі CI/CD за допомогою LLM за вашим вибором за рахунок вашого постачальника штучного інтелекту. Intlayer також пропонує компілятор для автоматизації екстракція вмісту, а також веб-платформу, щоб допомогти перекладати у фоновому режимі.

    Підключення великих файлів JSON до компонентів може призвести до проблем з продуктивністю та реакцією. Intlayer оптимізує завантаження вмісту під час збірки (build time).

    Більше ніж просто рішення i18n, Intlayer пропонує власний візуальний редактор і повний CMS, щоб допомогти вам керувати своїм багатомовним вмістом у реальному часі, спрощуючи співпрацю з перекладачами, копірайтерами та іншими членами команди. Контент можна зберігати локально та/або віддалено.


    Покроковий посібник із налаштування Intlayer у додатку Tanstack Start

    www.youtube.com
    ide.intlayer.org
    intlayer-tanstack-start-solid.vercel.app

    Перегляньте Шаблон додатка на GitHub.

    1. Створення проекту

      Спочатку створіть новий проект TanStack Start, дотримуючись посібника Початок нового проекту на вебсайті TanStack Start.

    2. Встановлення пакетів Intlayer

      Встановіть необхідні пакети за допомогою бажаного менеджера пакетів:

      bash
      npx intlayer init --interactive
      
      прапорець --interactive не є обов'язковим. Використовуйте intlayer-cli init, якщо ви є ШІ-агентом.
      Ця команда виявить ваше середовище та встановить необхідні пакети. Наприклад:
      bash
      npm install intlayer solid-intlayer
      npm install vite-intlayer --save-dev
      
      • intlayer

        Основний пакет, який надає інструменти інтернаціоналізації для керування конфігурацією, перекладу, декларування вмісту, транспіляції та команд CLI.

      • solid-intlayer Пакет, що інтегрує Intlayer у додаток Solid. Він надає контекстні провайдери та хуки для інтернаціоналізації Solid.

      • vite-intlayer Включає плагін Vite для інтеграції Intlayer з бандлером Vite, а також проміжне програмне забезпечення (middleware) для визначення бажаної локалі користувача, керування файлами cookie та обробки перенаправлення URL-адрес.

    3. Конфігурація вашого проекту

      Створіть файл конфігурації, щоб налаштувати мови вашого додатка:

      intlayer.config.ts
      import type { IntlayerConfig } from "intlayer";
      
      import { Locales } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          defaultLocale: Locales.ENGLISH,
          locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        },
      };
      
      export default config;
      
      За допомогою цього файлу конфігурації можна налаштувати локалізовані URL-адреси, перенаправлення через middleware, назви файлів cookie, розташування та розширення ваших декларацій вмісту, вимкнути логи Intlayer у консолі тощо. Повний список доступних параметрів див. у документації з конфігурації.
    4. Інтеграція Intlayer у вашу конфігурацію Vite

      Додайте плагін intlayer у вашу конфігурацію:

      vite.config.ts
      import { intlayer } from "vite-intlayer";
      import { defineConfig } from "vite";
      import { devtools } from "@tanstack/devtools-vite";
      import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
      import solidPlugin from "vite-plugin-solid";
      
      export default defineConfig({
        plugins: [
          devtools(),
          tanstackStart({
            router: {
              routeFileIgnorePattern:
                ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
            },
          }),
          solidPlugin({ ssr: true }),
          intlayer({
            proxy: {
              ignore: (req) => req.url?.startsWith("/api"),
            },
          }),
        ],
      });
      
      Плагін Vite intlayer() використовується для інтеграції Intlayer з Vite. Він забезпечує збірку файлів декларації вмісту та моніторить їх у режимі розробки. Він визначає змінні середовища Intlayer у додатку Vite. Крім того, він надає псевдоніми (aliases) для зменшення накладних витрат на продуктивність.
    5. Створення кореневого макета

      Налаштуйте свій кореневий макет для підтримки інтернаціоналізації, використовуючи useParams для визначення поточної локалі та встановлюючи атрибути lang і dir на тегу html.

      src/routes/__root.tsx
      import {
        HeadContent,
        Scripts,
        createRootRouteWithContext,
        getRouteApi,
      } from "@tanstack/solid-router";
      import { HydrationScript } from "solid-js/web";
      import { Suspense, type ParentComponent } from "solid-js";
      import { IntlayerProvider } from "solid-intlayer";
      import { defaultLocale, getHTMLTextDir } from "intlayer";
      
      const localeRoute = getRouteApi("/{-$locale}");
      
      export const Route = createRootRouteWithContext()({
        shellComponent: RootComponent,
      });
      
      const RootComponent: ParentComponent = (props) => {
        const params = localeRoute.useParams();
        const locale = params()?.locale ?? defaultLocale;
      
        return (
          <html dir={getHTMLTextDir(locale)} lang={locale}>
            <head>
              <HydrationScript />
              <HeadContent />
            </head>
            <body>
              <IntlayerProvider locale={locale}>
                <Suspense>{props.children}</Suspense>
              </IntlayerProvider>
              <Scripts />
            </body>
          </html>
        );
      };
      
    6. Створення макета локалі

      Створіть макет, який обробляє префікс локалі та виконує валідацію. Цей макет гарантуватиме, що обробляються лише дійсні локалі.

      Цей крок є необов'язковим, якщо вам не потрібно валідувати префікс локалі на рівні маршруту.
      src/routes/{-$locale}/route.tsx
      import { createFileRoute, Outlet, redirect } from "@tanstack/solid-router";
      import { validatePrefix } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}")({
        beforeLoad: ({ params }) => {
          const localeParam = params.locale;
      
          // Валідуйте префікс локалі
          const { isValid, localePrefix } = validatePrefix(localeParam);
      
          if (!isValid) {
            throw redirect({
              to: "/{-$locale}/404",
              params: { locale: localePrefix },
              replace: true,
            });
          }
        },
        component: Outlet,
      });
      
      Тут {-$locale} - це динамічний параметр маршруту, який замінюється поточною локаллю. Така нотація робить слот необов'язковим, дозволяючи йому працювати з такими режимами маршрутизації, як 'prefix-no-default' тощо.

      Майте на увазі, що цей слот може спричинити проблеми, якщо ви використовуєте кілька динамічних сегментів в одному маршруті (наприклад: /{-$locale}/other-path/$anotherDynamicPath/...). Для режиму 'prefix-all' ви можете віддати перевагу перемиканню слота на $locale. Для режиму 'no-prefix' або 'search-params' ви можете повністю видалити цей слот.

    7. Декларування вмісту

      Створюйте декларації вмісту та керуйте ними для зберігання перекладів:

      src/contents/page.content.ts
      import type { Dictionary } from "intlayer";
      
      import { t } from "intlayer";
      
      const appContent = {
        content: {
          links: {
            about: t({
              en: "About",
              es: "Acerca de",
              fr: "À propos",
            }),
            home: t({
              en: "Home",
              es: "Inicio",
              fr: "Accueil",
            }),
          },
          meta: {
            title: t({
              en: "Welcome to Intlayer + TanStack Router",
              es: "Bienvenido a Intlayer + TanStack Router",
              fr: "Bienvenue à Intlayer + TanStack Router",
            }),
            description: t({
              en: "This is an example of using Intlayer with TanStack Router",
              es: "Este es un ejemplo de uso de Intlayer con TanStack Router",
              fr: "Ceci est un exemple d'utilisation d'Intlayer avec TanStack Router",
            }),
          },
        },
        key: "app",
      } satisfies Dictionary;
      
      export default appContent;
      
      Ваші декларації вмісту можуть бути визначені будь-де у вашому додатку, за умови, що вони включені в каталог contentDir (за замовчуванням ./app). І відповідають розширенню файлу декларації вмісту (за замовчуванням .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).
      Докладнішу інформацію див. у документації з декларування вмісту.
    8. Використання компонентів та хуків з урахуванням локалі

      Створіть компонент LocalizedLink для навігації з урахуванням локалі:

      src/components/LocalizedLink.tsx
      import { Link, type LinkProps } from "@tanstack/solid-router";
      import { getPrefix } from "intlayer";
      import { useLocale } from "solid-intlayer";
      import type { JSX } from "solid-js";
      
      export const LOCALE_ROUTE = "{-$locale}" as const;
      
      export type RemoveLocaleParam<TVal> = TVal extends string
        ? RemoveLocaleFromString<TVal>
        : TVal;
      
      export type To = RemoveLocaleParam<LinkProps["to"]>;
      
      type CollapseDoubleSlashes<TString extends string> =
        TString extends `${infer THead}//${infer TTail}`
          ? CollapseDoubleSlashes<`${THead}/${TTail}`>
          : TString;
      
      export type LocalizedLinkProps = Omit<LinkProps, "to"> & {
        to?: To;
      } & JSX.AnchorHTMLAttributes<HTMLAnchorElement>;
      
      type RemoveAll<
        TString extends string,
        TSub extends string,
      > = TString extends `${infer THead}${TSub}${infer TTail}`
        ? RemoveAll<`${THead}${TTail}`, TSub>
        : TString;
      
      type RemoveLocaleFromString<TString extends string> = CollapseDoubleSlashes<
        RemoveAll<TString, typeof LOCALE_ROUTE>
      >;
      
      export const LocalizedLink = (props: LocalizedLinkProps) => {
        const { locale } = useLocale();
      
        return (
          <Link
            {...props}
            params={{
              locale: getPrefix(locale()).localePrefix,
              ...(typeof props.params === "object" ? props.params : {}),
            }}
            to={`/${LOCALE_ROUTE}${props.to ?? ""}` as LinkProps["to"]}
          />
        );
      };
      

      Цей компонент виконує дві функції:

      • Видалення непотрібного префікса {-$locale} з URL.
      • Вставлення параметра локалі в URL, щоб користувач був перенаправлений безпосередньо на локалізований маршрут.

      Потім ми можемо створити хук useLocalizedNavigate для програмної навігації:

      src/hooks/useLocalizedNavigate.tsx
      import { useNavigate } from "@tanstack/solid-router";
      import { getLocalizedUrl } from "intlayer";
      import { useLocale } from "solid-intlayer";
      
      export const useLocalizedNavigate = () => {
        const navigate = useNavigate();
        const { locale } = useLocale();
      
        const localizedNavigate = (to: string) => {
          const localizedTo = getLocalizedUrl(to, locale());
          return navigate({ to: localizedTo });
        };
      
        return localizedNavigate;
      };
      
    9. Використання Intlayer на ваших сторінках

      Використовуйте useIntlayer за замовчуванням: це рекомендований спосіб читати контент усередині компонентів, і компілятор розвʼязує його у локаль, яка рендериться. Звертайтеся до getIntlayer / getIntlayerAsync лише поза деревом Solid: у head маршрутів, лоадерах і серверних функціях.

      Отримуйте доступ до своїх словників вмісту в усьому додатку:

      Локалізована домашня сторінка

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      import { useIntlayer } from "solid-intlayer";
      import { LocalizedLink } from "@/components/LocalizedLink";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
      });
      
      function RouteComponent() {
        const content = useIntlayer("index-page");
      
        return (
          <main>
            <h1>{content.heroTitle}</h1>
            <p>{content.heroDesc}</p>
            <div>
              <LocalizedLink to="/">{content.navHome}</LocalizedLink>
              <LocalizedLink to="/about">{content.navAbout}</LocalizedLink>
            </div>
          </main>
        );
      }
      
      html
      <img src="{content.image.src.value}" alt="{content.image.value}" />
      <img src="{content.image.src.toString()}" alt="{content.image.toString()}" />
      <img src="{String(content.image.src)}" alt="{String(content.image)}" />
      

      In Solid, useIntlayer returns reactive content (e.g., content). You can access its properties directly.

      Щоб дізнатися більше про хук useIntlayer, зверніться до документації.

    10. Створення компонента перемикання локалі

      Створіть компонент, який дозволить користувачам змінювати мову:

      src/components/LocaleSwitcher.tsx
      import { useLocation } from "@tanstack/solid-router";
      import { getLocaleName, getPathWithoutLocale, getPrefix } from "intlayer";
      import { For } from "solid-js";
      import { useIntlayer, useLocale } from "solid-intlayer";
      import { LocalizedLink, type To } from "./LocalizedLink";
      
      export const LocaleSwitcher = () => {
        const content = useIntlayer("locale-switcher");
        const location = useLocation();
      
        const { availableLocales, locale, setLocale } = useLocale();
      
        const pathWithoutLocale = () => getPathWithoutLocale(location().pathname);
      
        return (
          <div class="flex flex-row gap-2">
            <For each={availableLocales}>
              {(localeEl) => (
                <LocalizedLink
                  aria-current={localeEl === locale() ? "page" : undefined}
                  onClick={() => setLocale(localeEl)}
                  params={{ locale: getPrefix(localeEl).localePrefix }}
                  to={pathWithoutLocale() as To}
                >
                  {getLocaleName(localeEl)}
                </LocalizedLink>
              )}
            </For>
          </div>
        );
      };
      
      export default LocaleSwitcher;
      

      у файлах Solid locale з useLocale є signal accessor. Використовуйте locale() (з дужками), щоб реактивно читати його поточне значення.

      Щоб дізнатися більше про хук useLocale, зверніться до документації.

    11. Керування атрибутами HTML

      Як було показано на кроці 5, ви можете керувати атрибутами lang і dir тегу html, використовуючи useParams у вашому кореневому компоненті. Це гарантує, що правильні атрибути встановлено як на сервері, так і на клієнті.

      src/routes/__root.tsx
      const RootComponent: ParentComponent = (props) => {
        const params = localeRoute.useParams();
        const locale = params()?.locale ?? defaultLocale;
      
        return (
          <html dir={getHTMLTextDir(locale)} lang={locale}>
            {/* ... */}
          </html>
        );
      };
      

    12. Додавання Middleware

      Ви також можете використовувати intlayerProxy, щоб додати маршрутизацію на стороні сервера до вашого додатка. Цей плагін автоматично визначатиме поточну локаль на основі URL-адреси та встановлюватиме відповідний файл cookie локалі. Якщо локаль не вказано, плагін визначить найбільш підходящу локаль на основі налаштувань мови браузера користувача. Якщо локаль не виявлено, він перенаправить на локаль за замовчуванням.

      Зверніть увагу, що для використання intlayerProxy у продакшні вам потрібно перенести пакет vite-intlayer з devDependencies до dependencies.
      З Intlayer v9, intlayerProxy() вбудований безпосередньо в плагін intlayer() і увімкнений за замовчуванням через опцію routing.enableProxy (true за замовчуванням). Реєстрація його окремо, як показано нижче, тепер необов'язкова: вона збережена для зворотної сумісності та для налаштувань, які потребують контролю порядку плагінів. Встановіть routing.enableProxy: false, щоб відмовитися. Див. примітки до випуску v9.
      vite.config.ts
      import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
      import solid from "vite-plugin-solid";
      import { nitro } from "nitro/vite";
      import { defineConfig } from "vite";
      import { intlayer } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          nitro(),
          intlayer({
            proxy: {
              ignore: (req) => req.url?.startsWith("/api"),
            },
          }),
          tanstackStart({
            router: {
              routeFileIgnorePattern:
                ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
            },
          }),
          solid(),
        ],
      });
      

    13. Інтернаціоналізація ваших метаданих

      getIntlayer розвʼязується синхронно за обʼєднаним словником, тобто тим, що містить усі оголошені локалі. head лишається синхронним і нічого не очікує, але весь багатомовний словник потрапляє до чанка маршруту, який надсилається у браузер.

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      import {
        defaultLocale,
        getIntlayer,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        head: ({ params }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // The path for this route
      
          const metaContent = getIntlayer("app", locale);
      
          return {
            links: [
              // Canonical link: Points to the current localized page
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: Tell Google about all localized versions
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: For users in unmatched languages
              // Define the default fallback locale (usually your primary language)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: metaContent.title },
              { name: "description", content: metaContent.meta.description },
            ],
          };
        },
      });
      

      Найкраще для невеликих словників метаданих, кількох локалей або на етапі прототипування.

      getIntlayerAsync (доступний починаючи з v9.4) поводиться як getIntlayer, але плагін збірки спрямовує його на пер-локальний чанк у .intlayer/dynamic_dictionaries/ замість обʼєднаного словника. Тож сторінка віддає лише ту локаль, яку рендерить. Оскільки цей чанк завантажується на вимогу, head стає async:

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      import {
        defaultLocale,
        getIntlayerAsync,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        head: async ({ params }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // The path for this route
      
          const metaContent = await getIntlayerAsync("app", locale);
      
          return {
            links: [
              // Canonical link: Points to the current localized page
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: Tell Google about all localized versions
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: For users in unmatched languages
              // Define the default fallback locale (usually your primary language)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: metaContent.title },
              { name: "description", content: metaContent.meta.description },
            ],
          };
        },
      });
      
      Якщо head читає кілька словників, розвʼязуйте їх через Promise.all: очікування кожного getIntlayerAsync окремим рядком вибудовує запити в ланцюжок замість паралельного виконання.

      Компроміс: динамічний імпорт розвʼязується під час виконання head, на критичному шляху рендерингу документа. На «холодному» маршруті це затримує head на кілька мілісекунд і може трохи погіршити LCP.

      Розвʼяжіть словник у loader маршруту й прочитайте його назад із loaderData у head. Лоадери збіглих маршрутів виконуються паралельно, а staleTime: Infinity повідомляє TanStack Router, що результат ніколи не застаріває, тож пер-локальний чанк розвʼязується один раз, а далі віддається з кешу роутера, лишаючи head синхронним.

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      import {
        defaultLocale,
        getIntlayerAsync,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        // Resolved in parallel with the other matched routes, off the head critical path
        loader: async ({ params }) => {
          const { locale = defaultLocale } = params;
      
          return { metaContent: await getIntlayerAsync("app", locale) };
        },
        // The dictionary never changes for a given locale: resolve the chunk once
        staleTime: Infinity,
        head: ({ params, loaderData }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // The path for this route
      
          return {
            links: [
              // Canonical link: Points to the current localized page
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: Tell Google about all localized versions
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: For users in unmatched languages
              // Define the default fallback locale (usually your primary language)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: loaderData?.metaContent.title },
              {
                name: "description",
                content: loaderData?.metaContent.meta.description,
              },
            ],
          };
        },
      });
      
      head може бути викликаний до завершення лоадера, тому loaderData типізовано як можливо undefined. Залиште опціональний ланцюжок або повертайте запасний заголовок.

      Ви зберігаєте пер-локальний чанк, не сплачуючи його вартість на критичному шляху head. Ціною стає DX: контент доводиться явно передавати з лоадера у head через loaderData.

      Яке розвʼязання обрати?

      Статичне розвʼязання Динамічне розвʼязання Кешоване динамічне розвʼязання
      API getIntlayer getIntlayerAsync (v9.4+) getIntlayerAsync у loader (v9.4+)
      Сигнатура head синхронна async синхронна, читає loaderData
      Надіслані локалі усі оголошені локалі лише запитана локаль лише запитана локаль
      Клієнтські переходи нічого розвʼязувати виконується знову за кожного збігу віддається з кешу роутера
      DX найпростіший один await контент передається через loaderData

    14. Отримання локалі у ваших діях на сервері

      Ви можете захотіти отримати доступ до поточної локалі з ваших серверних дій (server actions) або кінцевих точок API. Ви можете зробити це за допомогою допоміжної функції getLocale з intlayer.

      Ось приклад з використанням серверних функцій TanStack Start:

      src/routes/{-$locale}/index.tsx
      import { createServerFn } from "@tanstack/solid-start";
      import {
        getRequestHeader,
        getRequestHeaders,
      } from "@tanstack/solid-start/server";
      import { getCookie, getIntlayer, getLocale } from "intlayer";
      
      export const getLocaleServer = createServerFn().handler(async () => {
        const locale = await getLocale({
          // Отримати кукі з запиту (за замовчуванням: 'INTLAYER_LOCALE')
          getCookie: (name) => {
            const cookieString = getRequestHeader("cookie");
      
            return getCookie(name, cookieString);
          },
          // Отримати заголовок з запиту (за замовчуванням: 'x-intlayer-locale')
          // Запасний варіант з використанням узгодження Accept-Language
          getHeader: (name) => getRequestHeader(name),
        });
      
        // Отримати якийсь вміст за допомогою getIntlayer()
        const content = getIntlayer("app", locale);
      
        return { locale, content };
      });
      

    15. Керування сторінками &quot;не знайдено&quot; (404)

      Необов'язково

      Коли користувач відвідує неіснуючу сторінку, ви можете відобразити власну сторінку "не знайдено", і префікс локалі може вплинути на те, як ця сторінка запускається.

      Розуміння обробки 404 в TanStack Router з префіксами локалі

      У TanStack Router обробка сторінок 404 з локалізованими маршрутами вимагає багаторівневого підходу:

      1. Спеціальний маршрут 404: Окремий маршрут для відображення інтерфейсу 404
      2. Валідація на рівні маршруту: Перевіряє префікси локалі та перенаправляє недійсні на 404
      3. Catch-all маршрут: Захоплює будь-які шляхи, що не збігаються, всередині сегмента локалі
      src/routes/{-$locale}/404.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      
      // Це створює спеціальний маршрут /[locale]/404
      // Він використовується і як прямий маршрут, і як компонент в інших файлах
      export const Route = createFileRoute("/{-$locale}/404")({
        component: NotFoundComponent,
      });
      
      // Експортується окремо, щоб його можна було повторно використовувати в notFoundComponent та catch-all маршрутах
      export function NotFoundComponent() {
        return (
          <div>
            <h1>404</h1>
          </div>
        );
      }
      
      src/routes/{-$locale}/route.tsx
      import { createFileRoute, Outlet, redirect } from "@tanstack/solid-router";
      import { validatePrefix } from "intlayer";
      import { NotFoundComponent } from "./404";
      
      export const Route = createFileRoute("/{-$locale}")({
        // beforeLoad запускається перед рендерингом маршруту (і на сервері, і на клієнті)
        // Це ідеальне місце для валідації префікса локалі
        beforeLoad: ({ params }) => {
          const localeParam = params.locale;
      
          // validatePrefix перевіряє, чи є локаль дійсною відповідно до вашої конфігурації intlayer
          const { isValid, localePrefix } = validatePrefix(localeParam);
      
          if (!isValid) {
            // Недійсний префікс локалі - перенаправлення на сторінку 404 з дійсним префіксом локалі
            throw redirect({
              to: "/{-$locale}/404",
              params: { locale: localePrefix },
            });
          }
        },
        component: Outlet,
        // notFoundComponent викликається, коли дочірній маршрут не існує
        // напр.: /en/неіснуюча-сторінка запускає це всередині макета /en
        notFoundComponent: NotFoundComponent,
      });
      
      src/routes/{-$locale}/$.tsx
      import { createFileRoute } from "@tanstack/solid-router";
      
      import { NotFoundComponent } from "./404";
      
      // Маршрут $ (splat/catch-all) збігається з будь-яким шляхом, що не збігається з іншими маршрутами
      // напр.: /en/якийсь/глибоко/вкладений/недійсний/шлях
      // Це гарантує, що ВСІ невідповідні шляхи всередині локалі показують сторінку 404
      // Без цього глибокі невідповідні шляхи могли б показувати порожню сторінку або помилку
      export const Route = createFileRoute("/{-$locale}/$")({
        component: NotFoundComponent,
      });
      
    16. Вилучення вмісту з ваших компонентів

      Необов'язково

      Якщо у вас є існуюча кодова база, трансформація тисяч файлів може зайняти багато часу.

      Щоб полегшити цей процес, Intlayer пропонує компілятор / екстрактор для трансформації ваших компонентів та екстракція вмісту.

      Щоб налаштувати його, ви можете додати розділ compiler у свій файл intlayer.config.ts:

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... Решта вашої конфігурації
        compiler: {
          /**
           * Вказує, чи слід увімкнути компілятор.
           */
          enabled: true,
      
          /**
           * Визначає шлях до вихідних файлів
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * Вказує, чи слід зберігати компоненти після їх трансформації.
           *
           * - Якщо `true`, компілятор перезапише файл компонента на диску. Таким чином, трансформація буде постійною, і компілятор пропустить трансформацію для наступного процесу. У такий спосіб компілятор може трансформувати додаток, після чого його можна буде видалити.
           *
           * - Якщо `false`, компілятор вставить виклик функції `useIntlayer()` у код лише у вихідних даних збірки, зберігши базову кодову базу недоторканою. Трансформація проводитиметься лише в пам'яті.
           */
          saveComponents: false,
      
          /**
           * Префікс ключа словника
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;
      

      Запустіть екстрактор, щоб трансформувати ваші компоненти та вилучити вміст

      bash
      npx intlayer extract
      
      Since v9, the intlayerCompiler is included in the intlayer plugin. So you don't need to add it manually.

      Оновіть свій vite.config.ts, щоб включити плагін intlayerCompiler:

      vite.config.ts
      import { intlayer, intlayerCompiler } from "vite-intlayer";
      import { defineConfig } from "vite";
      import { devtools } from "@tanstack/devtools-vite";
      import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
      import solidPlugin from "vite-plugin-solid";
      
      export default defineConfig({
        plugins: [
          devtools(),
          tanstackStart({
            router: {
              routeFileIgnorePattern:
                ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
            },
          }),
          solidPlugin({ ssr: true }),
          intlayer(),
          intlayerCompiler(), // Adds the compiler plugin
        ],
      });
      
      bash
      npm run build # Або rpm run dev
      

    17. Попередній рендеринг і генерація Sitemap

      Intlayer поставляється з вбудованим генератором карти сайту, який допомагає легко створити карту сайту для вашого додатку. Він обробляє локалізовані маршрути та додає необхідні метаданні для пошукових систем.

      Карта сайту, згенерована Intlayer, підтримує простір імен xhtml:link (Hreflang XML Extensions). На відміну від стандартних генераторів карт сайту, які просто перелічують сирі URL-адреси, Intlayer автоматично створює необхідні двосторонні посилання між усіма мовними версіями сторінки (наприклад, /about, /about?lang=fr та /about?lang=es). Це гарантує, що пошукові системи коректно індексують та надають правильну мовну версію потрібній аудиторії.

      Щоб це використати, вам спочатку потрібно налаштувати vite.config.ts для ввімкнення попередньої обробки локалізованих маршрутів і вимкнення генерування карти сайту за замовчуванням TanStack Start.

      vite.config.ts
      import { localeMap, localeFlatMap } from "intlayer";
      // ... інші імпорти
      
      export const pathList = ["", "/about", "/404"];
      
      const localizedPages = localeFlatMap(({ urlPrefix }) =>
        pathList.map((path) => ({
          path: `${urlPrefix}${path}`,
          prerender: {
            enabled: true,
          },
        }))
      );
      
      export default defineConfig({
        plugins: [
          // ... інші плагіни
          tanstackStart({
            // ... інша конфігурація
            sitemap: {
              enabled: false,
            },
            prerender: {
              enabled: true,
              crawlLinks: false,
              concurrency: 10,
            },
            pages: localizedPages,
          }),
        ],
      });
      

      Потім створіть маршрут src/routes/sitemap[.]xml.ts, який використовує функцію generateSitemap:

      src/routes/sitemap[.]xml.ts
      import { createFileRoute } from "@tanstack/solid-router";
      import { generateSitemap } from "intlayer";
      
      const SITE_URL = "http://localhost:3000";
      
      export const Route = createFileRoute("/sitemap.xml")({
        server: {
          handlers: {
            GET: async () => {
              const sitemap = generateSitemap(
                [
                  { path: "/", changefreq: "daily", priority: 1.0 },
                  { path: "/about", changefreq: "monthly", priority: 0.8 },
                ],
                { siteUrl: SITE_URL }
              );
      
              return new Response(sitemap, {
                headers: { "Content-Type": "application/xml" },
              });
            },
          },
        },
      });
      

    18. Конфігурація TypeScript

      Intlayer використовує розширення модулів (module augmentation), щоб отримати переваги TypeScript і зміцнити вашу кодову базу.

      Переконайтеся, що ваша конфігурація TypeScript включає автоматично згенеровані типи:

      tsconfig.json
      {
        // ... ваші існуючі налаштування
        include: [
          // ... ваші існуючі включення
          ".intlayer/**/*.ts", // Включити автоматично згенеровані типи
        ],
      }
      

    Конфігурація Git

    Ми рекомендуємо ігнорувати файли, згенеровані Intlayer. Це дозволяє уникнути їх фіксації (commit) у вашому репозиторії Git.

    Для цього ви можете додати наступні інструкції до свого файлу .gitignore:

    .gitignore
    # Ігнорувати файли, згенеровані Intlayer
    .intlayer
    

    Розширення VS Code

    Щоб покращити свій досвід розробки з Intlayer, ви можете встановити офіційне розширення Intlayer VS Code.

    Встановити з VS Code Marketplace

    Це розширення пропонує:

    • Автодоповнення для ключів перекладу.
    • Виявлення помилок у реальному часі для відсутніх перекладів.
    • Вбудований попередній перегляд (inline previews) перекладеного вмісту.
    • Швидкі дії для легкого створення та оновлення перекладів.

    Докладніше про те, як користуватися розширенням, див. у документації до розширення Intlayer VS Code.


    Подальші кроки

    Щоб піти далі, ви можете впровадити візуальний редактор або винести свій вміст за допомогою CMS.


    Посилання на документацію