Source code for aeat.application.wizard._translations
"""Locale-coverage audit for wizard descriptor and CLI translation strings.``audit_wizard_translations`` walks every :class:`Translatable` valuedeclared anywhere in :data:`WIZARD_FLOWS` (titles, prompts, helps,choice labels and descriptions, plus the fixed error keys the runtimeraises) and the wizard-derived flag-help keys, returning the tuple ofkeys that fail to resolve in any of the four locale catalogues.``audit_cli_translations`` runs the same locale-resolution sweep overevery ``cli.<group>.*`` translation key referenced at a ``tr(...)``call site in any module under :mod:`aeat.entrypoints.cli`. The audittreats a locale that returns the literal key text -- the python-i18nfallback behaviour when a key is absent or its value mirrors the keyitself -- as a structured failure."""from__future__importannotationsimportrefromcollections.abcimportIterablefrompathlibimportPathfrom...core.i18nimporttrfrom._catalogueimportWIZARD_FLOWSfrom._modelsimportWizardFlow,WizardQuestion_LOCALES:tuple[str,...]=("en","es","ca","hu")_FIXED_RUNTIME_KEYS:tuple[str,...]=("wizard.setup.errors.missing_required_flags",)def_walk_keys(flows:Iterable[WizardFlow])->tuple[str,...]:"""Return every translation key referenced by ``flows``."""keys:list[str]=[]forflowinflows:keys.append(str(flow.title))keys.append(str(flow.description))forsectioninflow.sections:keys.append(str(section.title))forquestioninsection.questions:keys.extend(_question_translation_keys(question,flow_id=flow.id))keys.append(f"cli.config.{flow.id}.help")keys.extend(_FIXED_RUNTIME_KEYS)returntuple(keys)def_question_translation_keys(question:WizardQuestion,*,flow_id:str)->tuple[str,...]:"""Return every translation key contributed by one wizard question. Covers the prompt, the optional help string, every choice's label and optional description, and the derived ``wizard.<flow>.flags.<id>.help`` key consumed by ``build_wizard_command`` for Typer flag descriptions. """keys:list[str]=[str(question.prompt)]ifquestion.helpisnotNone:keys.append(str(question.help))forchoiceinquestion.choices:keys.append(str(choice.label))ifchoice.descriptionisnotNone:keys.append(str(choice.description))keys.append(f"wizard.{flow_id}.flags.{question.id}.help")returntuple(keys)_UNRESOLVED_SENTINEL="\x00aeat-wizard-translation-unresolved\x00"def_resolves_in(locale:str,key:str)->bool:"""Return True when ``key`` resolves to a real translation. ``tr`` falls back to a humanised form of the key (not the raw key) when no translation exists, so a raw-key comparison can never detect a miss. Passing a sentinel ``default`` makes the miss unambiguous: an unresolved key renders exactly the sentinel, a resolved one renders its translation. """rendered=tr(key,locale=locale,default=_UNRESOLVED_SENTINEL)returnrendered!=_UNRESOLVED_SENTINEL
[docs]defaudit_wizard_translations()->tuple[str,...]:"""Return the keys that fail to resolve in any locale. A key is considered missing for a locale when ``tr(key, locale=...)`` returns the raw key itself (the python-i18n fallback behaviour). """keys=_walk_keys(WIZARD_FLOWS)missing:list[str]=[]forkeyinkeys:forlocalein_LOCALES:ifnot_resolves_in(locale,key):missing.append(f"{locale}:{key}")returntuple(missing)
[docs]defcli_keys_referenced_in_source()->tuple[str,...]:"""Return every ``cli.<group>.*`` translation key referenced statically. Walks every ``.py`` module under :mod:`aeat.entrypoints.cli` and extracts literal ``cli.<group>.<rest>`` strings by regex. f-string interpolations that build keys at runtime (for example ``f"cli.config.{flow.id}.help"``) are not captured here; those keys are walked by :func:`audit_wizard_translations` through the wizard descriptor catalogue instead. """keys:set[str]=set()formodulein_cli_entrypoints_root().rglob("*.py"):# Test modules cite translation-key prefixes in assertions# (e.g. `"cli.app.live.iva_wallet.acquisition.outcome"` used as a# leak-detection sentinel in `not in label` checks). Those are# introspection literals, not `tr()` call sites; auditing them# as required catalogue entries would fabricate dead translations.ifmodule.name.startswith(("test_","_test_")):continuesource=module.read_text(encoding="utf-8")formatchin_CLI_KEY_PATTERN.finditer(source):keys.add(match.group(1))returntuple(sorted(keys))
[docs]defaudit_cli_translations()->tuple[str,...]:"""Return the ``cli.*`` keys that fail to resolve in any locale. A failure means the locale catalogue either omits the key or stores the literal key text as the value, both of which surface as raw key strings in operator-facing help output. """missing:list[str]=[]forkeyincli_keys_referenced_in_source():forlocalein_LOCALES:ifnot_resolves_in(locale,key):missing.append(f"{locale}:{key}")returntuple(missing)