Arquitetura
Visão geral da arquitetura
A base de código está organizada em quatro camadas. Use esta seção para o modelo mental; abra a árvore de origem quando precisar de detalhes em nível de arquivo.
Como uma execução de sync se encaixa
sync (e os comandos de tradução individuais) executam recursos habilitados em ordem:
| Etapa | Comando | O que ele faz |
|---|---|---|
| 1 | extract → translate-ui | Escanear fontes da UI → atualizar strings.json → preencher JSON de localidade plana (de.json, …) |
| 2 | translate-svg (opcional) | Traduzir texto SVG em config.svg |
| 3 | translate-docs | Traduzir páginas markdown, MDX, .astro; JSON de catálogo Docusaurus; _meta / dicionário .ts Nextra; catálogo de temas VitePress |
| 4 | translate-json (opcional) | Traduzir folhas JSON aninhadas em json[] |
Todo pipeline segue o mesmo loop principal: extrair segmentos → proteger sintaxe → agrupar → pesquisa de cache ou chamada LLM → gravar saída. Serviços compartilhados no meio — configuração, placeholders, cache, glossário, LlmClient — são descritos em Infraestrutura compartilhada.
Mapa de módulos
| Camada | Pasta | Função |
|---|---|---|
| Entrada | src/cli/ | Comandos CLI: init, extract, mark-html, translate-ui, translate-docs, translate-json, translate-svg, sync, status, dashboard, … |
| Pipelines | src/extractors/ | Extração de segmentos de JS/TS, marcadores HTML, markdown, JSON, SVG, .astro |
src/processors/ | Proteção de placeholder, agrupamento, validação, reescrita de link | |
| Compartilhado | src/core/ | Configuração, tipos, cache SQLite, prompts, caminhos de saída, utilitários de localidade |
src/api/ | LlmClient — cliente de chat agnóstico de provedor (Vercel AI SDK) com fallback de modelo | |
src/glossary/ | Carregamento de glossário e dicas de termos para prompts | |
src/utils/ | Logger, hashing, analisador de ignorados, tabelas de largura de exibição, carregador .env | |
| Tempo de execução do seu aplicativo | src/runtime/ | Ajudantes i18next e utilitários de exibição — exportados como 'ai-i18n-tools/runtime' (Ajudantes de tempo de execução) |
| UI da ferramenta (dogfooding) | src/i18n/, src/dashboard-app/, src/server/ | Localiza o próprio CLI e Painel de Tradução deste pacote — separado do conteúdo do seu projeto (Auto-localização) |
Tudo o que se destina ao uso programático é reexportado de src/index.ts (API Programática).
Resumos do pipeline
| Pipeline | Seção | Entrada → saída |
|---|---|---|
| Strings da UI | Internos das strings da UI | Arquivos de origem → strings.json → {locale}.json plano |
| Documentos | Internos dos documentos | Markdown / MDX / .astro / Docusaurus JSON → arquivos por localidade em docs[].outputDir |
| Pacotes JSON | Internos do JSON | JSON aninhado em json[] → arquivos JSON por localidade |
| SVG | Internos dos documentos — extratores | Arquivos SVG em config.svg → cópias SVG traduzidas |
Detalhes internos das strings da UI
| Etapa | Componente | Resultado |
|---|---|---|
| 1 | Arquivos de origem (JS/TS; .astro / .html opcionais) | Arquivos em disco |
| 2 | UIStringExtractor (i18next-scanner; .astro via ui-string-babel.ts) | Segmentos chaveados por hash MD5 |
| 3 | strings.json | Catálogo mestre: { hash: { source, translated, models?, locations? } } |
| 4 | LlmClient.translateUIBatch() | Array JSON de strings de origem → traduções (+ ID do modelo por lote) |
| 5 | de.json, pt-BR.json, … | Mapas planos: string de origem → tradução (sem metadados do modelo) |
UIStringExtractor
Usa i18next-scanner's Parser.parseFuncFromString para encontrar chamadas t("literal") e i18n.t("literal") em arquivos JS/TS. Para fontes .astro (quando listadas em ui.uiExtractor.extensions), ui-string-babel.ts analisa blocos de frontmatter e template {expression} com @babel/parser e aplica as mesmas regras funcNames. Os nomes de funções e extensões de arquivo são configuráveis via ui.uiExtractor (ui.reactExtractor é um alias suportado). extract também mescla entradas não-scanner no mesmo catálogo: o projeto package.json description quando includePackageDescription está habilitado (padrão), e cada englishName do catálogo master ui-languages embutido (construído a partir de sourceLocale + targetLocales) quando includeUiLanguageEnglishNames é true (strings já encontradas na fonte mantêm precedência; não lê languagesManifestPath). extract também regenera ui-languages.json em languagesManifestPath. Os hashes de segmento são MD5 dos 8 primeiros caracteres hex da string de origem trimada — esses se tornam as chaves em strings.json.
Para fontes .html / .htm (quando listadas em ui.uiExtractor.extensions), extract em vez disso roteia o arquivo através de html-i18n-marks.ts, que escaneia atributos de marcador data-i18n / data-i18n-title / data-i18n-placeholder (configurável via ui.uiExtractor.htmlI18nAttributes). Um marcador simples obtém seu texto de origem do próprio textContent / title / placeholder do elemento; um marcador com valor (data-i18n="Key") usa o valor. O mesmo módulo alimenta o comando mark-html, que insere os marcadores simples automaticamente. Arquivos HTML nunca chegam às etapas do Babel / i18next-scanner.
Sites Astro SSG simples podem pular o i18next: carregar {locale}.json plano no tempo de compilação e resolver t('English') por chave de texto-fonte (veja examples/astro-website/src/i18n/t.ts e UI strings — Astro website).
Aplicativos HTML simples seguem o mesmo modelo de catálogo com atributos de marcador em vez de chamadas t() — veja Marking HTML for translation.
strings.json
O catálogo mestre tem a seguinte estrutura:
{
"a1b2c3d4": {
"source": "The English string",
"translated": {
"de": "Der deutsche Text",
"pt-BR": "O texto em português"
},
"models": {
"de": "anthropic/claude-3.5-haiku",
"pt-BR": "openai/gpt-4o"
},
"locations": [{ "file": "src/app/page.tsx", "line": 51 }]
}
}models (opcional) — por locale, qual modelo produziu essa tradução após a última execução bem-sucedida de translate-ui para esse locale (ou user-edited se o texto foi salvo do Translation Dashboard). locations (opcional) — onde extract encontrou a string (scanner + linha de descrição do pacote; strings englishName embutidas-master podem omitir locations).
extract adiciona novas chaves e preserva os dados existentes translated / models para chaves ainda presentes na varredura (literais do scanner, descrição opcional, englishName embutida-master opcional). translate-ui preenche entradas translated faltantes, atualiza models para os locales que traduz, e escreve arquivos de locale planos.
ui-languages.json manifesto — array JSON de { code, label, englishName, direction } (BCP-47 code, UI label, referência englishName, "ltr" ou "rtl"). Use generate-ui-languages ou extract para construir um arquivo de projeto a partir de sourceLocale + targetLocales e do master data/ui-languages-complete.json embutido.
Arquivos de localidade planos
Cada localidade de destino recebe um arquivo JSON plano (de.json) mapeando string de origem → tradução (sem campo models):
{
"The English string": "Der deutsche Text",
"Save": "Speichern"
}O i18next carrega esses arquivos como pacotes de recursos e procura traduções pela string de origem (modelo de chave como padrão).
Solicitações de tradução de interface
buildUIPromptMessages constrói mensagens de sistema e do usuário que:
- Identifique os idiomas de origem e destino (pelo nome exibido em
localeDisplayNamesouui-languages.json). - Envie um array JSON de strings e solicite um array JSON de traduções em retorno.
- Inclua dicas de glossário quando disponíveis.
O LlmClient.translateUIBatch tenta cada modelo em ordem, recorrendo ao próximo em caso de erros de análise (parse) ou de rede. A CLI cria essa lista por localidade de destino a partir de localeModels, do opcional uiModels e de translationModels (consulte Provedores e modelos).
Detalhes internos dos documentos
| Etapa | Componente | Resultado |
|---|---|---|
| 1 | Arquivos Markdown / MDX / JSON / .astro (translate-docs) | Arquivos de origem |
| 2 | MarkdownExtractor / JsonExtractor / AstroTemplateExtractor | segments[] — segmentos tipados com hash + conteúdo |
| 3 | PlaceholderHandler | Texto protegido — HTML, advertências, âncoras, MDX, URLs, código inline, ênfase mascarada como tokens |
| 4 | splitTranslatableIntoBatches | batches[] — agrupado por contagem + limite de caracteres |
| 5 | Pesquisa TranslationCache | Cache hit → pular; miss → LlmClient.translateDocumentBatch |
| 6 | PlaceholderHandler.restoreAfterTranslation | Texto final — placeholders restaurados |
| 7 | resolveDocumentationOutputPath | Arquivo de saída — layout Docusaurus ou layout plano |
Extratores
Todos os extratores estendem BaseExtractor e implementam extract(content, filepath): Segment[].
MarkdownExtractor- divide o markdown em segmentos tipados:frontmatter,heading,paragraph,code,admonition. O frontmatter YAML é classificado como não traduzível (slug,ide outras chaves de roteamento permanecem estáveis). Blocosexport ...de nível superior (por exemplo, definições de componentes React) são classificados como segmentosothernão traduzíveis, juntamente com o tratamentoimport ...existente. Blocos de várias linhas que começam com uma tag JSX maiúscula (por exemplo, um bloco<Tabs>) são classificados como parágrafos traduzíveis. Segmentos não traduzíveis (blocos de código, HTML bruto) são preservados literalmente.AstroTemplateExtractor- análise e substituição para páginas de marketing.astro(translate-docsviatranslateAstroFileemdoc-translate.ts). Extrai nós de texto HTML visíveis para o usuário e atributos traduzíveis (alt,title,aria-label,placeholder), além de literais de string dentro de blocos de{expression}de modelo quando visíveis para o usuário. Ignora TypeScript de frontmatter,<script>,<style>, valores de atributo/chave protegidos e literais dentro det('…'). A remontagem ajusta as importações relativas quando os caminhos de saída são mais profundos (por exemplo,src/pages/de/index.astro). Veja Astro website pages.JsonExtractor- extrai valores de string de arquivos de rótulo JSON do Docusaurus (catálogos de UI do Docusaurus, não corpo MDX).SvgExtractor- extrai conteúdo<text>,<title>e<desc>de SVG (usado portranslate-svgpara arquivos emconfig.svg, não portranslate-docs).html-i18n-marks.ts- um scanner focado de tags HTML usado porextractpara fontes.html/.htme pelo comandomark-html.collectHtmlI18nStrings/collectHtmlI18nLocationsleem atributos de marcadordata-i18n*(marcador simples →textContent/title/placeholderdo elemento; marcador com valor → o valor), emarkHtmlContentinsere marcadores simples em texto folha / título / elementos de placeholder (idempotente, respeitadata-i18n-ignore, pula elementos parecidos com código e de conteúdo misto). O helper compartilhadonormalizeI18nTextmantém as chaves de tempo de compilação idênticas ao runtime do navegador.
Sites híbridos Astro (UI + HTML de página)
Aplicativos Astro simples geralmente habilitam ambas as strings da UI e os documentos em uma única configuração (referência: examples/astro-website/):
| Camada | Mecanismo | Saída |
|---|---|---|
| HTML do modelo | AstroTemplateExtractor + translate-docs | .astro por localidade em docs[].outputDir |
Frontmatter / t('…') | ui-string-babel.ts + extract + translate-ui | public/locales/{locale}.json plano (fonte em inglês como chave) |
O comando sync executa as etapas habilitadas em ordem: extrair e depois traduzir-ui (quando features.translateUIStrings) → traduzir-svg opcional → traduzir-docs → traduzir-json opcional (a menos que ignorado com --no-ui, --no-svg, --no-docs ou --no-json). O modelo de inicialização ui-astro-website gera apenas strings da UI; adicione docs[] e features.translateDocs para HTML da página.
Inserção de âncoras de título (write-heading-ids CLI)
O comando write-heading-ids é um pré-processador local, sem uso de LLM, para arquivos markdown de documentação. Implementação: src/cli/write-heading-ids.ts coordena a descoberta de arquivos; src/markdown/write-heading-ids-core.ts analisa as linhas e insere âncoras.
Ele requer uma configuração válida com pelo menos um bloco docs[]. Para cada bloco, ele coleta arquivos .md / .mdx em contentPaths, aplica as regras .translate-ignore do projeto (mesma ideia da tradução de documentos) e, opcionalmente, restringe a uma subárvore com --path / --file. Cada arquivo é transformado com applyHeadingAnchorsToMarkdown: para cada cabeçalho ATX simples (# … a ###### …) fora de blocos de código cercados, uma linha HTML vazia <a id="slug"></a> é inserida na linha acima quando ausente ou desatualizada. Os algoritmos de slug correspondem a ecossistemas comuns — github (padrão), bitbucket, gitlab, pymdown (sinalizadores opcionais de normalização Unicode / codificação de porcentagem), azure-devops — para que os IDs de âncora permaneçam consistentes com as ferramentas existentes (doctoc, PyMdown, etc.). --dry-run relata edições potenciais sem escrever.
Este comando não é executado dentro do translate-docs ou do sync; execute-o explicitamente quando desejar IDs de fragmento estáveis nos arquivos de origem antes da tradução ou publicação.
Proteção de espaços reservados
Antes da tradução, a sintaxe sensível é substituída por tokens opacos para evitar corrupção pelo LLM, aplicado nesta ordem (a restauração é inversa):
- Tags e comentários HTML (
<strong>,<!-- ... -->, etc.) - tags HTML em minúsculas de uma lista de permissões conhecida são substituídas por tokens. Tags JSX capitalizadas (<Highlight>,<Tabs>,</Tab>) são tratadas separadamente pela camada MDX (etapa 4). - Marcadores de advertência (
:::note,:::) - apenas o prefixo da diretiva na linha de abertura é substituído por; qualquer título na mesma linha é deixado para o modelo traduzir. Restaurado com o texto original exato. - Âncoras de documento (HTML
<a id="…">, cabeçalho Docusaurus{#…}) - preservadas literalmente. - Construções apenas MDX (
src/processors/mdx-placeholders.ts):- Comentários MDX (
{/* … */}, incluindo o formato de heading-id do Docusaurus{/* #my-id */}) substituídos por. - Tags JSX com iniciais maiúsculas (
<Highlight>,<Tabs>,<TabItem>,<TOCInline />,</Highlight>) - preservadas comocom atributos de string traduzíveis (label,tooltip,aria-label) reescritos paradentro da tag, a menos que o nome do atributo apareça emdocs[].protectAttributes;label:dentro de literais de objeto<Tabs values={[ { label: '…' } ]}>(ignoráveis viadocs[].protectKeys) e<TabItem value="…">(quando não existe o atributolabel, ignorando valores em minúsculas semelhantes a slugs) também são extraídos. Anexados ao segmento como linhas||JXA_N: …||, mesclados de volta porrestoreMdx. - Expressões de chaves MDX (
{frontMatter.title},style={{…}}) - correspondência sensível à profundidade, substituídas por.
- Comentários MDX (
- URLs Markdown (
](url),src="…") - restauradas de um mapa após a tradução. - Trechos de código embutidos (
`code`) e código embutido em negrito (**code**) - preservados. - Ênfase em markdown (opcional, ativado automaticamente para localidades CJK/RTL) - delimitadores de ênfase mascarados.
A proteção de atributos/chaves compartilhados para modelos Astro e MDX JSX é implementada em src/processors/expression-attribute-protection.ts e controlada por bloco por docs[].protectAttributes e docs[].protectKeys (consulte protectAttributes / protectKeys).
Cache (TranslationCache)
O banco de dados SQLite (via node:sqlite) armazena linhas indexadas por (source_hash, locale) com translated_text, model, filepath, last_hit_at e campos relacionados. O hash corresponde aos primeiros 16 caracteres hexadecimais SHA-256 do conteúdo normalizado (espaços em branco reduzidos).
A cada execução, os segmentos são pesquisados por hash × localidade. Apenas os erros de cache vão para o LLM. Após a tradução, last_hit_at é redefinido para as linhas de segmento no escopo de tradução atual que não foram atingidas. Os acertos de cache bem-sucedidos durante a tradução de documentos limpam as linhas translation_failures obsoletas para esse segmento. cleanup executa sync --force-update primeiro, depois remove as linhas de segmento obsoletas (last_hit_at nulo / caminho de arquivo vazio), remove as chaves file_tracking quando o caminho de origem resolvido está ausente no disco (doc-block:…, json-block:…, svg-files:…, etc.), remove as linhas de tradução cujo caminho de arquivo de metadados aponta para um arquivo ausente, remove as linhas translation_failures órfãs, remove as linhas markdown_source_issues órfãs cujo caminho de origem resolvido está ausente no disco e descarta as linhas de cache para localidades ausentes da configuração (sourceLocale, raiz targetLocales e qualquer docs[] / json[] targetLocales por bloco; apenas SQLite — use purge-locale para excluir arquivos gerados); ele não faz backup de cache.db a menos que --backup <path> seja passado, o que grava um backup nesse caminho primeiro.
O comando translate-docs também usa rastreamento de arquivos para que fontes inalteradas com saídas existentes e atualizadas possam pular o trabalho completamente. --force-update executa novamente o processamento de arquivos enquanto ainda usa o cache de segmento; --force limpa o rastreamento de arquivos e ignora as leituras do cache de segmento para tradução de API. Quando cada modelo configurado falha na validação AST em um segmento markdown, translate-docs pode dividir progressivamente o segmento e tentar novamente partes menores (docs[].segmentSplitting.qualityRetrySplit, padrão ativado). Consulte Documentos — comportamento do cache e sinalizadores para a tabela completa de sinalizadores.
Formato de prompt em lote: translate-docs --prompt-format seleciona XML (<seg> / <t>) ou formatos de array/objeto JSON apenas para LlmClient.translateDocumentBatch; extração, placeholders e validação permanecem inalterados. Consulte Formato de prompt em lote.
Resolução de caminho de saída
resolveDocumentationOutputPath(config, cwd, locale, relPath, kind) mapeia um caminho relativo à fonte para o caminho de saída:
- Estilo
nested(padrão):{outputDir}/{locale}/{relPath}para markdown. - Estilo
doc-system: emdocsRoot, as saídas usam{outputDir}/{locale}/[localeSubpath/]{relativeToDocsRoot}; caminhos fora dedocsRootvoltam para o layout aninhado. Aliases:docusaurus(padrãolocaleSubpath= caminho do plugin Docusaurus),astro-starlight(padrão vaziolocaleSubpath),vitepress(o mesmo quedoc-systemcomlocaleSubpathvazio; preserva o uso de maiúsculas e minúsculas da pasta BCP-47). - Estilo
flat:{outputDir}/{stem}.{locale}{extension}. QuandoflatPreserveRelativeDirétrue, os subdiretórios de origem são mantidos emoutputDir. - Personalizado
pathTemplate: qualquer layout markdown usando{outputDir},{locale},{LOCALE},{relPath},{stem},{basename},{extension},{docsRoot},{relativeToDocsRoot}. - Personalizado
jsonPathTemplate: layout personalizado separado para arquivos de rótulos JSON, usando os mesmos espaços reservados. linkRewriteDocsRootajuda o reescritor de links planos a calcular os prefixos corretos quando a saída traduzida está localizada em outro lugar além da raiz padrão do projeto.
Reescrita plana de links
Quando docsOutput.style === "flat", os arquivos markdown traduzidos são colocados ao lado da fonte com sufixos de localidade. Links relativos entre páginas são reescritos para que [Guide](./guide.md) em readme.de.md aponte para guide.de.md. Controlado por rewriteRelativeLinks (ativado automaticamente para estilo plano sem um pathTemplate personalizado). A mesma passagem adiciona um prefixo de profundidade por arquivo a URLs de ativos não-markdown antes que postProcessing.regexAdjustments seja executado — veja Flat link rewriter.
Detalhes internos do JSON
| Etapa | Componente | Resultado |
|---|---|---|
| 1 | json[].contentPaths | Arquivos resolvidos (arquivo, diretório ou glob) |
| 2 | NestedJsonExtractor | Folhas de string selecionadas por keyPolicy (caminhos de ponto + minimatch) |
| 3 | PlaceholderHandler + lote + TranslationCache | Cache hit → pular; miss → LlmClient.translateDocumentBatch (SQLite compartilhado) |
| 4 | NestedJsonExtractor.reassemble | Arquivo de saída via expandJsonBlockOutputPath(outputPathTemplate) |
NestedJsonExtractor(src/extractors/nested-json-extractor.ts) percorre JSON aninhado arbitrário e emite um segmento por folha de string traduzível.keyPolicy.mode(allowlist,denylistouboth) filtra caminhos com minimatch na notação de ponto (nomes simples comoslugcorrespondem ao segmento de chave final).- O rastreamento de arquivos de cache usa
json-block:{blockIndex}:{projectRelPath}emfile_tracking(o mesmocacheDirque documentos e SVG). - Não para catálogos
write-translationsdo Docusaurus (formato{ message, description }) — estes usam Documentos (docs[].docusaurusCatalogDir+JsonExtractordentro detranslate-docs). - Não para strings da UI
t()— strings da UI (strings.json+ pacotes planos). - CLI:
translate-json; orquestração emsrc/cli/translate-json-run.ts. Modelo init:ui-json-bundles.
Infraestrutura compartilhada
LlmClient
Cliente de chat independente de provedor construído sobre o Vercel AI SDK (ai + @ai-sdk/openai-compatible). Ele resolve o provedor ativo a partir de provider / providers, constrói um cliente compatível com OpenAI (createOpenAICompatible) para o baseUrl + chave de API desse provedor e roteia todas as chamadas através de generateText. OpenRouterClient é mantido como um alias obsoleto. Comportamentos chave:
- Fallback de modelo: tenta cada modelo na lista resolvida em ordem; retorna em caso de falha de solicitação ou análise. Cada localidade de destino obtém sua própria cadeia resolvida:
localeModels(locale)primeiro quando configurado, depoisuiModels(somente pipelines de UI), depoistranslationModels. A tradução de Documentos, JSON e SVG cria um cliente por localidade com a cadeia não-UI. O comandobench-modelsem vez disso, constrói um único cliente de modelo por ID configurado (união detranslationModels,uiModelselocaleModels;translationModels: [id], sem fallback) para que possa cronometrar e precificar cada modelo independentemente. - Tempo limite da solicitação: o
requestTimeoutMsdo provedor ativo (padrão 30 segundos) anula cada solicitação viaAbortSignal.timeout. O mesmo valor se aplica aGET /modelsquando a CLI carrega a lista de modelos de um provedor paracheck-models(qualquer provedor). O filtro de pré-voo opcional que descarta IDs de modelo desconhecidos é executado apenas quando o provedor ativo é o OpenRouter. - Extras do OpenRouter (somente quando
openrouterestá ativo): roteamento de throughput via campo de solicitaçãoprovider, cabeçalhosHTTP-Referer/X-Titlee custo exato em USD lido deusage.cost. O uso de token é relatado para cada provedor; o custo exato somente quando o provedor o retorna. - Log de tráfego de depuração: se
debugTrafficFilePathestiver definido, anexa JSON de solicitação e resposta a um arquivo.
Carregamento de configuração
Pipeline loadI18nConfigFromFile(configPath, cwd):
- Leia e analise
ai-i18n-tools.config.json(JSON). mergeWithDefaults- mescla profunda comdefaultI18nConfigPartial, e mescla quaisquer entradasdocs[].sourceFilesemcontentPaths.expandTargetLocalesFileReferenceInRawInput- coercetargetLocalespara um array e rejeite entradas semelhantes a caminhos (devem ser códigos BCP-47, não um caminho paraui-languages.json);languagesManifestPathé padrão para{ui.flatOutputDir}/ui-languages.jsondurantemergeWithDefaults.expandDocumentationTargetLocalesInRawInput- mesmo para cada entradadocs[].targetLocales.expandJsonTargetLocalesInRawInput- o mesmo para cada entradajson[].targetLocales.parseI18nConfig- validação Zod +validateI18nBusinessRules.applyProviderOverrideToRawInput- quando-P/--provideré passado na CLI.applyEnvOverrides- aplicaOPENROUTER_BASE_URL,OLLAMA_BASE_URL,I18N_SOURCE_LOCALEeI18N_TARGET_LOCALESquando definidos (as chaves de API são resolvidas separadamente por provedor dentro deLlmClient).augmentConfigWithUiLanguagesMaster- anexa nomes de exibição de manifesto do catálogo mestre empacotado.assertEffectiveLocalesInUiLanguagesMaster- valida códigos de localidade em relação ao catálogo mestre quando aplicável.
init escreve configurações iniciais de initConfigTemplates: ui-markdown (UI + markdown de aplicativo opcional), ui-docusaurus, ui-starlight, ui-vitepress (documentos VitePress + vitepressThemeCatalog), ui-nextra (documentos Nextra + nextraDictionaryPath), ui-astro-website (UI Astro simples; adicione docs[] para tradução de página .astro), ui-json-bundles (somente json[] JSON). Consulte Início rápido — Inicializar.
Registrador de eventos (Logger)
Logger suporta níveis debug, info, warn, error com saída de cores ANSI. O modo detalhado (-v) habilita debug. Quando logFilePath está definido, as linhas de log também são gravadas nesse arquivo.
Auto-localização (interface do usuário da ferramenta)
A ferramenta localiza sua própria interface — ajuda da CLI, mensagens de log/resumo/erro de alto tráfego e o Painel de Tradução — separadamente do conteúdo que ela traduz para você.
- Resolução de localidade (
resolveUiLocaleemsrc/core/ui-locale.ts): escolhe a localidade da UI de-L/--ui-lang>AI_I18N_LANG> configuraçãouiLanguage> localidade do SO host (Intl.DateTimeFormat().resolvedOptions().locale). O candidato é normalizado e comparado com o conjunto de pacotes enviados exatamente ou pela variação mais próxima (por exemplo,pt-PT→pt-BR,en-US→en-GB), retornando à localidade de origem (en-GB). A CLI resolve uma vez antes que a ajuda seja construída (verificação de argv pré-análise) e novamente após o carregamento da configuração para queuiLanguagese aplique (a flag e a variável de ambiente ainda prevalecem). - Tempo de execução (
src/i18n/index.ts): umt(source, vars)mínimo com interpolação, indexado pela string de origem em inglês em relação a pacotes planos por localidade emsrc/i18n/locales/<code>.json(copiado paradist/i18n/localesna compilação). Chaves ou pacotes ausentes retornam o texto de origem. Este é o mesmo modelo de chave como padrão que as strings da UI — não há pesquisa de hash. - Painel: o servidor expõe
GET /api/ui-i18nretornando{ locale, dir, bundle }para a localidade da UI resolvida; o frontend define<html lang>/dire localiza a marcação estática via atributosdata-i18n*. - Dogfooding: os pacotes são produzidos executando o próprio pipeline de extração →
translate-uido pacote contraai-i18n-self.config.json(pnpm i18n:self). As chaves do catálogo vêm de chamadast()emsrc/cli/esrc/i18n/, além dos marcadoresdata-i18n*do painel emsrc/dashboard-app/index.html.
Pontos de extensão
Nomes personalizados de funções (extração da interface)
Adicione nomes não padrão de funções de tradução via configuração:
{
"ui": {
"uiExtractor": {
"funcNames": ["t", "i18n.t", "translate", "i18n.translate"],
"extensions": [".js", ".jsx", ".ts", ".tsx", ".astro", ".html"],
"htmlI18nAttributes": ["data-i18n", "data-i18n-title", "data-i18n-placeholder"]
}
}
}(ui.reactExtractor é um alias totalmente suportado para ui.uiExtractor.)
Adicione .html / .htm a extensions para escanear atributos de marcador HTML durante extract. ui.uiExtractor.htmlI18nAttributes é opcional e usa o padrão ["data-i18n", "data-i18n-title", "data-i18n-placeholder"]; data-i18n mapeia para o textContent do elemento e data-i18n-<attr> mapeia para o valor do atributo (por exemplo, data-i18n-aria-label).
Extratores personalizados
Implemente ContentExtractor a partir do pacote:
import { BaseExtractor, type Segment } from 'ai-i18n-tools';
class MyExtractor extends BaseExtractor {
readonly name = 'my-format';
canHandle(filepath: string) { return filepath.endsWith('.myext'); }
extract(content: string, filepath: string): Segment[] { /* … */ }
reassemble(segments: Segment[], translations: Map<string, string>): string { /* … */ }
}Registre extratores personalizados estendendo as classes de extrator públicas exportadas de 'ai-i18n-tools' (por exemplo, subclasse MarkdownExtractor). A CLI conecta extratores internos internamente; não há importação profunda suportada de doc-translate.ts.
Caminhos de saída personalizados
Use docsOutput.pathTemplate para qualquer estrutura de arquivos:
{
"docs": [
{
"docsOutput": {
"pathTemplate": "{outputDir}/{locale}/{relativeToDocsRoot}"
}
}
]
}Árvore de origem
Layout completo de src/ (referência em nível de arquivo)
src/
├── index.ts Public API re-exports
│
├── cli/
│ ├── index.ts CLI entry point (commander)
│ ├── extract-strings.ts `extract` command implementation
│ ├── mark-html.ts `mark-html` command (insert bare `data-i18n*` markers into HTML)
│ ├── translate-ui-strings.ts `translate-ui` command implementation
│ ├── doc-translate.ts `translate-docs` command (documentation files only)
│ ├── translate-json-run.ts `translate-json` command (`json[]` nested locale bundles)
│ ├── translate-svg.ts `translate-svg` command (SVG files from `config.svg`)
│ ├── write-heading-ids.ts `write-heading-ids` command (markdown heading anchors)
│ ├── bench-models.ts `bench-models` command (per-model translate latency/token/cost benchmark)
│ ├── helpers.ts Shared CLI utilities
│ └── file-utils.ts File collection helpers
│
├── markdown/
│ └── write-heading-ids-core.ts Slug styles + `<a id="…">` insertion for `write-heading-ids`
│
├── core/
│ ├── types.ts Zod schemas + TypeScript types for all config shapes
│ ├── config.ts Config loading, merging, validation, init templates
│ ├── cache.ts SQLite translation cache (node:sqlite)
│ ├── prompt-builder.ts LLM prompt construction for docs and UI strings
│ ├── output-paths.ts Docusaurus / flat output path resolution
│ ├── ui-languages.ts ui-languages.json loading and locale resolution
│ ├── ui-locale.ts Resolve the tool's own UI locale (flag/env/config/OS → shipped bundle)
│ ├── locale-utils.ts BCP-47 normalisation, locale list parsing, script/Han-variant validation
│ └── errors.ts Typed error classes
│
├── extractors/
│ ├── base-extractor.ts Abstract base class for all extractors
│ ├── ui-string-extractor.ts JS/TS source scanner (i18next-scanner + Babel for `.astro`)
│ ├── ui-string-babel.ts Babel-based `t()` discovery in `.astro` frontmatter and `{expression}` blocks
│ ├── ui-string-locations.ts Source locations for extracted UI strings
│ ├── html-i18n-marks.ts HTML `data-i18n*` marker scanner + `mark-html` annotator
│ ├── classify-segment.ts Heuristic segment type classification
│ ├── markdown-extractor.ts Markdown / MDX segment extraction
│ ├── markdown-segment-split.ts Optional segment splitting for long markdown blocks
│ ├── frontmatter-fields.ts Selective YAML front matter field translation
│ ├── astro-template-extractor.ts `.astro` parse-and-replace (HTML + template expressions; used by `translate-docs`)
│ ├── json-extractor.ts Docusaurus catalog JSON extraction (`translate-docs`)
│ ├── nested-json-extractor.ts Arbitrary nested JSON leaves (`translate-json`, `json[]`)
│ └── svg-extractor.ts SVG text extraction
│
├── processors/
│ ├── placeholder-handler.ts Chain: HTML → admonitions → anchors → MDX → URLs → emphasis
│ ├── expression-attribute-protection.ts Shared protected attribute/key lists (Astro + MDX JSX)
│ ├── url-placeholders.ts Markdown URL protection/restore
│ ├── admonition-placeholders.ts Docusaurus admonition protection/restore
│ ├── anchor-placeholders.ts HTML anchor / heading ID protection/restore
│ ├── html-tag-placeholders.ts Lowercase HTML tag / comment protection ({{HTM_N}})
│ ├── mdx-placeholders.ts MDX comments, JSX tags, brace expressions, JSX attribute extraction
│ ├── batch-processor.ts Segment → batch grouping (count + char limits)
│ ├── validator.ts Post-translation structural checks
│ └── flat-link-rewrite.ts Relative link rewriting for flat output
│
├── api/
│ ├── llm-client.ts LlmClient: provider-agnostic chat client (AI SDK) with model fallback chain
│ └── provider-models-catalog.ts Fetch/parse any provider's OpenAI-compatible GET /models catalog
│
├── glossary/
│ ├── glossary.ts Glossary loading (CSV + auto-build from strings.json)
│ └── matcher.ts Term hint extraction for prompts
│
├── runtime/
│ ├── index.ts Runtime re-exports
│ ├── template.ts interpolateTemplate, flipUiArrowsForRtl
│ ├── ui-language-display.ts getUILanguageLabel, getUILanguageLabelNative
│ └── i18next-helpers.ts RTL detection, i18next setup factories
│
├── i18n/ Self-localization runtime for the tool's own UI
│ ├── index.ts t(source, vars) + bundle/manifest loaders (keyed by English source string)
│ └── locales/ Shipped UI bundles (de.json, es.json, …; generated by `pnpm i18n:self`)
│
├── dashboard-app/
│ ├── index.html Translation Dashboard static UI (HTML/CSS/JS)
│ ├── app.js
│ └── styles.css
│
├── server/
│ └── translation-dashboard.ts Express app for Translation Dashboard (cache / strings.json / glossary)
│
└── utils/
├── logger.ts Leveled logger with ANSI support
├── hash.ts Segment hash (SHA-256 first 16 hex)
├── table.ts Display-width aware table rendering (CJK/emoji column alignment)
├── load-dotenv.ts Auto-load `.env` from the cwd at CLI startup (never overrides existing env)
└── ignore-parser.ts .translate-ignore file parser