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
- "Initial history"v9.1.306/08/2025
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
Traduza seu site SolidStart usando Intlayer | Internacionalização (i18n)
Índice
Este guia cobre uma aplicação SolidStart renderizada no servidor: a detecção de localidade acontece na requisição, as páginas são renderizadas no servidor no idioma correto e os sinais de <html lang>, hreflang e mapa do site (sitemap) que os motores de busca precisam são emitidos no lado do servidor.
Por que Intlayer em vez de alternativas?
Comparado a soluções principais como @solid-primitives/i18n ou i18next, o Intlayer é uma solução que vem com otimizações integradas, tais como:
O Intlayer é otimizado para funcionar perfeitamente com o Solid, oferecendo escopo de conteúdo no nível do componente, traduções reativas 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 seu bundle e das páginas em até 50%.
Definir o escopo do conteúdo do seu aplicativo facilita a manutenção para aplicações de grande escala. Você pode duplicar ou excluir uma única pasta de recurso sem o fardo mental de revisar toda a sua base de código de conteúdo. Além disso, o Intlayer é totalmente tipado para garantir a precisão do seu conteúdo.
A co-localização de conteúdo reduz o contexto necessário pelos Grandes Modelos de Linguagem (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 agentes de IA.
Use a automação para traduzir em seu pipeline de CI/CD usando o LLM de sua escolha ao custo do 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 massivos a componentes pode levar a problemas de desempenho e reatividade. O Intlayer otimiza o carregamento do seu conteúdo no momento do build.
Mais do que apenas uma solução de i18n, o Intlayer fornece um editor visual auto-hospedado e um CMS completo para ajudá-lo a gerenciar seu conteúdo multilíngue em tempo real, tornando a colaboração com tradutores, redatores e outros membros da equipe perfeita. O conteúdo pode ser armazenado localmente e/ou remotamente.
Guia passo a passo para configurar o Intlayer em uma aplicação SolidStart
Instalar Dependências
Instale os pacotes necessários usando npm:
bashCopiar códigoCopiar o código para a área de transferência
a flag
--interactiveé opcional. Useintlayer-cli initse você for um agente de IA.Este comando detectará seu ambiente e instalará os pacotes necessários. Por exemplo:
bashCopiar códigoCopiar o código para a área de transferência
intlayer
O pacote principal que fornece ferramentas de internacionalização para gerenciamento de configuração, tradução, declaração de conteúdo, transpilação e comandos CLI.
solid-intlayer
O pacote que integra o Intlayer com aplicações Solid. Ele fornece provedores de contexto e hooks para a internacionalização no Solid.
vite-intlayer
Inclui o plugin do Vite para integrar o Intlayer ao empacotador Vite, bem como o manipulador de roteamento de localidade que detecta a localidade preferida do usuário, gerencia cookies e lida com o redirecionamento de URL.
vite-intlayeré uma preocupação do lado do servidor aqui, não apenas em tempo de build: ele fornece o manipulador de requisições executado pelo servidor Nitro do SolidStart. Mantê-lo emdependenciesé o padrão seguro — você só deve movê-lo paradevDependenciesse implantar o diretório.outputcompilado, onde o Nitro insere o manipulador inline.Configuração do seu projeto
Crie um arquivo de configuração para configurar os idiomas do seu aplicativo:
intlayer.config.tsCopiar códigoCopiar o código para a área de transferência
import { type IntlayerConfig, Locales } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // Suas outras localidades ], defaultLocale: Locales.ENGLISH, }, routing: { mode: "prefix-no-default", }, }; export default config;Com
prefix-no-default, a localidade padrão é servida a partir de URLs sem prefixo:plaintextCopiar códigoCopiar o código para a área de transferência
Através deste arquivo de configuração, você pode configurar URLs localizados, redirecionamento de middleware, nomes de cookies, a localização e extensão das suas declarações de conteúdo, desativar logs do Intlayer no console e muito mais. Para obter uma lista completa dos parâmetros disponíveis, consulte a documentação de configuração.
Integrar o Intlayer na sua configuração do Vite
Adicione o plugin do Intlayer à sua configuração:
vite.config.tsCopiar códigoCopiar o código para a área de transferência
import { solidStart } from "@solidjs/start/config"; import { nitro } from "nitro/vite"; import { defineConfig } from "vite"; import { intlayer } from "vite-intlayer"; export default defineConfig({ plugins: [solidStart(), nitro(), intlayer()], });O plugin
intlayer()do Vite compila seus arquivos de declaração de conteúdo, os observa no modo de desenvolvimento e define as variáveis de ambiente do Intlayer dentro da aplicação. Ele também fornece aliases que otimizam o desempenho.O roteamento de localidade vem com o plugin
O SolidStart roda no Nitro, e o
intlayer()registra seu manipulador de roteamento de localidade diretamente no pipeline do servidor Nitro (através da opçãorouting.enableProxy,truepor padrão). Nada mais para configurar: em um servidor compilado, cada requisição é inspecionada antes de chegar ao roteador, e- a localidade é lida do prefixo da URL, depois do cookie
INTLAYER_LOCALE, e depois do cabeçalhoAccept-Language; - uma URL sem prefixo é redirecionada para sua contraparte localizada quando a localidade resolvida não for a padrão (
/→/fr); - uma URL com prefixo redundante é redirecionada de volta para sua forma canônica (
/en/about→/about); - o cookie de localidade é gravado de volta na resposta.
- a localidade é lida do prefixo da URL, depois do cookie
Declarar Seu Conteúdo
Crie e gerencie suas declarações de conteúdo para armazenar traduções:
src/contents/home.content.tsCopiar códigoCopiar o código para a área de transferência
import { type Dictionary, t } from "intlayer"; const homeContent = { key: "home-page", content: { title: t({ en: "Hello world!", fr: "Bonjour le monde !", es: "¡Hola mundo!", }), metaTitle: "SolidStart + Intlayer", metaDescription: t({ en: "A SolidStart application internationalized with Intlayer.", fr: "Une application SolidStart internationalisée avec Intlayer.", es: "Una aplicación SolidStart internacionalizada con Intlayer.", }), documentation: t({ en: "Visit start.solidjs.com to learn how to build SolidStart apps.", fr: "Visitez start.solidjs.com pour apprendre à créer des applications SolidStart.", es: "Visita start.solidjs.com para aprender a crear aplicaciones SolidStart.", }), }, } satisfies Dictionary; export default homeContent;⚠️ Aviso específico do SolidStart: cada arquivo
.ts/.tsxemsrc/routestorna-se uma rota, e um arquivo.content.tspossui uma exportação padrão, portanto seria interpretado como uma página. Mantenha as declarações de conteúdo das suas páginas fora do diretório de rotas (src/contents/funciona bem). O conteúdo dos componentes pode permanecer co-localizado, já quesrc/componentsnão é verificado pelo roteador baseado no sistema de arquivos.Suas declarações de conteúdo podem ser definidas em qualquer lugar da sua aplicação, desde que estejam incluídas no diretório
contentDir(por padrão,./src) e correspondam à extensão de arquivo de declaração de conteúdo (por padrão,.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).Para obter mais detalhes, consulte a documentação de declaração de conteúdo.
Adicionar roteamento localizado
O objetivo desta etapa é dar a cada idioma sua própria URL, que é o que os motores de busca indexam.
Mova suas páginas para um segmento dinâmico opcional. No roteador baseado no sistema de arquivos do SolidStart,
[[locale]]é compilado para o padrão de caminho:locale?:plaintextCopiar códigoCopiar o código para a área de transferência
O único trabalho do arquivo de layout é restringir o segmento a uma localidade configurada:
src/routes/[[locale]].tsxCopiar códigoCopiar o código para a área de transferência
@solidjs/routerexpande:locale?em dois padrões — um com o segmento e outro sem — e os testa por especificidade decrescente.matchFiltersé o que faz a diferença entre uma configuração funcional e uma confusa:Mostrar todo o conteúdo da tabelaAbrir a tabela em um modal para ver todo o conteúdo claramente
URL Sem matchFiltersCom matchFilters/fr/aboutPágina "sobre" em francês Página "sobre" em francês /aboutPágina "sobre" (segmento estático vence) Página "sobre" /unknownPágina inicial, silenciosamente, com locale=unknownNenhuma correspondência → cai no 404 genérico Prefira
[locale](obrigatório) em vez de[[locale]]se você usar o modo de roteamento'prefix-all', e remova o segmento completamente para'no-prefix'ou'search-params'.Fornecer a localidade para sua aplicação
A URL é a fonte única de verdade para a localidade: o middleware já redirecionou a requisição para o seu caminho localizado, então ler o caminho no layout raiz mantém a renderização no servidor e a hidratação no cliente em conformidade, e atualiza a localidade gratuitamente a cada navegação no lado do cliente.
src/app.tsxCopiar códigoCopiar o código para a área de transferência
O
IntlayerProviderreage à sua proplocale, portanto passar a chamada do acessadorlocale()dentro do JSX é suficiente — o Solid o compila para um getter, e toda a árvore é renderizada novamente no novo idioma quando a URL muda.Definir os atributos lang e dir do HTML no servidor
O elemento
<html>é renderizado peloentry-server.tsx, fora doRouter. Em vez disso, leia a localidade a partir da URL da requisição:src/entry-server.tsxCopiar códigoCopiar o código para a área de transferência
Os crawlers agora recebem o idioma correto logo no primeiro byte:
htmlCopiar códigoCopiar o código para a área de transferência
Utilizar o Intlayer em suas páginas
Acesse seus dicionários de conteúdo em toda a sua aplicação:
src/routes/[[locale]]/index.tsxCopiar códigoCopiar o código para a área de transferência
No Solid,
useIntlayerretorna conteúdo reativo (ex.:content). Você pode acessar suas propriedades diretamente.Se você quiser usar seu conteúdo em um atributo do tipo
string, comoalt,title,href,aria-label, etc., você pode usar o valor da função, como:htmlCopiar códigoCopiar o código para a área de transferência
Para saber mais sobre o hook
useIntlayer, consulte a documentação.Os nós de conteúdo não estão limitados a traduções simples. Um contador pluralizado, por exemplo:
src/components/Counter.content.tsCopiar códigoCopiar o código para a área de transferência
src/components/Counter.tsxCopiar códigoCopiar o código para a área de transferência
plural()seleciona a categoria através doIntl.PluralRulespara a localidade ativa, de modo que idiomas com mais de duas formas no plural funcionem sem código adicional.Criar um componente de Link Localizado
Crie um componente
Linkpersonalizado que adiciona automaticamente o prefixo do idioma atual às URLs internas:src/components/LocalizedLink.tsxCopiar códigoCopiar o código para a área de transferência
src/components/Nav.tsxCopiar códigoCopiar o código para a área de transferência
Escrever
href="/about"uma única vez agora produz/about,/fr/aboutou/es/about, dependendo da localidade ativa — sem necessidade de adicionar prefixos manualmente em suas páginas.Criar um componente Seletor de Localidade
Renderize o seletor como âncoras reais em vez de um
<select>: cada idioma da página atual se torna um link rastreável que pode ser aberto em uma nova guia, algo que um controle baseado apenas em JavaScript não pode oferecer.getPathWithoutLocaleremove o segmento de localidade do caminho atual, egetLocalizedUrlo reconstrói para a localidade de destino, para que os links sigam seu modo de roteamento sem codificar nada permanentemente. A navegação é o que altera a localidade renderizada — a rota[[locale]]a deriva da URL —, enquantosetLocalepersiste a escolha no cookieINTLAYER_LOCALE, para que uma visita posterior a uma URL sem localidade seja resolvida para o mesmo idioma.src/components/LocaleSwitcher.tsxCopiar códigoCopiar o código para a área de transferência
import { A, useLocation } from "@solidjs/router"; import { getHTMLTextDir, getLocaleName, getLocalizedUrl, getPathWithoutLocale, } from "intlayer"; import { useIntlayer, useLocale } from "solid-intlayer"; import { type Component, For } from "solid-js"; export const LocaleSwitcher: Component = () => { const content = useIntlayer("locale-switcher"); const location = useLocation(); const { locale, setLocale, availableLocales } = useLocale(); // Caminho canônico (sem localidade) da página exibida no momento const pathWithoutLocale = () => getPathWithoutLocale(location.pathname); return ( <div> <button aria-label={content.label.value} popoverTarget="localePopover" type="button" > {getLocaleName(locale())} </button> <div id="localePopover" popover="auto"> <For each={availableLocales}> {(localeItem) => ( <A dir={getHTMLTextDir(localeItem)} // Correspondência exata apenas, para que o link da localidade padrão não seja marcado // como ativo em todas as páginas end href={getLocalizedUrl(pathWithoutLocale(), localeItem)} hreflang={localeItem} lang={localeItem} onClick={() => setLocale(localeItem)} // Garante que o botão "voltar" do navegador retorne à página anterior replace > {/* Idioma em sua própria localidade - ex.: Français */} {getLocaleName(localeItem)} </A> )} </For> </div> </div> ); };No Solid,
localeretornado poruseLocaleé um acessador de sinal. Uselocale()(com parênteses) para ler seu valor atual de forma reativa.getLocaleName(localeItem)renderiza cada idioma em seu próprio idioma —English / Français / Español. Passe um segundo argumento para traduzir os nomes no idioma exibido no momento:getLocaleName(localeItem, locale())resulta emEnglish / French / Spanishem inglês,anglais / français / espagnolem francês.O
<A>já definearia-current="page"no link correspondente à URL atual, portanto não há nada a adicionar.replaceé lido do atributo renderizado pelo roteador: ele substitui a entrada no histórico em vez de adicionar uma nova, de modo que o botão "voltar" do navegador retorna à página visitada antes da troca, e não à mesma página no idioma anterior.direhreflangem cada link mantêm os nomes dos idiomas da direita para a esquerda orientados corretamente e informam às tecnologias assistivas e crawlers para qual idioma cada link aponta.Para saber mais sobre o hook
useLocale, consulte a documentação.Emitir links canônicos e hreflang
OpcionalAs anotações
hreflanginformam aos motores de busca que/about,/fr/aboute/es/aboutsão a mesma página em idiomas diferentes.getMultilingualUrlsas deriva a partir do caminho canônico (sem localidade), seguindo o seu modo de roteamento, para que nada seja codificado manualmente:src/components/AlternateLinks.tsxCopiar códigoCopiar o código para a área de transferência
Renderize-o no cabeçalho do documento, onde a URL da requisição está disponível:
src/entry-server.tsxCopiar códigoCopiar o código para a área de transferência
GET /fr/aboutentão serve:htmlCopiar códigoCopiar o código para a área de transferência
Nota sobre
@solidjs/meta: no momento em que este artigo foi escrito,<Title>e<Meta>do@solidjs/metasão aplicados no cliente após a hidratação, mas não são emitidos no<head>renderizado no servidor no SolidStart v2. Até que isso seja corrigido upstream, renderize as tags que os crawlers devem ver sem JavaScript —canonical,hreflange, se necessário,title/description— diretamente noentry-server.tsx, como mostrado acima.Gerenciar páginas não encontradas
OpcionalUma rota curinga (splat route) na raiz de
src/routescaptura todos os caminhos que não corresponderam ao segmento de localidade — incluindo prefixos de localidade inválidos rejeitados pormatchFilters. Como a localidade ainda vem da URL através do layout raiz, a página 404 é exibida no idioma do visitante:src/routes/[...404].tsxCopiar códigoCopiar o código para a área de transferência
Mostrar todo o conteúdo da tabelaAbrir a tabela em um modal para ver todo o conteúdo claramente
Requisição Resultado /xx404—xxnão é uma localidade configurada/nonexistent404na localidade padrão/fr/nonexistent404em francês (Page introuvable)Gerar um mapa do site (sitemap) multilíngue
OpcionalO gerador de mapa do site do Intlayer expande cada caminho em uma entrada por localidade e conecta as alternativas
xhtml:linkentre elas, de modo que a rota precisa apenas listar os caminhos canônicos e sem localidade.Ao contrário de geradores básicos que apenas emitem URLs planas, o Intlayer conecta links bidirecionais entre cada variante localizada de cada página, o que ajuda os motores de busca a relacionar URLs localizadas e servir a correta para o público certo.
O SolidStart transforma um arquivo que exporta um método HTTP em uma rota de API e remove a extensão
.tsdo caminho — portantosrc/routes/sitemap.xml.tsé servido em/sitemap.xml:src/routes/sitemap.xml.tsCopiar códigoCopiar o código para a área de transferência
import type { APIEvent } from "@solidjs/start/server"; import { generateSitemap } from "intlayer"; const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000"; export const GET = (_event: APIEvent) => { 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" }, }); };output of GET /sitemap.xmlCopiar códigoCopiar o código para a área de transferência
Rotas de API não oferecem suporte a parâmetros opcionais, portanto mantenha este arquivo na raiz de
src/routes, fora do segmento[[locale]]. O sitemap já contém todas as localidades.Você pode construir um
robots.txtda mesma forma comgetMultilingualUrls, para que as entradasDisallowcubram todas as grafias localizadas de um caminho sensível:src/routes/robots.txt.tsCopiar códigoCopiar o código para a área de transferência
import { getMultilingualUrls } from "intlayer"; const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000"; const disallowedPaths = ["/admin", "/private"].flatMap((path) => Object.values(getMultilingualUrls(path)) ); export const GET = () => new Response( [ "User-agent: *", "Allow: /", ...disallowedPaths.map((path) => `Disallow: ${path}`), "", `Sitemap: ${SITE_URL}/sitemap.xml`, ].join("\n"), { headers: { "Content-Type": "text/plain" } } );Obter a localidade em suas funções de servidor
OpcionalVocê pode querer acessar a localidade atual de dentro de uma função de servidor ou de uma rota de API.
Em uma configuração baseada em prefixo como esta, a URL é soberana:
getLocaleFromPathlê o prefixo da URL da requisição.getLocaleé o recurso de fallback para requisições que não possuem prefixo de localidade — ele inspeciona o cookieINTLAYER_LOCALE, depois o cabeçalhox-intlayer-localee, em seguida, negocia oAccept-Language.src/routes/[[locale]]/index.tsxCopiar códigoCopiar o código para a área de transferência
Não confie apenas no
getLocaleaqui: o cookie de localidade só é gravado quando um visitante altera ativamente o idioma, portanto uma primeira visita a/fr/...seria resolvida para a localidade padrão.Extrair o conteúdo dos seus componentes
OpcionalSe você possui uma base de código existente, transformar milhares de arquivos pode exigir muito tempo.
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
compilerno seu arquivointlayer.config.ts:intlayer.config.tsCopiar códigoCopiar o código para a área de transferência
import { type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { // ... Restante da sua configuração compiler: { /** * Indica se o compilador deve estar 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. * * - Se `true`, o compilador reescreverá o arquivo do componente no disco. Assim, a transformação será permanente e o compilador pulará a transformação no próximo processo. Dessa forma, o compilador pode transformar o app e depois ser removido. * * - Se `false`, o compilador injetará a chamada da função `useIntlayer()` no código apenas na saída do build e manterá a base de código original intacta. A transformação será feita apenas em memória. */ saveComponents: false, /** * Prefixo da chave do dicionário */ dictionaryKeyPrefix: "", }, }; export default config;Execute o extrator para transformar seus componentes e extrair o conteúdo
bashCopiar códigoCopiar o código para a área de transferência
Mova os arquivos de conteúdo gerados das suas páginas para fora de
src/routesposteriormente, pelo motivo explicado na etapa 5.A partir da v9, o
intlayerCompilerestá incluído no pluginintlayer. Portanto, você não precisa adicioná-lo manualmente.Atualize seu
vite.config.tspara incluir o pluginintlayerCompiler:vite.config.tsCopiar códigoCopiar o código para a área de transferência
bashCopiar códigoCopiar o código para a área de transferência
Configurar o TypeScript
O Intlayer usa aumentação de módulo para obter os benefícios do TypeScript e tornar sua base de código mais sólida.
Garanta que sua configuração do TypeScript inclua os tipos gerados automaticamente:
tsconfig.jsonCopiar códigoCopiar o código para a área de transferência
As chaves do dicionário e os caminhos de conteúdo agora são verificados no momento da compilação:
tsxCopiar códigoCopiar o código para a área de transferência
Verificando sua configuração
Faça o build e inicie o servidor, depois verifique se estas requisições se comportam como esperado:
Copiar o código para a área de transferência
Abrir a tabela em um modal para ver todo o conteúdo claramente
| Requisição | Resposta esperada |
|---|---|
GET / | 200 — Inglês |
GET / com Accept-Language: fr | 302 → /fr |
GET / com cookie INTLAYER_LOCALE=es | 302 → /es |
GET /fr | 200 — Francês, <html lang="fr"> |
GET /fr/about | 200 — Página "sobre" em francês |
GET /en/about | 302 → /about (redirecionamento canônico) |
GET /xx | 404 |
GET /fr/nonexistent | 404 em francês |
GET /sitemap.xml | 200 — sitemap XML multilíngue |
As linhas que renderizam uma página se comportam de forma idêntica em vite dev. As três linhas de redirecionamento só se aplicam a um servidor compilado, a menos que você mesmo registre o manipulador como um middleware — consulte a etapa 3.
Execute o servidor de dev no Node (vite dev) em vez de no Bun (bun --bun vite dev): a SSR do SolidStart atualmente falha no ambiente de execução do Bun comExpected a Response object, but received 'NodeResponse'. Isso não tem relação com o Intlayer — reproduz-se no template padrão — e afeta apenas o servidor de desenvolvimento, não ovite build.
Configuração do Git
É recomendado ignorar os arquivos gerados pelo Intlayer. Isso permite evitar o commit deles no seu repositório Git.
Para fazer isso, você pode adicionar as seguintes instruções ao seu arquivo .gitignore:
Copiar o código para a área de transferência
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.
Instalar a partir do 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.
Ir Mais Longe
Para ir mais longe, você pode implementar o editor visual ou externalizar seu conteúdo usando o CMS.
