#2409·labelme

Guard against untranslatable non-literal tr() calls repo-wide

Author: wkentaroCreated Jul 25, 2026Updated Aug 25, 2026
Labelsready-for-humantype:task

This was generated by AI during triage.

Noticed while reviewing #2405.

Context

pyside6-lupdate only extracts string literals passed to tr(). A call like self.tr(some_variable) compiles and runs fine, but the source string never reaches any .ts catalog, so the text silently renders untranslated in all 20 bundled locales. There is no error, no warning, and make check_translate stays green — the string simply isn't there to be flagged as unfinished.

That is exactly the bug #2405 fixed in brightness_contrast_dialog.py, where two slider labels reached self.tr() through a loop variable.

Problem

The fix in #2405 is correct but local. Its regression test (test_slider_labels_are_extractable_by_lupdate) runs pyside6-lupdate over that one module and asserts the two strings are extracted. Nothing stops the same mistake from being reintroduced in any other widget.

The codebase is clean today: the only remaining non-literal tr() calls are in labelme/_widgets/settings_dialog.py (self.tr(section), self.tr(setting.label), self.tr(setting.note), self.tr(setting.choice_labels[index])), and those are legitimate because their sources are marked with QT_TRANSLATE_NOOP in labelme/_config/_schema.py — the supported way to hand a variable to tr(). So this is about keeping that property, not repairing a current breakage.

Idea

Add a repo-wide guard so a new non-literal tr() call fails CI unless its source is registered via QT_TRANSLATE_NOOP. Options, roughly in increasing order of effort:

  • An AST-based test that walks labelme/**/*.py, finds tr(...) calls whose argument is not a string literal, and allowlists those whose underlying strings are covered by QT_TRANSLATE_NOOP.
  • A ruff/flake8 custom rule, if one is worth maintaining.
  • Generalize #2405's approach: run pyside6-lupdate over the whole package and assert every user-facing string that should be translatable appears in the extracted output. This is closer to what make check_translate already does and may fold in there.

The AST test is probably the cheapest and most precise; the QT_TRANSLATE_NOOP allowlist is the part that needs the most care.

Not blocking

This does not block #2405, which is complete and correct on its own.