Skip to content

i18n: messages.pot is 428 strings behind source, so those strings cannot be translated in any language #44403

Description

@glaterza

Bug description

superset/translations/messages.pot is the extraction template every language catalog is updated
from. It has drifted from source: 428 translatable strings exist in the code but are absent from
the template
, and 109 strings remain in the template but no longer exist in source.

Because a string only reaches the 30 .po catalogs via the template, those 428 strings cannot be
translated into any language
. They are not untranslated-pending-a-volunteer; they are invisible to
translators and to the AI backfill alike.

Measured at c426186a2e:

count
committed messages.pot 5117
fresh pybabel extract from source 5436
in source, not in the template 428
in the template, no longer in source 109

Raw set difference is 429 / 110; the figures above exclude whitespace-only variants, so they are
real drift rather than formatting churn.

Examples of strings users see but no translator can reach: % of column total, %s chart updated,
%s dataset updated, Add to favorites, %s MCP scopes, A rule with this name already exists.

Reproduction

# clean tree matters: generated files left in the working tree corrupt this measurement
git status --porcelain            # must be empty

pybabel extract -F superset/translations/babel.cfg -o /tmp/fresh.pot \
  --no-location --sort-output \
  --copyright-holder=Superset --project=Superset \
  -k _ -k __ -k t -k tn:1,2 -k tct .

# compare the msgid sets of /tmp/fresh.pot and superset/translations/messages.pot with Babel
# (collapse whitespace before comparing to discount wrapping-only variants)

Expected: the committed template matches a fresh extraction, give or take strings added since the
last regeneration.
Actual: it is 428 strings behind, and the gap grows with every PR that adds a translatable string.

Why it persists

The template has not been regenerated since 2026-09-02 (e8540b7c49). Nothing fails when it
goes stale:

.github/workflows/superset-translations.yml runs babel_update.sh on base and PR and compares
translated/fuzzy counts in the .po catalogs via check_translation_regression.py. It never
compares the committed template against a fresh extract, and the regression step is
continue-on-error: true. So a PR that adds a translatable string without regenerating the
template is indistinguishable from one that does.

A related symptom: superset/translations/do-not-translate.txt lists 27 msgids, but a current run
stamps only 24 markers — pivoted_xlsx, step-after and step-before are listed yet no longer
extractable from source. Same root cause.

Possible directions

Not proposing an implementation here, but the options seem to be:

  1. Regenerate the template (and propagate to the catalogs) as a one-off, which fixes today's gap but
    not tomorrow's.
  2. Add a CI check that fails when the committed template differs from a fresh extract — the missing
    guard, and the only option that stops it recurring.
  3. Regenerate the template on a schedule.

Happy to open the PR for whichever direction maintainers prefer; (1) and (2) together seem like the
useful pair.

Screenshots/recordings

Not applicable — build-pipeline defect, nothing renders.

Superset version

master / latest-dev

Python version

3.11

Node version

Not applicable

Browser

Not applicable

Additional context

Measured with pybabel 2.17.0 (the version pinned in requirements/base.txt) and GNU gettext 1.0,
on a clean tree asserted both before and after extraction.

Raised from discussion #43562, where
@rusackas suggested tracking it separately. Related but independent: #44395 repairs the msgcat
normalization step in babel_update.sh, and #44397 adds translator context comments. Neither
changes the drift measured here.

Checklist

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I
    included it here as text in the "additional context" section.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions