Skip to content

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:

EtapaComandoO que ele faz
1extract → translate-uiEscanear fontes da UI → atualizar strings.json → preencher JSON de localidade plana (de.json, …)
2translate-svg (opcional)Traduzir texto SVG em config.svg
3translate-docsTraduzir páginas markdown, MDX, .astro; JSON de catálogo Docusaurus; _meta / dicionário .ts Nextra; catálogo de temas VitePress
4translate-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 ​

CamadaPastaFunção
Entradasrc/cli/Comandos CLI: init, extract, mark-html, translate-ui, translate-docs, translate-json, translate-svg, sync, status, dashboard, …
Pipelinessrc/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
Compartilhadosrc/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, dicas de termos e arquivos opcionais de contexto de projeto para prompts
src/utils/Logger, hashing, analisador de ignorados, tabelas de largura de exibição, carregador .env
Tempo de execução do seu aplicativosrc/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 ​

PipelineSeçãoEntrada → saída
Strings da UIInternos das strings da UIArquivos de origem → strings.json → {locale}.json plano
DocumentosInternos dos documentosMarkdown / MDX / .astro / Docusaurus JSON → arquivos por localidade em docs[].outputDir
Pacotes JSONInternos do JSONJSON aninhado em json[] → arquivos JSON por localidade
SVGInternos dos documentos — extratoresArquivos SVG em config.svg → cópias SVG traduzidas

Detalhes internos das strings da UI ​

EtapaComponenteResultado
1Arquivos de origem (JS/TS; .astro / .html opcionais)Arquivos em disco
2UIStringExtractor (i18next-scanner; .astro via ui-string-babel.ts)Segmentos chaveados por hash MD5
3strings.jsonCatálogo mestre: { hash: { source, translated, models?, locations? } }
4LlmClient.translateUIBatch()Array JSON de strings de origem → traduções (+ ID do modelo por lote)
5de.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:

json
{
  "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):

json
{
  "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 de destino (pelo nome de exibição de localeDisplayNames ou ui-languages.json).
  • Preponha uma diretiva de script quando o local de destino tiver um sistema de escrita esperado (script BCP-47 explícito ou um padrão de idioma como hi → Devanagari, ar → Árabe, ja → Kana/Kanji japonês).
  • Envie um array JSON de strings e solicite um array JSON de traduções em troca.
  • Inclua dicas de glossário quando disponíveis.

LlmClient.translateUIBatch tenta cada modelo em ordem, recorrendo a erros de análise, rede ou script incorreto (incluindo fallback romanizado/latino para locais de script nativo). A CLI constrói essa lista por local de destino a partir de localeModels, uiModels opcional e translationModels (consulte Provedores e modelos).


Detalhes internos dos documentos ​

EtapaComponenteResultado
1Arquivos Markdown / MDX / JSON / .astro (translate-docs)Arquivos de origem
2MarkdownExtractor / JsonExtractor / AstroTemplateExtractorsegments[] — segmentos tipados com hash + conteúdo
3PlaceholderHandlerTexto protegido — HTML, advertências, âncoras, MDX, URLs, código inline, ênfase mascarada como tokens
4splitTranslatableIntoBatchesbatches[] — agrupado por contagem + limite de caracteres
5Pesquisa TranslationCacheCache hit → pular; miss → LlmClient.translateDocumentBatch
6PlaceholderHandler.restoreAfterTranslationTexto final — placeholders restaurados
7resolveDocumentationOutputPathArquivo 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, id e outras chaves de roteamento permanecem estáveis). Blocos export ... de nível superior (por exemplo, definições de componentes React) são classificados como segmentos other não traduzíveis, juntamente com o tratamento import ... 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-docs via translateAstroFile em doc-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 de t('…'). 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 por translate-svg para arquivos em config.svg, não por translate-docs).
  • html-i18n-marks.ts - um scanner focado de tags HTML usado por extract para fontes .html / .htm e pelo comando mark-html. collectHtmlI18nStrings / collectHtmlI18nLocations leem atributos de marcador data-i18n* (marcador simples → textContent / title / placeholder do elemento; marcador com valor → o valor), e markHtmlContent insere marcadores simples em texto folha / título / elementos de placeholder (idempotente, respeita data-i18n-ignore, pula elementos parecidos com código e de conteúdo misto). O helper compartilhado normalizeI18nText manté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/):

CamadaMecanismoSaída
HTML do modeloAstroTemplateExtractor + translate-docs.astro por localidade em docs[].outputDir
Frontmatter / t('…')ui-string-babel.ts + extract + translate-uipublic/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.

É necessário um arquivo de configuração válido 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 dos blocos de código cercados, os IDs de cabeçalho existentes de qualquer forma são substituídos pelo estilo selecionado. Os estilos HTML escrevem <a id="slug"></a> na linha acima de um cabeçalho sem sufixo; --slug-style mdx-comment escreve {/* #slug */} na linha do cabeçalho (e remove uma âncora HTML anterior). Os slugs sempre vêm do texto do cabeçalho atual. --remove remove âncoras HTML, sufixos clássicos {#id} e IDs de comentários MDX sem escrever novos. Os algoritmos de slug correspondem a ecossistemas comuns — github (padrão), bitbucket, gitlab, pymdown (sinalizadores opcionais de normalização Unicode / codificação percentual), azure-devops, mais mdx-comment (slug do github + saída de comentário MDX) — para que os IDs de âncora permaneçam consistentes com as ferramentas existentes (doctoc, PyMdown, Docusaurus, etc.). --dry-run relata edições potenciais sem escrever.

Após a passagem da fonte, o mesmo comando reposiciona esses IDs em inglês no markdown traduzido existente de cada localidade (resolveTranslatedOutputPath). Títulos traduzidos nunca são re-slugged; um {#id} / {/* #id */} no meio do título é movido de volta para o sufixo (ou âncora HTML) que o estilo selecionado espera. Arquivos de localidade ausentes são ignorados.

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):

  1. Sufixos de ID de cabeçalho ({#id} clássico / {/* #id */} MDX no final de um cabeçalho ATX) — removidos completamente da linha e não enviados para o modelo. Após a restauração, eles são fixados de volta ao final do cabeçalho correspondente para que o Docusaurus ainda veja um ID válido. Comentários no meio do cabeçalho permanecem no texto e são tratados pelas camadas MDX / {#…} posteriores.
  2. Tags e comentários HTML (<strong>, <!-- ... -->, etc.) - tags HTML 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 5).
  3. 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.
  4. Âncoras de documento (HTML <a id="…">, {#…} Docusaurus remanescente no meio do cabeçalho) - preservadas literalmente.
  5. Constructos apenas MDX (src/processors/mdx-placeholders.ts):
    • Comentários MDX ({/* … */}, incluindo um {/* #my-id */} no meio do cabeçalho que não era um sufixo de fim de linha) substituídos por .
    • Tags JSX capitalizadas (<Highlight>, <Tabs>, <TabItem>, <TOCInline />, </Highlight>) - preservadas como com atributos de string traduzíveis (label, tooltip, aria-label) reescritos para dentro da tag, a menos que o nome do atributo apareça em docs[].protectAttributes; label: dentro de literais de objeto <Tabs values={[ { label: '…' } ]}> (ignoráveis via docs[].protectKeys) e <TabItem value="…"> (quando nenhum atributo label existe, ignorando valores slug-like minúsculos) também são extraídos. Anexados ao segmento como linhas ||JXA_N: …||, mesclados de volta por restoreMdx.
    • Expressões de chave MDX ({frontMatter.title}, style={{…}}) - correspondência sensível à profundidade, substituída por .
  6. URLs Markdown (](url), src="…") - restauradas de um mapa após a tradução.
  7. Spans de código inline (`code`) e código inline envolto em negrito (**code**) - preservados.
  8. Ênfase Markdown (opcional, ativada automaticamente para localidades CJK/RTL) - delimitadores de ênfase mascarados.

Após o retorno do modelo, o translate-docs restaura os mapas e valida o segmento: o mesmo multiconjunto de tokens de chaves duplas deve estar presente, os tokens estruturais ({{HTM_N}}, marcadores de advertência) devem manter sua subsequência ordenada (tokens de conteúdo como {{ILC_N}} / {{URL_N}} / {{SE}} podem se mover com a ordem das palavras), os tipos de tags HTML restauradas devem corresponder à fonte desprotegida, e qualquer identificador de chaves duplas restante já deve ter existido na fonte (portanto, tokens inventados falham). O prompt do documento também pede aos modelos para copiar cada token uma vez, manter a ordem dos tokens estruturais e não inventar novos wrappers de chaves duplas; as verificações mecânicas permanecem autoritárias.

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.

As chamadas de modelo faturadas (traduções aceitas e retentativas descartadas) são armazenadas em api_calls. Após um comando que registrou chamadas, as linhas de detalhes com mais de sete dias corridos em UTC são consolidadas nas api_totals mensais. usage e a visualização Uso e custos do painel combinam ambas as tabelas. Consulte Uso e custos.

As notas do glossário Context e as glossary.contextFiles são identificadas por fingerprint (prompt_context_hash) e injetadas na UI, na documentação, em JSON, SVG e nos prompts de revisão. Alterar essa orientação invalida os segmentos em cache correspondentes e as linhas de rastreamento de arquivos na próxima execução. As linhas de cache de user-edited do painel são mantidas. Alterar apenas uma tradução preferida do glossário mantém o cache existente intacto até --force / --force-update.

O comando translate-docs também usa o rastreamento de arquivos para que as fontes inalteradas com saídas existentes e atualizadas possam ignorar o trabalho completamente. --check-cache reabre os locais com um sistema de escrita esperado para que os segmentos armazenados em cache sejam revalidados; --force-update reexecuta o processamento de arquivos para cada local, ainda usando o cache de segmento; --force limpa o rastreamento de arquivos e ignora as leituras do cache de segmento para a tradução da API. Quando todos os modelos configurados falham na validação AST em um segmento de markdown, translate-docs pode dividir progressivamente o segmento e tentar novamente partes menores (docs[].segmentSplitting.qualityRetrySplit, padrão ativado). Consulte Documentos — comportamento e sinalizadores de cache 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: em docsRoot, as saídas usam {outputDir}/{locale}/[localeSubpath/]{relativeToDocsRoot}; caminhos fora de docsRoot voltam para o layout aninhado. Aliases: docusaurus (padrão localeSubpath = caminho do plugin Docusaurus), astro-starlight (padrão vazio localeSubpath), vitepress (o mesmo que doc-system com localeSubpath vazio; preserva o uso de maiúsculas e minúsculas da pasta BCP-47).
  • Estilo flat: {outputDir}/{stem}.{locale}{extension}. Quando flatPreserveRelativeDir é true, os subdiretórios de origem são mantidos em outputDir.
  • 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.
  • linkRewriteDocsRoot ajuda 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.

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 ​

EtapaComponenteResultado
1json[].contentPathsArquivos resolvidos (arquivo, diretório ou glob)
2NestedJsonExtractorFolhas de string selecionadas por keyPolicy (caminhos de ponto + minimatch)
3PlaceholderHandler + lote + TranslationCacheCache hit → pular; miss → LlmClient.translateDocumentBatch (SQLite compartilhado)
4NestedJsonExtractor.reassembleArquivo 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, denylist ou both) filtra caminhos com minimatch na notação de ponto (nomes simples como slug correspondem ao segmento de chave final).
  • O rastreamento de arquivos de cache usa json-block:{blockIndex}:{projectRelPath} em file_tracking (o mesmo cacheDir que documentos e SVG).
  • Não para catálogos write-translations do Docusaurus (formato { message, description }) — estes usam Documentos (docs[].docusaurusCatalogDir + JsonExtractor dentro de translate-docs).
  • Não para strings da UI t() — strings da UI (strings.json + pacotes planos).
  • CLI: translate-json; orquestração em src/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 do modelo: tenta cada modelo na lista resolvida em ordem; faz fallback em caso de falhas de solicitação ou análise. Cada localidade de destino obtém sua própria cadeia resolvida: localeModels(locale) primeiro quando configurado, depois uiModels (apenas pipelines de UI), depois translationModels. A tradução de Documentos, JSON e SVG cria um cliente por localidade com a cadeia não-UI. O comando bench-models em vez disso constrói um cliente de modelo único por ID configurado (união de translationModels, uiModels e localeModels; translationModels: [id], sem fallback) para que possa cronometrar e precificar cada modelo independentemente.
  • Tempo limite da solicitação: requestTimeout (segundos) ou requestTimeoutMs no provedor ativo, caso contrário, as mesmas chaves no topo da configuração (padrão 45 segundos), aborta cada solicitação via AbortSignal.timeout. O mesmo valor se aplica a GET /models quando a CLI carrega uma lista de modelos de um provedor para check-models (qualquer provedor). O filtro opcional de pré-voo que descarta IDs de modelo desconhecidos é executado apenas quando o provedor ativo é o OpenRouter.
  • Extras do OpenRouter (somente quando openrouter está ativo): roteamento de throughput via campo de solicitação provider, cabeçalhos HTTP-Referer / X-Title e custo exato em USD lido de usage.cost. O uso de tokens é relatado para cada provedor. Quando o provedor omite usage.cost, o custo em USD é calculado a partir de providers.<name>.modelPricing ou do padrão pricing de todo o provedor e armazenado na linha api_calls. Um custo relatado pelo provedor nunca é substituído.
  • Log de tráfego de depuração: se debugTrafficFilePath estiver definido, anexa JSON de solicitação e resposta a um arquivo (programático). O --debug-failed da CLI escreve FAILED-TRANSLATION arquivos em cacheDir com o prompt do sistema/usuário, a resposta bruta do assistente e erros de validação para tentativas falhas de verificação de tradução de UI, documentos, JSON e SVG. Falhas de API do provedor / corpo vazio são impressas no console em vez de despejar um arquivo somente de prompt.

Carregamento de configuração ​

Pipeline loadI18nConfigFromFile(configPath, cwd):

  1. Leia e analise ai-i18n-tools.config.json (JSON).
  2. mergeWithDefaults - mescla profunda com defaultI18nConfigPartial, e mescla quaisquer entradas docs[].sourceFiles em contentPaths.
  3. expandTargetLocalesFileReferenceInRawInput - coerce targetLocales para um array e rejeite entradas semelhantes a caminhos (devem ser códigos BCP-47, não um caminho para ui-languages.json); languagesManifestPath é padrão para {ui.flatOutputDir}/ui-languages.json durante mergeWithDefaults.
  4. expandDocumentationTargetLocalesInRawInput - mesmo para cada entrada docs[].targetLocales.
  5. expandJsonTargetLocalesInRawInput - o mesmo para cada entrada json[].targetLocales.
  6. parseI18nConfig - validação Zod + validateI18nBusinessRules.
  7. applyProviderOverrideToRawInput - quando -P / --provider é passado na CLI.
  8. applyEnvOverrides - aplica OPENROUTER_BASE_URL, OLLAMA_BASE_URL, I18N_SOURCE_LOCALE e I18N_TARGET_LOCALES quando definidos (as chaves de API são resolvidas separadamente por provedor dentro de LlmClient).
  9. augmentConfigWithUiLanguagesMaster - anexa nomes de exibição de manifesto do catálogo mestre empacotado.
  10. 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 (resolveUiLocale em src/core/ui-locale.ts): escolhe a localidade da UI de -L / --ui-lang > AI_I18N_LANG > configuração uiLanguage > 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 que uiLanguage se aplique (a flag e a variável de ambiente ainda prevalecem).
  • Tempo de execução (src/i18n/index.ts): um t(source, vars) mínimo com interpolação , indexado pela string de origem em inglês em relação a pacotes planos por localidade em src/i18n/locales/<code>.json (copiado para dist/i18n/locales na 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-i18n retornando { locale, dir, bundle } para a localidade da UI resolvida; o frontend define <html lang> / dir e localiza a marcação estática via atributos data-i18n*.
  • Dogfooding: os pacotes são produzidos executando o próprio pipeline de extração → translate-ui do pacote contra ai-i18n-self.config.json (pnpm i18n:self). As chaves do catálogo vêm de chamadas t() em src/cli/ e src/i18n/, além dos marcadores data-i18n* do painel em src/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:

json
{
  "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:

ts
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:

json
{
  "docs": [
    {
      "docsOutput": {
        "pathTemplate": "{outputDir}/{locale}/{relativeToDocsRoot}"
      }
    }
  ]
}

Árvore de origem ​

Layout completo de src/ (referência em nível de arquivo)
text
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}})
│   ├── placeholder-integrity.ts    Pre/post-restore token sequence + tag-kind + invented {{IDENT}} checks
│   ├── 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
│   └── translation-context.ts      contextFiles loader and guidance fingerprints
│
├── 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

Lançado sob a Licença MIT.