Skip to content

feat(i18n): traduzir ui/components e coordinators (fase 2 de 3) - #462

Merged
MarkSant merged 13 commits into
mainfrom
claude/i18n-phase-2-components-40b608
Aug 13, 2026
Merged

feat(i18n): traduzir ui/components e coordinators (fase 2 de 3)#462
MarkSant merged 13 commits into
mainfrom
claude/i18n-phase-2-components-40b608

Conversation

@MarkSant

Copy link
Copy Markdown
Owner

Fase 2 de 3 da internacionalização, seguindo a fase 1 mergeada em #461.

O PR #461 já foi mergeado, então esta fase abre um PR próprio a partir do
merge dele.

Escopo

src/zebtrack/ui/components/** e src/zebtrack/coordinators/** — juntos de
propósito: os coordinators emitem o texto dos messagebox que os components
disparam, e separá-los deixaria metade de cada diálogo traduzido.

O literal português é a tradução: cada par vai para
src/zebtrack/locales/_pairs/pr2-*.json, então o diff do .po é o inverso
exato do diff do fonte.

Landed até agora

  • model_diagnostics_panel, global_model_configuration_panel,
    model_diagnostics_coordinator
  • config_editor, canvas/zone_editor, zone_controls

Defeitos corrigidos de passagem

Ambos do tipo que a tradução quebraria em silêncio:

  • "Ambos" era comparado com == entre o combobox do painel de
    diagnóstico e o coordinator. Virou ui/sentinels.both_models_label(),
    o mesmo padrão dos outros rótulos que são exibidos num módulo e testados
    noutro.
  • show_aquarium_selector ramificava pelo texto exibido
    ("Desenho" in child.cget("text")). Traduzido o rótulo, o seletor de
    aquário cairia no fallback sem avisar. Agora ancora no próprio widget.
  • _ usado como descarte de tupla sombreava o gettext dentro da mesma
    função (ruff F823).

Constantes de corpo de módulo/classe viraram funções, conforme
tests/i18n/test_no_import_time_translation.py.

Verificação

ruff check ., mypy ., pytest -q e pytest -m gui -n0 verdes a cada
commit; update_translations.py reporta All catalogues are complete.
Cada pacote migrado entra em MIGRATED_PATHS no mesmo commit.

🤖 Generated with Claude Code

MarkSant and others added 2 commits August 12, 2026 07:13
Migra model_diagnostics_panel, global_model_configuration_panel e o
model_diagnostics_coordinator que emite o texto dos messagebox que eles
disparam -- separa-los deixaria metade de cada dialogo em portugues.

- "Ambos" era comparado com == no coordinator a partir do combobox do
  painel: vira ui/sentinels.both_models_label(), como os demais rotulos
  que sao exibidos e testados em modulos diferentes.
- Os quatro dicionarios de rotulos do painel global (_TARGET_LABELS e
  companhia) viram funcoes; um dict montado no corpo do modulo congela
  a traducao no import.
- O alias aceito no prompt de alvo passa a ser comparado sem acentos, de
  modo que "aquario" e "aquário" continuam valendo sem carregar um
  literal acentuado.
- `_` deixou de ser usado como descarte de tupla nos tres arquivos: ali
  ele sombreava o gettext dentro da propria funcao.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e 2)

config_editor, canvas/zone_editor e zone_controls -- os tres painieis que
o operador usa para definir zona e regra de ROI.

Dois defeitos de i18n corrigidos de passagem, ambos do tipo que degrada
em silencio:

- `show_aquarium_selector` procurava o frame de acoes de desenho pelo
  texto exibido (`"Desenho" in child.cget("text")`). Traduzido o rotulo,
  a busca falharia e o seletor de aquario cairia no fallback sem avisar.
  Agora ancora no proprio widget (`self.drawing_actions_frame`).
- `_` era usado como descarte de tupla em `save_arena`/`discard_arena`,
  sombreando o gettext dentro da mesma funcao -- o ruff (F823) pegou.

Constantes de corpo de modulo/classe viram funcoes:
SEG_OVERLAP_MISSING_MASKS_WARNING, _BGR_COLOR_MAP (e o alias em
canvas_manager) e _HIERARCHY_LABEL_MAP.

Os nomes de cor de color_selection_dialog ficam para a fase 3; as duas
listas nao se comparam por igualdade, so exibem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 12, 2026 10:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Phase 2/3 of the GUI i18n migration, converting ui/components/** and the coupled model_diagnostics_coordinator to use runtime gettext resolution (no import-time translation), while fixing a couple of “display text used as logic” hazards (sentinel label + widget anchoring) that would silently break once translated.

Changes:

  • Migrates multiple UI components and model_diagnostics_coordinator from Portuguese literals to _() calls, with {msgid: pt_BR_literal} pairs recorded under src/zebtrack/locales/_pairs/.
  • Introduces/extends i18n-safe sentinels and function-based label maps to prevent “translated in one module, compared in another” failures.
  • Updates UI tests and the migrated-paths gate to reflect English-as-source behavior.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/ui/components/test_zone_editor_selection.py Updates assertion to match new English status message on arena-save failure.
tests/ui/components/test_zone_controls_widget.py Updates assertions for translated UI strings (English source) in zone controls.
tests/ui/components/test_model_diagnostics_panel.py Updates assertion for translated project-weight summary string.
tests/i18n/test_no_untranslated_literals.py Extends MIGRATED_PATHS to include newly migrated modules.
src/zebtrack/ui/sentinels.py Adds both_models_label() sentinel to share a translated-but-compared label across modules.
src/zebtrack/ui/components/zone_controls.py Converts UI strings to _(), removes text-based widget matching, and adds runtime label mapping for context menu.
src/zebtrack/ui/components/model_diagnostics_panel.py Converts panel strings to _(), centralizes engine names, and uses the shared “Both” sentinel in the combobox.
src/zebtrack/ui/components/global_model_configuration_panel.py Converts labels/prompts to _(), replaces import-time dict constants with functions, and adds accent-folding helper for target input.
src/zebtrack/ui/components/config_editor.py Converts warning constant to a function to avoid import-time translation; migrates additional UI strings to _().
src/zebtrack/ui/components/canvas/zone_editor.py Converts dialog/status strings to _() and moves BGR color-name map to a runtime function for i18n safety.
src/zebtrack/ui/components/canvas_manager.py Removes class alias to the now-removed ZoneEditor._BGR_COLOR_MAP.
src/zebtrack/coordinators/model_diagnostics_coordinator.py Converts coordinator-emitted messagebox/status/report strings to _() and uses the shared “Both” sentinel for branching.
src/zebtrack/locales/_pairs/pr2-zone-editor.json Records msgid→original-PT pairs for zone_editor.py.
src/zebtrack/locales/_pairs/pr2-zone-controls.json Records msgid→original-PT pairs for zone_controls.py.
src/zebtrack/locales/_pairs/pr2-sentinels.json Records msgid→original-PT pairs for sentinels.py (adds “Both”).
src/zebtrack/locales/_pairs/pr2-model-diagnostics-panel.json Records msgid→original-PT pairs for model_diagnostics_panel.py.
src/zebtrack/locales/_pairs/pr2-model-diagnostics-coordinator.json Records msgid→original-PT pairs for model_diagnostics_coordinator.py.
src/zebtrack/locales/_pairs/pr2-global-model-configuration-panel.json Records msgid→original-PT pairs for global_model_configuration_panel.py.
src/zebtrack/locales/_pairs/pr2-config-editor.json Records msgid→original-PT pairs for config_editor.py.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

MarkSant and others added 11 commits August 12, 2026 07:42
Colapsa a duplicata de PROJECT_STATUS_META: gui.py carregava uma copia
byte-identica da tabela do validation_manager e nao a usava. Sobra um
acessor so, `validation_manager.project_status_meta()`, funcao porque um
dict de corpo de modulo congela a traducao no import.

Outros pontos:

- `icon, _ = PROJECT_STATUS_META[...]` sombreava o gettext dentro das
  funcoes que agora chamam `_()`; virou `icon, _label`.
- `validate_positive_integer(field_name="valor")` tinha o default no
  proprio parametro -- avaliado no import. Passa a `None` e resolve
  `_("value")` no corpo.
- "Nao informado" passa a sair de `sentinels.not_reported_label()`, que
  ja existia para esse mesmo valor.
- Os IDs de agrupamento continuam em portugues de proposito: "Sem Dia",
  "Sem Grupo" e "Dia_N" sao espaco de chave, nao rotulo. So o
  `day_label` do placeholder passou a usar `day_prefix()`, que
  `resolve_day_display` ja aceita nos dois idiomas.
- Dois msgids colidiam com traducoes diferentes entre lotes
  ("Confirm Deletion", "No video selected"); foram separados para que
  cada sitio preserve o literal que substituiu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ao ao vivo

dialog_coordinator, video_processing_coordinator e
live_camera_session_coordinator -- os tres que emitem o texto dos
messagebox disparados pelos paineis ja migrados.

- `LIVE_PROFILE_DISPLAY_DEFAULT` era constante de modulo; virou
  `live_profile_display_default()`.
- O helper de exibicao de dia continua ACEITANDO os prefixos "Dia_"/"Dia "
  que a metadata gravada contem, e passa a RENDERIZAR com `day_prefix()`.
- Tres msgids colidiam entre lotes com traducoes diferentes
  ("Processing", "Analysis in Progress", alem dos dois do commit
  anterior); cada sitio ficou com um msgid proprio para preservar o
  literal que substituiu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Colapsa a segunda duplicata prevista: ANALYSIS_PROFILE_TOOLTIP existia em
analysis_controls e analysis_display com textos JA divergentes -- o do
display tinha uma frase a mais nomeando o fallback. Sobra um acessor so,
`ui/components/analysis_profile.analysis_profile_tooltip()`, com o texto
mais completo dos dois.

Outras constantes de corpo de modulo/classe viraram funcoes:
`_BADGE_STYLES` (zone_context_panel) e `AQUARIUM_COLORS`
(multi_aquarium_overlay, mais o alias em canvas_manager).

analysis_view_controller entrou junto porque monta o mesmo rotulo de
perfil que os dois paineis exibem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fecha o pacote: `src/zebtrack/coordinators` inteiro entra em
MIGRATED_PATHS como um caminho so, no lugar dos quatro arquivos avulsos.

Mais tres sitios em que `_` era sombreado -- todos pegos por ferramenta,
nenhum por leitura:

- `for _ in range(5)` em live_calibration_coordinator (ruff F402);
- `_ = arduino_enabled` em recording_session_coordinator, o idioma de
  "parametro deliberadamente nao usado", que rebindava o gettext para o
  resto da funcao -- justo a funcao que monta as mensagens de recusa do
  gatilho externo (mypy: "bool not callable");
- `_, roi_index, roi_name` ja corrigido no lote anterior.

Tags de proveniencia e chaves de dicionario ficam em portugues de
proposito: 'auto', 'manual', 'arena', 'camera', 'frame', 'cobaia',
'single_video'. Sao comparadas, nao exibidas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
arduino_bindings_panel, arduino_dashboard e weight_hardware_manager --
o painel de comandos por zona, o dashboard de status e o resumo de
pesos/GPU do painel de projeto.

Tres constantes de corpo de modulo viraram funcoes (DISCLAIMER,
NOTE_NO_ARDUINO, CONFLICT_WARNING -> disclaimer(), note_no_arduino(),
conflict_warning()); nenhuma era importada de fora do modulo.

Dois defeitos corrigidos de passagem, ambos do tipo que degrada em
silencio depois da traducao:

- `update_gpu_hardware_display` ramificava por `"CPU" in gpu_name`, ou
  seja, pelo proprio texto exibido. Traduzido o rotulo, o ramo escolhido
  passaria a depender do idioma. Agora um booleano `accelerator_found`
  carrega a informacao, e a fidelidade do caso `cuda_available=True` com
  `torch.cuda.is_available()=False` (que mantinha "CPU apenas") foi
  preservada.
- `handle_request_weight_type` comparava a entrada digitada contra a
  lista fixa ["seg", "segmentation", "segmentacao"]. O prompt agora e
  traduzido, entao a lista virou casamento por prefixo -- aceita as tres
  grafias sem depender do idioma instalado.

Reaproveitados os msgids ja existentes de "No Project Loaded",
"Segmentation", "Detection", "Enabled", "Disabled" e "Error" em vez de
criar duplicatas com traducao divergente.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Os seis modulos de ui/components/project_views: helpers de formatacao,
construtor da arvore de relatorios, acoes de geracao e de artefato, e os
dois tree managers. O pacote entra inteiro em MIGRATED_PATHS.

Um bug JA ATIVO no main, encontrado ao migrar:
`navigate_to_processing_reports_tab` procurava a aba pelo texto exibido
(`"Processamento e Relatorios" in tab_text`). A aba passou a ser criada
com `_("Processing and Reports")` na fase 1 (ui/builders), entao a busca
nunca mais casou -- e o unico sintoma era um log.warning, com a aba
simplesmente nao abrindo. Agora ambos os sitios (video_selector_tree_-
manager e project_initializer) selecionam
`gui.processing_reports_tab_frame`, que nao depende de idioma.

Outros pontos:

- `_HIERARCHY_LABELS` era um ClassVar com "grupo"/"dia"/"sujeito" no
  corpo da classe: virou a funcao `hierarchy_label()`. O valor alimenta
  `target_kind`, que o dialog_manager interpola dentro de mensagem ja
  traduzida.
- `for _ in range(3)` em `delete_all_unified_reports` sombreava o
  gettext: virou `_attempt`.
- `format_status_label` usa dois msgids simples em vez de ngettext --
  os arquivos de pares nao carregam formas plurais, e nenhum outro
  sitio do projeto usa ngettext.
- Status da coluna da arvore: "Processado"/"Pendente" viraram
  `_("Processed")`/`_("Not processed")`. O msgid "Pending" ja existe
  mapeado para "Pendentes" (rotulo de card, plural), e reusa-lo poria
  o plural numa coluna de linha unica.
- Dois textos de "excluir arquivos do disco" que diferiam so por
  "do disco"/"no disco" foram unificados num msgid so.
- `roi_template_var != "Nenhum"` foi deixado como esta: e comparacao
  com valor armazenado, nao texto exibido, e hoje nada grava "Nenhum".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ento

project_model_configuration_panel e behavioral_config_widget -- os dois
formularios que o pesquisador usa para definir pesos por projeto e os
parametros de tigmotaxia/geotaxia.

`WEIGHT_INHERIT_LABEL` era constante de corpo de classe e virou a funcao
`weight_inherit_label()`. Ela e um caso especial: o texto e exibido no
dropdown E comparado com `!=` para decidir se o slot tem override. Como
os dois lados agora chamam a mesma funcao, o sentinela continua casando
qualquer que seja o idioma -- o que NAO aconteceria se so o lado exibido
fosse traduzido.

`lambda *_: ...` em `_build_slot_override_controls` virava um `_` local
dentro da lambda; renomeado para `*_a` agora que o modulo importa o
gettext.

O mapa perspectiva-exibida -> valor-persistido do behavioral_config_widget
ja era construido em tempo de execucao a partir de uma unica lista, entao
traduzir os rotulos nao desalinha `_perspective_mapping` de
`_perspective_reverse`; os valores gravados seguem "top_down"/"lateral".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Os rotulos das abas do notebook, os botoes do painel de controle e todo o
texto que o StateSynchronizer escreve na barra de status e no cabecalho de
analise (metadados, tarefa em andamento, resumo de interacao social).

`update_analysis_task_status` removia o prefixo redundante do passo com
`step_text.lower().startswith("etapa:")` -- ramo por texto exibido. O
produtor (`core/video/progress_notifier`) ainda escreve "Etapa: ", mas vai
para o ingles numa fase seguinte; agora o strip aceita os dois prefixos,
entao nenhuma das duas ordens de migracao deixa "Etapa: Etapa: ..." na
tela.

`tests/test_analysis_metadata_display.py` reimplementa a mao os dois
formatos que o StateSynchronizer produz, e uma das asserts compara com
`_default_analysis_metadata_text()` de verdade -- a copia migrou junto,
senao o teste passaria a comparar portugues com ingles.

Msgids reaproveitados em vez de duplicados: "Detection Model Status",
"Settings", "No analysis in progress.", "No task in progress.",
"Individual: {value}", "Group: {value}", "Day: {value}" e
"▶️ Start Recording". O LabelFrame "Processamento" do control_panel usa
"Video Processing" porque "Processing" ja esta mapeado para "Processando"
(gerundio), que nao serve como titulo de secao.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
video_frame_manager, event_handler, renderer e polygon_drawing_service --
o caminho que carrega o frame no canvas, o menu de contexto dos vertices e
as mensagens de conclusao de arena/ROI.

Mais um `_` sombreado que so o ruff (F823) enxergou:
`h, w, _ = frame.shape` em `display_roi_frame`, na mesma funcao que abre
quatro dialogos de erro. Renomeado para `_channels`.

Msgids reaproveitados: "No Video Selected", "ROI Name", "Error Loading" e
"Could not load the selected video.\n{path}".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
roi_template_manager, zone_edit_guard e validators/config_validator -- a
biblioteca de templates, o dialogo que impede sair da aba com desenho por
concluir, e as mensagens de validacao numerica do editor de configuracao.

Msgids reaproveitados de lotes anteriores em vez de duplicados: "Video not
selected", "Template applied", "Confirm Deletion", "Error applying the
template", "Import ROI Template into the Library", "ROI Templates", "All
files", "Import error", "Template imported", "Overlap fraction must be
between 0 and 1", "Window length must be odd and at least 3." e "Polyorder
must be at least 1." -- varios deles ja existiam porque dialog_manager e
validation_manager exibem as mesmas frases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ultimo lote: processing_reports, project_overview, single_video_workflow,
event_dispatcher e project_initializer. Com ele o scanner reporta ZERO
literais em src/zebtrack/ui/components.

MIGRATED_PATHS deixa de crescer arquivo a arquivo nesse pacote: as ~30
entradas de ui/components/* viram uma unica "src/zebtrack/ui/components".
Assim um arquivo NOVO no pacote ja nasce coberto pelo ratchet, em vez de
ficar de fora ate alguem lembrar de acrescenta-lo a lista.

Os seis cards de status de processing_reports e project_overview eram duas
copias literais da mesma tabela; agora as duas chamam os msgids que o
validation_manager ja usava ("Pending", "Processing", "With data",
"Completed", "Failed"), entao os rotulos nao podem mais divergir entre as
duas abas.

`_describe_roi_rule` montava a frase da regra de ROI por concatenacao de
fragmentos; virou um msgid por caso mais um molde final, que e o que
permite ao tradutor reordenar a sentenca.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MarkSant
MarkSant merged commit df4e977 into main Aug 13, 2026
6 checks passed
@MarkSant
MarkSant deleted the claude/i18n-phase-2-components-40b608 branch August 13, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants