Autor:
    Criação:2026-09-13Última atualização:2026-09-27

    next-intl VS Intlayer: Benchmark de Internacionalização (i18n) do Next.js

    next-intl VS Intlayer

    next-intl é a biblioteca i18n mais popular para Next.js. Intlayer é uma alternativa baseada em compilador e com escopo de componente. Ambas localizam uma aplicação App Router. A questão é quanto cada uma custa uma vez que a aplicação está compilada.

    Este artigo não é um tutorial. É uma comparação apoiada por números do Benchmark Bloom, um conjunto de benchmark open-source que constrói a mesma aplicação com cada biblioteca e mede o que o navegador realmente faz download e executa.

    tl;dr: Na mesma aplicação Next.js, next-intl adiciona +12.6 KB gzip de JavaScript em cada página, versus +0.3 KB para Intlayer. Sem trabalho extra, next-intl envia ~90% das strings de páginas estrangeiras com cada página. Alcançar 0% de vazamento com next-intl requer escopo de namespace e pick(messages, [...]) por página. Intlayer alcança 0% por padrão, porque seu compiler escopeia o conteúdo por componente. Se você quer a API next-intl com a saída do Intlayer, o adaptador @intlayer/next-intl mediu 147.5 KB por página versus 153.6 KB com o original.

    Em resumo

    • next-intl - Leve, bem documentado, formato de mensagem ICU, suporte de primeira classe ao App Router com middleware, formatters e helpers de navegação. O conteúdo reside em catálogos JSON centralizados; otimizações de desempenho (namespaces, seleção de mensagens por página, lazy loading) são sua responsabilidade.
    • Intlayer - Modelo de conteúdo centrado em componentes. Dicionários .content.ts ficam ao lado do componente que servem, um compilador em tempo de build faz tree-shake e lazy-loads deles por componente e por locale, tipos TypeScript rigorosos são gerados a partir do seu conteúdo, e traduções ausentes falham em tempo de build. Inclui middleware, helpers de SEO, um Visual Editor / CMS e tradução assistida por IA.
    BibliotecaEstrelas do GitHubTotal de CommitsÚltimo CommitPrimeira VersãoVersão NPMDownloads NPM
    aymericzip/intlayerGitHub Repo starsGitHub commit activityLast CommitAbril 2024npmnpm downloads
    amannn/next-intlGitHub Repo starsGitHub commit activityLast CommitNov 2020npmnpm downloads
    Os emblemas são atualizados automaticamente. Os snapshots variarão ao longo do tempo.

    Comparação de recursos lado a lado

    Recursonext-intlayer (Intlayer)next-intl
    Traduções próximas aos componentes✅ Sim, .content.ts colocado junto com cada componente❌ Não, centralizado em messages/{locale}.json
    Integração TypeScript✅ Tipos estritos gerados automaticamente a partir do conteúdo✅ Bom, chaves tipadas via augmentação global.d.ts
    Detecção de tradução ausente✅ Erro TypeScript + erro/aviso em tempo de build⚠️ Fallback em tempo de execução + aviso no console
    Conteúdo rico (JSX / Markdown / componentes)✅ Suporte direto⚠️ t.rich() / t.markup() com placeholders de tag
    Suporte ICU⚠️ Em desenvolvimento✅ Sim
    Formatação (datas, números, moedas)✅ useNumber, useDate, ... (Intl sob o capô)✅ useFormatter() (Intl sob o capô)
    Roteamento localizado e middleware✅ Proxy/middleware integrado, getMultilingualUrls✅ Middleware integrado, Link, redirect, usePathname
    Auxiliares de SEO (hreflang, sitemap, robots)✅ Auxiliares integrados⚠️ Manual, baseado na configuração de roteamento
    Componentes de servidor síncrono✅ useIntlayer de next-intlayer/server funciona em qualquer componente servidor filho⚠️ getTranslations é assíncrono; filhos síncronos precisam de t passado como props
    Renderização estática✅ Não bloqueia a renderização estática⚠️ Requer setRequestLocale(); catálogos nomeados ainda optaram páginas fora da renderização estática em nossos testes
    Tree-shaking (enviar apenas conteúdo usado)✅ Por componente, por locale, automatizado pelo compilador⚠️ Manual: namespaces + pick(messages, [...]) por página
    Lazy loading✅ importMode: 'dynamic' (uma linha de config)⚠️ Importações dinâmicas manuais em getRequestConfig
    Purge unused content✅ Dicionários não utilizados são removidos no momento da compilação❌ Não incluído
    Testing missing translations (CLI / CI)✅ npx intlayer content test⚠️ Não incluído; docs sugerem npx @lingual/i18n-check
    AI-powered translation✅ Incluído, usa suas próprias chaves de provedor❌ Não
    Editor Visual / CMS✅ Editor Visual gratuito + CMS opcional❌ Não (plataformas de localização externas)
    Servidor MCP & Agent Skills✅ Sim❌ Não
    Ecossistema / comunidade⚠️ Menor mas crescendo rapidamente✅ Grande, a referência do Next.js

    O benchmark

    O que foi medido

    O suite Benchmark Bloom constrói a mesma aplicação com cada biblioteca: 10 páginas (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 locales (en, fr, es, de, it, pt, zh, ja, ko, ru), componentes idênticos e conteúdo idêntico. As páginas são medidas em en e fr. Cada biblioteca é implementada em até quatro estratégias de carregamento, da configuração ingênua até a otimizada:

    StrategyDescriptionWho does this
    staticCada locale e cada página agrupadas juntasProtótipos rápidos, código gerado por IA
    dynamicApenas a locale ativa é carregada, mas todas as páginas de uma vezA maioria dos projetos
    scoped-staticNamespaces por rota, sem lazy loadingRaro
    scoped-dynamicNamespaces por rota + lazy loading. Apenas a página atual na locale atual é enviadaApps com orçamento de performance rigoroso

    Intlayer não possui uma variante "scoped": o compilador agrupa conteúdo por componente automaticamente, então suas linhas static e dynamic já estão agrupadas.

    Para cada build, a suite registra:

    • Lib size: tamanho gzip da biblioteca i18n. O custo fixo do runtime.
    • Page JS: JavaScript gzip baixado por página, calculado em média sobre todas as páginas e locales.
    • Locale leak %: proporção de strings traduzidas encontradas no JS baixado que pertencem a um locale que o usuário não está visualizando (fingerprinted em en e fr, então 50% significa "o outro locale medido está totalmente presente"; com 10 locales agrupados, o desperdício real é maior).
    • Page leak %: proporção de strings traduzidas encontradas no JS baixado que pertencem a uma página em que o usuário não está.
    • Component avg: tamanho gzip médio de cada componente compilado isoladamente. Mostra quanto runtime i18n um único componente carrega.
    • E2E reactivity: tempo real entre selecionar uma nova locale e html[lang] atualizar no DOM (Playwright, 5 iterações).
    • Hydration: duração da fase de hidratação do React.
    Os números abaixo vêm da execução datada de 2026-09-12 com next-intl 4.14.2, use-intl 4.14.2 e intlayer 9.5.1. A aplicação de teste é deliberadamente pequena (algumas dezenas de strings por locale), portanto as porcentagens de vazamento descrevem um padrão: eles crescem com seu conteúdo enquanto o custo de runtime permanece fixo.

    Resultados no Next.js (App Router)

    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

    LibraryStrategyLib size (gz)Page JS avg (gz)Locale leakPage leakComponent avg (gz)E2E reactivityHydration
    base (sem i18n)-0.0 KB141.0 KB0.0%0.0%0.9 KB13.4 ms11.8 ms
    next-intlstatic14.7 KB153.6 KB4.2%89.8%21.8 KB16.0 ms14.7 ms
    next-intldynamic14.7 KB153.6 KB9.7%89.9%21.8 KB15.6 ms14.8 ms
    next-intlscoped-static14.7 KB153.6 KB0.0%0.0%80.1 KB17.9 ms17.4 ms
    next-intlscoped-dynamic14.7 KB153.6 KB0.0%0.0%22.9 KB17.8 ms16.8 ms
    next-intlayerstatic5.5 KB141.3 KB0.0%0.0%8.5 KB15.5 ms16.9 ms
    next-intlayerdynamic5.5 KB141.3 KB0.0%0.0%6.9 KB15.3 ms15.9 ms
    @intlayer/next-intl (compat)static8.0 KB147.5 KB0.0%0.0%8.1 KB14.5 ms12.8 ms
    @intlayer/next-intl (compat)dynamic8.0 KB148.7 KB0.0%0.0%8.1 KB11.7 ms12.8 ms

    Como ler isso

    • Custo de runtime. A aplicação base pesa 141.0 KB por página. next-intl a leva para 153.6 KB (+12.6 KB gzip em cada página), Intlayer para 141.3 KB (+0.3 KB). Esta diferença não depende de quantas strings você tem: é o runtime da biblioteca.
    • Vazamento. Nos dois setups que a maioria das equipes realmente implementa (static e dynamic), next-intl entrega ~90% das strings de páginas estrangeiras com cada página: todo o en.json vai para o provider do cliente. Para chegar a 0% é necessário os setups scoped-*: dividir catálogos em namespaces e depois fazer pick() dos corretos em cada página. Intlayer está em 0% em ambas as linhas sem nada disso.
    • O JS por página não se moveu para next-intl entre estratégias. O conteúdo do teste é pequeno, então o vazamento de ~90% é apenas alguns KB aqui. Em uma app real com centenas de strings por página, essa proporção se torna o custo dominante. Enquanto isso, o runtime de +12.6 KB é pago em cada configuração.
    • Tamanho do componente. Um componente que chama useTranslations() compila para 21.8 KB em média; o mesmo componente com useIntlayer() compila para 6.9 KB. Na configuração scoped-static, os componentes next-intl saltam para 80.1 KB porque cada um internaliza seu catálogo de namespace.
    • Reatividade e hidratação estão no mesmo patamar para ambas as bibliotecas no Next.js (15-18 ms). Nenhuma delas é um gargalo aqui.
    Tabela completa, cada biblioteca e cada estratégia, no relatório de benchmark do Next.js.

    Resultados no TanStack Start (use-intl)

    use-intl é o núcleo agnóstico de framework do next-intl. Mesma API, mesmo formato de mensagem. Comparar isso contra intlayer no TanStack Start remove as partes específicas do Next.js da equação.

    LibraryStrategyLib size (gz)Page JS avg (gz)Locale leakPage leakComponent avg (gz)E2E reactivity
    base (sem i18n)-0.0 KB111.0 KB0.0%0.0%0.7 KB8.1 ms
    use-intlstatic14.1 KB179.8 KB50.0%89.8%76.0 KB6.7 ms
    use-intldynamic14.1 KB119.4 KB0.0%89.8%75.9 KB7.0 ms
    use-intlscoped-static14.1 KB128.7 KB0.0%0.0%87.1 KB20.9 ms
    use-intlscoped-dynamic14.1 KB128.7 KB0.0%0.0%87.1 KB13.3 ms
    intlayerstatic5.0 KB125.8 KB50.0%0.0%8.1 KB3.2 ms
    intlayerdynamic5.0 KB118.6 KB0.0%0.0%6.3 KB3.6 ms
    @intlayer/use-intl (compat)dynamic7.3 KB129.7 KB0.0%0.0%9.3 KB8.7 ms

    Como ler isso

    • A configuração ingênua use-intl envia 68.8 KB a mais de JS por página do que a aplicação base, com metade das strings pertencendo à locale errada e 90% à página errada.
    • use-intl em modo dynamic chega a 119.4 KB, próximo ao 118.6 KB do Intlayer, mas ainda carrega 89.8% de vazamento de página: as strings de todas as páginas para a locale ativa são carregadas em cada página. Escopo-las por rota (scoped-*) remove o vazamento, mas custa outro ~9 KB de overhead de chunk.
    • Intlayer's static já tem 0% de vazamento de página: o compilador só agrupa os dicionários usados pelos componentes na página. Habilitando importMode: 'dynamic' (uma linha em intlayer.config.ts) remove também o vazamento de locale.
    • O tamanho do componente é onde a arquitetura se manifesta: 76-87 KB por componente com use-intl versus 6-8 KB com Intlayer. useTranslations() vincula cada componente à árvore de mensagens global; useIntlayer() vincula-o ao seu próprio dicionário.
    • Mudança de locale é 2x-4x mais rápida com Intlayer (3 ms vs 7-21 ms).
    Tabela completa no relatório de benchmark do TanStack Start.

    Por que a diferença? Catálogos centralizados vs. dicionários compilados

    Centralized catalogs versus per-component dictionaries

    next-intl segue o modelo clássico: um JSON por locale, carregado em getRequestConfig, inserido em um NextIntlClientProvider, lido através de t("namespace.key").

    bash
    .
    ├── messages
    │   ├── en.json
    │   └── fr.json
    └── src
        ├── i18n
        │   ├── request.ts
        │   └── routing.ts
        ├── middleware.ts
        └── app
            └── [locale]
                ├── layout.tsx
                └── about
                    └── page.tsx
    

    O runtime não consegue saber quais keys uma página usará, então o padrão seguro é enviar o catálogo completo. Otimizar significa você dividir o catálogo em namespaces, você decidir quais namespaces cada página precisa, e você manter esse mapeamento sincronizado conforme os componentes se movem. A linha scoped-dynamic do benchmark é a recompensa por esse trabalho, e a maioria das equipes nunca chega lá.

    O custo de não chegar lá cresce em dois eixos ao mesmo tempo, páginas e idiomas:

    Theoretical content leakage by architecture

    Intlayer inverte a responsabilidade. O conteúdo é declarado ao lado do componente:

    bash
    .
    ├── intlayer.config.ts
    └── src
        ├── middleware.ts
        ├── app
        │   └── [locale]
        │       ├── layout.tsx
        │       └── about
        │           ├── page.tsx
        │           └── page.content.ts
        └── components
            └── Counter
                ├── index.tsx
                └── index.content.ts
    

    No momento da compilação, o compilador (@intlayer/swc / @intlayer/babel) vê qual componente importa qual dicionário. Ele agrupa apenas esses dicionários, apenas para o locale ativo, e descarta os que nada importa. O padrão "scoped-dynamic" torna-se a saída da compilação em vez de uma disciplina que o time tem que manter.

    Para obter os números da linha dynamic, defina dictionary.importMode: 'dynamic' em intlayer.config.ts. Veja a documentação de otimização de bundle.

    Experiência do desenvolvedor

    Componente cliente

    messages/en.json
    {
      "counter": {
        "label": "Counter",
        "increment": "Increment"
      }
    }
    
    src/components/Counter.tsx
    "use client";
    
    import { useState } from "react";
    import { useTranslations, useFormatter } from "next-intl";
    
    export const Counter = () => {
      const t = useTranslations("counter");
      const format = useFormatter();
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{format.number(count)}</p>
          <button aria-label={t("label")} onClick={() => setCount((c) => c + 1)}>
            {t("increment")}
          </button>
        </div>
      );
    };
    
    Lembrez-se de incluir o namespace counter nas mensagens passadas para NextIntlClientProvider em cada página que renderiza este componente.
    src/components/Counter/index.content.ts
    import { t, type Dictionary } from "intlayer";
    
    const counterContent = {
      key: "counter",
      content: {
        label: t({ pt: "Contador", en: "Counter", fr: "Compteur" }),
        increment: t({ pt: "Incrementar", en: "Increment", fr: "Incrémenter" }),
      },
    } satisfies Dictionary;
    
    export default counterContent;
    
    src/components/Counter/index.tsx
    "use client";
    
    import { useState } from "react";
    import { useIntlayer } from "next-intlayer";
    import { useNumber } from "next-intlayer/format";
    
    export const Counter = () => {
      // Obter o rótulo e o texto do incremento do conteúdo da internacionalização
      const { label, increment } = useIntlayer("counter");
      // Obter a função de formatação de números
      const number = useNumber();
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{number(count)}</p>
          <button aria-label={label} onClick={() => setCount((c) => c + 1)}>
            {increment}
          </button>
        </div>
      );
    };
    

    Nada para registrar na página: o componente traz seu próprio conteúdo.

    Componente de servidor síncrono

    Peças de design-system (navbar, footer, cards) são frequentemente componentes server renderizados como children de componentes client, então não podem ser async.

    src/components/ServerCounter.tsx
    type ServerCounterProps = {
      t: (key: string) => string;
      formattedCount: string;
    };
    
    export const ServerCounter = ({ t, formattedCount }: ServerCounterProps) => (
      <div>
        <p>{formattedCount}</p>
        <button aria-label={t("label")}>{t("increment")}</button>
      </div>
    );
    

    A página tem que await getTranslations("counter") e await getFormatter(), depois passar os resultados para baixo como props. O componente não é mais auto-contido.

    src/components/ServerCounter.tsx
    import { useIntlayer } from "next-intlayer/server";
    import { useNumber } from "next-intlayer/server/format";
    
    export const ServerCounter = ({ count }: { count: number }) => {
      const { label, increment } = useIntlayer("counter");
      const number = useNumber();
    
      return (
        <div>
          <p>{number(count)}</p>
          <button aria-label={label}>{increment}</button>
        </div>
      );
    };
    

    Metadados

    src/app/[locale]/about/page.tsx
    import type { Metadata } from "next";
    import { getTranslations } from "next-intl/server";
    import { routing } from "@/i18n/routing";
    
    const localizedPath = (locale: string, path: string) =>
      locale === routing.defaultLocale ? path : `/${locale}${path}`;
    
    export const generateMetadata = async ({
      params,
    }: {
      params: Promise<{ locale: string }>;
    }): Promise<Metadata> => {
      const { locale } = await params;
      const t = await getTranslations({ locale, namespace: "about" });
    
      const languages = Object.fromEntries(
        routing.locales.map((l) => [l, localizedPath(l, "/about")])
      );
    
      return {
        title: t("title"),
        description: t("description"),
        alternates: {
          canonical: localizedPath(locale, "/about"),
          languages: { ...languages, "x-default": "/about" },
        },
      };
    };
    
    src/app/[locale]/about/page.tsx
    import { getIntlayer, getMultilingualUrls } from "intlayer";
    import type { Metadata } from "next";
    import type { LocalPromiseParams } from "next-intlayer";
    
    export const generateMetadata = async ({
      params,
    }: LocalPromiseParams): Promise<Metadata> => {
      const { locale } = await params;
      const metadata = getIntlayer("about-metadata", locale);
      const multilingualUrls = getMultilingualUrls("/about");
    
      return {
        ...metadata,
        alternates: {
          canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
          languages: { ...multilingualUrls, "x-default": "/about" },
        },
      };
    };
    

    Mantenha a API do next-intl, obtenha a saída do Intlayer

    Você não precisa reescrever componentes para obter os números de benchmark acima. @intlayer/next-intl é um adaptador pronto para usar: mantém useTranslations, getTranslations, useFormatter, t.rich(), plurais ICU e os auxiliares next-intl/navigation, e os fornece a partir dos dicionários compilados do Intlayer pelo compilador Intlayer.

    next.config.ts
    import type { NextConfig } from "next";
    import { createNextIntlPlugin } from "@intlayer/next-intl/plugin";
    
    const withIntlayer = createNextIntlPlugin();
    
    const nextConfig: NextConfig = {};
    
    export default withIntlayer(nextConfig);
    

    Na benchmark, a build de compatibilidade da mesma aplicação passou de 153.6 KB para 147.5 KB por página, de 21.8 KB para 8.1 KB por componente, e de ~90% page leakage para 0%, com o código da aplicação intacto. Seus arquivos messages/{locale}.json existentes podem continuar sendo a fonte de verdade através do plugin JSON sync.

    Veja o guia de migração next-intl para o passo a passo.

    Quando escolher qual?

    Você quer o padrão do ecossistema para Next.js, depende do formato ICU MessageFormat, seu aplicativo é de porte pequeno a médio, ou você integra com uma plataforma de tradução (Crowdin, Phrase, Lokalise...) que espera JSON centralizado. Reserve tempo para estruturar catálogos por namespace e selecionar mensagens com pick() por página se o desempenho for essencial.

    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 de servidor síncronos 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á usando o next-intl e quer os ganhos de tamanho de bundle sem uma reescrita completa. O adaptador de compatibilidade mantém seus imports e seu arquivo messages/{locale}.json como a fonte da verdade. Medido lado a lado em next-intl vs @intlayer/next-intl.

    FAQ

    Não no momento da renderização. A diferença está no que é enviado ao cliente: o next-intl custa +12.6 KB gzip de runtime em cada página e, na maioria das configurações comuns, envia cerca de 90% das strings de páginas estrangeiras em cada página. A troca de idioma e a hidratação são comparáveis no Next.js (15-18 ms); no TanStack Start, o use-intl leva de 7 a 21 ms contra 3 a 4 ms do Intlayer.

    Sim, com a configuração scoped-dynamic: divida messages/{locale}.json em um namespace por rota, depois use pick(messages, [...]) em cada página e mantenha esse mapeamento correto conforme os componentes mudam. As linhas scoped-* do benchmark representam exatamente esse esforço. O Intlayer atinge 0% por padrão sem nada disso, pois o compilador delimita o conteúdo por componente. Veja otimização de bundle.

    Não. O @intlayer/next-intl mantém useTranslations, getTranslations, useFormatter, t.rich(), plurais ICU e os helpers de navegação, servindo-os a partir de dicionários compilados. Apenas uma linha de plugin no next.config.ts. Passo a passo no guia de migração do next-intl.

    O suporte a ICU está em desenvolvimento na API nativa. Os adaptadores de compatibilidade (@intlayer/next-intl, @intlayer/use-intl) executam o ICU: plurais, select, selectordinal, # e {ts, date, long} passam pelo resolvedor ICU do Intlayer. Leia formato de mensagem ICU para mais detalhes.

    Sim. O plugin de sincronização JSON lê os arquivos, divide as chaves principais em dicionários e regrava as traduções nos mesmos arquivos quando a CLI ou o CMS os atualiza. O fluxo de trabalho de seus tradutores não muda.

    Comparações relacionadas

    Mesmo benchmark, outras bibliotecas:

    Indo além com next-intl:

    Documentos de referência:

    Para entender de onde vêm essas bibliotecas, leia a história do i18n em JavaScript.

    GitHub STARs

    As estrelas do GitHub são um forte indicador de popularidade de um projeto, confiança da comunidade e relevância de longo prazo. Embora não sejam uma medida direta de qualidade técnica, elas refletem quantos desenvolvedores acham o projeto útil, acompanham seu progresso e provavelmente vão adotá-lo.

    Star History Chart

    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.

    • amannn/next-intl
    • 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

    • next-intl
    • next-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

    next-intl é uma biblioteca sólida e bem mantida, e o benchmark confirma que está longe de ser a pior opção no Next.js. Mas seu modelo de catálogo centralizado coloca cada otimização nas mãos do desenvolvedor: a configuração ingênua vaza ~90% do conteúdo de páginas estrangeiras, e o runtime sozinho custa +12.6 KB gzip em cada página.

    Intlayer move esse trabalho para o compilador. Dicionários por componente, lazy loading por idioma e eliminação de conteúdo não utilizado são saídas da compilação, não convenções manuais. O resultado na mesma aplicação: +0.3 KB por página, 0% de vazamento, componentes 3x menores, e troca de idioma 2x-4x mais rápida no TanStack Start.

    Todos os dados brutos, aplicações de teste e scripts estão no repositório Benchmark Bloom. Execute você mesmo.

    Consulte a documentação 'Por que Intlayer?' para mais detalhes.

    Comentários

    Ainda sem comentários. Seja o primeiro a compartilhar seus pensamentos.

    Artigos relacionados

    Últimos artigos