Autor:
    Criação:2026-04-24Última atualização:2026-08-30

    Traduza seu website Astro + Lit usando Intlayer | Internacionalização (i18n)

    ide.intlayer.org
    intlayer-astro-template.vercel.app

    Índice

    Por que Intlayer em vez de alternativas?

    Comparado com soluções principais como astro-i18n ou i18next, Intlayer é uma solução que vem com otimizações integradas como:

    O Intlayer é otimizado para funcionar perfeitamente com o Astro, oferecendo roteamento multilíngue, mapa do site e todos os recursos necessários para dimensionar a internacionalização (i18n).

    Em vez de carregar arquivos JSON enormes em suas páginas, carregue apenas o conteúdo necessário. O Intlayer ajuda a reduzir o tamanho do bundle e das páginas em até 50%.

    Definir o escopo do conteúdo do seu aplicativo facilita a manutenção de aplicativos de grande escala. Você pode duplicar ou excluir uma única pasta de recursos sem o fardo mental de revisar toda a base de código de seu conteúdo. Além disso, o Intlayer é totalmente tipado (fully typed) para garantir a precisão do seu conteúdo.

    A co-localização de conteúdo reduz o contexto necessário pelos Large Language Models (LLMs). O Intlayer também vem com um conjunto de ferramentas, como uma CLI para testar traduções ausentes,LSP, MCP, e agent skills, para tornar a experiência do desenvolvedor (DX) ainda mais tranquila para os agentes de IA.

    Use a automação para traduzir seu pipeline de CI/CD usando o LLM de sua escolha às custas de seu provedor de IA. O Intlayer também oferece um compilador para automatizar a extração de conteúdo, bem como uma plataforma web para ajudar a traduzir em segundo plano.

    Conectar arquivos JSON enormes a componentes pode levar a problemas de desempenho e reatividade. O Intlayer otimiza o carregamento do seu conteúdo no momento da construção.

    Mais do que apenas uma solução i18n, o Intlayer fornece um [editor visual] auto-hospedado(/pt/doc/concept/editor)* e um *CMS completo para ajudá-lo a gerenciar seu conteúdo multilíngue em tempo real, facilitando a colaboração com tradutores, redatores e outros membros da equipe. O conteúdo pode ser armazenado local e/ou remotamente.

    Guia passo a passo para configurar o Intlayer no Astro + Lit

    Confira o modelo da aplicação no GitHub.

    1. Instalar Dependências

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

      bash
      npx intlayer init --interactive
      
      a flag --interactive é opcional. Use intlayer-cli init se você for um agente de IA.
      Este comando detectará seu ambiente e instalará os pacotes necessários. Por exemplo:
      bash
      npm install intlayer astro-intlayer lit lit-intlayer @astrojs/lit
      
      • intlayer O pacote principal que fornece ferramentas de i18n para gerenciamento de configuração, traduções, declaração de conteúdo, transpilação e comandos CLI.

      • astro-intlayer Inclui o plugin de integração do Astro para vincular o Intlayer ao bundler Vite, bem como o middleware para detectar o idioma preferido do usuário, gerenciar cookies e lidar com redirecionamentos de URL.

      • lit Pacote principal do Lit para criar Web Components rápidos e leves.

      • lit-intlayer Pacote para integrar o Intlayer em aplicações Lit. Ele fornece hooks baseados em ReactiveController (useIntlayer, useLocale, etc.) que instruem automaticamente o LitElement a renderizar novamente quando o idioma muda.

      • @astrojs/lit Integração oficial do Astro que permite o uso de custom elements Lit dentro de páginas Astro.

    2. Configurar seu Projeto

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

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            Locales.PORTUGUESE,
            // Seus outros idiomas
          ],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      
      Através deste arquivo de configuração, você pode configurar URLs localizadas, redirecionamentos de middleware, nomes de cookies, localização e extensões de declarações de conteúdo, desativar logs do Intlayer no console e muito mais. Para uma lista completa de parâmetros disponíveis, consulte a documentação de configuração.
    3. Integrar o Intlayer na sua configuração do Astro

      Adicione o plugin intlayer e a integração do Lit à sua configuração do Astro.

      astro.config.ts
      // @ts-check
      
      import { intlayer } from "astro-intlayer";
      import lit from "@astrojs/lit";
      import { defineConfig } from "astro/config";
      
      // https://astro.build/config
      export default defineConfig({
        integrations: [intlayer(), lit()],
      });
      
      O plugin de integração intlayer() é usado para integrar o Intlayer ao Astro. Ele garante a geraçã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 Astro e fornece aliases para otimizar o desempenho.
      A integração lit() permite o uso de custom elements Lit dentro de páginas Astro.
    4. Declarar seu conteúdo

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

      src/components/lit/app.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const litDemoContent = {
        key: "lit-demo",
        content: {
          greeting: t({
            en: "Hello World",
            fr: "Bonjour le monde",
            es: "Hola mundo",
            pt: "Olá Mundo",
          }),
          description: t({
            en: "Welcome to my multilingual Astro + Lit site.",
            fr: "Bienvenue sur mon site Astro + Lit multilingue.",
            es: "Bienvenido a mi sitio Astro + Lit multilingüe.",
            pt: "Bem-vindo ao meu site Astro + Lit multilíngue.",
          }),
        },
      } satisfies Dictionary;
      
      export default litDemoContent;
      
      As declarações de conteúdo podem ser definidas em qualquer lugar da sua aplicação, desde que estejam incluídas no contentDir (por padrão ./src) e correspondam à extensão do arquivo de declaração de conteúdo (por padrão .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).
      Para mais informações, consulte a documentação de declaração de conteúdo.
    5. Usar o conteúdo no Astro

      Você pode consumir os dicionários diretamente nos seus arquivos .astro usando os ajudantes principais exportados do intlayer. Você também deve adicionar metadados de SEO (como hreflang e links canônicos) a cada página. Os custom elements Lit são importados via um <script> no cliente e colocados no corpo da página.

      src/pages/[...locale]/index.astro
      ---
      import {
        getIntlayer,
        getLocaleFromPath,
        getLocalizedUrl,
        getHTMLTextDir,
        getPrefix,
        localeMap,
        defaultLocale,
        type LocalesValues,
      } from "intlayer";
      
      export const getStaticPaths = () => {
        return localeMap(({ locale }) => ({
          params: { locale: getPrefix(locale).localePrefix },
        }));
      };
      
      const locale = getLocaleFromPath(Astro.url.pathname) as LocalesValues;
      const { greeting } = getIntlayer("lit-demo", locale);
      ---
      
      <!doctype html>
      <html lang={locale} dir={getHTMLTextDir(locale)}>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width" />
          <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
          <title>{greeting}</title>
      
          <!-- Link Canônico -->
          <link
            rel="canonical"
            href={new URL(getLocalizedUrl(Astro.url.pathname, locale), Astro.site)}
          />
      
          <!-- Links Hreflang -->
          {
            localeMap(({ locale: mapLocale }) => (
              <link
                rel="alternate"
                hreflang={mapLocale}
                href={new URL(
                  getLocalizedUrl(Astro.url.pathname, mapLocale),
                  Astro.site
                )}
              />
            ))
          }
      
          <link
            rel="alternate"
            hreflang="x-default"
            href={new URL(
              getLocalizedUrl(Astro.url.pathname, defaultLocale),
              Astro.site
            )}
          />
        </head>
        <body>
          <!-- Custom element Lit - recebe a localidade detectada pelo servidor como uma propriedade -->
          <lit-demo locale={locale}></lit-demo>
        </body>
      </html>
      
      <script>
        import "../../components/lit/LitDemo";
      </script>
      
      Se você quiser usar seu conteúdo em un atributo de string, como alt, title, href, aria-label, etc., você pode usar o valor da função, como:
      tsx
      <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)} />
      

      Nota sobre a configuração de roteamento: A estrutura de diretórios que você usa depende da configuração middleware.routing no intlayer.config.ts:

      • prefix-no-default (padrão): mantém o idioma padrão na raiz (sem prefixo) e adiciona prefixos aos outros. Use [...locale] para capturar todos os casos.
      • prefix-all: todos os URLs recebem um prefixo de idioma. Você pode usar o padrão [locale] se não precisar lidar com a raiz separadamente.
      • search-param ou no-prefix: não são necessários diretórios de idioma. O idioma é tratado via parâmetros de consulta ou cookies.
    6. Criar um componente Custom Element de Lit

      Crie um custom element Lit. Chame installIntlayer no connectedCallback usando o atributo locale do servidor para inicializar o singleton de tradução no lado do cliente.

      src/components/lit/LitDemo.ts
      import { LitElement, html } from "lit";
      import { installIntlayer, useIntlayer, useLocale } from "lit-intlayer";
      import { getLocalizedUrl, getLocaleName, type LocalesValues } from "intlayer";
      
      class LitDemo extends LitElement {
        static properties = {
          locale: { type: String },
        };
      
        locale: LocalesValues = "en" as LocalesValues;
      
        private _content = useIntlayer(this, "lit-demo");
        private _localeCtrl = useLocale(this, {
          onLocaleChange: (newLocale: LocalesValues) => {
            window.location.href = getLocalizedUrl(
              window.location.pathname,
              newLocale
            );
          },
        });
      
        override connectedCallback() {
          super.connectedCallback();
          // Inicializa com a localidade detectada pelo servidor
          installIntlayer({ locale: this.locale as any });
        }
      
        override render() {
          const { greeting, description } = this._content;
          const {
            locale: currentLocale,
            availableLocales,
            setLocale,
          } = this._localeCtrl;
      
          return html`
            <div>
              <h1>${greeting}</h1>
              <p>${description}</p>
              <!-- Seletor de idioma renderizado dentro do LitElement -->
              <div class="locale-switcher">
                <span class="switcher-label">Mudar idioma:</span>
                <div class="locale-buttons">
                  ${availableLocales.map(
                    (localeItem) => html`
                      <button
                        class="locale-btn ${
                          localeItem === currentLocale ? "active" : ""
                        }"
                        ?disabled=${localeItem === currentLocale}
                        @click=${() => setLocale(localeItem)}
                      >
                        <span class="ls-own-name">${getLocaleName(localeItem)}</span>
                        <span class="ls-current-name"
                          >${getLocaleName(localeItem, currentLocale)}</span
                        >
                        <span class="ls-code">${localeItem.toUpperCase()}</span>
                      </button>
                    `
                  )}
                </div>
              </div>
            </div>
          `;
        }
      }
      
      customElements.define("lit-demo", LitDemo);
      
      O atributo locale é passado da página Astro (detecção no servidor) e usado para inicializar o installIntlayer no connectedCallback, definindo o idioma inicial para todos os hooks ReactiveController dentro do elemento.
      useIntlayer é registrado como um ReactiveController. Ele solicita automaticamente uma nova renderização do elemento quando o idioma muda, portanto, nenhuma lógica de inscrição adicional é necessária.
    7. Adicionar um Seletor de Idioma

      A funcionalidade de troca de idioma está integrada diretamente no método render() do custom element Lit (veja o passo 6 acima). Ela usa o useLocale do lit-intlayer e navega para a URL localizada quando um usuário seleciona um novo idioma:

      src/components/lit/LitDemo.ts
      // Dentro da classe LitElement, após a configuração do useLocale no passo 6:
      
      private _localeCtrl = useLocale(this, {
        onLocaleChange: (newLocale: LocalesValues) => {
          // Navega para a URL localizada ao mudar de idioma
          window.location.href = getLocalizedUrl(window.location.pathname, newLocale);
        },
      });
      
      override render() {
        const { locale: currentLocale, availableLocales, setLocale } = this._localeCtrl;
      
        return html`
          <div class="locale-switcher">
            <span class="switcher-label">Mudar idioma:</span>
            <div class="locale-buttons">
              ${availableLocales.map(
                (localeItem) => html`
                  <button
                    class="locale-btn ${localeItem === currentLocale ? "active" : ""}"
                    ?disabled=${localeItem === currentLocale}
                    @click=${() => setLocale(localeItem)}
                  >
                    <span class="ls-own-name">${getLocaleName(localeItem)}</span>
                    <span class="ls-current-name">${getLocaleName(localeItem, currentLocale)}</span>
                    <span class="ls-code">${localeItem.toUpperCase()}</span>
                  </button>
                `
              )}
            </div>
          </div>
        `;
      }
      

      Nota sobre a reatividade do Lit: useLocale retorna um ReactiveController. Quando o setLocale é chamado, o controlador solicita automaticamente uma nova renderização, atualizando o estado do botão ativo sem a necessidade de manipulação manual do DOM.

      Nota sobre persistência: O uso de onLocaleChange para redirecionar via window.location.href garante que a nova URL linguística seja visitada, permitindo que o middleware do Intlayer defina o cookie de idioma e lembre da preferência do usuário em visitas futuras.

    8. Sitemap e Robots.txt

      O Intlayer oferece utilitários para criar dinamicamente o seu sitemap localizado e os arquivos robots.txt.

      Sitemap

      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.

      Crie src/pages/sitemap.xml.ts para gerar um sitemap que inclua todas as suas rotas localizadas.

      src/pages/sitemap.xml.ts
      import type { APIRoute } from "astro";
      import { generateSitemap, type SitemapUrlEntry } from "intlayer";
      
      const pathList: SitemapUrlEntry[] = [
        { path: "/", changefreq: "daily", priority: 1.0 },
        { path: "/about", changefreq: "monthly", priority: 0.7 },
      ];
      
      const SITE_URL = import.meta.env.SITE ?? "http://localhost:4321";
      
      export const GET: APIRoute = async ({ site }) => {
        const xmlOutput = generateSitemap(pathList, { siteUrl: SITE_URL });
      
        return new Response(xmlOutput, {
          headers: { "Content-Type": "application/xml" },
        });
      };
      

      Robots.txt

      Crie src/pages/robots.txt.ts para controlar o rastreamento dos motores de busca.

      src/pages/robots.txt.ts
      import type { APIRoute } from "astro";
      import { getMultilingualUrls } from "intlayer";
      
      const getAllMultilingualUrls = (urls: string[]) =>
        urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
      
      const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);
      
      export const GET: APIRoute = ({ site }) => {
        const robotsTxt = [
          "User-agent: *",
          "Allow: /",
          ...disallowedPaths.map((path) => `Disallow: ${path}`),
          "",
          `Sitemap: ${new URL("/sitemap.xml", site).href}`,
        ].join("\n");
      
        return new Response(robotsTxt, {
          headers: { "Content-Type": "text/plain" },
        });
      };
      
    9. Extrair o conteúdo dos seus componentes

      Opcional

      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
      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
      npx intlayer extract
      
      Since v9, the intlayerCompiler is included in the intlayer plugin. So you don't need to add it manually.

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

      vite.config.ts
      import { defineConfig } from "vite";
      import { intlayer, intlayerCompiler } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          intlayer(),
          intlayerCompiler(), // Adds the compiler plugin
        ],
      });
      
      bash
      npm run build # Ou npm run dev
      

    Configuração do TypeScript

    O Intlayer usa o aumento de módulos (module augmentation) para aproveitar o TypeScript, tornando sua base de código mais robusta. Se você usar a sintaxe de decoradores, certifique-se de habilitar experimentalDecorators nas suas opções de compilador.

    Preenchimento automático

    Erro de tradução

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

    tsconfig.json
    {
      compilerOptions: {
        // ...
        experimentalDecorators: true,
        useDefineForClassFields: false, // Necessário para suporte a decoradores no Lit
      },
      "include": [
        // ... sua configuração existente do TypeScript
        ".intlayer/**/*.ts", // Incluir tipos gerados automaticamente
      ],
    }
    

    Configuração do Git

    Recomenda-se ignorar os arquivos gerados pelo Intlayer. Isso evita committá-los no seu repositório Git.

    Para fazer isso, adicione as seguintes instruções ao seu arquivo .gitignore:

    bash
    # 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 do Intlayer para VS Code.

    Instalação pelo VS Code Marketplace

    Esta extensão fornece:

    • Preenchimento automático para chaves de tradução.
    • Detecção de erros em tempo real para traduções ausentes.
    • Visualização inline do conteúdo traduzido.
    • Ações rápidas para criar e atualizar traduções facilmente.

    Para mais informações sobre o uso da extensão, consulte a documentação da Extensão do VS Code.

    Aprofunde seu conhecimento

    Se quiser saber mais, você também pode implementar o Editor Visual ou usar o CMS para externalizar seu conteúdo.

    Perguntas Frequentes

    A opção nativa de i18n do Astro cuida dos prefixos de URL e redirecionamentos, mas não gerencia as mensagens, e uma ilha traz uma complicação a mais por rodar Lit em vez de Astro.

    • i18n integrado do Astro com dicionários manuais, junto com @lit/localize dentro da ilha: duas fontes de conteúdo para manter e sem tipagem compartilhada entre si.
    • Intlayer: uma camada única de conteúdo para ambos. O astro-intlayer cuida das páginas .astro e o lit-intlayer das ilhas Lit, consumindo as mesmas declarações.

    Declarar um texto uma única vez e utilizá-lo tanto em uma página estática quanto em uma ilha interativa é a grande razão para adotar uma camada unificada de conteúdo. Consulte por que Intlayer.

    Muito menos do que uma configuração baseada em namespaces, porque uma página nunca baixa um catálogo que não renderiza. As páginas Astro são renderizadas em tempo de build, portanto enviam HTML traduzido e nenhum dicionário; apenas as ilhas recebem dados. O compilador em tempo de build resolve as chamadas de conteúdo para as entradas exatas que o componente utiliza, e os dicionários dinâmicos dividem o restante por locale. Comparado às alternativas habituais, o Intlayer reduz o tamanho do bundle e da página em até 50%. Consulte otimização de bundle e o benchmark.

    Em grande parte, sim. Siga a visão geral dos adaptadores de compatibilidade para migrar o conteúdo. Você também pode migrar gradualmente: o plugin sync JSON mantém seus catálogos JSON existentes como fonte de verdade e gera dicionários Intlayer a partir deles, mantendo ambas as camadas sincronizadas enquanto você migra componentes um a um.

    Sim. O plugin sync JSON mantém seus arquivos /messages/{locale}/{namespace}.json como fonte de verdade e gera dicionários Intlayer a partir deles, em ambas as direções. O plugin sync PO faz o mesmo para catálogos gettext, e os arquivos por locale permitem dividir o conteúdo por idioma em vez de agrupar todos os locales em um único arquivo.

    Não. Execute npx intlayer extract e o Intlayer lê seus componentes, extrai as strings voltadas para o usuário e escreve um arquivo .content ao lado de cada um, para que você revise um diff em vez de copiar strings para um catálogo uma a uma. O passo 15 deste guia detalha esse processo.

    Para um fluxo de trabalho totalmente automatizado, o Intlayer Compiler faz o mesmo em tempo de build: ele analisa seu código JSX, TSX, Vue e Svelte a cada alteração, gera os dicionários e os mantém sincronizados via hot module replacement, dispensando completamente a manutenção manual de chaves.

    Dois limites são importantes considerar: o compilador opera por análise estática, de modo que strings criadas apenas em tempo de execução (como códigos de erro de API ou campos dinâmicos de CMS) ficam fora de alcance. Além disso, ele precisa distinguir texto visível de lógicas de aplicação como className="active" ou status codes, exigindo algumas anotações em bases de código extensas. O comando extract evita ambos mantendo você no controle.

    Cinco ferramentas, todas opcionais:

    • Extensão VS Code: navegue de uma chave useIntlayer diretamente para o arquivo de conteúdo que a declara, extraia conteúdo de um componente e execute build, fill, test, push e pull pela paleta de comandos ou pela aba dedicada do Intlayer.
    • Servidor LSP: a mesma inteligência em qualquer editor compatível com LSP, com ir para definição, localizar referências, pré-visualizações de valores traduzidos ao passar o mouse, autocompletar e alertas para chaves não declaradas. Também resolve chamadas de i18next, react-i18next, next-intl e use-intl, facilitando a migração.
    • Servidor MCP: expõe a documentação e a CLI do Intlayer para Cursor, VS Code, Claude Desktop, Claude Code e ChatGPT, permitindo que os assistentes respondam com base na documentação atualizada e executem comandos como intlayer fill.
    • Agent Skills: habilidades focadas como intlayer-config, intlayer-cli e intlayer-content, além de uma por framework, ensinando ao agente suas regras de roteamento e tipos de nós.
    • Plugin ESLint: a regra no-raw-text identifica strings hardcoded, com regras adicionais para chaves estáticas e conteúdo não utilizado.