InícioAmbiente de testeVitrineAppDocBlog
    • Englishinglês
      EN
    • русскийrusso
      RU
    • 日本語japonês
      JA
    • françaisfrancês
      FR
    • 한국어coreano
      KO
    • 中文chinês
      ZH
    • españolespanhol
      ES
    • Deutschalemão
      DE
    • العربيةárabe
      AR
    • italianoitaliano
      IT
    • British Englishinglês (Reino Unido)
      EN-GB
    • portuguêsportuguês
      PT
    • हिन्दीhindi
      HI
    • Türkçeturco
      TR
    • polskipolonês
      PL
    • Indonesiaindonésio
      ID
    • Tiếng Việtvietnamita
      VI
    • українськаucraniano
      UK
    /
    Filtrar documentação por framework
    Alt+←
    Por que Intlayer?
    Começar
    Conceito
    • Como o Intlayer funciona
    • Configuração
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Editor visual
    • CMS
    • Integração CI/CD
    • TraduçãoPluralEnumeraçãoCondiçãoGêneroInserçãoArquivoAninhamentoMarkdownHTMLBusca de função
    • Arquivo por locale
    • Compilador
    • Preenchimento automático
    • Testes
    • Otimização de bundle
    Ambiente
    • Next.js 14 e App Router
      Next.js 15
      Next.js sem locale URL
      Next.js e Page Router
      Compiler
    • Tanstack Start Solid
    • Astro e React
      Astro e Svelte
      Astro e Vue
      Astro e Solid
      Astro e Preact
      Astro e Lit
      Astro e Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt e Vue
    • Vite e Solid
    • SvelteKit
    • Vite e Preact
    • Vite e Vanilla JS
    • Vite e Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native e Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx e React
    Plugins
    • JSON
    • gettext (.po)
    Extensão VS Code
    Agente
    • Servidor MCP
    • Habilidades do agente
    Versões
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Faça uma pergunta
    1. Documentation
    2. Ambiente
    3. Tanstack Start
    Criação:2025-09-09Última atualização:2026-05-06
    Ver o modelo de aplicação no GitHub

    Esta página tem um modelo de aplicação disponível.

    Ver a aplicação de demonstração

    Esta página liga a uma demonstração ao vivo do modelo.

    Assistir ao vídeo tutorial

    Esta página tem um vídeo tutorial disponível.

    Referência esta documentação ao seu assistente AI favorito
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Faça sua pergunta e obtenha um resumo do documento referenciando esta página e o provedor AI de sua escolha

    Histórico de versões

    1. "Atualizar o uso da API useIntlayer do Solid para acesso direto a propriedades"
      v8.9.004/05/2026
    2. "Adicionar comando init"
      v7.5.930/12/2025
    3. "Introduz validatePrefix e adiciona o passo 14: Tratamento de páginas 404 com rotas localizadas."
      v7.4.011/12/2025
    4. "Adiciona o passo 13: Recuperar o locale em suas server actions (Opcional)"
      v7.3.905/12/2025
    5. "Adiciona o passo 13: Adaptar Nitro"
      v7.2.318/11/2025
    6. "Fix prefix default ao adicionar a função getPrefix useLocalizedNavigate, LocaleSwitcher e LocalizedLink."
      v7.1.017/11/2025
    7. "Atualizar doc"
      v6.5.203/10/2025
    8. "Adicionado para Tanstack Start"
      v5.8.109/09/2025

    O conteúdo desta página foi traduzido com uma IA.

    Veja a última versão do conteúdo original em inglês
    Editar esta documentação

    Se você tiver uma ideia para melhorar esta documentação, sinta-se à vontade para contribuir enviando uma pull request no GitHub.

    Link do GitHub para a documentação
    Copiar

    Copiar o Markdown do documento para a área de transferência

    Traduza seu Tanstack Start com Intlayer | Internacionalização (i18n)

    Índice

    Este guia demonstra como integrar o Intlayer para uma internacionalização perfeita em projetos Tanstack Start com roteamento sensível ao locale, suporte a TypeScript e práticas modernas de desenvolvimento.

    O que é o Intlayer?

    Intlayer é uma biblioteca inovadora e de código aberto para internacionalização (i18n) 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 a TypeScript com tipos gerados automaticamente, melhorando o autocompletar e a detecção de erros.
    • Aproveitar recursos avançados, como detecção e troca dinâmica de locale.
    • Ativar roteamento sensível ao locale com o sistema de roteamento baseado em arquivos do Tanstack Start.

    Guia Passo a Passo para Configurar o Intlayer em uma Aplicação Tanstack Start

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

    Veja o Template de aplicação no GitHub.

    Passo 1: Criar o Projeto

    Comece criando um novo projeto TanStack Start seguindo o guia Iniciar novo projeto no site do TanStack Start.

    Passo 2: Instalar os Pacotes do Intlayer

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

    bash
    Copiar código

    Copiar o código para a área de transferência

    npm install intlayer react-intlayernpm install vite-intlayer --save-devnpx intlayer init
    • intlayer

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

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

    • vite-intlayer Inclui o plugin Vite para integrar o Intlayer com o empacotador Vite, assim como middleware para detectar o locale preferido do usuário, gerenciar cookies e lidar com redirecionamento de URLs.

    Passo 3: Configuração do seu projeto

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

    intlayer.config.ts
    Copiar código

    Copiar o código para a área de transferência

    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;
    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 logs do Intlayer no console, e muito mais. Para uma lista completa dos parâmetros disponíveis, consulte a documentação de configuração.

    Passo 4: Integre o Intlayer na sua Configuração do Vite

    Adicione o plugin intlayer na sua configuração:

    vite.config.ts
    Copiar código

    Copiar o código para a área de transferência

    import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";const config = defineConfig({  plugins: [    nitro(),    intlayer(),    tanstackStart({      router: {        routeFileIgnorePattern:          ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5)$",      },    }),    viteReact(),  ],});export default config;
    O plugin intlayer() para Vite é usado para integrar o Intlayer com o Vite. Ele garante a construção dos arquivos de declaração de conteúdo e os monitora no modo de desenvolvimento. Define as variáveis de ambiente do Intlayer dentro da aplicação Vite. Além disso, fornece aliases para otimizar o desempenho.

    Passo 5: Criar Layout Raiz

    Configure seu layout raiz para suportar internacionalização usando useParams para detectar o locale atual e configurando os atributos lang e dir na tag html.

    src/routes/__root.tsx
    Copiar código

    Copiar o código para a área de transferência

    import {  createRootRouteWithContext,  HeadContent,  Scripts,} from "@tanstack/react-router";import { defaultLocale, getHTMLTextDir } from "intlayer";import { type ReactNode } from "react";import { IntlayerProvider } from "react-intlayer";import { Route as LocaleRoute } from "./{-$locale}/route";export const Route = createRootRouteWithContext<{}>()({  head: () => ({    meta: [      {        charSet: "utf-8",      },      {        content: "width=device-width, initial-scale=1",        name: "viewport",      },      {        title: "TanStack Start Starter",      },    ],  }),  shellComponent: RootDocument,});function RootDocument({ children }: { children: ReactNode }) {  const params = LocaleRoute.useParams();  const locale = params?.locale ?? defaultLocale;  return (    <html dir={getHTMLTextDir(locale)} lang={locale}>      <head>        <HeadContent />      </head>      <body>        <IntlayerProvider locale={locale}>{children}</IntlayerProvider>        <Scripts />      </body>    </html>  );}
    Se você quiser usar seu conteúdo em um atributo do tipo string, como alt, title, href, aria-label, etc., você deve chamar o valor da função, assim:
    html
    Copiar código

    Copiar o código para a área de transferência

    <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)}" />

    Passo 6: Criar Layout de Localidade

    Crie um layout que lide com o prefixo de locale e realize a validação.

    src/routes/{-$locale}/route.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";import { validatePrefix } from "intlayer";export const Route = createFileRoute("/{-$locale}")({  beforeLoad: ({ params }) => {    const localeParam = params.locale;    // Validar o prefixo de locale    const { isValid, localePrefix } = validatePrefix(localeParam);    if (!isValid) {      throw redirect({        to: "/{-$locale}/404",        params: { locale: localePrefix },      });    }  },  component: Outlet,});
    Aqui, {-$locale} é um parâmetro de rota dinâmica que é substituído pelo locale atual. Esta notação torna o slot opcional, permitindo que funcione com modos de roteamento como 'prefix-no-default', etc.

    Esteja ciente de que este slot pode causar problemas se você usar múltiplos segmentos dinâmicos na mesma rota (ex: /{-$locale}/other-path/$anotherDynamicPath/...). Para o modo 'prefix-all', você pode preferir mudar o slot para $locale em vez disso. Para o modo 'no-prefix' ou 'search-params', você pode remover o slot inteiramente.

    Passo 7: Declare Seu Conteúdo

    Crie e gerencie suas declarações de conteúdo para armazenar traduções:

    src/contents/page.content.ts
    Copiar código

    Copiar o código para a área de transferência

    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 exemplo de uso de Intlayer con TanStack Router",        fr: "Ceci est un exemplo d'utilisation d'Intlayer avec TanStack Router",      }),    },  },  key: "app",} satisfies Dictionary;export default appContent;export default appContent;
    Suas declarações de conteúdo podem ser definidas em qualquer lugar da sua aplicação assim que forem incluídas no diretório contentDir (por padrão, ./app). E devem corresponder à extensão do arquivo de declaração de conteúdo (por padrão, .content.{json,ts,tsx,js,jsx,mjs,cjs}).
    Para mais detalhes, consulte a documentação de declaração de conteúdo.

    Passo 8: Crie Componentes e Hooks Sensíveis ao Locale

    Crie um componente LocalizedLink para navegação sensível ao locale:

    src/components/localized-link.tsx
    Copiar código

    Copiar o código para a área de transferência

    import type { FC } from "react";import { Link, type LinkComponentProps } from "@tanstack/react-router";import { useLocale } from "react-intlayer";import { getPrefix } from "intlayer";export const LOCALE_ROUTE = "{-$locale}" as const;export type To = StripLocalePrefix<LinkComponentProps["to"]>;export type StripLocalePrefix<T extends string | undefined> = T extends  | `/${typeof LOCALE_ROUTE}/`  | `/${typeof LOCALE_ROUTE}`  ? "/"  : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`    ? `/${Rest}`    : T;type LocalizedLinkProps = {  to?: To;} & Omit<LinkComponentProps, "to">;export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {  const { locale } = useLocale();  const { localePrefix } = getPrefix(locale);  return (    <Link      {...props}      params={{        locale: localePrefix,        ...(typeof props?.params === "object" ? props?.params : {}),      }}      to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps["to"]}    />  );};

    Este componente tem dois objetivos:

    • Remover o prefixo {-$locale} desnecessário da URL.
    • Injetar o parâmetro de locale na URL para garantir que o usuário seja redirecionado diretamente para a rota localizada.

    Então, podemos criar um hook useLocalizedNavigate para navegação programática:

    src/hooks/useLocalizedNavigate.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { useNavigate } from "@tanstack/react-router";import { getPrefix } from "intlayer";import { useLocale } from "react-intlayer";import type { StripLocalePrefix } from "@/components/localized-link";import type { FileRouteTypes } from "@/routeTree.gen";type NavigateFn = ReturnType<typeof useNavigate>;type BaseNavigateOptions = Parameters<NavigateFn>[0];type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;export type LocalizedNavigateOptions = Omit<  BaseNavigateOptions,  "to" | "params"> & {  to: LocalizedTo;  params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;};type LocalizedNavigate = (  options: LocalizedNavigateOptions) => ReturnType<NavigateFn>;export const useLocalizedNavigate = () => {  const navigate = useNavigate();  const { locale } = useLocale();  const localizedNavigate: LocalizedNavigate = (args: any) => {    const { localePrefix } = getPrefix(locale);    if (typeof args === "string") {      return navigate({        to: `/${LOCALE_ROUTE}${args}`,        params: { locale: localePrefix },      });    }    const { to, ...rest } = args;    const localizedTo = `/${LOCALE_ROUTE}${to}` as any;    return navigate({      to: localizedTo,      params: { locale: localePrefix, ...rest } as any,    });  };  return localizedNavigate;};

    Passo 9: Utilize o Intlayer em Suas Páginas

    Acesse seus dicionários de conteúdo em toda a sua aplicação:

    Página Inicial Localizada

    src/routes/{-$locale}/index.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";import { useIntlayer } from "react-intlayer";import LocaleSwitcher from "@/components/locale-switcher";import { LocalizedLink } from "@/components/localized-link";import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";export const Route = createFileRoute("/{-$locale}/")({  component: RouteComponent,});function RouteComponent() {  const content = useIntlayer("app");  const navigate = useLocalizedNavigate();  return (    <div>      <div>        {content.title}        <LocaleSwitcher />        <div>          <LocalizedLink to="/">{content.links.home}</LocalizedLink>          <LocalizedLink to="/about">{content.links.about}</LocalizedLink>        </div>        <div>          <button onClick={() => navigate({ to: "/" })}>            {content.links.home}          </button>          <button onClick={() => navigate({ to: "/about" })}>            {content.links.about}          </button>        </div>      </div>    </div>  );}
    Para saber mais sobre o hook useIntlayer, consulte a documentação.

    Passo 10: Criar um Componente de Troca de Locale

    Crie um componente para permitir que os usuários mudem de idioma:

    src/components/locale-switcher.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { useLocation } from "@tanstack/react-router";import {  getHTMLTextDir,  getLocaleName,  getPathWithoutLocale,  getPrefix,  Locales,} from "intlayer";import type { FC } from "react";import { useLocale } from "react-intlayer";import { LocalizedLink, type To } from "./localized-link";export const LocaleSwitcher: FC = () => {  const { pathname } = useLocation();  const { availableLocales, locale, setLocale } = useLocale();  const pathWithoutLocale = getPathWithoutLocale(pathname);  return (    <ol>      {availableLocales.map((localeEl) => (        <li key={localeEl}>          <LocalizedLink            aria-current={localeEl === locale ? "page" : undefined}            onClick={() => setLocale(localeEl)}            params={{ locale: getPrefix(localeEl).localePrefix }}            to={pathWithoutLocale as To}          >            <span>              {/* Locale - ex. FR */}              {localeEl}            </span>            <span>              {/* Idioma na sua própria Localidade - ex. Français */}              {getLocaleName(localeEl, locale)}            </span>            <span dir={getHTMLTextDir(localeEl)} lang={localeEl}>              {/* Idioma na Localização atual - ex. Francés com a localização atual definida para Locales.SPANISH */}              {getLocaleName(localeEl)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Idioma em Inglês - ex. French */}              {getLocaleName(localeEl, Locales.ENGLISH)}            </span>          </LocalizedLink>        </li>      ))}    </ol>  );};
    Para saber mais sobre o hook useLocale, consulte a documentação.

    Passo 11: Gerenciamento de Atributos HTML

    Como visto no Passo 5, você pode gerenciar os atributos lang e dir da tag html usando useParams no seu componente raiz. Isso garante que os atributos corretos sejam definidos no servidor e no cliente.

    src/routes/__root.tsx
    Copiar código

    Copiar o código para a área de transferência

    function RootDocument({ children }: { children: ReactNode }) {  const params = LocaleRoute.useParams();  const locale = params?.locale ?? defaultLocale;  return (    <html dir={getHTMLTextDir(locale)} lang={locale}>      {/* ... */}    </html>  );}

    Passo 12: Adicionar middleware (Opcional)

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

    Observe que, para usar o intlayerProxy em produção, você precisa mover o pacote vite-intlayer de devDependencies para dependencies.
    vite.config.ts
    Copiar código

    Copiar o código para a área de transferência

    import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";export default defineConfig({  plugins: [    intlayerProxy(), // O proxy deve ser colocado antes do servidor se você usar Nitro    nitro(),    intlayer(),    tanstackStart({      router: {        routeFileIgnorePattern:          ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5)$",      },    }),    viteReact(),  ],});

    Passo 13: Internacionalizar seus Metadados (Opcional)

    Você também pode usar o hook getIntlayer para acessar seus dicionários de conteúdo em toda a sua aplicação:

    src/routes/{-$locale}/index.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";export const Route = createFileRoute("/{-$locale}/")({  component: RouteComponent,  head: ({ params }) => {    const { locale } = 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 },      ],    };  },});

    Passo 14: Recuperar a localidade em suas ações do servidor (Opcional)

    Você pode querer acessar a localidade atual de dentro de suas ações do servidor ou endpoints de API. Você pode fazer isso usando o auxiliar getLocale de intlayer.

    Aqui está um exemplo usando as funções de servidor do TanStack Start:

    src/routes/{-$locale}/index.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createServerFn } from "@tanstack/react-start";import {  getRequestHeader,  getRequestHeaders,} from "@tanstack/react-start/server";import { getCookie, getIntlayer, getLocale } from "intlayer";export const getLocaleServer = createServerFn().handler(async () => {  const locale = await getLocale({    // Obtenha o cookie da solicitação (padrão: 'INTLAYER_LOCALE')    getCookie: (name) => {      const cookieString = getRequestHeader("cookie");      return getCookie(name, cookieString);    },    // Obtenha o cabeçalho da solicitação (padrão: 'x-intlayer-locale')    // Fallback usando negociação Accept-Language    getHeader: (name) => getRequestHeader(name),  });  // Recupere algum conteúdo usando getIntlayer()  const content = getIntlayer("app", locale);  return { locale, content };});

    Passo 15: Gerenciar páginas não encontradas (Opcional)

    Quando um usuário visita uma página inexistente, você pode exibir uma página personalizada de não encontrada e o prefixo de locale pode afetar a forma como a página de não encontrada é acionada.

    Entendendo o tratamento de 404 do TanStack Router com prefixos de locale

    No TanStack Router, lidar com páginas 404 com rotas localizadas requer uma abordagem multicamadas:

    1. Rota 404 dedicada: Uma rota específica para exibir a interface 404
    2. Validação no nível da rota: Valida os prefixos de locale e redireciona os inválidos para 404
    3. Rota catch-all: Captura todos os caminhos não correspondentes dentro do segmento de locale
    src/routes/{-$locale}/404.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute } from "@tanstack/react-router";// Isso cria uma rota dedicada /[locale]/404// É usada tanto como uma rota direta quanto importada como um componente em outros arquivosexport const Route = createFileRoute("/{-$locale}/404")({  component: NotFoundComponent,});// Exportado separadamente para que possa ser reutilizado em notFoundComponent e rotas catch-allexport function NotFoundComponent() {  return (    <div>      <h1>404</h1>    </div>  );}
    src/routes/{-$locale}/route.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";import { validatePrefix } from "intlayer";import { NotFoundComponent } from "./404";export const Route = createFileRoute("/{-$locale}")({  // beforeLoad executa antes da rota ser renderizada (tanto no servidor quanto no cliente)  // É o lugar ideal para validar o prefixo de locale  beforeLoad: ({ params }) => {    const localeParam = params.locale;    // validatePrefix verifica se o locale é válido de acordo com sua configuração intlayer    const { isValid, localePrefix } = validatePrefix(localeParam);    if (!isValid) {      // Prefixo de locale inválido - redirecionar para a página 404 com um prefixo de locale válido      throw redirect({        to: "/{-$locale}/404",        params: { locale: localePrefix },      });    }  },  component: Outlet,  // notFoundComponent é chamado quando uma rota filha não existe  // por exemplo, /en/pagina-inexistente dispara isso dentro do layout /en  notFoundComponent: NotFoundComponent,});
    src/routes/{-$locale}/$.tsx
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute } from "@tanstack/react-router";import { NotFoundComponent } from "./404";// A rota $ (splat/catch-all) corresponde a qualquer caminho que não corresponda a outras rotas// por exemplo, /en/algum/caminho/profundamente/aninhado/invalido// Isso garante que TODOS os caminhos não correspondentes dentro de um locale mostrem a página 404// Sem isso, caminhos profundos não correspondentes podem mostrar uma página em branco ou erroexport const Route = createFileRoute("/{-$locale}/$")({  component: NotFoundComponent,});

    (Opcional) Passo 15: Extrair o conteúdo dos seus componentes

    Se você tiver uma base de código existente, transformar milhares de arquivos pode ser demorado.

    Para facilitar esse processo, o Intlayer propõe um compilador / extrator para transformar seus componentes e extrair o conteúdo.

    Para configurá-lo, você pode adicionar uma seção compiler no seu arquivo intlayer.config.ts:

    intlayer.config.ts
    Copiar código

    Copiar o código para a área de transferência

    import { type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      // ... Resto da sua configuração
      compiler: {
        /**
         * Indica se o compilador deve ser ativado.
         */
        enabled: true,
    
        /**
         * Define o caminho dos arquivos de saída
         */
        output: ({ fileName, extension }) => `./${fileName}${extension}`,
    
        /**
         * Indica se os componentes devem ser salvos após serem transformados. Dessa forma, o compilador pode ser executado apenas uma vez para transformar o aplicativo e depois removido.
         */
        saveComponents: false,
    
        /**
         * Prefixo da chave do dicionário
         */
        dictionaryKeyPrefix: "",
      },
    };
    
    export default config;

    Execute o extrator para transformar seus componentes e extrair o conteúdo

    bash
    Copiar código

    Copiar o código para a área de transferência

    npx intlayer extract

    Atualize seu vite.config.ts para incluir o plugin intlayerCompiler:

    vite.config.ts
    Copiar código

    Copiar o código para a área de transferência

    import { defineConfig } from "vite";import { intlayer, intlayerCompiler } from "vite-intlayer";export default defineConfig({ plugins: [   intlayer(),   intlayerCompiler(), // Adiciona o plugin do compilador ],});
    bash
    Copiar código

    Copiar o código para a área de transferência

    npm run build # Ou npm run dev

    Passo 16: Gerar um Sitemap (Opcional)

    O Intlayer vem com um gerador de sitemap integrado para ajudá-lo a criar facilmente um sitemap para sua aplicação. Ele cuida das rotas localizadas e adiciona os metadados necessários para os mecanismos de busca.

    O sitemap gerado pelo Intlayer suporta o namespace xhtml:link (Hreflang XML Extensions). Ao contrário dos geradores de sitemap padrão que apenas listam URLs brutos, o Intlayer cria automaticamente os links bidirecionais necessários entre todas as versões de idioma de uma página (por exemplo, /about, /about?lang=fr e /about?lang=es). Isso garante que os mecanismos de busca indexem e sirvam corretamente a versão de idioma certa para o público certo.

    Para usá-lo, você primeiro precisa configurar o seu vite.config.ts para habilitar a pré-renderização de suas rotas localizadas e desabilitar a geração de sitemap padrão do TanStack Start.

    vite.config.ts
    Copiar código

    Copiar o código para a área de transferência

    import { localeFlatMap } from "intlayer";// ... outras importaçõesexport const pathList = ["", "/about", "/404"];const localizedPages = localeFlatMap(({ urlPrefix }) =>  pathList.map((path) => ({    path: `${urlPrefix}${path}`,    prerender: {      enabled: true,    },  })));export default defineConfig({  plugins: [    // ... outros plugins    tanstackStart({      // ... outras configurações      sitemap: {        enabled: false,      },      prerender: {        enabled: true,        crawlLinks: false,        concurrency: 10,      },      pages: localizedPages,    }),  ],});

    Em seguida, crie uma rota src/routes/sitemap[.]xml.ts que use a função generateSitemap:

    src/routes/sitemap[.]xml.ts
    Copiar código

    Copiar o código para a área de transferência

    import { createFileRoute } from "@tanstack/react-router";import { generateSitemap } from "intlayer";const SITE_URL = (  import.meta.env.VITE_SITE_URL ?? "http://localhost:3000").replace(/\/$/, "");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" },        });      },    },  },});

    Passo 17: Configurar TypeScript (Opcional)

    O Intlayer utiliza a ampliação de módulos para aproveitar os benefícios do TypeScript e fortalecer sua base de código.

    Certifique-se de que sua configuração do TypeScript inclua os tipos gerados automaticamente:

    tsconfig.json
    Copiar código

    Copiar o código para a área de transferência

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

    Configuração do Git

    É recomendado ignorar os arquivos gerados pelo Intlayer. Isso permite evitar que eles sejam comitados no seu repositório Git.

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

    .gitignore
    Copiar código

    Copiar o código para a área de transferência

    # Ignorar os arquivos gerados pelo Intlayer.intlayer

    Extensão VS Code

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

    Instalar no VS Code Marketplace

    Esta extensão oferece:

    • Autocompletar para chaves de tradução.
    • Detecção de erros em tempo real para traduções ausentes.
    • 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 para 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

    • Documentação do Intlayer
    • Documentação do Tanstack Start
    • Hook useIntlayer
    • useLocale hook
    • Declaração de Conteúdo
    • Configuração
    Compiler
    Tanstack Start Solid
    Alt+→

    Nesta página

      As discussões são anônimas e regularmente revisadas para resolver problemas comuns. Sinta-se à vontade para compartilhar ideias de funcionalidades, feedback sobre a documentação ou qualquer coisa relacionada ao Intlayer, usamos essas informações para moldar nosso roadmap e melhorar o produto.

      npm install intlayer react-intlayernpm install vite-intlayer --save-devnpx intlayer init
      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;
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";const config = defineConfig({  plugins: [    nitro(),    intlayer(),    tanstackStart({      router: {        routeFileIgnorePattern:          ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5)$",      },    }),    viteReact(),  ],});export default config;
      import {  createRootRouteWithContext,  HeadContent,  Scripts,} from "@tanstack/react-router";import { defaultLocale, getHTMLTextDir } from "intlayer";import { type ReactNode } from "react";import { IntlayerProvider } from "react-intlayer";import { Route as LocaleRoute } from "./{-$locale}/route";export const Route = createRootRouteWithContext<{}>()({  head: () => ({    meta: [      {        charSet: "utf-8",      },      {        content: "width=device-width, initial-scale=1",        name: "viewport",      },      {        title: "TanStack Start Starter",      },    ],  }),  shellComponent: RootDocument,});function RootDocument({ children }: { children: ReactNode }) {  const params = LocaleRoute.useParams();  const locale = params?.locale ?? defaultLocale;  return (    <html dir={getHTMLTextDir(locale)} lang={locale}>      <head>        <HeadContent />      </head>      <body>        <IntlayerProvider locale={locale}>{children}</IntlayerProvider>        <Scripts />      </body>    </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)}" />
      import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";import { validatePrefix } from "intlayer";export const Route = createFileRoute("/{-$locale}")({  beforeLoad: ({ params }) => {    const localeParam = params.locale;    // Validar o prefixo de locale    const { isValid, localePrefix } = validatePrefix(localeParam);    if (!isValid) {      throw redirect({        to: "/{-$locale}/404",        params: { locale: localePrefix },      });    }  },  component: Outlet,});
      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 exemplo de uso de Intlayer con TanStack Router",        fr: "Ceci est un exemplo d'utilisation d'Intlayer avec TanStack Router",      }),    },  },  key: "app",} satisfies Dictionary;export default appContent;export default appContent;
      import type { FC } from "react";import { Link, type LinkComponentProps } from "@tanstack/react-router";import { useLocale } from "react-intlayer";import { getPrefix } from "intlayer";export const LOCALE_ROUTE = "{-$locale}" as const;export type To = StripLocalePrefix<LinkComponentProps["to"]>;export type StripLocalePrefix<T extends string | undefined> = T extends  | `/${typeof LOCALE_ROUTE}/`  | `/${typeof LOCALE_ROUTE}`  ? "/"  : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`    ? `/${Rest}`    : T;type LocalizedLinkProps = {  to?: To;} & Omit<LinkComponentProps, "to">;export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {  const { locale } = useLocale();  const { localePrefix } = getPrefix(locale);  return (    <Link      {...props}      params={{        locale: localePrefix,        ...(typeof props?.params === "object" ? props?.params : {}),      }}      to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps["to"]}    />  );};
      import { useNavigate } from "@tanstack/react-router";import { getPrefix } from "intlayer";import { useLocale } from "react-intlayer";import type { StripLocalePrefix } from "@/components/localized-link";import type { FileRouteTypes } from "@/routeTree.gen";type NavigateFn = ReturnType<typeof useNavigate>;type BaseNavigateOptions = Parameters<NavigateFn>[0];type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;export type LocalizedNavigateOptions = Omit<  BaseNavigateOptions,  "to" | "params"> & {  to: LocalizedTo;  params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;};type LocalizedNavigate = (  options: LocalizedNavigateOptions) => ReturnType<NavigateFn>;export const useLocalizedNavigate = () => {  const navigate = useNavigate();  const { locale } = useLocale();  const localizedNavigate: LocalizedNavigate = (args: any) => {    const { localePrefix } = getPrefix(locale);    if (typeof args === "string") {      return navigate({        to: `/${LOCALE_ROUTE}${args}`,        params: { locale: localePrefix },      });    }    const { to, ...rest } = args;    const localizedTo = `/${LOCALE_ROUTE}${to}` as any;    return navigate({      to: localizedTo,      params: { locale: localePrefix, ...rest } as any,    });  };  return localizedNavigate;};
      import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";import { useIntlayer } from "react-intlayer";import LocaleSwitcher from "@/components/locale-switcher";import { LocalizedLink } from "@/components/localized-link";import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";export const Route = createFileRoute("/{-$locale}/")({  component: RouteComponent,});function RouteComponent() {  const content = useIntlayer("app");  const navigate = useLocalizedNavigate();  return (    <div>      <div>        {content.title}        <LocaleSwitcher />        <div>          <LocalizedLink to="/">{content.links.home}</LocalizedLink>          <LocalizedLink to="/about">{content.links.about}</LocalizedLink>        </div>        <div>          <button onClick={() => navigate({ to: "/" })}>            {content.links.home}          </button>          <button onClick={() => navigate({ to: "/about" })}>            {content.links.about}          </button>        </div>      </div>    </div>  );}
      import { useLocation } from "@tanstack/react-router";import {  getHTMLTextDir,  getLocaleName,  getPathWithoutLocale,  getPrefix,  Locales,} from "intlayer";import type { FC } from "react";import { useLocale } from "react-intlayer";import { LocalizedLink, type To } from "./localized-link";export const LocaleSwitcher: FC = () => {  const { pathname } = useLocation();  const { availableLocales, locale, setLocale } = useLocale();  const pathWithoutLocale = getPathWithoutLocale(pathname);  return (    <ol>      {availableLocales.map((localeEl) => (        <li key={localeEl}>          <LocalizedLink            aria-current={localeEl === locale ? "page" : undefined}            onClick={() => setLocale(localeEl)}            params={{ locale: getPrefix(localeEl).localePrefix }}            to={pathWithoutLocale as To}          >            <span>              {/* Locale - ex. FR */}              {localeEl}            </span>            <span>              {/* Idioma na sua própria Localidade - ex. Français */}              {getLocaleName(localeEl, locale)}            </span>            <span dir={getHTMLTextDir(localeEl)} lang={localeEl}>              {/* Idioma na Localização atual - ex. Francés com a localização atual definida para Locales.SPANISH */}              {getLocaleName(localeEl)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Idioma em Inglês - ex. French */}              {getLocaleName(localeEl, Locales.ENGLISH)}            </span>          </LocalizedLink>        </li>      ))}    </ol>  );};
      function RootDocument({ children }: { children: ReactNode }) {  const params = LocaleRoute.useParams();  const locale = params?.locale ?? defaultLocale;  return (    <html dir={getHTMLTextDir(locale)} lang={locale}>      {/* ... */}    </html>  );}
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";export default defineConfig({  plugins: [    intlayerProxy(), // O proxy deve ser colocado antes do servidor se você usar Nitro    nitro(),    intlayer(),    tanstackStart({      router: {        routeFileIgnorePattern:          ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5)$",      },    }),    viteReact(),  ],});
      import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";export const Route = createFileRoute("/{-$locale}/")({  component: RouteComponent,  head: ({ params }) => {    const { locale } = 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 },      ],    };  },});
      import { createServerFn } from "@tanstack/react-start";import {  getRequestHeader,  getRequestHeaders,} from "@tanstack/react-start/server";import { getCookie, getIntlayer, getLocale } from "intlayer";export const getLocaleServer = createServerFn().handler(async () => {  const locale = await getLocale({    // Obtenha o cookie da solicitação (padrão: 'INTLAYER_LOCALE')    getCookie: (name) => {      const cookieString = getRequestHeader("cookie");      return getCookie(name, cookieString);    },    // Obtenha o cabeçalho da solicitação (padrão: 'x-intlayer-locale')    // Fallback usando negociação Accept-Language    getHeader: (name) => getRequestHeader(name),  });  // Recupere algum conteúdo usando getIntlayer()  const content = getIntlayer("app", locale);  return { locale, content };});
      import { createFileRoute } from "@tanstack/react-router";// Isso cria uma rota dedicada /[locale]/404// É usada tanto como uma rota direta quanto importada como um componente em outros arquivosexport const Route = createFileRoute("/{-$locale}/404")({  component: NotFoundComponent,});// Exportado separadamente para que possa ser reutilizado em notFoundComponent e rotas catch-allexport function NotFoundComponent() {  return (    <div>      <h1>404</h1>    </div>  );}
      import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";import { validatePrefix } from "intlayer";import { NotFoundComponent } from "./404";export const Route = createFileRoute("/{-$locale}")({  // beforeLoad executa antes da rota ser renderizada (tanto no servidor quanto no cliente)  // É o lugar ideal para validar o prefixo de locale  beforeLoad: ({ params }) => {    const localeParam = params.locale;    // validatePrefix verifica se o locale é válido de acordo com sua configuração intlayer    const { isValid, localePrefix } = validatePrefix(localeParam);    if (!isValid) {      // Prefixo de locale inválido - redirecionar para a página 404 com um prefixo de locale válido      throw redirect({        to: "/{-$locale}/404",        params: { locale: localePrefix },      });    }  },  component: Outlet,  // notFoundComponent é chamado quando uma rota filha não existe  // por exemplo, /en/pagina-inexistente dispara isso dentro do layout /en  notFoundComponent: NotFoundComponent,});
      import { createFileRoute } from "@tanstack/react-router";import { NotFoundComponent } from "./404";// A rota $ (splat/catch-all) corresponde a qualquer caminho que não corresponda a outras rotas// por exemplo, /en/algum/caminho/profundamente/aninhado/invalido// Isso garante que TODOS os caminhos não correspondentes dentro de um locale mostrem a página 404// Sem isso, caminhos profundos não correspondentes podem mostrar uma página em branco ou erroexport const Route = createFileRoute("/{-$locale}/$")({  component: NotFoundComponent,});
      npx intlayer extract
      import { defineConfig } from "vite";import { intlayer, intlayerCompiler } from "vite-intlayer";export default defineConfig({ plugins: [   intlayer(),   intlayerCompiler(), // Adiciona o plugin do compilador ],});
      npm run build # Ou npm run dev
      import { localeFlatMap } from "intlayer";// ... outras importaçõesexport const pathList = ["", "/about", "/404"];const localizedPages = localeFlatMap(({ urlPrefix }) =>  pathList.map((path) => ({    path: `${urlPrefix}${path}`,    prerender: {      enabled: true,    },  })));export default defineConfig({  plugins: [    // ... outros plugins    tanstackStart({      // ... outras configurações      sitemap: {        enabled: false,      },      prerender: {        enabled: true,        crawlLinks: false,        concurrency: 10,      },      pages: localizedPages,    }),  ],});
      import { createFileRoute } from "@tanstack/react-router";import { generateSitemap } from "intlayer";const SITE_URL = (  import.meta.env.VITE_SITE_URL ?? "http://localhost:3000").replace(/\/$/, "");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" },        });      },    },  },});
      {  // ... suas configurações existentes  include: [    // ... seus includes existentes    ".intlayer/**/*.ts", // Incluir os tipos gerados automaticamente  ],}
      # Ignorar os arquivos gerados pelo Intlayer.intlayer