Receba notificações sobre os próximos lançamentos de Intlayer
    Criação:2025-12-07Última atualização:2025-12-07

    Traduza seu site React Router v7 (File-System Routes) usando Intlayer | Internacionalização (i18n)

    Este guia demonstra como integrar o Intlayer para internacionalização perfeita em projetos React Router v7 usando roteamento baseado em sistema de arquivos (@react-router/fs-routes) com roteamento consciente de localidade, suporte a TypeScript e práticas modernas de desenvolvimento.

    Para roteamento do lado do cliente, consulte o guia Intlayer com React Router v7.

    Índice

    O que é o Intlayer?

    Intlayer é uma biblioteca de internacionalização (i18n) inovadora e de código aberto projetada para simplificar o suporte multilíngue em aplicações web modernas.

    Com o Intlayer, você pode:

    • Gerenciar traduções facilmente usando dicionários declarativos no nível do componente.
    • Localizar dinamicamente metadados, rotas e conteúdo.
    • Garantir suporte ao TypeScript com tipos autogerados, melhorando o preenchimento automático e a detecção de erros.
    • Aproveitar recursos avançados, como detecção dinâmica de localidade e alternância de idioma.
    • Habilitar roteamento consciente de localidade com o sistema de roteamento baseado em sistema de arquivos do React Router v7.

    Guia Passo a Passo para Configurar o Intlayer em uma Aplicação React Router v7 com File-System Routes

    Veja o Application Template no GitHub.

    Passo 1: Instalar Dependências

    Instale os pacotes necessários usando seu gerenciador de pacotes preferido:

    npm install intlayer react-intlayernpm install vite-intlayer --save-devnpm install @react-router/fs-routes --save-dev
    • intlayer

      O pacote principal que fornece ferramentas de internacionalização para gerenciamento de configuração, tradução, declaração de conteúdo, transpilação e comandos CLI.

    • react-intlayer O pacote que integra o Intlayer com aplicações React. Fornece providers de contexto e hooks para internacionalização em React.

    • vite-intlayer Inclui o plugin Vite para integrar o Intlayer com o Vite bundler, bem como middleware para detectar a localidade preferida do usuário, gerenciar cookies e lidar com redirecionamento de URL.

    • @react-router/fs-routes O pacote que habilita roteamento baseado em sistema de arquivos para React Router v7.

    Passo 2: Configuração do seu projeto

    Crie um arquivo de configuração para configurar os idiomas da sua aplicação:

    intlayer.config.ts
    import { type IntlayerConfig, Locales } from "intlayer";const config: IntlayerConfig = {  internationalization: {    defaultLocale: Locales.ENGLISH,    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],  },};export default config;
    Através deste arquivo de configuração, você pode configurar URLs localizadas, redirecionamento de middleware, nomes de cookies, a localização e extensão das suas declarações de conteúdo, desabilitar os logs do Intlayer no console e mais. Para uma lista completa dos parâmetros disponíveis, consulte a documentação de configuração.

    Passo 3: Integrar o Intlayer na sua Configuração do Vite

    Adicione o plugin intlayer na sua configuração:

    vite.config.ts
    import { reactRouter } from "@react-router/dev/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";import tsconfigPaths from "vite-tsconfig-paths";export default defineConfig({  plugins: [reactRouter(), tsconfigPaths(), intlayer()],});
    O plugin Vite intlayer() é usado para integrar o Intlayer com o Vite. Ele garante a construção dos arquivos de declaração de conteúdo e os monitora em modo de desenvolvimento. Ele define variáveis de ambiente do Intlayer dentro da aplicação Vite. Além disso, fornece aliases para otimizar o desempenho.

    Passo 4: Configurar Rotas File-System do React Router v7

    Configure sua configuração de rotas para usar rotas baseadas em sistema de arquivos com flatRoutes:

    app/routes.ts
    import type { RouteConfig } from "@react-router/dev/routes";import { flatRoutes } from "@react-router/fs-routes";import { configuration } from "intlayer";const routes: RouteConfig = flatRoutes({  // Ignorar arquivos de declaração de conteúdo para não serem tratados como rotas  ignoredRouteFiles: configuration.content.fileExtensions.map(    (fileExtension) => `**/*${fileExtension}`  ),});export default routes;
    A função flatRoutes do @react-router/fs-routes habilita roteamento baseado em sistema de arquivos, onde a estrutura de arquivos no diretório routes/ determina as rotas da sua aplicação. A opção ignoredRouteFiles garante que os arquivos de declaração de conteúdo do Intlayer (.content.ts, etc.) não sejam tratados como arquivos de rota.

    Passo 5: Criar Arquivos de Rota com Convenções File-System

    Com roteamento baseado em sistema de arquivos, você usa uma convenção de nomenclatura plana onde pontos (.) representam segmentos de caminho e parênteses () denotam segmentos opcionais.

    Crie os seguintes arquivos no seu diretório app/routes/:

    Estrutura de Arquivos

    app/├── root.tsx                         # Wrapper de layout para rotas de locale└──routes/    ├── ($locale)._index.tsx         # Página inicial (/, /es, etc.)    ├── ($locale)._index.content.ts  # Conteúdo da página inicial    ├── ($locale).about.tsx          # Página About (/about, /es/about, etc.)    └── ($locale).about.content.ts   # Conteúdo da página About

    As convenções de nomenclatura:

    • ($locale) - Segmento dinâmico opcional para o parâmetro locale
    • _layout - Rota de layout que envolve as rotas filhas
    • _index - Rota index (renderiza no caminho pai)
    • . (ponto) - Separa segmentos de caminho (ex.: ($locale).about/:locale?/about)

    Componente de Layout

    app/root.tsx
    import { getLocaleFromPath } from "intlayer";import { IntlayerProvider } from "react-intlayer";import {  isRouteErrorResponse,  Meta,  Outlet,  Scripts,  ScrollRestoration,  useLoaderData,} from "react-router";import type { Route } from "./+types/root";import "./app.css";// links and ErrorBoundary codeexport async function loader({ request }: Route.LoaderArgs) {  const locale = getLocaleFromPath(request.url);  return { locale };}export function Layout({  children,}: { children: React.ReactNode } & Route.ComponentProps) {  const data = useLoaderData<typeof loader>();  const { locale } = data ?? {};  return (    <html lang={locale}>      <head>        <meta charSet="utf-8" />        <meta content="width=device-width, initial-scale=1" name="viewport" />        <Meta />        <Links />      </head>      <body>        <IntlayerProvider locale={locale}>{children}</IntlayerProvider>        <ScrollRestoration />        <Scripts />      </body>    </html>  );}

    Página Index

    app/routes/($locale)._index.tsx
    import { getIntlayer, validatePrefix } from "intlayer";import { useIntlayer } from "react-intlayer";import { data } from "react-router";import { LocaleSwitcher } from "~/components/locale-switcher";import { Navbar } from "~/components/navbar";import type { Route } from "./+types/($locale)._index";export const loader = ({ params }: Route.LoaderArgs) => {  const { locale } = params;  const { isValid } = validatePrefix(locale);  if (!isValid) {    throw data("Locale not supported", { status: 404 });  }};export const meta: Route.MetaFunction = ({ params }) => {  const content = getIntlayer("page", params.locale);  return [    { title: content.title },    { content: content.description, name: "description" },  ];};export default function Page() {  const { title, description, aboutLink } = useIntlayer("page");  return (    <div>      <h1>{title}</h1>      <p>{description}</p>      <nav>        <LocalizedLink to="/about">{aboutLink}</LocalizedLink>      </nav>    </div>  );}

    Página About

    app/routes/($locale).about.tsx
    import { getIntlayer, validatePrefix } from "intlayer";import { useIntlayer } from "react-intlayer";import { data } from "react-router";import { LocaleSwitcher } from "~/components/locale-switcher";import { Navbar } from "~/components/navbar";import type { Route } from "./+types/($locale).about";export const loader = ({ params }: Route.LoaderArgs) => {  const { locale } = params;  const { isValid } = validatePrefix(locale);  if (!isValid) {    throw data("Locale not supported", { status: 404 });  }};export const meta: Route.MetaFunction = ({ params }) => {  const content = getIntlayer("about", params.locale);  return [    { title: content.title },    { content: content.description, name: "description" },  ];};export default function AboutPage() {  const { title, content, homeLink } = useIntlayer("about");  return (    <div>      <h1>{title}</h1>      <p>{content}</p>      <nav>        <LocalizedLink to="/">{homeLink}</LocalizedLink>      </nav>    </div>  );}

    Passo 6: Declarar seu Conteúdo

    Crie e gerencie suas declarações de conteúdo para armazenar traduções. Coloque os arquivos de conteúdo ao lado dos seus arquivos de rota:

    app/routes/($locale)._index.content.ts
    import { t, type Dictionary } from "intlayer";const pageContent = {  key: "page",  content: {    title: t({      en: "Welcome to React Router v7 + Intlayer",      es: "Bienvenido a React Router v7 + Intlayer",      fr: "Bienvenue sur React Router v7 + Intlayer",    }),    description: t({      en: "Build multilingual applications with ease using React Router v7 and Intlayer.",      es: "Cree aplicaciones multilingües fácilmente usando React Router v7 y Intlayer.",      fr: "Créez des applications multilingues facilement avec React Router v7 et Intlayer.",    }),    aboutLink: t({      en: "Learn About Us",      es: "Aprender Sobre Nosotros",      fr: "En savoir plus sur nous",    }),  },} satisfies Dictionary;export default pageContent;
    app/routes/($locale).about.content.ts
    import { t, type Dictionary } from "intlayer";const aboutContent = {  key: "about",  content: {    title: t({      en: "About Us",      es: "Sobre Nosotros",      fr: "À propos de nous",    }),    content: t({      en: "This is the about page content.",      es: "Este es el contenido de la página de información.",      fr: "Ceci est le contenu de la page à propos.",    }),    homeLink: t({      en: "Home",      es: "Inicio",      fr: "Accueil",    }),  },} satisfies Dictionary;export default aboutContent;
    Suas declarações de conteúdo podem ser definidas em qualquer lugar da sua aplicação, desde que sejam incluídas no diretório contentDir (por padrão, ./app). E correspondam à extensão de arquivo de declaração de conteúdo (por padrão, .content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}).
    Para mais detalhes, consulte a documentação de declaração de conteúdo.

    Passo 7: Criar Componentes Locale-Aware

    Crie um componente LocalizedLink para navegação consciente de localidade:

    app/components/localized-link.tsx
    import type { FC } from "react";import { getLocalizedUrl, type LocalesValues } from "intlayer";import { useLocale } from "react-intlayer";import { Link, type LinkProps, type To } from "react-router";const isExternalLink = (to: string) => /^(https?:)?\/\//.test(to);export const locacalizeTo = (to: To, locale: LocalesValues): To => {  if (typeof to === "string") {    if (isExternalLink(to)) {      return to;    }    return getLocalizedUrl(to, locale);  }  if (isExternalLink(to.pathname ?? "")) {    return to;  }  return {    ...to,    pathname: getLocalizedUrl(to.pathname ?? "", locale),  };};export const LocalizedLink: FC<LinkProps> = (props) => {  const { locale } = useLocale();  return <Link {...props} to={locacalizeTo(props.to, locale)} />;};

    No caso de você querer navegar para as rotas localizadas, você pode usar o hook useLocalizedNavigate:

    app/hooks/useLocalizedNavigate.ts
    import { useLocale } from "react-intlayer";import { type NavigateOptions, type To, useNavigate } from "react-router";import { locacalizeTo } from "~/components/localized-link";export const useLocalizedNavigate = () => {  const navigate = useNavigate();  const { locale } = useLocale();  const localizedNavigate = (to: To, options?: NavigateOptions) => {    const localedTo = locacalizeTo(to, locale);    navigate(localedTo, options);  };  return localizedNavigate;};

    Passo 8: Criar um Componente de Alternância de Locale

    Crie um componente para permitir que os usuários alterem idiomas:

    app/components/locale-switcher.tsx
    import type { FC } from "react";import {  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,  getPathWithoutLocale,  Locales,} from "intlayer";import { useIntlayer, useLocale } from "react-intlayer";import { Link, useLocation } from "react-router";export const LocaleSwitcher: FC = () => {  const { localeSwitcherLabel } = useIntlayer("locale-switcher");  const { pathname } = useLocation();  const { availableLocales, locale } = useLocale();  const pathWithoutLocale = getPathWithoutLocale(pathname);  return (    <ol>      {availableLocales.map((localeItem) => (        <li key={localeItem}>          <Link            aria-current={localeItem === locale ? "page" : undefined}            aria-label={`${localeSwitcherLabel.value} ${getLocaleName(localeItem)}`}            reloadDocument // Recarregar a página para aplicar o novo locale            to={getLocalizedUrl(pathWithoutLocale, localeItem)}          >            <span>              {/* Locale - ex.: FR */}              {localeItem}            </span>            <span>              {/* Idioma na sua própria Locale - ex.: Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Idioma na Locale atual - ex.: Francés com a locale atual definida como Locales.SPANISH */}              {getLocaleName(localeItem)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Idioma em inglês - ex.: French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>          </Link>        </li>      ))}    </ol>  );};
    Para saber mais sobre o hook useLocale, consulte a documentação.

    Passo 9: Adicionar Gerenciamento de Atributos HTML (Opcional)

    Crie um hook para gerenciar os atributos HTML lang e dir:

    app/hooks/useI18nHTMLAttributes.tsx
    import { getHTMLTextDir } from "intlayer";import { useEffect } from "react";import { useLocale } from "react-intlayer";export const useI18nHTMLAttributes = () => {  const { locale } = useLocale();  useEffect(() => {    document.documentElement.lang = locale;    document.documentElement.dir = getHTMLTextDir(locale);  }, [locale]);};

    Este hook já é usado no componente de layout (root.tsx) mostrado no Passo 5.

    Passo 10: Adicionar middleware (Opcional)

    Você também pode usar o intlayerProxy para adicionar roteamento do lado do servidor à sua aplicação. Este plugin detectará automaticamente a localidade atual com base na URL e definirá o cookie de localidade apropriado. Se nenhuma localidade for especificada, o plugin determinará a localidade mais adequada com base nas preferências de idioma do navegador do usuário. Se nenhuma localidade for detectada, ele redirecionará para a localidade padrão.

    Note que para usar o intlayerProxy em produção, você precisa mover o pacote vite-intlayer de devDependencies para dependencies.
    vite.config.ts
    import { reactRouter } from "@react-router/dev/vite";import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";import tsconfigPaths from "vite-tsconfig-paths";export default defineConfig({  plugins: [reactRouter(), tsconfigPaths(), intlayer(), intlayerProxy()],});

    Configurar TypeScript

    O Intlayer usa module augmentation para aproveitar os benefícios do TypeScript e tornar sua codebase mais robusta.

    Certifique-se de que sua configuração do TypeScript inclui os tipos autogerados:

    tsconfig.json
    {  // ... suas configurações existentes  include: [    // ... seus includes existentes    ".intlayer/**/*.ts", // Incluir os tipos autogerados  ],}

    Configuração do Git

    É recomendado ignorar os arquivos gerados pelo Intlayer. Isso permite que você evite commitá-los no seu repositório Git.

    Para fazer isso, você pode adicionar as seguintes instruções ao seu arquivo .gitignore:

    .gitignore
    # Ignorar os arquivos gerados pelo Intlayer.intlayer

    Extensão do VS Code

    Para melhorar sua experiência de desenvolvimento com o Intlayer, você pode instalar a extensão oficial Intlayer VS Code Extension.

    Instalar no VS Code Marketplace

    Esta extensão fornece:

    • Autocompletar para chaves de tradução.
    • Detecção de erros em tempo real para traduções faltando.
    • Pré-visualizações inline do conteúdo traduzido.
    • Ações rápidas para criar e atualizar traduções facilmente.

    Para mais detalhes sobre como usar a extensão, consulte a documentação da Extensão Intlayer VS Code.


    Ir Além

    Para ir além, você pode implementar o editor visual ou externalizar seu conteúdo usando o CMS.


    Referências da Documentação

    Este guia completo fornece tudo o que você precisa para integrar o Intlayer com o React Router v7 usando roteamento baseado em sistema de arquivos para uma aplicação totalmente internacionalizada com roteamento consciente de localidade e suporte a TypeScript.

    Receba notificações sobre os próximos lançamentos de Intlayer