Em detalhe
Internacionalização de SaaS desde o primeiro dia: nove idiomas e árabe da direita para a esquerda
Publicado em · 4 min de leitura· Anton Shubin
Em resumo
- O app, o painel de administração, o site e os e-mails do Seed estão em nove idiomas, árabe incluído, com cerca de 3.900 mensagens em cada um.
- Um teste quebra o build se falta uma mensagem, se ela ficou desatualizada ou perdeu um marcador. Outro recusa uma margem “esquerda” ou “direita” que não inverteria em árabe.
- O idioma é uma configuração da pessoa, salva no servidor, separada do formato de data, do fuso horário e do relógio.
- Um décimo idioma é uma entrada numa lista, um arquivo por catálogo e algumas linhas de carregamento.
Como fazer um SaaS em vários idiomas, com árabe da direita para a esquerda, sem precisar reescrever tudo depois? Começando pela primeira tela e deixando os testes tomarem conta. O Seed sai em nove idiomas: português do Brasil, inglês, russo, espanhol, alemão, árabe, francês, japonês e chinês simplificado. Isso vale para o app, o painel de administração, o site e os e-mails. Em árabe, o layout inteiro vira do avesso.
Este texto é para fundadores e desenvolvedores que sabem que “a gente traduz depois” quer dizer “a gente nunca traduz”. Vou mostrar onde ficam os textos, o que os testes pegam e quanto o RTL custa de verdade.
Por que desde o primeiro dia?
Porque traduzir depois obriga você a passar duas vezes por cada tela. É preciso achar cada texto
escrito direto no código, cada data montada à mão, cada margin-left, num código que a essa altura
já está cheio de funcionalidades. Traduzindo desde o início, cada tela nova é traduzida enquanto é
construída: alguns minutos, e não um projeto que ninguém quer começar.
E há um motivo mais simples: a maioria das pessoas na internet não lê primeiro em inglês. Um produto que fala a língua delas sai na frente.
Onde ficam os textos?
Cada palavra que as telas do Seed mostram está num catálogo: um arquivo TypeScript por área e
idioma, como i18n/app/pt-BR.ts ou i18n/site/ja.ts. São cinco áreas: o app, o painel, o site,
os e-mails e as mensagens de erro da API. O inglês é a fonte, e os outros arquivos têm as mesmas
chaves.
| Área | Mensagens por idioma |
|---|---|
| O app | 1.503 |
| Painel de admin | 1.487 |
| Site | 682 |
| Códigos de erro | 164 |
| E-mails | 79 |
São cerca de 3.900 mensagens por idioma, contadas em 2 de novembro de 2026. Os componentes do preact-components trazem também seus próprios catálogos.
O app carrega só o seu idioma, num arquivo pequeno separado: quem lê em português não baixa o japonês.
O que impede uma tradução de ficar desatualizada?
Um teste, i18n/i18n.test.ts. Ele falha quando:
- falta uma mensagem em algum idioma, ou sobra uma que o inglês não tem mais;
- o inglês mudou depois da tradução (cada idioma guarda um arquivo lock que registra de qual versão do inglês a tradução foi feita);
- uma tradução perdeu ou escreveu errado um marcador como
{count}, ou uma tag em volta de um link; - falta a um plural uma forma de que o idioma precisa. O árabe tem seis;
- nenhum código usa mais uma mensagem em inglês.
Assim não vai para o ar um botão escrito Notes.create, nem uma tela em alemão uma semana atrás da
versão em inglês.
Quanto custa de verdade a escrita da direita para a esquerda?
Menos do que parece, desde que o layout nunca diga “esquerda” ou “direita”. Os estilos do Seed usam lados lógicos: “início” e “fim”. Numa página da esquerda para a direita, o início fica à esquerda; em árabe, à direita. Quem inverte é o navegador.
Um teste transforma isso em regra: tests/spacing.test.ts percorre todos os apps e falha em
qualquer classe de espaçamento que cite um lado físico. A página define dir pelo idioma: o site
no servidor, e o app no momento em que você troca de idioma.
Mais dois detalhes que doem tarde se você pular:
- Nomes dentro de frases. “Ana convidou você para o grupo Team” mistura direções em árabe, e
um nome em alfabeto latino pode arrastar a pontuação para o lado errado. Os valores dos usuários
ficam dentro de
<bdi>, que isola a direção deles do resto do texto. - Datas, números e horas. Toda data de toda tela passa por um único formatador. Outro teste,
tests/no-direct-date-format.test.ts, falha em qualquer chamada direta atoLocaleString().
Idioma, formato regional e relógio são três configurações
O idioma é salvo no servidor junto com o perfil, então vale em todos os seus aparelhos e em todos
os e-mails. O formato regional, o fuso horário e o relógio de 12 ou 24 horas são configurações à
parte. Uma brasileira morando em Lisboa quer o app em português do Brasil e o horário de Lisboa.
Um americano morando em São Paulo quer textos em inglês e datas como 03/11/2026. Amarrar tudo
numa coisa só é o jeito certo de mostrar a data errada para metade dos seus usuários.
No site, o idioma fica no endereço (/pt-BR/pricing, /ar/pricing), sem redirecionamento por
navegador ou IP, e cada página diz aos buscadores quais versões existem.
Quem traduz?
Agentes de IA, seguindo um guia escrito, i18n/TRANSLATING.md. Ele define o tom de cada idioma
(em português, tratando por “você”), um glossário para que cada coisa tenha um nome só em todas as
telas, e a regra de traduzir a situação, não as palavras. Um segundo agente traduz cada tradução
nova de volta para o inglês e compara o sentido. Não é uma agência de tradução profissional, e não
vou fingir que é. Mas é muito melhor do que uma tela que ninguém consegue ler.
Como adicionar um décimo idioma
Uma entrada na lista de idiomas, um arquivo de catálogo por área e algumas linhas em cada app que o carregam. Depois, os testes listam cada mensagem que falta ao idioma novo e continuam vermelhos até ele ficar completo.
Experimente
Abra a demo, vá ao seu perfil e mude o idioma para árabe. Veja o app inteiro virar do avesso e depois volte para o português. Este artigo também existe nos nove idiomas, e o código é MIT.