Penulis:
    Dibuat:2026-09-09Terakhir diperbarui:2026-09-27

    Terjemahkan Situs Web Remix 3 Anda Menggunakan Intlayer

    Panduan ini menunjukkan cara mengintegrasikan Intlayer untuk internasionalisasi yang mulus dalam aplikasi Remix 3 dengan perutean berbasis bahasa, deklarasi konten yang aman secara tipe, komponen JSX yang dirender di server, serta dukungan lintas runtime di Node.js, Bun, Deno, dan Cloudflare Workers.

    Apa itu Remix 3?

    Remix 3 mewakili perubahan arsitektur fundamental menuju kerangka kerja web modular dan agnostik runtime yang dibangun sepenuhnya di atas standar web. Alih-alih terikat pada bundler tertentu atau API server proprietary, Remix 3 didistribusikan sebagai paket modular serbaguna:

    • remix/fetch-router (atau remix/router): Perutean ringan yang mematuhi standar dan dibangun di atas Fetch API (Request dan Response).
    • remix/ui: Model komponen JSX (jsxImportSource: "remix/ui"). Sebuah komponen adalah fungsi setup yang mengembalikan fungsi render, menerima props melalui handle bertipe.
    • remix/middleware/render: Memasang context.render(<Page />) pada setiap permintaan, mengalirkan (streaming) pohon JSX ke HTML Response.
    • remix/node-fetch-server: Adapter server untuk Node.js dengan dukungan bawaan untuk Bun, Deno, dan runtime edge.
    • remix/cookie: Penguraian dan serialisasi cookie yang ditandatangani secara kriptografis.

    Dikombinasikan dengan Intlayer dan paket remix-intlayer, middleware lokal plus hook useIntlayer / useDictionary / useLocale yang sama dengan react-intlayer, yang terikat pada konteks permintaan Remix, Anda mendapatkan sistem internasionalisasi lengkap yang menghadirkan keamanan saat kompilasi, terjemahan otomatis AI, rendering server tanpa beban tambahan, dan perutean lokal yang lancar.

    Daftar Isi

    Mengapa Memilih Intlayer Dibandingkan Alternatif Lain?

    Dibandingkan dengan solusi tradisional seperti i18next atau pemuat terjemahan kustom, Intlayer menawarkan pengalaman pengembang terintegrasi yang dioptimalkan untuk arsitektur web modern:

    Intlayer dirancang untuk bekerja secara mulus dengan standar web (Request, Response, Headers, dan URL). remix-intlayer terhubung ke perute Fetch Remix 3 sebagai middleware ringan, mengekstrak lokal dari jalur URL, cookie, atau header Accept-Language dan mengeksposnya ke sisa permintaan, penangan, tampilan, dan komponen remix/ui, tanpa meneruskannya secara manual atau mengunci Anda ke runtime tertentu.

    Ucapkan selamat tinggal pada kunci JSON yang longgar dan error runtime akibat kunci yang hilang. Intlayer menerapkan pemeriksaan TypeScript di semua bahasa yang dideklarasikan, memperingatkan Anda saat build jika ada terjemahan yang hilang atau tidak valid.

    Saat menggunakan komponen JSX yang dirender di server Remix 3, hanya teks yang diselesaikan untuk lokalitas yang diminta yang dialirkan ke output stream. Komponen berjalan sepenuhnya di server kecuali Anda secara eksplisit mengonfigurasi hidrasi klien melalui clientEntry. Secara default, tidak ada katalog terjemahan atau runtime hidrasi yang dikirim ke klien.

    Intlayer menempatkan deklarasi konten (.content.ts) bersama logika rute Anda, mengurangi konteks token yang dibutuhkan oleh Large Language Models (LLM). Perintah CLI bawaan seperti intlayer fill dan intlayer test memungkinkan Anda mengotomatiskan terjemahan dalam pipeline CI/CD dengan biaya langsung dari penyedia AI Anda.

    Di luar alur kerja berbasis kode, Intlayer menyediakan Editor Visual mandiri dan CMS Jarak Jauh, memungkinkan editor dan penerjemah memperbarui konten tanpa harus menerapkan ulang kode.

    Panduan Langkah demi Langkah

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

    Lihat Template Aplikasi di GitHub.

    1. Instal Dependensi

      Instal intlayer, remix-intlayer, dan remix (versi 3) menggunakan pengelola paket pilihan Anda:

      bash
      npm install intlayer remix-intlayer remix@next
      
      • intlayer: Mesin inti internasionalisasi yang menyediakan manajemen konfigurasi, deklarasi kamus (t(), Dictionary), alat CLI, dan penerjemah runtime.
      • remix-intlayer: Integrasi Remix 3: middleware perute intlayer() yang menyelesaikan lokal setiap permintaan, dan hook useIntlayer, useDictionary, dan useLocale yang membacanya di mana pun setelahnya.
      • remix: Paket kerangka kerja terpadu Remix 3 yang mengekspor remix/router, remix/routes, remix/ui, remix/middleware/render, dan remix/node-fetch-server.
    2. Konfigurasikan Intlayer

      Arsitektur

      Dalam arsitektur ini, middleware intlayer() dari remix-intlayer didaftarkan di createRouter() sebelum middleware render(). Middleware ini menghapus awalan locale sebelum router mencocokkan, sehingga rute dideklarasikan sekali di src/routes.ts tanpa segmen :locale, dan menjalankan sisa permintaan di dalam cakupan AsyncLocalStorage, yang memungkinkan useIntlayer / useLocale membaca locale tanpa argumen di route handler dan tampilan remix/ui. Deklarasi konten ditempatkan bersama tampilan Anda di 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
      

      Konfigurasi

      Buat file intlayer.config.ts di root proyek Anda untuk mendeklarasikan bahasa yang didukung dan pengaturan internasionalisasi:

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            Locales.INDONESIAN,
          ],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      
      Untuk pengaturan konfigurasi tambahan, silakan merujuk ke dokumentasi konfigurasi.
    3. Deklarasikan Konten Multibahasa Anda

      Deklarasikan konten lokal Anda dalam file .content.ts:

      src/home.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const homeContent = {
        key: "home",
        content: {
          title: t({
            id: "Selamat datang di Remix 3",
            en: "Welcome to Remix 3",
            fr: "Bienvenue sur Remix 3",
            es: "Bienvenido a Remix 3",
          }),
          description: t({
            id: "Aplikasi modular berbasis standar web dengan dukungan i18n bawaan.",
            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({
            id: "Ganti bahasa:",
            en: "Switch language:",
            fr: "Changer de langue :",
            es: "Cambiar idioma:",
          }),
        },
      } satisfies Dictionary;
      
      export default homeContent;
      
      Intlayer juga mendukung format JSON, YAML, dan CommonJS. Lihat Dokumentasi Deklarasi Konten.
    4. Bangun Kamus Intlayer

      Kompilasi definisi kamus untuk menghasilkan tipe TypeScript dan registri runtime:

      bash
      npx intlayer build
      

      Ini mengompilasi konten Anda ke dalam direktori artefak .intlayer, memungkinkan pelengkapan otomatis TypeScript penuh dan pencarian kamus yang cepat.

    5. Tambahkan Middleware Intlayer

      Remix 3 menyediakan pipa middleware yang dapat disusun melalui createRouter({ middleware: [...] }).

      remix-intlayer menyediakan middleware intlayer(). Untuk setiap permintaan masuk, ia menyelesaikan lokal menggunakan:

      1. URL, dalam setiap mode perutean kecuali no-prefix: awalan jalur (mis. /id atau /en) atau parameter pencarian ?locale=.
      2. Lokal yang disimpan oleh klien: cookie penyimpanan (INTLAYER_LOCALE) atau header kustom (x-intlayer-locale).
      3. Negosiasi standar Accept-Language, kembali ke defaultLocale yang Anda konfigurasikan.

      Hasilnya disimpan dalam konteks permintaan Remix sebagai context.intlayer (atau context.get(Intlayer)), dengan locale, defaultLocale, dan availableLocales. Middleware kemudian menjalankan sisa permintaan di dalam cakupan AsyncLocalStorage yang terikat pada konteks tersebut, yang memungkinkan hook dari paket membaca lokal tanpa argumen, baik di penangan rute, tampilan, maupun komponen remix/ui:

      typescript
      import { useIntlayer, useLocale } from "remix-intlayer";
      
      // Di mana saja setelah middleware
      const { locale, availableLocales } = useLocale();
      const { title } = useIntlayer("home");
      

      useIntlayer("home", "fr") atau useIntlayer("faq", { item: 2 }) mengganti lokal permintaan untuk satu panggilan, dan useDictionary(homeContent) membaca kamus yang diimpor alih-alih kunci. Di luar permintaan, hook kembali ke lokal default.

      Middleware juga menyiapkan kamus Intlayer saat server dimulai, sehingga intlayer build yang terlewat tidak membiarkan registri kosong.
      Atur routing.enableProxy: false di intlayer.config.ts untuk hanya mempertahankan resolusi locale dan menangani routing sendiri. intlayer({ ignore }) membiarkan permintaan yang cocok tidak tersentuh (misalnya prefiks API), dan intlayer({ isDevServer }) mengontrol apakah locale yang tersimpan menentukan redirect dalam mode otomatis default enableProxy.
    6. Definisikan Rute yang Aman Secara Tipe

      Definisikan rute aplikasi Anda menggunakan route() dari remix/routes:

      src/routes.ts
      import { route } from "remix/routes";
      
      export const routes = route({
        // Rute bahasa default
        home: "/",
      
        // Rute terlokalisasi dengan segmen dinamis :locale
        localizedHome: "/:locale",
      });
      

      Menggunakan route() memberikan pembuatan URL yang aman secara tipe di seluruh aplikasi Anda:

      typescript
      routes.home.href(); // "/"
      routes.localizedHome.href({ locale: "id" }); // "/id"
      
    7. Render Halaman Terlokalisasi dengan JSX

      Remix 3 menggunakan remix/ui untuk komponen JSX. Sebuah komponen adalah fungsi setup yang mengembalikan fungsi render. Props diteruskan melalui handle yang bertipe (misalnya, handle.props.locale):

      Mulailah dengan shell Document bersama yang menyetel atribut <html lang="..." dir="..."> dari lokal yang diselesaikan oleh 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>
        );
      };
      

      Kemudian buat halaman beranda. Halaman ini membaca kamus yang dilokalkan dengan useIntlayer dan merender pengalih bahasa:

      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 bukanlah React: class ditulis apa adanya (className juga diterima), dan render ulang dipicu secara eksplisit dengan handle.update(). Nilai yang diinterpolasi otomatis lolos (escaped). Hook Intlayer adalah fungsi biasa yang membaca cakupan permintaan, sehingga dapat dipanggil dari fungsi setup atau fungsi render.
    8. Hubungkan Router dan Server

      Buat src/router.tsx untuk mendaftarkan middleware dan menentukan aksi rute. Gunakan remix/middleware/render untuk memasang utilitas context.render(), dan teruskan komponen JSX Anda secara langsung:

      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 menerima ResponseInit opsional sebagai argumen kedua, mis. context.render(<NotFoundPage />, { status: 404 }). Lokal yang diselesaikan tetap dapat dijangkau dari penangan sebagai context.intlayer.locale, misalnya untuk membangun respons Response.json.

      Sekarang hubungkan src/server.ts menggunakan remix/node-fetch-server untuk Node.js (atau ekspor handler fetch secara langsung untuk Bun, Deno, atau 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);
      
      // Server HTTP Node.js
      const server = http.createServer(
        createRequestListener((request) => router.fetch(request))
      );
      
      server.listen(PORT, () => {
        console.log(`Server berjalan di http://localhost:${PORT}`);
      });
      
      // Ekspor Bun / Deno / Cloudflare Workers
      export default {
        port: PORT,
        fetch(request: Request) {
          return router.fetch(request);
        },
      };
      
    9. Audit dan Isi Terjemahan Otomatis

      Intlayer menyediakan CLI untuk mengaudit terjemahan yang hilang dan mengisinya secara otomatis menggunakan AI:

      bash
      # Audit terjemahan yang hilang
      npx intlayer test
      
      # Isi terjemahan yang hilang menggunakan AI
      npx intlayer fill
      

    Konfigurasi TypeScript

    Konfigurasikan tsconfig.json untuk mengarahkan JSX ke runtime remix/ui dan menyertakan tipe .intlayer yang dihasilkan:

    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" adalah apa yang membuat <HomePage /> diselesaikan ke createElement milik Remix dan bukan React. Tidak ada runtime React yang dimuat.

    Kesimpulan

    Dengan Remix 3 dan Intlayer, Anda memiliki tumpukan teknologi yang ramping, sepenuhnya bertipe, dan portabel yang mematuhi standar web terbuka. Aplikasi Anda dapat diskalakan dengan mudah dari halaman pemasaran lokal sederhana hingga layanan terdistribusi global yang dirender di edge.