Falar Todas as Línguas: Como Funciona a Localização neste Starter
A localização não é uma funcionalidade que se acrescenta depois do lançamento. É uma decisão tomada ao nível da arquitetura — no routing, no modelo de conteúdo e nas ferramentas do Studio. Este starter toma essa decisão por ti, ligando next-intl e @tinloof/sanity-document-i18n para que toda a stack fale todas as línguas desde o primeiro dia.

1. As Duas Camadas de i18n
Há dois problemas distintos ao construir um site multilíngue.
- Traduções da UI — labels, navegação, formatos de datas, plurais. Estas vivem no código.
- Traduções de conteúdo — artigos, páginas, copy de marketing. Estas vivem no CMS.
A maioria dos starters resolve apenas um deles e deixa o outro como “exercício para o leitor”. Este resolve ambos.
2. Camada de UI: next-intl
next-intl trata de tudo o que pertence ao código:
- Routing com prefixo de locale —
/en/about,/pt/sobre,/pl/o-nas - Catálogos de mensagens tipados via ficheiros JSON por locale
- Pluralização, formatação de datas e números
- Suporte nativo para React Server Components
- Um único middleware que negocia o locale, faz redirects e liga tudo
A configuração de routing vive num único ficheiro e é partilhada entre o middleware e as APIs de navegação. Ao adicionar um locale, o routing, os redirects e os links alternativos atualizam automaticamente.
A negociação de locale segue uma ordem clara de prioridade: primeiro o prefixo na URL, depois um cookie guardado, depois o header Accept-Language do browser e, por fim, o default configurado. Os utilizadores entram logo na língua correta na primeira visita e mantêm-na nas seguintes.
Dentro de Server Components, as traduções são carregadas por request e totalmente tipadas com base nos catálogos. Em Client Components, a mesma API está disponível de forma síncrona. Um provider no layout raiz faz a ponte entre servidor e cliente para evitar duplicação de mensagens no bundle.
3. Camada de Conteúdo: @tinloof/sanity-document-i18n
As strings da UI são apenas metade da história. O conteúdo escrito no Sanity Studio também precisa de ser traduzível, revisto e publicado por locale.
@tinloof/sanity-document-i18n é um fork da comunidade do plugin oficial @sanity/document-internationalization, melhorado com gestão de templates e uma configuração mais opinativa para traduções ao nível de documento.
O plugin adiciona:
- Um separador de Translations no editor — um documento por locale, ligado por metadata de tradução
- Um badge de língua em cada documento para os editores saberem sempre em que idioma estão a trabalhar
- Lógica de fallback — traduções em falta regressam ao idioma default
- Preview por locale no Sanity Studio — ver exatamente como a página fica em cada língua antes de publicar
- Templates iniciais por locale para novos documentos já começarem configurados corretamente
Cada tipo de documento traduzível é registado na configuração do plugin juntamente com a lista de idiomas suportados. Cada documento inclui depois um campo oculto de linguagem que as queries GROQ usam para filtrar conteúdo por locale — limpo, explícito e previsível.
4. Como as Duas Camadas se Ligam
O segmento de locale na URL é a única fonte de verdade.
O middleware do next-intl lê o request, negocia o locale e disponibiliza-o a todos os Server Components na árvore.
A camada de dados usa esse mesmo locale para consultar o Sanity e obter os documentos na língua correta. O locale flui de cima para baixo — da URL para o layout, para o catálogo de traduções da UI e para a query GROQ que obtém o documento certo. Sem magia escondida, sem divergências entre router e CMS.
5. Adicionar um Novo Locale
Estender o starter para uma nova língua é um processo de três passos:
- Adicionar ao config de routing — o novo prefixo de URL fica ativo de imediato
- Adicionar um novo ficheiro de mensagens — por exemplo
messages/de.json— para strings da UI - Adicionar à lista de idiomas suportados no plugin — os editores podem agora criar documentos nesse idioma no Studio
Sem alterações a layouts, sem alterações a componentes de página, sem alterações a queries. A arquitetura absorve novos idiomas sem tocar no código da aplicação.
Porque Isto Importa
A maioria das configurações de localização está dividida em dois sistemas sem contrato partilhado — o frontend trata do routing, o CMS trata do conteúdo, e os dois raramente concordam em identificadores de locale ou regras de fallback.
Este starter faz com que concordem por design:
- A lista de locais é definida uma vez no routing e espelhada na configuração do Sanity
- next-intl trata da camada de routing e UI sem código adicional
- @tinloof/sanity-document-i18n trata da camada de conteúdo com previews e fallback por locale
- As queries GROQ são locale-aware desde o início — sem necessidade de adaptação
O resultado é uma stack onde adicionar uma nova língua é algo aditivo, não invasivo. Os editores trabalham num Studio que mostra o locale correto. Os developers fazem queries a um CMS que devolve os documentos certos. Os utilizadores entram em URLs que falam a sua língua.
Esse é o contrato que este starter impõe — e ele mantém-se consistente à escala.