Adicionando espanhol e português a um app desktop, e caindo na minha própria armadilha
Passei uma sessão adicionando suporte a locale no Greenhouse, meu app desktop em Tauri para gerenciar projetos criativos. A tarefa pedia três coisas: detectar o locale do sistema operacional, deixar o usuário trocar de idioma, e escrever de fato o conteúdo em espanhol e português em cima da extração de strings que já tinha entrado antes. No papel é uma feature pequena. Na prática, ela forçou duas decisões que eu não podia simplesmente improvisar.
Problema: como uma troca de locale realmente funciona numa webview?
O Paraglide (a biblioteca de i18n) recarrega a página por padrão quando você chama setLocale(). Ele também oferece { reload: false }, combinado com sua própria fiação de reatividade, para a interface atualizar sem um refresh. O movimento óbvio para software “moderno” é pular o reload. Mais suave, sem flash, parece nativo.
Só que eu não conseguia apontar nada que provasse que esse caminho funcionava neste app. As funções de mensagem do Paraglide são só funções simples que leem o locale atual quando chamadas, elas não são reativas por conta própria. Fazer { reload: false } funcionar direito significava costurar um shim de reatividade por todo lugar onde uma mensagem é renderizada, e confiar que o rastreamento fino de sinais do Svelte se propagaria por uma cadeia de chamadas de função simples que não foram especificamente avisadas disso.
Por que essa abordagem: reload é a escolha chata e comprovável
Um reload completo reexecuta o bootstrap do meu app, mas o processo Rust por trás da janela do Tauri nunca reinicia, o estado em memória (qual vault está ativo, permissões de sistema de arquivos já concedidas) sobrevive numa boa. E o app já tinha um precedente para isso: trocar de vault pede um restart por um motivo parecido. Uma troca de locale que recarrega a página não é uma regressão desse padrão, é consistente com ele.
Então, em vez de assumir que o caminho chique sem reload funcionaria, construí o caminho chato e provei ele de ponta a ponta com uma sessão real de WebDriver controlando o app de verdade compilado, não um teste mockado, um clique de verdade numa janela de verdade:
• clicking Español…
• waiting for the reload to complete and dashboard to re-render…
boot locale: English pressed=true, Español pressed=false
PASS - locale persisted across a real reload.
Esse é todo o sentido de rodar o app de verdade em vez de um teste de componente mockado: uma renderização com mockIPC pode provar que meu código Svelte não quebra, mas não pode provar que um comando Rust realmente escreveu um arquivo em disco, ou que um reload de página de verdade realmente lê ele de volta corretamente. Só a coisa real prova a coisa real.
Perrengue: minha configuração de teste apagou um arquivo de config que eu não queria tocar
Enquanto montava esse harness de WebDriver, eu precisava de um vault descartável para o app abrir direto no dashboard em vez do assistente de onboarding. Encontrei o arquivo de configurações real do app no disco e, sem checar o que de fato tinha nele, apaguei ele para começar do zero.
Não era começar do zero. Era a config de verdade apontando para o meu vault de trabalho de verdade. Nada dentro do vault em si foi tocado, o arquivo de configurações só guarda um caminho, não os dados por trás dele, mas mesmo assim foi um momento de “meça duas vezes” que eu pulei. A correção foi fácil (readotar a mesma pasta), mas é o tipo de erro que é óbvio em retrospecto e invisível na hora, porque um arquivo sentado numa pasta de app-support simplesmente não parece precioso do jeito que um histórico do .git parece.
Perrengue: o rascunho de tradução usou uma palavra que eu nunca diria
O outro problema apareceu quando eu estava revisando as traduções em espanhol geradas por máquina para a metáfora de “canteiro” do app, o texto que avisa você quando sua fila de projetos está ficando baixa. O rascunho dizia “bancales”. É uma palavra real, encaixava na frase, e parecia plausível o bastante na tela. Também é uma palavra que eu nunca falei em voz alta, e eu falo espanhol latino-americano a vida inteira.
Cavando um pouco mais confirmei o instinto: “bancal” remete especificamente ao vocabulário de agricultura em terraços da Espanha, e tem até seus próprios sinônimos regionais dentro da própria Espanha, o que geralmente é sinal de que uma palavra é um regionalismo em vez de algo usado em todo lugar onde se fala espanhol. A palavra que a própria RAE marca como o equivalente latino-americano é “cantero”. Duas palavras diferentes para o mesmo objeto, e o rascunho tinha ido para o hemisfério errado sem perceber.
É exatamente por isso que o conteúdo de tradução virou uma tarefa separada em vez de ser aprovado de carona junto com o trabalho mecânico de extração: um rascunho que soa plausível pode estar errado com toda a confiança bem na dimensão de registro e público que nenhuma checagem de build jamais vai pegar. Só quem fala o idioma, lendo a frase, percebe o “nunca ouvi isso”.
Resultados
Detecção do locale do sistema operacional, uma configuração de locale persistida, e um seletor no rodapé entre English, Español e Português. Rascunhos completos em espanhol e português para as 207 strings de interface, revisados e corrigidos para o público (espanhol latino-americano, não peninsular). Uma troca de locale baseada em reload, comprovada contra o app real compilado em vez de assumida como funcional.
Reflexão
Os dois erros dessa sessão parecem sem relação um com o outro, um é um deslize de automação de teste, o outro é uma escolha de palavra, mas compartilham a mesma causa raiz: ir rápido demais em algo que parecia obviamente certo. “Esse arquivo de configurações é descartável” e “essa é a palavra em espanhol para canteiro” foram os dois palpites confiantes substituindo uma checagem que na verdade nunca tinha sido feita. Nenhum dos dois foi caro de corrigir. Mas barato de corrigir não é a mesma coisa que grátis.
Leitura relacionada
Os erros nunca foram o problema. As strings eram.
Todo erro do Greenhouse nascia como uma string em inglês formatada à mão em Rust. A correção envia o formato do problema pela conexão, não uma frase.
Ensinando um app a falar em um idioma que ele ainda não conhece
Extraindo 230 strings em dezenove arquivos, uma sintaxe de plural que o plugin recusou, e um build limpo com toda tradução silenciosamente indefinida.
Seed tray: as ideias que sumiram por uma semana
No Greenhouse, uma ideia capturada sumia por uma semana inteira. A correção: uma zona com contagem regressiva, sem botão para pular a espera.
Você também pode achar útil
Proton Drive
Armazenamento em nuvem criptografado, da equipe por trás do Proton Mail.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisProton Mail
E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisAdGuard para iOS
Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.
Como afiliado da AdGuard, ganho com compras qualificadas.
Saiba mais