---
title: "i18n sem sofrimento: o que aprendemos com next-intl em 9 produtos"
description: "Internacionalização não é um arquivo de tradução — é uma decisão de arquitetura. URLs com prefixo de locale, navegação tipada e fallback consciente."
author: "Anderson Henrique"
date: "2026-04-21T14:30:00Z"
updated: "2026-05-12T14:04:42.167481Z"
category: "engineering"
tags: ["i18n","next-intl","next.js","arquitetura","engenharia"]
canonical: "https://www.ntlabs.dev/blog/i18n-without-pain-next-intl"
locale: "pt"
---

Quando começamos a NTLabs, a internacionalização parecia um detalhe que resolvíamos depois. Bastava um JSON com chaves traduzidas e pronto. Em três meses descobrimos que i18n não é tradução — é arquitetura.

A primeira escolha estrutural foi adotar o prefixo de locale na URL. /pt/blog e /en/blog em vez de detectar idioma por cookie ou header. Soa trivial, mas decide tudo o que vem depois: o crawler do Google vê duas páginas distintas com alternates, o compartilhamento em redes sociais preserva o idioma, e o cache de borda funciona sem fragmentação por header.

A segunda foi tipar a navegação. Em next-intl, a função Link e o useRouter vêm de @/i18n/navigation, não de next/link. Isso parece burocrático até o dia em que alguém escreve href="/blog" e o link quebra silenciosamente em /en porque não recebeu o prefixo. Com a navegação tipada, o TypeScript recusa o atalho.

A terceira foi sobre fallback. Quando uma chave existe em pt mas não em en, o que acontece? Por padrão, next-intl quebra. Decidimos manter assim — preferimos um erro de build a um post publicado pela metade. Isso obriga a tradução a ser parte da definição de pronto, não um detalhe operacional.

Hoje rodamos nove produtos bilíngues com o mesmo padrão. Cada um carrega seus próprios namespaces (blog, careers, dedalo, agora), mas todos compartilham a mesma infraestrutura: o middleware que detecta o locale, as rotas com [locale], o cliente do Supabase que recebe locale como parâmetro de query.

O que mudou em mim foi entender que i18n é uma camada transversal — não um plugin que se instala. Cada decisão de produto carrega uma decisão de idioma junto, e quanto mais cedo isso entra na conversa, mais barata fica a manutenção.
