Faça sua pergunta e obtenha um resumo do documento referenciando esta página e o provedor AI de sua escolha
O conteúdo desta página foi traduzido com uma IA.
Veja a última versão do conteúdo original em inglêsSe 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çãoCopiar o Markdown do documento para a área de transferência
Lingui VS Intlayer: Benchmark de Internacionalização (i18n) para React e Next.js
Lingui e Intlayer são as duas bibliotecas deste benchmark que utilizam um compilador em vez de operarem estritamente como um runtime. O Lingui extrai mensagens a partir de macros durante o build e compila catálogos por idioma. O Intlayer compila dicionários por componente e aplica tree-shaking por idioma. Na teoria, deveriam ser muito parecidos. Os números revelam onde eles se distanciam.
Os dados são provenientes do Benchmark Bloom, uma suíte de código aberto que constrói a mesma aplicação com cada biblioteca e afere o que o navegador efetivamente baixa e executa.
tl;dr: O Lingui é a biblioteca mais próxima do Intlayer em volume bruto de JavaScript por página: 115-120 KB contra 118,6 KB no TanStack Start após a configuração de lazy loading, e 148,6 KB contra 141,3 KB no Next.js. A diferença real surge nos demais indicadores: um componente do Lingui compilado isoladamente pesa 58-153 KB contra 6-8 KB no Intlayer, a hidratação leva 28-34 ms contra 11-14 ms, o fallback do idioma original vaza entre 3% e 15% de textos em inglês nas páginas em francês em qualquer configuração otimizada, e atingir essa otimização requer extrair, compilar e selecionar catálogos manualmente por rota. O Intlayer alcança esses números sem qualquer configuração complexa.
Em resumo
- Lingui - Baseado em macros (
t`...`,<Trans>,msg), formato ICU MessageFormat, catálogos em.po/ JSON, fluxo de trabalholingui extract+lingui compile. Compila IDs de mensagem em hashes compactos, suporta carregamento dinâmico de catálogos por idioma. Consolidado, agnóstico de framework e com excelente ecossistema de ferramentas de tradução em torno do formato.po. - Intlayer - Modelo de conteúdo orientado a componentes. Dicionários
.content.tsresidem ao lado do componente ao qual atendem; um compilador de build realiza tree-shaking e carregamento sob demanda por componente e por idioma; tipos TypeScript rigorosos são gerados automaticamente a partir do conteúdo, e traduções ausentes geram erro de compilação. Inclui middleware, utilitários de SEO, um Editor Visual / CMS e tradução assistida por IA.
Abrir a tabela em um modal para ver todo o conteúdo claramente
Os badges são atualizados de forma automática. Instantâneos podem mudar ao longo do tempo.
Comparação funcional lado a lado
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Recurso | Intlayer (react-intlayer / next-intlayer) | Lingui (@lingui/core / @lingui/react) |
|---|---|---|
| Traduções próximas aos componentes | ✅ Sim, .content.ts colocalizado com cada componente | ⚠️ Strings originais no JSX via macros; traduções em catálogos .po centralizados |
| Integração com TypeScript | ✅ Tipos estritos gerados automaticamente a partir do conteúdo | ⚠️ Macros tipadas; IDs de mensagem sem tipos, chaves ausentes não são apontadas |
| Detecção de traduções ausentes | ✅ Erro no TypeScript + erro/aviso no build | ⚠️ lingui extract exibe estatísticas; no runtime recorre silenciosamente ao texto original |
| Conteúdo rico (JSX / Markdown / componentes) | ✅ Suporte nativo e direto | ✅ Elemento <Trans> com componentes aninhados |
| Suporte a ICU | ⚠️ Em andamento | ✅ Sim (macros plural, select, selectOrdinal) |
| Formatação (datas, números, moedas) | ✅ useNumber, useDate, ... (suportado por Intl) | ✅ i18n.date(), i18n.number() |
| Roteamento localizado e middleware | ✅ Proxy e middleware integrados, utilitário getMultilingualUrls | ❌ Não faz parte do núcleo |
| Auxiliares de SEO (hreflang, sitemap...) | ✅ Utilitários prontos para uso | ❌ Configuração manual |
| Componentes de servidor síncronos (RSC) | ✅ useIntlayer de next-intlayer/server funciona em qualquer subcomponente de servidor | ⚠️ Exige uma instância I18n por requisição, repassada manualmente ou via setI18n |
| Tree-shaking (entregar só o que for usado) | ✅ Por componente e por idioma, automatizado pelo compilador | ⚠️ Por idioma via lingui compile; por rota exige divisão manual de catálogos |
| Carregamento sob demanda (Lazy loading) | ✅ importMode: 'dynamic' (uma única linha de configuração) | ⚠️ Uso manual de import() de catálogos + i18n.load() / i18n.activate() |
| Limpeza de conteúdo não utilizado | ✅ Dicionários órfãos são descartados no build | ✅ lingui extract --clean remove mensagens obsoletas |
| Testar traduções ausentes (CLI / CI) | ✅ npx intlayer content test | ⚠️ Estatísticas de lingui extract (sem código de falha por padrão) |
| Pipeline de compilação | ✅ Um único plugin (@intlayer/swc / @intlayer/babel / vite-intlayer) | ⚠️ Plugin de macro (Babel ou SWC) + etapas extract + compile |
| Tradução assistida por IA | ✅ Integrada, utiliza suas próprias chaves de API | ❌ Não |
| Editor Visual / CMS | ✅ Editor Visual gratuito + CMS opcional | ❌ Não (.po integra com ferramentas TMS externas) |
| Servidor MCP e Agent Skills | ✅ Sim | ❌ Não |
| Ecossistema e comunidade | ⚠️ Mais recente, porém em expansão acelerada | ✅ Etabelecido, agnóstico de framework |
O benchmark
O que foi medido
A suíte Benchmark Bloom compila a mesma aplicação com cada biblioteca: 10 páginas (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 idiomas (en, fr, es, de, it, pt, zh, ja, ko, ru), componentes idênticos e conteúdo idêntico. As páginas são avaliadas em en e fr. Cada biblioteca foi avaliada em até quatro estratégias de carregamento:
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Estratégia | Descrição | Cenário de aplicação comum |
|---|---|---|
| static | Todos os catálogos compilados são importados e carregados no início | Protótipos rápidos, código de IA |
| dynamic | Apenas o catálogo do idioma ativo é importado via import(), mas engloba todas as páginas | Maioria dos projetos cotidianos |
| scoped-static | Um catálogo por rota, todos embutidos no pacote inicial | Raro |
| scoped-dynamic | Um catálogo por rota + import() dinâmico. Apenas a página atual e o idioma ativo | Apps com orçamento rigoroso de bytes |
O Intlayer não tem variante "scoped" isolada: o compilador delimita o escopo de conteúdo por componente automaticamente, logo suas linhas static e dynamic já nascem perfeitamente segmentadas.
Para cada compilação, registram-se:
- Lib size: tamanho gzip de um componente vazio que importa unicamente a biblioteca de i18n (o custo fixo do runtime).
- Page JS: média de JavaScript gzip baixado por página, calculada sobre todas as páginas e idiomas.
- Locale leak %: proporção de strings traduzidas no JS baixado pertencentes a idiomas que o usuário não está visualizando.
- Page leak %: proporção de strings traduzidas no JS baixado pertencentes a páginas onde o usuário não está navegando.
- Component avg: tamanho gzip médio de cada componente compilado de forma isolada.
- E2E reactivity: intervalo de tempo real entre selecionar um novo idioma e o DOM atualizar a tag
html[lang](Playwright, 5 iterações). - Hydration: duração da fase de hidratação do React.
Os dados abaixo referem-se ao teste de 2026-09-12 com@lingui/react6.6.0 eintlayer9.5.1. A aplicação de testes é enxuta por design (poucas dezenas de strings por idioma), portanto os índices de vazamento expressam um padrão estrutural que se amplifica com o volume de dados.
Resultados no Next.js
Escolha as métricas e bibliotecas do seu interesse:
Métrica
Carregamento JSON dinâmico
Carrega as traduções tardiamente em tempo de execução
JSON com escopo (namespacing)
Namespaces de tradução por página
O que é essa métrica?
O tamanho total compactado em gzip do pacote da biblioteca de internacionalização. Inclui apenas o provedor e a lógica de recuperação de conteúdo após o tree-shaking e a minificação.
Por que é importante?
Um tamanho de biblioteca menor reduz a carga útil inicial de JavaScript, resultando em tempos de download e execução mais rápidos no cliente.
Ver como
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Biblioteca | Estratégia | Lib size (gz) | Page JS méd (gz) | Vazamento idioma | Vazamento página | Componente méd (gz) | Reatividade E2E | Hidratação |
|---|---|---|---|---|---|---|---|---|
| base (sem i18n) | - | 0,0 KB | 141,0 KB | 0,0% | 0,0% | 0,9 KB | 13,4 ms | 11,8 ms |
| Lingui | static | 11,9 KB | 207,4 KB | 50,0% | 90,0% | 73,3 KB | 15,3 ms | 15,2 ms |
| Lingui | dynamic | 11,9 KB | 145,4 KB | 2,8% | 89,9% | 19,9 KB | 15,7 ms | 12,7 ms |
| Lingui | scoped-static | 11,9 KB | 148,2 KB | 2,7% | 89,1% | 20,4 KB | 15,1 ms | 13,1 ms |
| Lingui | scoped-dynamic | 11,9 KB | 148,6 KB | 14,8% | 0,0% | 152,6 KB | 16,1 ms | 14,8 ms |
next-intlayer | static | 5,5 KB | 141,3 KB | 0,0% | 0,0% | 8,5 KB | 15,5 ms | 16,9 ms |
next-intlayer | dynamic | 5,5 KB | 141,3 KB | 0,0% | 0,0% | 6,9 KB | 15,3 ms | 15,9 ms |
Análise dos números
- Custo do runtime. Um componente vazio pesa 11,9 KB gzip no Lingui contra 5,5 KB no Intlayer. Na página completa, o melhor arranjo do Lingui fica em +7,3 KB em relação ao Intlayer (148,6 contra 141,3 KB); o Intlayer situa-se em modestos +0,3 KB acima da aplicação base sem i18n.
- A abordagem ingênua tem custo elevado. Carregar todos os catálogos compilados no início resulta em 207,4 KB por página, +66 KB sobre o app base. Metade das strings pertence ao idioma errado e 90% a páginas não visualizadas.
- Carregamento dinâmico ajusta o idioma, mas não a página. Com um catálogo por idioma, o vazamento de página permanece em ~90%: o catálogo completo de francês é entregue em cada página em francês. Para alcançar 0% de vazamento de página no Lingui é necessário recorrer a
scoped-dynamic: um catálogo por rota, extraído e compilado individualmente, importado manualmente em cada página. - O fallback do idioma de origem vaza por construção. Mesmo nas configurações mais bem planejadas, entre 3% e 15% das strings em inglês são enviadas nas páginas em francês. As macros do Lingui guardam o texto fonte como salvaguarda, de modo que ele aterrissa no bundle. O Intlayer resolve fallbacks no build e entrega exclusivamente o idioma ativo.
- O tamanho dos componentes isolados dispara em
scoped-dynamic. Cada componente compilado isoladamente projeta uma média de 152,6 KB, pois os catálogos das rotas permanecem alcançáveis pelos imports. O mesmo componente usandouseIntlayer()registra uma média de 6,9 KB.
Tabela completa, cada biblioteca e cada estratégia, no relatório de benchmark do Next.js.
Resultados no TanStack Start
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Biblioteca | Estratégia | Lib size (gz) | Page JS méd (gz) | Vazamento idioma | Vazamento página | Componente méd (gz) | Reatividade E2E | Hidratação |
|---|---|---|---|---|---|---|---|---|
| base (sem i18n) | - | 0,0 KB | 111,0 KB | 0,0% | 0,0% | 0,7 KB | 8,1 ms | 21,6 ms |
| Lingui | static | 11,2 KB | 152,2 KB | 50,0% | 90,0% | 58,0 KB | 3,9 ms | 19,9 ms |
| Lingui | dynamic | 11,2 KB | 115,2 KB | 9,3% | 0,0% | 85,5 KB | 5,9 ms | 28,0 ms |
| Lingui | scoped-static | 11,2 KB | 120,8 KB | 4,0% | 0,0% | 147,9 KB | 7,1 ms | 33,9 ms |
| Lingui | scoped-dynamic | 11,2 KB | 120,2 KB | 8,6% | 0,0% | 83,7 KB | 42,1 ms | 32,9 ms |
intlayer | static | 5,0 KB | 125,8 KB | 50,0% | 0,0% | 8,1 KB | 3,2 ms | 11,5 ms |
intlayer | dynamic | 5,0 KB | 118,6 KB | 0,0% | 0,0% | 6,3 KB | 3,6 ms | 14,1 ms |
@intlayer/lingui (compat) | dynamic | 10,3 KB | 137,0 KB | 9,9% | 0,0% | 12,8 KB | 2,9 ms | 19,7 ms |
Análise dos números
- No volume de JavaScript por página, o Lingui vence por margem mínima. O Lingui em modo
dynamicatinge 115,2 KB, apenas 3,4 KB abaixo dos 118,6 KB do Intlayer. Seus catálogos compilados com hashes são extremamente densos, e o roteador do TanStack Start particiona as rotas tão bem que o vazamento de página é nulo logo na linhadynamic. - Todos os outros índices favorecem o Intlayer. A hidratação toma 28-34 ms no Lingui contra 11-14 ms no Intlayer:
i18n.load()+i18n.activate()rodam no cliente antes que o React possa hidratar. Os componentes isolados pesam 58-148 KB em vez de 6-8 KB. O vazamento de idioma nunca zera (fica entre 4% e 9%) por causa do fallback inglês. - A troca de idioma fica sensivelmente lenta no modo otimizado. O Lingui em
scoped-dynamicdemanda 42 ms para refletir a nova língua nohtml[lang], já que o novo catálogo precisa ser baixado, inserido e ativado antes da renderização visual. O Intlayer alterna em 3-4 ms em qualquer modo. - A linha
staticdo Intlayer já apresenta 0% de vazamento de página, pois inclui unicamente os dicionários consumidos pelos componentes daquela tela. Uma única linha de configuração (importMode: 'dynamic') extingue igualmente o vazamento de idioma. @intlayer/linguimantém a sintaxe das macros do Lingui consumindo dicionários do Intlayer. Ele cede um pouco no tamanho final da página (137 KB, devido à presença do runtime de macros) em troca de componentes muito mais leves (12,8 KB) e hidratação mais ágil. Uma excelente rota de transição.
Tabela completa no relatório de benchmark do TanStack Start.
Qual é a origem desse contraste? Dois compiladores, duas unidades de trabalho

Ambas as soluções utilizam um compilador. O divisor de águas é o que elas compilam.
O Lingui compila catálogos. As macros espalhadas pelo seu código são recolhidas em um arquivo .po por idioma e compiladas em um módulo JS por idioma. A unidade central é o idioma. Dividir além disso, por rota ou por componente, pressupõe criar catálogos adicionais, configurar o lingui.config.ts para extrair cada pedaço separadamente e administrar o carregamento manualmente. A instância I18n é global; cada useLingui() subscreve o componente a ela.
Copiar o código para a área de transferência
O Intlayer compila dicionários. Cada arquivo .content.ts é um dicionário atrelado a uma chave; o compilador identifica qual componente requisita qual chave e gera, por dicionário e por idioma, rigorosamente o JSON que aquele componente precisa. A unidade central é o componente. O escopo por rotas é uma consequência natural: uma tela apenas baixa os dicionários dos componentes que efetivamente renderiza.
Copiar o código para a área de transferência
É por essa razão que o padrão scoped-dynamic é uma entrega nativa e automática do Intlayer, enquanto no Lingui constitui um projeto próprio de engenharia de configuração. O abismo aumenta em dois eixos ao mesmo tempo, páginas e idiomas:

Para reproduzir as marcas da linhadynamic, definadictionary.importMode: 'dynamic'no seuintlayer.config.ts. Acesse a documentação sobre otimização de bundle.
Experiência do desenvolvedor
Configuração
Copiar o código para a área de transferência
Copiar o código para a área de transferência
Depois é necessário incluir @lingui/babel-plugin-lingui-macro (ou @lingui/swc-plugin) ao bundler, rodar lingui extract após alterar textos, rodar lingui compile antes do build e encapsular a aplicação em <I18nProvider i18n={i18n}>.
Copiar o código para a área de transferência
Basta adicionar intlayer() ao seu vite.config.ts (ou withIntlayer() no next.config.ts) e envolver a árvore de renderização com <IntlayerProvider>. Sem etapas de extração ou compilação manuais: os dicionários são montados diretamente quando o empacotador roda.
Componente
Copiar o código para a área de transferência
O texto em inglês vive no próprio componente; a tradução em francês fica em src/locales/fr/messages.po sob um ID em hash após a execução de lingui extract. Esquecer de extrair ou compilar aciona silenciosamente a string em inglês como fallback.
Copiar o código para a área de transferência
Copiar o código para a área de transferência
Ambos os idiomas coexistem no mesmo arquivo ao lado do componente. Um valor de fr em falta gera erro no build; uma chave digitada de forma errada aciona o verificador de tipos do TypeScript na hora.
Fora dos componentes
Metadados, funções de carregamento (loaders), funções de servidor: em qualquer ponto fora da árvore do React.
Copiar o código para a área de transferência
Gera-se uma nova instância I18n por execução, faz-se a importação manual do catálogo específico e emprega-se msg + i18n._() em vez de t. Conforme registrado nas notas do benchmark, saber a hora exata de recorrer a t, t` ` , i18n.t(), msg ou <Trans> é reconhecidamente confuso.
Copiar o código para a área de transferência
Mantenha as macros do Lingui, adote dicionários do Intlayer
O @intlayer/lingui atua como um adaptador compatível para @lingui/core e @lingui/react. As macros continuam compilando normalmente; as chamadas resultantes para i18n._() passam a ser atendidas pelos dicionários do Intlayer, enquanto os plugins de sincronização .po sustentam seus catálogos originais como fonte da verdade. Plurais e condicionais ICU comportam-se com paridade absoluta.
Copiar o código para a área de transferência
Mantenha @lingui/babel-plugin-lingui-macro ou @lingui/swc-plugin no processo de build, executando antes do compilador do Intlayer. Verifique a documentação de compatibilidade com Lingui.
Qual ferramenta escolher?
Você quer ICU MessageFormat com macros tipadas, seus tradutores trabalham em .po com um pipeline TMS existente, prefere strings de origem inline em JSX e sua equipe gerencia confortavelmente o fluxo de extração / compilação / divisão de catálogos. Seu JS por página é competitivo uma vez configurado o lazy loading.
Você quer conteúdo com escopo por componente, TypeScript rigoroso, erros de chaves ausentes em tempo de build, tree-shaking e lazy loading sem esforço, componentes leves, hidratação rápida, troca instantânea de idioma e ferramentas editoriais integradas (Editor Visual, CMS, tradução por IA, servidor MCP). Especialmente relevante para bases de código modulares grandes e sistemas de design.
Você já está no Lingui e quer migrar para os dicionários Intlayer gradualmente sem tocar nas macros. Seus catálogos .po permanecem a fonte da verdade através do plugin de sincronização PO. Medido lado a lado em Lingui vs @intlayer/lingui.
FAQ
Porque a unidade de compilação difere. O Lingui compila um catálogo por idioma: tudo abaixo disso (catálogos por rota, lazy loading, exclusão do fallback do bundle) depende de configuração. O Intlayer compila um dicionário por componente, de modo que a divisão por rotas é resultado direto do build. É por isso que um componente Lingui compilado isoladamente pesa 58-153 KB contra 6-8 KB no Intlayer.
As macros mantêm a mensagem de origem disponível como fallback em tempo de execução, então a string em inglês é enviada junto com a tradução. O benchmark mede 3-15% de strings en dentro de páginas fr em cada configuração otimizada. O Intlayer resolve fallbacks no build e envia apenas o idioma ativo.
Sim, e no TanStack Start vence por muito pouco: 115.2 KB no modo dynamic contra 118.6 KB do Intlayer. Catálogos compilados com IDs hasheados são compactos. O custo aparece em outros pontos: hidratação em 28-34 ms contra 11-14 ms, e uma troca de idioma de 42 ms na configuração scoped-dynamic.
Não. O @intlayer/lingui mantém a compilação de t`...` , <Trans>, msg, plural, select e selectOrdinal como antes; apenas a resolução de i18n._() muda. Mantenha @lingui/babel-plugin-lingui-macro ou @lingui/swc-plugin no build. Veja a documentação de compatibilidade do Lingui.
Elas continuam para as macros e desaparecem para o conteúdo nativo do Intlayer. Dicionários .content.ts são gerados na execução do bundler, sem etapa separada de CLI, e intlayer test falha no CI em caso de chave ausente em vez de usar silenciosamente a string de origem.
Comparações correlatas

Mesmo benchmark, outras bibliotecas:
Indo além:
Documentação de referência:
Para entender de onde vêm essas bibliotecas, leia a história do i18n em JavaScript.
Estrelas no GitHub
As estrelas no GitHub expressam a aprovação do público, a confiança técnica da comunidade e a sustentabilidade de uma iniciativa a longo prazo. Embora não sejam um aferidor estrito de qualidade de código, revelam o volume de desenvolvedores que confiam na solução.
Atividade de commits
As estrelas mostram popularidade. Os commits mostram quanto trabalho é investido num projeto. No momento em que este texto foi escrito, o Intlayer soma cerca de 7.500 commits, mais do que a maioria das bibliotecas comparadas aqui e cerca de 5 vezes mais do que next-intl ou next-i18next.
- lingui/js-lingui
- aymericzip/intlayer
Commits no branch padrão, fonte: API do GitHub.
O Intlayer é um monorepo, então o total inclui cada pacote de framework, a CLI e a documentação. Leia os commits como um sinal de atividade, não de qualidade.
Downloads no npm
- @lingui/core
- intlayer
Fonte: API de downloads do registro npm.
Os downloads recompensam as soluções mais antigas, não as melhores. Uma biblioteca lançada há anos continua sendo instalada por cada projeto que a escolheu na época, por cada execução de CI e por cada pacote que depende dela. O número mede a inércia mais do que uma escolha atual.
Os assistentes de IA amplificam o efeito. next-intl, i18next e vue-i18n estão por toda parte no código com que foram treinados, então eles os sugerem por padrão, sem comparar as alternativas. Cada sugestão gera downloads, que alimentam a próxima sugestão. Compare pelo benchmark, não pelo número de downloads.
Conclusão
O Lingui desponta como a biblioteca híbrida de runtime e compilador mais robusta deste teste comparativo. Seus catálogos compactados com chaves hasheadas proporcionam uma contagem de JavaScript por página a escassos kilobytes do Intlayer, chegando a superá-lo por fração mínima no TanStack Start. Se o peso total por página fosse a única meta, teríamos um empate prático.
Contudo, não é. O compilador do Lingui encerra sua atuação no limite do idioma; qualquer subdivisão abaixo disso (catálogos por rota, carregamento sob demanda, supressão de textos de fallback) é responsabilidade manual do desenvolvedor. O benchmark explicita o custo dessa barreira: componentes 10 a 20 vezes maiores, hidratação 2 a 3 vezes mais lenta, 3-15% de vazamento perpétuo de textos de fallback e um atraso de 42 ms ao alternar idiomas no modo otimizado. O compilador do Intlayer atua no nível atômico do componente: essas marcas caem por padrão para 6-8 KB, 11-14 ms, 0% e 3-4 ms, sem qualquer esforço de configuração.
A totalidade dos dados brutos, dos projetos de teste e dos scripts analíticos está aberta no repositório Benchmark Bloom. Fique à vontade para executar as medições em sua máquina.
Consulte a documentação 'Por que o Intlayer?' para aprofundar seu conhecimento.
Comentários
Ainda sem comentários. Seja o primeiro a compartilhar seus pensamentos.
