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
- "Versão inicial"v9.5.1026/09/2026
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
Como internacionalizar sua aplicação TanStack Start usando Lingui em 2026
Sumário
O que é o Lingui?
O Lingui é uma biblioteca de i18n construída em torno de macros e extração de mensagens. Você escreve o texto de origem diretamente em seus componentes ( t`Hello` , <Trans>Hello</Trans>), o lingui extract coleta todas as mensagens em catálogos (arquivos PO por padrão), tradutores os preenchem e o plugin do Vite os compila para JavaScript compacto. As mensagens utilizam o ICU MessageFormat, portanto, plurais e seleções são suportados.
O TanStack Start não possui uma camada nativa de i18n, portanto este guia configura o Lingui nele do zero:
- Macros compiladas pelo Babel através do
@rolldown/plugin-babel(necessário com@vitejs/plugin-reactv6 e Vite 8). - Roteamento de localidade com um segmento opcional
{-$locale}(/about,/fr/about). - Um catálogo por localidade, carregado sob demanda, e uma instância de
I18npor renderização para que requisições SSR simultâneas nunca compartilhem uma localidade. - SEO multilíngue completo:
<title>e descrição traduzidos, URL canônica,hreflangcomx-default, localidades Open Graph, JSON-LD, sitemap,robots.txt, pré-renderização e páginas 404 localizadas.
Procurando outra stack? Veja o guia de TanStack Start + use-intl, o guia de TanStack Start + Paraglide ou o guia de TanStack Start + Intlayer.
Usando Next.js? Veja o guia de Next.js + Lingui. Comparando bibliotecas? Leia Lingui vs Intlayer.
O que o benchmark diz sobre o Lingui no TanStack Start
O benchmark de i18n executa a mesma aplicação TanStack Start de 10 páginas e 10 localidades com as principais bibliotecas e mede o que o navegador realmente baixa.
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
Benchmark de Desempenho I18n
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
Principais números para @lingui/core@6.6.0, medidos em 2026-09-26 (gzip):
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Configuração | Tamanho da biblioteca | JS por página | Vazamento de outras localidades | Vazamento de outras páginas |
|---|---|---|---|---|
| Sem i18n (app base) | - | 111.0 KB | 0% | 0% |
| Lingui (configuração deste guia) | 56.7 KB | 115.2 KB | 9.3% | 0% |
@intlayer/lingui (compat) | 9.8 KB | 136.7 KB | 9.9% | 0% |
react-intlayer (Intlayer nativo) | 4.5 KB | 126.8 KB | 0% | 0% |
Principais conclusões:
- Carregue um catálogo por localidade, sob demanda. Isso mantém as páginas próximas ao tamanho da aplicação base.
- O runtime permanece pesado (~57 KB gzip). O adaptador de compatibilidade
@intlayer/lingui(etapa 16) mantém suas macros e o reduz para ~10 KB.
Veja os dados completos: Relatório de benchmark do TanStack Start e o repositório do benchmark.
Comparação de recursos no TanStack Start
Como o Lingui se compara com outras bibliotecas comumente usadas no TanStack Start:
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Recurso | react-intlayer (Intlayer) | use-intl | Paraglide JS | Lingui |
|---|---|---|---|---|
| Traduções próximas aos componentes | ✅ Co-localizado | ❌ JSON centralizado | ❌ Um arquivo JSON por localidade | ⚠️ Texto fonte nos componentes |
| Integração com TypeScript | ✅ Tipos gerados automaticamente | ✅ Via AppConfig | ✅ Funções de mensagens tipadas | ⚠️ Apenas macros |
| Detecção de traduções ausentes | ✅ Erros de tipo e avisos no build | ⚠️ Fallback em runtime | ⚠️ Fallback para localidade base | ⚠️ Fallback para o texto fonte |
| Conteúdo rico (JSX, Markdown) | ✅ Suporte direto | ⚠️ Tags via t.rich | ⚠️ Strings | ✅ JSX dentro de <Trans> |
| Roteamento localizado | ✅ Integrado | ❌ Manual {-$locale} | ✅ urlPatterns + reescrita do roteador | ❌ Manual {-$locale} |
| Troca de localidade sem recarga | ✅ Sim | ✅ Sim | ❌ Recarregamento total da página | ✅ Sim |
| Pluralização | ✅ Baseada em enumeração | ✅ ICU | ✅ Variantes | ✅ ICU |
| ICU MessageFormat | ✅ Via format: "icu" | ✅ Nativo | ⚠️ Via plugin inlang | ✅ Nativo |
| Formatos de conteúdo | ✅ .ts, .json, .md, .yaml... | ⚠️ .json | ⚠️ JSON inlang | ✅ PO, JSON, CSV |
| Tradução com IA | ✅ Seu próprio provedor e chave | ❌ Não | ❌ Não | ❌ Não |
| Editor visual / CMS | ✅ Editor local + CMS opcional | ❌ Plataformas externas | ⚠️ Apps do ecossistema inlang | ❌ Plataformas externas |
| Auxiliares de SEO (hreflang, sitemap) | ✅ Integrado | ❌ Manual | ⚠️ URLs localizadas, restante manual | ❌ Manual |
| Tamanho do runtime (gzip, benchmark) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Vazamento, melhor configuração (localidade / página) | 0% / 0% | 0% / 0% | 49.7% / 0% | 8.6% / 0% |
| Traduções ausentes no CI | ✅ npx intlayer test | ⚠️ Não integrado | ⚠️ Não integrado | ✅ lingui compile --strict |
Os números de tamanho de runtime e vazamento vêm do benchmark do TanStack Start. O vazamento é medido na melhor configuração de cada biblioteca.
Outros guias de TanStack Start: use-intl, Paraglide JS e Intlayer.
Práticas recomendadas que você deve seguir
- Defina
langedirem<html>a partir da localidade da rota, para que fiquem corretos no HTML do servidor. - Mantenha uma URL por localidade com um prefixo, para que cada versão de idioma seja indexável.
- Crie uma instância de
I18npor localidade, nunca altere uma global durante o SSR: duas requisições simultâneas sobrescreveriam a localidade uma da outra. - Carregue apenas o catálogo ativo, nunca importe todos eles no código do cliente.
- Escolha um estilo de macro (
useLingui+tem componentes,msgpara descritores tardios) e mantenha-se fiel a ele. Misturart,i18n._,i18n.te<Trans>torna o código mais difícil de ler para humanos e assistentes de IA. - Execute
lingui extractno CI para que uma nova mensagem nunca seja enviada sem tradução. - Traduza seus metadados e declare
canonical,hreflangex-defaultem cada página. - Gere um sitemap multilíngue e robots.txt, e faça a pré-renderização de todas as localidades.
- Use links reais para o seletor de localidade, para que os rastreadores descubram todos os idiomas.
Veja nosso guia sobre internacionalização e SEO e o guia de hreflang.
Guia Passo a Passo para Configurar o Lingui em uma Aplicação TanStack Start
Aqui está a estrutura de projeto que iremos criar:
Copiar o código para a área de transferência
Instalar Dependências
bashCopiar códigoCopiar o código para a área de transferência
- @lingui/core / @lingui/react: runtime,
I18nProvidere as macros (@lingui/core/macro,@lingui/react/macro). - @lingui/cli:
lingui extractpara coletar mensagens em catálogos. - @lingui/vite-plugin: compila catálogos
.pona importação, dispensando o uso delingui compile. - @lingui/babel-plugin-lingui-macro + @rolldown/plugin-babel: transformam as macros no momento do build.
- @lingui/core / @lingui/react: runtime,
Centralizar a Configuração de Localidades
A localidade padrão permanece sem prefixo (
/about), enquanto as outras localidades são prefixadas (/fr/about).src/i18n/config.tsCopiar códigoCopiar o código para a área de transferência
Configurar o Lingui
A configuração do Lingui reutiliza a mesma lista de localidades, garantindo que os catálogos, o roteador e o sitemap nunca entrem em conflito.
lingui.config.tsCopiar códigoCopiar o código para a área de transferência
Adicione os scripts de extração:
package.jsonCopiar códigoCopiar o código para a área de transferência
O script
i18n:checkfalha no CI quando um componente contém uma mensagem que não foi extraída e commitada.Configurar o Vite
Com o
@vitejs/plugin-reactv6, o Babel não vem mais embutido. O@rolldown/plugin-babelexecuta o plugin de macros do Lingui, e olinguiTransformerBabelPresetprocessa apenas arquivos que importam uma macro, mantendo os builds rápidos.vite.config.tsCopiar códigoCopiar o código para a área de transferência
Carregar Catálogos por Localidade
O template literal em
import()permite que o Vite emita um chunk por catálogo, e o plugin do Lingui compila o arquivo.podentro dele. Um visitante francês baixa apenas o catálogo em francês.As mensagens compiladas são dados puros, portanto podem ser retornadas por um loader de rota, serializadas no HTML e reutilizadas na hidratação.
src/i18n/lingui.tsCopiar códigoCopiar o código para a área de transferência
Para que o TypeScript aceite a importação de
.po, declare o módulo uma vez:src/i18n/po.d.tsCopiar códigoCopiar o código para a área de transferência
Criar o Documento Raiz
A rota raiz lê o parâmetro opcional de localidade para definir
langedirno<html>renderizado no servidor.src/routes/__root.tsxCopiar códigoCopiar o código para a área de transferência
Criar a Rota de Layout de Localidade
A pasta
{-$locale}cria um segmento de caminho opcional:/aboute/fr/aboutcorrespondem a/{-$locale}/about. O layout rejeita prefixos desconhecidos, carrega o catálogo da localidade atual e fornece uma instância dedicada deI18n.src/routes/{-$locale}/route.tsxCopiar códigoCopiar o código para a área de transferência
Utilizar Traduções em Suas Páginas
Escreva o texto de origem no componente. As macros o transformam em IDs de mensagem durante o build, e o
lingui extracto captura.<Trans>para conteúdo JSX, incluindo elementos aninhados;useLingui().tpara strings (atributos, propriedades);<Plural>para plurais ICU.
src/routes/{-$locale}/about.tsxCopiar códigoCopiar o código para a área de transferência
O
import()dinâmico de um catálogo é armazenado em cache pelo sistema de módulos, portanto, chamarloadI18nem múltiplos loaders não faz o download do catálogo duas vezes.Extrair e Traduzir Suas Mensagens
Execute a extração. O Lingui grava cada mensagem no catálogo de cada localidade:
bashCopiar códigoCopiar o código para a área de transferência
Em seguida, traduza o
msgstrde cada entrada:src/locales/fr/messages.poCopiar códigoCopiar o código para a área de transferência
src/locales/es/messages.poCopiar códigoCopiar o código para a área de transferência
Por padrão, os IDs das mensagens são hashes do texto de origem: alterar o texto em inglês cria uma nova mensagem. Use IDs explícitos (
<Trans id="about.title">About us</Trans>) para textos que mudam com frequência.Criar um Componente de Link Localizado
OpcionalCada rota existe sob
{-$locale}, portanto os links devem carregar o parâmetro da localidade atual.src/components/LocalizedLink.tsxCopiar códigoCopiar o código para a área de transferência
Alterar o Idioma do Seu Conteúdo
OpcionalRenderize o seletor como links, para que os rastreadores encontrem todas as versões de idioma.
to="."mantém a página atual e substitui o parâmetro de localidade. O loader do layout de localidade então busca o novo catálogo.src/components/LocaleSwitcher.tsxCopiar códigoCopiar o código para a área de transferência
Internacionalizar Seus Metadados
OpcionalCada versão de idioma pode se posicionar de forma independente nos mecanismos de busca, desde que cada página exponha um
<title>e descrição traduzidos, uma URL canônica autorreferenciada, uma taghreflangpor localidade maisx-default, localidades Open Graph e JSON-LD cominLanguage. Os metadados são traduzidos no loader (etapa 8), e este utilitário constrói o restante:src/i18n/seo.tsCopiar códigoCopiar o código para a área de transferência
Internacionalizar Seu Sitemap e robots.txt
OpcionalO sitemap lista todas as URLs de cada localidade, com cada entrada declarando todas as suas alternativas usando
xhtml:link. Orobots.txtbloqueia rotas privadas em todos os idiomas e aponta para o sitemap. Removapublic/robots.txtcaso o starter tenha criado um.src/routes/sitemap[.]xml.tsCopiar códigoCopiar o código para a área de transferência
src/routes/robots[.]txt.tsCopiar códigoCopiar o código para a área de transferência
Pré-renderizar Todas as Localidades
OpcionalListe todos os caminhos localizados para que o TanStack Start pré-renderize todas as versões de idioma no momento do build:
vite.config.tsCopiar códigoCopiar o código para a área de transferência
Redirecionar Visitantes de Primeira Viagem e Tratar Páginas 404
OpcionalUm middleware de requisição encaminha um visitante que acessa
/para o seu idioma preferido (cookie primeiro, depoisAccept-Language). Links profundos nunca são redirecionados, garantindo que rastreadores e URLs compartilhadas sempre acessem a página solicitada.src/i18n/negotiateLocale.tsCopiar códigoCopiar o código para a área de transferência
src/start.tsCopiar códigoCopiar o código para a área de transferência
Para páginas 404, uma rota catch-all renderiza o
notFoundComponentlocalizado do layout. Marque-a comnoindex: o React 19 eleva o<meta>para o<head>.src/components/NotFound.tsxCopiar códigoCopiar o código para a área de transferência
src/routes/{-$locale}/$.tsxCopiar códigoCopiar o código para a área de transferência
Mantenha Suas Macros, Reduza o Runtime com o Intlayer
OpcionalO adaptador de compatibilidade
@intlayer/linguimantém seu código-fonte intacto: as macros compilam exatamente como antes e as chamadas resultantes dei18n._(),useLingui()e<Trans>são atendidas por dicionários compilados do Intlayer. No benchmark, o runtime cai de ~56.7 KB para ~9.8 KB gzip.bashCopiar códigoCopiar o código para a área de transferência
Adicione o plugin após a transformação de macros, para que ele crie aliases de
@lingui/coree@lingui/reactpara o adaptador:vite.config.tsCopiar códigoCopiar o código para a área de transferência
Os catálogos são sincronizados com o plugin de sincronização JSON (catálogos JSON) ou o plugin de sincronização PO (catálogos PO). Veja a configuração completa no guia de compatibilidade do Lingui e uma comparação lado a lado em Lingui vs @intlayer/lingui.
Automatize Suas Traduções Usando o Intlayer
OpcionalO Lingui extrai mensagens, mas preencher dezenas de catálogos manualmente é onde a maior parte do tempo é gasta. O Intlayer é gratuito e de código aberto, e suas ferramentas funcionam perfeitamente ao lado do Lingui:
- Traduza com IA usando sua própria chave de API e provedor. Veja o preenchimento automático e a CLI.
- Mantenha seus arquivos PO como a fonte da verdade com o plugin de sincronização PO.
- Teste traduções ausentes no CI. Veja testando suas traduções.
- Audite seu site publicado em busca de tags
hreflangausentes, URLs canônicas incorretas e vazamentos de localidade com o comando scan.
Perguntas Frequentes
Sim. O Lingui não possui uma integração dedicada para o TanStack Start, mas seu plugin Vite e o plugin de macro Babel funcionam perfeitamente. Os dois pontos cruciais são executar as macros através do @rolldown/plugin-babel (o Vite 8 e o @vitejs/plugin-react v6 não incluem mais o Babel) e criar uma instância de I18n por localidade em vez de ativar uma global durante o SSR.
No servidor, um único processo renderiza muitas requisições ao mesmo tempo. Chamar i18n.activate("fr") em um objeto compartilhado alteraria o idioma de uma requisição sendo renderizada em inglês em paralelo. O setupI18n cria uma instância isolada por localidade, o que é seguro.
Não. O @lingui/vite-plugin compila os catálogos .po quando eles são importados. Você só precisa executar lingui extract para coletar novas mensagens.
Declare-os com a macro msg e traduza-os no loader da rota com i18n._(msg`...`). O loader retorna strings puras, portanto o head() permanece síncrono e os valores são serializados para a hidratação. A etapa 8 e a etapa 12 mostram a configuração completa.
O benchmark mede ~56.7 KB gzip para o runtime. Com um catálogo por localidade carregado sob demanda, as páginas pesam ~115 KB contra 111 KB sem i18n. Importar todos os catálogos estaticamente eleva o tamanho para ~152 KB.
Sim. O adaptador @intlayer/lingui mantém as macros e substitui o runtime. Depois, você pode migrar os componentes para useIntlayer um de cada vez. Veja os adaptadores de compatibilidade.
Comentários
Ainda sem comentários. Seja o primeiro a compartilhar seus pensamentos.
