Autor:
    Data utworzenia:2026-09-09Ostatnia aktualizacja:2026-09-27

    Przetłumacz swoją stronę Remix 3 za pomocą Intlayer

    Ten przewodnik pokazuje, jak zintegrować Intlayer w celu bezproblemowej internacjonalizacji w aplikacjach Remix 3 z routingiem uwzględniającym język, bezpiecznymi pod kątem typów deklaracjami treści, komponentami JSX renderowanymi na serwerze oraz wsparciem dla środowisk Node.js, Bun, Deno i Cloudflare Workers.

    Czym jest Remix 3?

    Remix 3 reprezentuje fundamentalną zmianę architektoniczną w kierunku modułowego, niezależnego od środowiska uruchomieniowego frameworka opartego w całości na standardach internetowych. Zamiast powiązania z konkretnymi bundlerami lub własnościowymi API serwerowymi, Remix 3 jest dystrybuowany jako zestaw modułowych pakietów:

    • remix/fetch-router (lub remix/router): Lekki, zgodny ze standardami routing oparty na Fetch API (Request i Response).
    • remix/ui: Model komponentów JSX (jsxImportSource: "remix/ui"). Komponent to funkcja konfiguracyjna (setup function), która zwraca funkcję renderującą (render function), odbierając propsy za pośrednictwem typowanego uchwytu (handle).
    • remix/middleware/render: Instaluje context.render(<Page />) dla każdego żądania, strumieniując drzewo JSX do obiektu HTML Response.
    • remix/node-fetch-server: Adaptery serwerowe dla Node.js z natywnym wsparciem dla Bun, Deno i środowisk edge.
    • remix/cookie: Kryptograficznie podpisane parsowanie i serializacja ciasteczek.

    W połączeniu z Intlayer i pakietem remix-intlayer, middleware ustawień regionalnych oraz tymi samymi hookami useIntlayer / useDictionary / useLocale co w react-intlayer, powiązanymi z kontekstem żądania Remix, otrzymujesz kompletny system internacjonalizacji zapewniający bezpieczeństwo typów w czasie kompilacji, automatyczne tłumaczenia AI, renderowanie serwerowe bez narzutu i płynne trasowanie językowe.

    Spis treści

    Dlaczego warto wybrać Intlayer?

    W porównaniu z tradycyjnymi rozwiązaniami, takimi jak i18next czy dedykowane loadery tłumaczeń, Intlayer oferuje zintegrowane środowisko programistyczne zoptymalizowane pod kątem nowoczesnej architektury aplikacji webowych:

    Intlayer został zbudowany z myślą o bezproblemowej współpracy ze standardami sieciowymi (Request, Response, Headers i URL). remix-intlayer integruje się z routerem Fetch Remix 3 jako lekkie middleware, pobierając ustawienia regionalne ze ścieżek URL, plików cookie lub nagłówków Accept-Language i udostępniając je reszcie żądania, procedurom obsługi, widokom i komponentom remix/ui, bez konieczności przekazywania ich jako argumentów.

    Pożegnaj luźne klucze JSON i błędy brakujących tłumaczeń w czasie działania aplikacji. Intlayer wymusza weryfikację TypeScript dla wszystkich zadeklarowanych języków, ostrzegając już na etapie kompilacji, jeśli tłumaczenie jest niekompletne lub niepoprawne.

    Podczas korzystania z komponentów JSX Remix 3 renderowanych na serwerze, do strumienia odpowiedzi trafia wyłącznie przetłumaczony tekst dla wybranego języka. Komponenty działają w całości na serwerze, chyba że wyraźnie skonfigurujesz hydratację klienta za pomocą clientEntry. Domyślnie do klienta nie są wysyłane żadne katalogi tłumaczeń ani środowiska uruchomieniowe hydratacji.

    Intlayer umieszcza deklaracje treści (.content.ts) bezpośrednio przy logice tras, zmniejszając kontekst tokenów potrzebny dla modeli LLM. Wbudowane polecenia CLI, takie jak intlayer fill i intlayer test, pozwalają na automatyzację tłumaczeń w pipeline'ach CI/CD po bezpośrednim koszcie wybranego dostawcy AI.

    Oprócz pracy z kodem, Intlayer zapewnia hostowany lokalnie Edytor Wizualny oraz Zdalny CMS, umożliwiając edytorom i tłumaczom aktualizację treści bez ponownego wdrażania kodu.

    Przewodnik krok po kroku

    ide.intlayer.org
    intlayer-remix-3-template.vercel.app

    Zobacz Szablon Aplikacji na GitHubie.

    1. Instalacja zależności

      Zainstaluj intlayer, remix-intlayer i remix (wersja 3) za pomocą preferowanego menedżera pakietów:

      bash
      npm install intlayer remix-intlayer remix@next
      
      • intlayer: Główny silnik internacjonalizacji zapewniający zarządzanie konfiguracją, deklarację słowników (t(), Dictionary), narzędzia CLI oraz interpreter czasu wykonania.
      • remix-intlayer: Integracja z Remix 3: middleware routera intlayer(), które rozpoznaje ustawienia regionalne każdego żądania, oraz hooki useIntlayer, useDictionary i useLocale, które odczytują je w dowolnym miejscu poniżej.
      • remix: Ujednolicony pakiet frameworka Remix 3 eksportujący remix/router, remix/routes, remix/ui, remix/middleware/render oraz remix/node-fetch-server.
    2. Konfiguracja Intlayer

      Architektura

      W tej architekturze middleware intlayer() z remix-intlayer jest rejestrowany w createRouter() przed middleware render(). Usuwa prefiks locale przed dopasowaniem przez router, dzięki czemu trasy są deklarowane tylko raz w src/routes.ts bez segmentu :locale, oraz wykonuje resztę żądania w zasięgu AsyncLocalStorage, co pozwala useIntlayer / useLocale odczytywać locale bez argumentów w handlerach tras i widokach remix/ui. Deklaracje zawartości są umieszczane obok Twoich widoków w src/:

      bash
      .
      ├── src
      │   ├── home.content.ts               # Home page content declaration
      │   ├── router.tsx                    # createRouter() with the intlayer() and render() middleware
      │   ├── routes.ts                     # Type-safe routes, declared once without locale segment
      │   ├── server.ts                     # fetch handler (Node.js, Bun, Deno, Cloudflare Workers)
      │   └── views
      │       ├── document.tsx              # HTML shell setting <html lang dir> from the locale
      │       └── home.tsx                  # Localized page using useIntlayer / useLocale
      ├── intlayer.config.ts
      ├── package.json
      └── tsconfig.json
      

      Konfiguracja

      Utwórz plik intlayer.config.ts w katalogu głównym projektu, aby zadeklarować obsługiwane języki i ustawienia:

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, Locales.POLISH],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      
      Dodatkowe informacje o konfiguracji znajdziesz w dokumentacji konfiguracji.
    3. Deklarowanie treści wielojęzycznych

      Zadeklaruj przetłumaczoną treść w pliku .content.ts:

      src/home.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const homeContent = {
        key: "home",
        content: {
          title: t({
            pl: "Witaj w Remix 3",
            en: "Welcome to Remix 3",
            fr: "Bienvenue sur Remix 3",
            es: "Bienvenido a Remix 3",
          }),
          description: t({
            pl: "Modułowa aplikacja oparta na standardach webowych z natywną obsługą i18n.",
            en: "A composable, web-standard application with native i18n.",
            fr: "Une application composable basée sur les standards web avec i18n native.",
            es: "Una aplicación componible basada en estándares web con i18n nativa.",
          }),
          switchLanguage: t({
            pl: "Zmień język:",
            en: "Switch language:",
            fr: "Changer de langue :",
            es: "Cambiar idioma:",
          }),
        },
      } satisfies Dictionary;
      
      export default homeContent;
      
      Intlayer obsługuje również formaty JSON, YAML i CommonJS. Zobacz Dokumentację deklaracji treści.
    4. Budowanie słowników Intlayer

      Skompiluj definicje słowników, aby wygenerować typy TypeScript oraz rejestry:

      bash
      npx intlayer build
      

      To polecenie kompiluje zawartość do katalogu .intlayer, zapewniając autouzupełnianie w TypeScript i szybki dostęp do słowników.

    5. Dodaj middleware Intlayer

      Remix 3 zapewnia konfigurowalny potok middleware za pośrednictwem createRouter({ middleware: [...] }).

      remix-intlayer dostarcza middleware intlayer(). Dla każdego przychodzącego żądania rozpoznaje ustawienia regionalne przy użyciu:

      1. Adresu URL, w każdym trybie trasowania oprócz no-prefix: prefiksu ścieżki (np. /pl lub /en) lub parametru wyszukiwania ?locale=.
      2. Ustawień regionalnych zapisanych przez klienta: pliku cookie (INTLAYER_LOCALE) lub niestandardowego nagłówka (x-intlayer-locale).
      3. Standardowej negocjacji Accept-Language, z powrotem do skonfigurowanego defaultLocale.

      Wynik jest przechowywany w kontekście żądania Remix jako context.intlayer (lub context.get(Intlayer)), z wartościami locale, defaultLocale i availableLocales. Następnie middleware uruchamia resztę żądania w zakresie AsyncLocalStorage powiązanym z tym kontekstem, co pozwala hookom pakietu odczytywać ustawienia regionalne bez argumentów, zarówno w procedurach obsługi tras, widokach, jak i komponentach remix/ui:

      typescript
      import { useIntlayer, useLocale } from "remix-intlayer";
      
      // W dowolnym miejscu poniżej middleware
      const { locale, availableLocales } = useLocale();
      const { title } = useIntlayer("home");
      

      useIntlayer("home", "fr") lub useIntlayer("faq", { item: 2 }) nadpisują ustawienia regionalne żądania dla jednego wywołania, a useDictionary(homeContent) odczytuje zaimportowany słownik zamiast klucza. Poza żądaniem hooki powracają do domyślnych ustawień regionalnych.

      Middleware przygotowuje również słowniki Intlayer podczas uruchamiania serwera, dzięki czemu brakujące intlayer build nie pozostawia rejestru pustego.
      Ustaw routing.enableProxy: false w intlayer.config.ts, aby zachować wyłącznie rozpoznawanie locale i samodzielnie obsługiwać routing. intlayer({ ignore }) pozostawia pasujące żądania bez zmian (na przykład prefiks API), a intlayer({ isDevServer }) określa, czy zapisane locale steruje przekierowaniami w domyślnym trybie automatycznym enableProxy.
    6. Definiowanie bezpiecznych typowo tras

      Zdefiniuj trasy aplikacji za pomocą route() z remix/routes:

      src/routes.ts
      import { route } from "remix/routes";
      
      export const routes = route({
        // Trasa domyślnego języka
        home: "/",
      
        // Trasa zlokalizowana z dynamicznym segmentem :locale
        localizedHome: "/:locale",
      });
      

      Użycie route() zapewnia bezpieczne typowo generowanie adresów URL w całej aplikacji:

      typescript
      routes.home.href(); // "/"
      routes.localizedHome.href({ locale: "pl" }); // "/pl"
      
    7. Renderowanie zlokalizowanych stron za pomocą JSX

      Remix 3 używa remix/ui do komponentów JSX. Komponent to funkcja konfiguracyjna (setup function), która zwraca funkcję renderującą (render function). Props są przekazywane przez typowany handle (na przykład handle.props.locale):

      Zacznij od współdzielonej powłoki Document, która ustawia atrybuty <html lang="..." dir="..."> na podstawie ustawień regionalnych rozpoznanych przez middleware:

      src/views/document.tsx
      import { getHTMLTextDir } from "intlayer";
      import { useLocale } from "remix-intlayer";
      import type { Handle, RemixNode } from "remix/ui";
      
      type DocumentProps = {
        title: string;
        children?: RemixNode;
      };
      
      export const Document = (handle: Handle<DocumentProps>) => () => {
        const { title, children } = handle.props;
        const { locale } = useLocale();
      
        return (
          <html lang={locale} dir={getHTMLTextDir(locale)}>
            <head>
              <meta charSet="utf-8" />
              <meta name="viewport" content="width=device-width, initial-scale=1" />
              <title>{title}</title>
            </head>
            <body>{children}</body>
          </html>
        );
      };
      

      Następnie utwórz stronę główną. Odczytuje ona zlokalizowany słownik za pomocą useIntlayer i renderuje przełącznik języków:

      src/views/home.tsx
      import { getLocaleName, getLocalizedUrl, getPathWithoutLocale } from "intlayer";
      import { useIntlayer, useLocale } from "remix-intlayer";
      import { Document } from "./document";
      
      export const HomePage = () => () => {
        const { locale, availableLocales } = useLocale();
        const home = useIntlayer("home");
        const pathWithoutLocale = getPathWithoutLocale();
      
        return (
          <Document title={home.title}>
            <header>
              <nav aria-label="Languages">
                <span>{home.switchLanguage}</span>
                <ul>
                  {availableLocales.map((localeItem) => {
                    const isActive = localeItem === locale;
      
                    return (
                      <li key={localeItem} class="p-1">
                        <a
                          href={getLocalizedUrl(pathWithoutLocale, localeItem)}
                          class={isActive ? "active" : undefined}
                          aria-current={isActive ? "page" : undefined}
                        >
                          {getLocaleName(localeItem, locale)}
                        </a>
                      </li>
                    );
                  })}
                </ul>
              </nav>
            </header>
            <main>
              <h1>{home.title}</h1>
              <p>{home.description}</p>
            </main>
          </Document>
        );
      };
      
      Remix JSX to nie React: class jest zapisywane bez zmian (className jest również akceptowane), a ponowne renderowanie jest wyzwalane jawnie za pomocą handle.update(). Interpolowane wartości są automatycznie uciekane. Hooki Intlayer to zwykłe funkcje odczytujące zakres żądania, więc można je wywoływać zarówno z funkcji konfiguracji (setup), jak i funkcji renderowania.
    8. Łączenie routera i serwera

      Utwórz src/router.tsx, aby zarejestrować middleware i zdefiniować akcje tras. Użyj remix/middleware/render, aby zainstalować pomocnika context.render(), i przekaż swój komponent JSX bezpośrednio:

      src/router.tsx
      import { isDeclaredLocale } from "intlayer";
      import { intlayer } from "remix-intlayer";
      import { render } from "remix/middleware/render";
      import { createRouter } from "remix/router";
      import { routes } from "./routes";
      import { HomePage } from "./views/home";
      
      // 1. Initialize router with Intlayer + render middleware
      export const router = createRouter({
        middleware: [intlayer(), render()],
      });
      
      // 2. Map route handlers
      router.map(routes, {
        actions: {
          // Default locale route
          home(context) {
            return context.render(<HomePage />);
          },
      
          // Localized route
          localizedHome(context) {
            if (!isDeclaredLocale(context.params.locale)) {
              return new Response("Not Found", { status: 404 });
            }
            return context.render(<HomePage />);
          },
        },
      });
      
      context.render przyjmuje opcjonalny ResponseInit jako drugi argument, np. context.render(<NotFoundPage />, { status: 404 }). Rozpoznane ustawienia regionalne pozostają dostępne z poziomu procedury obsługi jako context.intlayer.locale, na przykład w celu utworzenia odpowiedzi Response.json.

      Teraz połącz src/server.ts za pomocą remix/node-fetch-server dla Node.js (lub wyeksportuj moduł obsługi fetch bezpośrednio dla Bun, Deno lub Cloudflare Workers):

      src/server.ts
      import * as http from "node:http";
      import { createRequestListener } from "remix/node-fetch-server";
      import { router } from "./router";
      
      const PORT = Number(process.env.PORT || 3000);
      
      // Serwer HTTP Node.js
      const server = http.createServer(
        createRequestListener((request) => router.fetch(request))
      );
      
      server.listen(PORT, () => {
        console.log(`Serwer działa pod adresem http://localhost:${PORT}`);
      });
      
      // Eksport dla Bun / Deno / Cloudflare Workers
      export default {
        port: PORT,
        fetch(request: Request) {
          return router.fetch(request);
        },
      };
      
    9. Audyt i automatyczne uzupełnianie tłumaczeń

      Intlayer udostępnia narzędzie CLI do sprawdzania brakujących tłumaczeń i ich automatycznego uzupełniania za pomocą AI:

      bash
      # Sprawdź brakujące tłumaczenia
      npx intlayer test
      
      # Uzupełnij brakujące tłumaczenia za pomocą AI
      npx intlayer fill
      

    Konfiguracja TypeScript

    Skonfiguruj tsconfig.json, aby wskazać środowisko wykonawcze remix/ui dla JSX i dołączyć wygenerowane typy .intlayer:

    tsconfig.json
    {
      "compilerOptions": {
        "moduleResolution": "Bundler",
        "module": "ESNext",
        "target": "ESNext",
        "jsx": "react-jsx",
        "jsxImportSource": "remix/ui",
        "skipLibCheck": true,
        "strict": true
      },
      "include": ["src/**/*", ".intlayer/**/*.ts"]
    }
    
    jsxImportSource: "remix/ui" sprawia, że <HomePage /> odwołuje się do funkcji createElement z Remix zamiast z Reacta. Żadne środowisko wykonawcze React nie jest ładowane.

    Podsumowanie

    Dzięki Remix 3 i Intlayer otrzymujesz lekki, w pełni typowany i elastyczny stos technologiczny oparty na otwartych standardach sieciowych. Twoja aplikacja może bez wysiłku skalować się od prostych stron marketingowych po globalnie dystrybuowane usługi renderowane na krawędzi (edge).