שאלו את שאלתכם וקבלו סיכום של המסמך על ידי הפניה לדף הזה ולספק ה-AI שתבחרו
היסטוריית גרסאות
- "Use the remix-intlayer middleware and hooks"v9.5.519.9.2026
- "Initial documentation for Remix 3"v9.5.09.9.2026
התוכן של הדף הזה תורגם באמצעות AI.
צפייה בגרסה האחרונה של התוכן המקורי באנגליתאם יש לכם רעיון לשיפור התיעוד הזה, אל תהססו לתרום על ידי הגשת Pull Request ב-GitHub.
קישור GitHub לתיעודהעתקת ה-Markdown של המסמך ללוח
Translate your Remix 3 website using Intlayer
This guide demonstrates how to integrate Intlayer for seamless internationalization in Remix 3 applications with locale-aware routing, type-safe content declarations, server-rendered JSX components, and cross-runtime support across Node.js, Bun, Deno, and Cloudflare Workers.
What is Remix 3?
Remix 3 represents a fundamental architectural shift towards a composable, runtime-agnostic web framework built entirely on web standards. Rather than being coupled to specific bundlers or proprietary server APIs, Remix 3 is distributed as single-purpose, composable packages:
remix/fetch-router(orremix/router): Lightweight, standard-compliant routing built on the Fetch API (RequestandResponse).remix/component: A JSX component model (jsxImportSource: "remix/component"). A component is a setup function that returns a render function, so it looks like React but keeps state in plain JavaScript closures.remix/middleware/render: Installscontext.render(<Page />)on every request, streaming the JSX tree to an HTMLResponse.remix/node-fetch-server: Server adapters for Node.js, while natively supporting Bun, Deno, and edge runtimes.remix/cookie: Cryptographically secure cookie parsing and serialization.
Combined with Intlayer and the remix-intlayer package, a locale middleware plus the same useIntlayer / useDictionary / useLocale hooks as react-intlayer, bound to the Remix request context, you get a complete internationalization system that delivers compile-time safety, automated AI translations, zero-overhead server rendering, and seamless locale routing.
Table of Contents
Why Intlayer over alternatives?
Compared to traditional solutions like i18next or bespoke translation loaders, Intlayer offers an integrated developer experience optimized for modern web architecture:
Intlayer is built to work seamlessly with web standards (Request, Response, Headers, and URL). remix-intlayer plugs into Remix 3's Fetch router as a lightweight middleware, extracting the locale from URL paths, cookies, or Accept-Language headers and exposing it to the rest of the request (handlers, views and remix/component components) without passing it around or locking you into a specific runtime.
Say goodbye to loose JSON keys and runtime missing-key crashes. Intlayer enforces TypeScript checks across all declared locales, warning you at build time if a translation is missing or invalid.
Remix 3 renders JSX components on the server and streams the HTML to the client. Only the resolved text for the requested locale ends up in the output stream. No client hydration bundles or bulky translation catalogs are needed unless a component is explicitly marked as a clientEntry.
Intlayer co-locates content declarations (.content.ts) with your route logic, reducing the token context required by Large Language Models (LLMs). Built-in CLI commands like intlayer fill and intlayer test let you automate translations in CI/CD pipelines at the cost of your own AI provider.
Beyond code-first workflows, Intlayer provides a self-hosted Visual Editor and a Remote CMS allowing non-technical editors, translators, and copywriters to update content without redeploying code.
Step-by-Step Guide
See the Application Template on GitHub.
Install Dependencies
Install
intlayer,remix-intlayerandremix(version 3) using your preferred package manager:bashהעתקת קודהעתקת הקוד ללוח
intlayer: Core internationalization engine providing configuration management, dictionary declaration (t(),Dictionary), CLI tools, and runtime interpreter.remix-intlayer: The Remix 3 integration: theintlayer()router middleware that resolves the locale of each request, and theuseIntlayer,useDictionaryanduseLocalehooks that read it anywhere downstream.remix: The unified Remix 3 framework package exportingremix/router,remix/routes,remix/component,remix/middleware/render, andremix/node-fetch-server.
Configure Intlayer
Architecture
In this architecture, the
intlayer()middleware ofremix-intlayeris registered increateRouter()ahead of therender()middleware. It strips the locale prefix before the router matches, so routes are declared once insrc/routes.tswithout a:localesegment, and it runs the rest of the request inside anAsyncLocalStoragescope, which is what letsuseIntlayer/useLocaleread the locale with no argument in route handlers andremix/componentviews. Content declarations are placed alongside your views insrc/:bashהעתקת קודהעתקת הקוד ללוח
Configuration
Create an
intlayer.config.tsin the root of your project to declare your supported languages and internationalization settings:intlayer.config.tsהעתקת קודהעתקת הקוד ללוח
import { Locales, type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH], defaultLocale: Locales.ENGLISH, }, }; export default config;For additional configuration settings (such as strict mode or routing storage preferences), refer to the configuration documentation.
Declare Your Multilingual Content
Declare your localized content in a
.content.tsfile:src/home.content.tsהעתקת קודהעתקת הקוד ללוח
import { t, type Dictionary } from "intlayer"; const homeContent = { key: "home", content: { title: t({ en: "Welcome to Remix 3", fr: "Bienvenue sur Remix 3", es: "Bienvenido a Remix 3", }), description: t({ 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({ en: "Switch language:", fr: "Changer de langue :", es: "Cambiar idioma:", }), }, } satisfies Dictionary; export default homeContent;Intlayer also supports JSON, YAML, and CommonJS declaration formats. See the Content Declaration Documentation.
Build Intlayer Dictionaries
Compile the dictionary definitions to generate TypeScript types and runtime registries:
bashהעתקת קודהעתקת הקוד ללוח
This compiles your content into the
.intlayerartifact directory, enabling full TypeScript autocompletion and rapid dictionary lookup.Add the Intlayer Middleware
Remix 3 provides a composable middleware pipeline via
createRouter({ middleware: [...] }).remix-intlayerships theintlayer()middleware, the Remix counterpart of thenext-intlayerandvite-intlayerproxies. For each incoming request it:- Routes the locale, following
routing.mode(prefix-no-defaultby default). A URL without a locale prefix is redirected to the localized URL of the detected locale (the storage cookieINTLAYER_LOCALEor custom headerx-intlayer-locale, then standardAccept-Languagenegotiation, then yourdefaultLocale) unless that locale needs no prefix. A prefixed URL such as/fr/aboutis served from the/aboutroute as French,/en/aboutis redirected to/about, androuting.rewriterules are applied both ways (/fr/about→/fr/a-propos). Static assets and, inrouting.domainssetups, locale domains are handled the same way as in the other integrations. - Resolves the locale into the Remix request context, as
context.intlayer(orcontext.get(Intlayer)), withlocale,defaultLocaleandavailableLocales. - Persists the locale through the configured cookie / header, so the follow-up requests resolve the same locale.
Because the locale prefix is stripped before the router matches, your routes are declared once, without a
:localesegment, whatever the routing mode. The middleware then runs the rest of the request inside anAsyncLocalStoragescope bound to the request context, which is what lets the hooks of the package read the locale with no argument, in route handlers, views andremix/componentcomponents alike:typescriptהעתקת קודהעתקת הקוד ללוח
useIntlayer("home", "fr")oruseIntlayer("faq", { item: 2 })override the request locale for one call, anduseDictionary(homeContent)reads an imported dictionary instead of a key. Outside of a request the hooks fall back to the default locale.The middleware also prepares the Intlayer dictionaries when the server starts, so a missing
intlayer builddoes not leave the registry empty.Set
routing.enableProxy: falseinintlayer.config.tsto keep the locale resolution only and handle the routing yourself.intlayer({ ignore })leaves the matching requests untouched (an API prefix, for instance), andintlayer({ isDevServer })controls whether the stored locale drives redirects in the defaultenableProxyauto mode.- Routes the locale, following
Define Type-Safe Routes
Define your application routes using
route()fromremix/routes. Declare them once, without a locale segment. The middleware serves every locale from them:src/routes.tsהעתקת קודהעתקת הקוד ללוח
import { route } from "remix/routes"; export const routes = route({ home: "/", });Using
route()gives you type-safe URL generation across your application, andgetLocalizedPathapplies the routing mode to it:typescriptהעתקת קודהעתקת הקוד ללוח
Render Localized Pages with JSX
Remix 3 renders UI with JSX components from
remix/component. A component is a setup function that receives aHandleand returns a render function. Setup runs once per instance, render runs on every update, and props are read throughhandle.props.Start with a shared
Documentshell that sets the<html lang="..." dir="...">attributes from the locale resolved by the middleware:src/views/document.tsxהעתקת קודהעתקת הקוד ללוח
import { getHTMLTextDir } from "intlayer"; import { useLocale } from "remix-intlayer"; import type { Handle, RemixNode } from "remix/component"; 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> ); };Then create the home page. It reads the localized dictionary with
useIntlayerand renders a language switcher: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 is not React:
classis written as-is (classNameis also accepted), and re-renders are triggered explicitly withhandle.update(). Interpolated values are escaped automatically. The Intlayer hooks are plain functions reading the request scope, so they can be called from the setup function or the render function alike.Wire Up the Router and Server
Add the
render()middleware fromremix/middleware/rendernext to the Intlayer middleware. It installscontext.render(node, init)on every request, which streams the JSX tree into an HTMLResponse(prepending<!DOCTYPE html>and setting theContent-Typeheader):src/router.tsxהעתקת קודהעתקת הקוד ללוח
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: `/`, `/fr`, `/es`… all reach `home` router.map(routes, { actions: { home(context) { return context.render(<HomePage />); }, }, });context.renderaccepts an optionalResponseInitas second argument, e.g.context.render(<NotFoundPage />, { status: 404 }). The resolved locale stays reachable from the handler ascontext.intlayer.locale, for instance to build aResponse.jsonpayload.Finally, expose the router through a standard
fetchhandler. The same router runs on Node.js, Bun, Deno, and 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); // Node.js const server = http.createServer( createRequestListener((request) => router.fetch(request)) ); server.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); }); // Bun / Deno / Cloudflare Workers export default { port: PORT, fetch(request: Request) { return router.fetch(request); }, };Audit and Auto-Fill Translations
Intlayer provides a CLI to audit for missing translations and automatically fill them using AI:
bashהעתקת קודהעתקת הקוד ללוח
TypeScript Configuration
Point JSX at the remix/component runtime and ensure that your tsconfig.json includes the generated .intlayer types:
העתקת הקוד ללוח
jsxImportSource: "remix/component"is what makes<HomePage />resolve to Remix'screateElementinstead of React's.
Conclusion
With Remix 3 and Intlayer, you have a lean, fully typed, runtime-portable stack that adheres to open web standards. Your application can scale effortlessly from simple localized marketing pages to globally distributed, edge-rendered services.
