mapa-frontend-i18n
mapa-frontend-i18n
Biblioteca Angular de internacionalização (i18n) construída sobre
@angular/localize. Fornece os catálogos de
tradução do produto MAPA (pt-BR, en, es) e funções para inicializar o idioma da
aplicação.
A partir da 2.0, as traduções podem ser carregadas de arquivos JSON hospedados na AWS (S3/CloudFront), permitindo corrigir termos e acentuação sem republicar a lib nem fazer redeploy das aplicações. Os catálogos embutidos continuam no pacote como fallback.
Compatibilidade: a 2.0 é aditiva — a API síncrona da 1.x (
initializeAppLanguage,getMapaUiTexts, tipos e catálogos) continua igual. O carregamento remoto é opt-in viainitializeAppLanguageAsync. O major marca a mudança de arquitetura (traduções podem vir da rede), não uma quebra de API.
Sumário
- Instalação
- Como funciona
- Inicialização
- Opções de carregamento remoto
- Cache e revalidação
- Arquivos de tradução na AWS
- Gerar/atualizar os JSON
- Processo de hotfix de termo
- Requisitos de infraestrutura
- Outras APIs
- Idiomas suportados
Instalação
npm install mapa-frontend-i18n
peerDependency: @angular/localize ~20.3.0 (já presente nas aplicações MAPA).
Como funciona
- As traduções são um mapa achatado
{ "chave.do.localize": "texto" }, injetado no@angular/localizevialoadTranslations(). - O
$localizeresolve cada mensagem no momento em que ela é avaliada, usando o mapa global. Por isso, as traduções precisam ser carregadas antes dobootstrapApplication()— caso contrário a tela aparece com o texto-fonte (pt-BR) ou com as chaves cruas. - O carregamento remoto faz o merge
{ ...embutido, ...remoto }: o remoto sobrescreve o embutido, e qualquer chave ausente no remoto ainda resolve pelo embutido. Ou seja, arquivos remotos parciais são seguros.
Inicialização
Modo 1 — Embutido (síncrono)
Usa apenas os catálogos embutidos no pacote. É o comportamento clássico, sem rede.
import { initializeAppLanguage } from "mapa-frontend-i18n";
initializeAppLanguage(); // lê o idioma do localStorage e carrega o embutido
Modo 2 — Remoto com fallback (recomendado)
Carrega da AWS, com cache local e fallback automático para o embutido. Deve ser aguardado antes do bootstrap.
// main.ts
import { bootstrapApplication } from "@angular/platform-browser";
import { initializeAppLanguageAsync } from "mapa-frontend-i18n";
import { AppComponent } from "./app/app.component";
import { appConfig } from "./app/app.config";
import { environment } from "./environments/environment";
initializeAppLanguageAsync({ baseUrl: environment.i18nBaseUrl })
.catch(() => undefined) // nunca lança; em falha já usa o fallback embutido
.then(() => bootstrapApplication(AppComponent, appConfig));
environment.i18nBaseUrl aponta para a pasta que contém os JSON por idioma, por
ambiente (dev/staging/prod). Ex.: https://cdn.mapa.com.br/i18n.
Modo 3 — Host distribui aos MFEs
Em micro-frontends, o host busca as traduções uma única vez e as repassa para
cada MFE, evitando um request por MFE. Use quando cada MFE roda em um contexto de
@angular/localize próprio.
// no host (antes do bootstrap):
import { getStoredAppLanguage, loadRemoteTranslations } from "mapa-frontend-i18n";
const language = getStoredAppLanguage();
const remote = await loadRemoteTranslations(language, {
baseUrl: environment.i18nBaseUrl,
});
// disponibilize `language` + `remote` para os MFEs (window, store compartilhado, etc.)
// em cada MFE (antes do seu bootstrap):
import { initializeAppLanguageFromData } from "mapa-frontend-i18n";
initializeAppLanguageFromData(language, remote ?? {});
Se os MFEs compartilham o mesmo
@angular/localize(singleton via module federation), basta o host chamarinitializeAppLanguageAsyncuma vez.
Opções de carregamento remoto
RemoteTranslationOptions (usado por initializeAppLanguageAsync e
loadRemoteTranslations):
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
baseUrl |
string |
— (obrigatório) | URL base dos JSON, sem barra final. Busca ${baseUrl}/${idioma}.json. |
version |
string |
undefined |
Tag de versão (?v=) para cache-busting manual (requer CloudFront com query string na chave de cache). |
timeoutMs |
number |
5000 |
Aborta o request após esse tempo (o boot não trava se a AWS demorar). |
fetchImpl |
typeof fetch |
globalThis.fetch |
fetch customizado (testes/SSR). |
onError |
(error: unknown) => void |
undefined |
Notificação de erro de fetch/parse (não-fatal; o fallback é usado). |
Cache e revalidação
Estratégia stale-while-revalidate:
- Cache em
localStorage, chavei18n.cache.<idioma>(apenas o idioma ativo). - 1º acesso: aguarda o fetch; em falha, usa o embutido.
- Acessos seguintes: aplica o cache na hora (boot instantâneo) e revalida em segundo plano. Se o conteúdo mudou, o cache é atualizado e a nova versão entra no próximo reload.
O request é um GET simples (sem cabeçalhos customizados) com cache: "no-cache": a revalidação contra o CDN é feita pelo próprio browser via
ETag/Last-Modified, de forma transparente. Isso evita preflight CORS — o
servidor só precisa do cabeçalho Access-Control-Allow-Origin.
Cadeia de fallback em qualquer falha: cache → catálogo embutido (nunca a
chave crua).
Arquivos de tradução na AWS
Um arquivo JSON por idioma, contendo o mapa achatado já mesclado de todos os módulos:
${baseUrl}/pt-BR.json
${baseUrl}/en.json
${baseUrl}/es.json
Formato (mesmo shape consumido pelo loadTranslations()):
{
"common.cancel": "Cancelar",
"common.close": "Fechar",
"home.title": "Painel"
}
Gerar/atualizar os JSON
O script de export gera os arquivos a partir dos catálogos embutidos. Use para semear o conteúdo inicial na AWS e para manter o fallback embutido sincronizado a cada release.
npm run export:i18n
# escreve dist/i18n-remote/{pt-BR,en,es}.json
Processo de hotfix de termo (sem republicar)
- Edite o termo/acentuação diretamente no JSON do idioma na AWS (ou ajuste só as chaves alteradas — arquivos parciais são suportados).
- Faça upload para o S3.
- Invalide o cache do CloudFront ou confie no
ETag+Cache-Controlcurto (a revalidação aplica a mudança no próximo reload dos usuários).
Nenhuma publicação de versão da lib nem redeploy das aplicações é necessária.
Os catálogos
*.tsembutidos seguem como fallback (último-bom-conhecido). Para mantê-los alinhados com a AWS, rodenpm run export:i18nperiodicamente e publique uma release quando quiser atualizar o fallback.
Requisitos de infraestrutura (AWS)
- S3 (com ou sem CloudFront) servindo
/i18n/{idioma}.jsonpor ambiente. - CORS (obrigatório): basta
Access-Control-Allow-Originliberando as origens das aplicações no GET (não há preflight, pois o request é simples). Bucket público não dispensa CORS — sem ele o browser bloqueia a leitura viafetch. Ver config de exemplo emexamples/aws/s3-cors.json. ETag(o S3 já envia) para a revalidação condicional do browser funcionar.- Propagação de hotfix:
- S3 direto (sem CDN): a alteração é imediata no próximo reload.
- Via CloudFront: use
Cache-Controlcurto (ex.:max-age=300) ou invalide o caminho a cada hotfix — senão o edge serve a versão antiga até a TTL padrão (24h).
Outras APIs
import {
// Idioma
getStoredAppLanguage,
persistAppLanguage,
applyDocumentLanguage,
getAngularLocale,
getIntlLocale,
resolveAppLanguage,
APP_LANGUAGE_OPTIONS,
DEFAULT_APP_LANGUAGE,
// Textos de UI (validações, paginador, etc.)
getMapaUiTexts,
applyPaginatorIntl,
} from "mapa-frontend-i18n";
getMapaUiTexts(language) retorna textos de UI reutilizáveis (filtros, tabela,
validações). Alguns valores são funções (paginador e validações com
interpolação) e permanecem no código da lib — não são externalizados para JSON.
Idiomas suportados
| Código | Idioma | Padrão |
|---|---|---|
pt-BR |
Português | (fonte/fallback) |
es |
Español | |
en |
English |
O idioma escolhido é persistido em localStorage na chave menu.language.