Copy visível sai de catálogos, não de strings concatenadas no JSX. Locale BCP 47 (pt-BR, en). Formate data/número/moeda com Intl (ou o wrapper da lib). Mobile: i18n-mobile. APIs: i18n-backend. Copy: website-copywriting. Desktop nativo egui: i18n-frontend não aplica — use Fluent/rust-i18n apontado em egui.
Preserve a lib já no repo. Não troque next-intl por react-i18next numa feature.
Regras inegociáveis
- Nenhuma string de UI hardcoded em código novo (
"Salvar","Welcome, " + name). - Chaves estáveis (
account.save), não a frase inglesa como única chave sem contexto para o tradutor. - ICU / plural / select (
{count, plural, one {# item} other {# items}}). Não façacount === 1na view. html lang+dir(rtlparaar,he, …) no documento.- Fallback explícito (ex.:
pt-BR→pt→en). Nunca tela com chave crua em produção. - Datas/números:
Intl.DateTimeFormat/NumberFormatcom o locale ativo. ISO na API; formatar na UI. - Pseudo-locale ou lint de chaves no CI (
t('missing')falha).
Catálogos
locales/
en/common.json
pt-BR/common.json
- Namespaces por domínio (
common,auth,errors), não um JSON de 4k linhas. - Interpolação da lib (
t('hello', { name })), nuncareplacemanual. - Comentários/descrição da chave para tradutor (contexto, max length).
- Não traduzir: IDs, SKUs, rotas de API, nomes de marca protegidos.
Locale e roteamento
Ordem típica: path (/pt-BR/settings) ou cookie/header do usuário autenticado > Accept-Language > default.
- SEO:
hreflang, URL por idioma se o conteúdo for público. - SPA: locale no router; não só
localStoragesem persistir no perfil quando houver login. - SSR (Next/Nuxt): o HTML inicial usa o mesmo locale da hidratação — sem flash
en→pt.
React / Next.js
- SPA:
react-i18next(ou a lib do repo) no provider;useTranslationnas views. - App Router:
next-intl(ou equivalente já adotado).[locale]noapp/;middlewarepara prefixo. - Server Components:
getTranslationsno servidor; não puxe o catálogo inteiro no client sem necessidade. - Não localize Server Actions com string de erro só no client —
codeestável +i18n-backend/ mapa de erros.
Vue / Nuxt
- Vue SPA:
vue-i18n+ Composition API (useI18n). - Nuxt:
@nuxtjs/i18n(estratégiaprefix/prefix_except_defaultalinhada ao produto). langDir+localesnonuxt.config.localePath/localeRouteem links, não path hardcoded.
Angular
- Código novo:
@angular/localize+$localizeou a lib do repo (ngx-translate/ Transloco) — uma só. LOCALE_IDeregisterLocaleDatapara pipes de data/número.langnoindex.html/Document. Build por locale (ng extract-i18n) se o projeto já for compile-time.
Tauri
- Mesma stack i18n do frontend web. Locale do OS (
navigator.language) como default, override do usuário persistido. - Não traduzir
tauri.confidentifiers.
RTL e layout
dir="rtl"no root; CSS lógico (margin-inline-start,ps-4) em vez demargin-leftsó.- Ícones direcionais (setas) espelham; logos e fotos não.
- Form controls e tables: teste
armesmo que o MVP sejapt/en.
E-mail e SEO
- Templates:
react-emailcom catálogo ou props já traduzidas pelo backend.langnoHtml. - Metadata (
title,description) por locale.
Anti-padrões
"Hello " + userName- Traduzir
error.messagecru do servidor - Um JSON monolíngue com
if (lang === 'pt') toLocaleDateString()sem locale explícito- Trocar de lib i18n no meio da feature
- Esconder RTL “depois”
Integração com outras skills
- Next:
nextjs-architecture - React SPA:
reactjs-application-development - Vue/Nuxt:
vue/nuxt - Angular:
angular - UI:
better-web-interface - Mobile:
i18n-mobile - API:
i18n-backend - E-mail:
react-email - Copy:
website-copywriting
Critérios de conclusão
- Novas strings em catálogo; ICU para plural
lang/dircorretos; sem flash de locale no SSR- Datas/números via
Intl+ locale ativo - Fallback sem chaves cruas
- Rotas/links cientes do locale