Internacionalizacao e localizacao — preparar o produto para outro idioma, regiao ou direcao de escrita antes de existir tradutor no projeto. Use ao construir qualquer UI que possa receber outro idioma, ao formatar data/numero/moeda, ao lidar com plural, ao testar expansao de texto e RTL, ou quando texto traduzido quebra o layout. Trigger em: "i18n", "internacionalizacao", "localizacao", "l10n", "traducao", "multi-idioma", "outro idioma", "RTL", "arabe", "hebraico", "direita para esquerda", "pseudolocale", "texto quebrou traduzido", "formato de data", "formato de moeda", "plural", "locale", "timezone", "fuso horario", "expansao de texto".
67
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Internacionalizacao (i18n) e trabalho de arquitetura, nao de tradutor. Se a string esta concatenada no meio do componente, a largura foi calculada para o portugues e a data foi montada com dia + "/" + mes, nenhuma traducao conserta — o codigo precisa mudar primeiro. Esta skill cobre o que fazer antes da primeira palavra ser traduzida.
Esta skill segue GLOBAL.md, policies/execution.md, policies/handoffs.md, policies/token-efficiency.md, policies/stack-flexibility.md e policies/evals.md.
Para tabelas de expansao por idioma, exemplos de formatter por plataforma e receitas de teste, consultar docs/skill-guides/i18n-localization.md apenas quando necessario.
Fronteira com skills vizinhas:
lang/dir corretos e leitura por screen reader no idioma certo sao o recorte compartilhadoRetrofit de i18n custa muito mais que fazer certo desde o inicio, porque o problema nao esta nas strings — esta na forma como o codigo foi escrito:
| Decisao tomada sem pensar em i18n | O que quebra depois |
|---|---|
"Ola, " + nome + "!" | Ordem das palavras muda entre idiomas; a frase fica sem sentido |
width: 120px num botao | Alemao e ~30% mais longo que o portugues; o texto corta |
margin-left: 16px | Em RTL o espaco fica do lado errado |
${dia}/${mes}/${ano} | EUA le 08/03 como 3 de agosto, nao 8 de marco |
count + " itens" | Idiomas com 3+ formas de plural (russo, arabe, polones) ficam errados |
| Texto dentro de PNG | Precisa refazer a imagem por idioma |
Ordenacao com sort() cru | Acentos e alfabetos nao-latinos ordenam errado |
Nenhum destes e resolvido por tradutor. Todos exigem mudanca de codigo.
# String literal em JSX/template (o suspeito principal)
grep -rnE '>[A-Za-zÀ-ÿ]{4,}[^<]*<' src/ app/ --include=*.tsx --include=*.jsx
# Concatenacao de frase
grep -rnE '"[^"]*" *\+ *[a-zA-Z_$]|\+ *" [a-z]' src/ app/
# Data/numero montados a mao
grep -rnE 'getMonth\(\)|getDate\(\)|toFixed\(2\).*R\$|"R\$ *" *\+' src/ app/
# Direcao fisica em vez de logica
grep -rnE 'margin-left|margin-right|padding-left|padding-right|text-align: *(left|right)|\b(ml|mr|pl|pr)-[0-9]' src/ app/
# Largura fixa (vai cortar texto mais longo)
grep -rnE 'width: *[0-9]{2,}px|w-\[[0-9]+px\]' src/ app/Cada hit e candidato, nao bug confirmado — validar na Fase 2.
Pseudolocale transforma Salvar em algo como [Ŝåṽåŕ ---]: mantem legivel, mas expande o texto e troca os caracteres. Revela de uma vez:
? ou caixinhaAndroid tem pseudolocales nativos (en-XA para expansao, ar-XB para RTL). Na web e em outras stacks, gerar o pseudolocale a partir do arquivo de strings resolve — a tecnica importa mais que a ferramenta.
Regra de dimensionamento: assumir +30% de expansao sobre o portugues como piso de teste. Texto curto (rotulo de botao) expande proporcionalmente mais que texto longo.
Nao basta espelhar tudo. Espelha o layout; nao espelha conteudo que tem direcao propria:
| Espelha | Nao espelha |
|---|---|
| Direcao da leitura e do fluxo | Numeros |
| Posicao de sidebar, icone e label | Grafico com eixo temporal convencional |
| Seta de "voltar"/"avancar" | Logo da marca |
| Barra de progresso | Icone de relogio, de midia (play/pause) |
| Alinhamento de texto | Codigo, URL, e-mail |
O teste minimo e alternar dir="rtl" no root e percorrer o fluxo principal. O que usa propriedade logica (margin-inline-start) acompanha sozinho; o que usa margin-left fica errado — e esse e justamente o inventario da Fase 1.
Ver o catalogo abaixo. Trocar margin-left por margin-inline-start um a um sem entender o padrao gera regressao na proxima tela.
Rodar pseudolocale e RTL de novo (não só no elemento corrigido — a troca de propriedade lógica pode ter afetado espaçamento vizinho). Se algo que passava antes do fix quebrou agora, o fix vazou escopo — revisar antes de considerar a correção concluída.
Toda string visivel ao usuario sai do componente e vai para arquivo de recurso, com chave semantica (checkout.confirmButton), nao a frase em si como chave (a frase muda; a chave nao deveria).
Interpolacao com variavel nomeada, nunca concatenacao:
Errado: "Ola, " + nome + "! Voce tem " + n + " mensagens."
Certo: t("home.greeting", { nome, count: n })
// pt: "Ola, {nome}! Voce tem {count} mensagens."
// ja: "{nome}さん、{count}件のメッセージがあります。" ← ordem diferenteA ordem das palavras muda entre idiomas. Concatenacao fixa a ordem do portugues no codigo.
Portugues e ingles tem 2 formas (1 / outros). Russo tem 3, arabe tem 6, japones tem 1. if (n === 1) funciona em pt e quebra no resto.
Usar a API de plural da plataforma (Intl.PluralRules na web, plurals no Android, stringsdict no iOS) e deixar cada locale declarar suas proprias formas. Zero merece caso proprio quando o texto muda ("Nenhuma mensagem" em vez de "0 mensagens").
Nunca montar a mao. O formatter da plataforma ja sabe a convencao de cada locale:
08/03/2026 → pt-BR: 8 de marco en-US: 3 de agosto ← mesma string, sentido oposto
1.234,56 → pt-BR en-US: 1,234.56
R$ 1.000 → simbolo, posicao e separador variam por localeRegras que evitam a maioria dos bugs:
Assumir que o texto vai crescer, e projetar para isso:
min-width/min-height, nunca dimensao fixaMesma raiz do bug de min-width: auto da skill 56 — container que se recusa a crescer — aqui disparado pelo idioma.
| Fisico (quebra em RTL) | Logico (acompanha) |
|---|---|
margin-left / margin-right | margin-inline-start / margin-inline-end |
padding-left / padding-right | padding-inline-start / padding-inline-end |
text-align: left | text-align: start |
left / right | inset-inline-start / inset-inline-end |
border-left | border-inline-start |
Tailwind: usar ms-*/me-*/ps-*/pe-* em vez de ml-*/mr-*/pl-*/pr-*.
Texto em PNG/JPG nao e traduzivel sem refazer o arquivo, nao e lido por screen reader e nao escala com a fonte. Texto sobre imagem vai em HTML por cima; texto em SVG e traduzivel se estiver em <text>, nao vetorizado.
array.sort() cru ordena por code point: "Zebra" vem antes de "Ácido", e alfabetos nao-latinos saem embaralhados. Usar comparador sensivel a locale (Intl.Collator). Busca precisa decidir explicitamente se ignora acento e caixa — e o comportamento deve ser o mesmo para "cafe" e "café".
Nome, endereco, telefone e documento variam por pais:
[a-zA-Z] rejeita "José" e "أحمد"lang e dir corretosO atributo lang no root diz ao screen reader qual pronuncia usar e ao browser como quebrar linha. Trecho em outro idioma no meio da pagina leva lang proprio. dir acompanha o idioma. Sem isso, leitor de tela le portugues com fonetica inglesa — e isso e falha de acessibilidade, nao so de i18n.
if (n === 1) como logica de pluralmargin-left/text-align: left em produto que pode receber RTLsort() cru em lista visivel ao usuario[a-zA-Z]Arquitetura:
Layout:
min-*, sem dimensao fixa em elemento com textoinline-start/inline-end) em vez de left/rightdir="rtl" no fluxo principalDados e conteudo:
lang e dir corretos no root e em trecho de outro idiomalang/dir e leitura por screen reader entram na auditoria WCAGComentario so onde a regra de locale nao e obvia — por que um formato especifico foi fixado, ou por que determinado campo nao e obrigatorio em certo pais. Chave de traducao bem nomeada dispensa comentario.
Intl (ECMAScript), Foundation (Apple), bibliotecas equivalentes por plataforma.lang/dir e leitura assistiva: WCAG 2.2 (criterios de idioma da pagina e de partes).lang/dir e o recorte compartilhadofelvieira/claude-skills-fv
90329e3
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.