+1 binding
On Fri, Aug 28, 2026 at 4:01 PM Evan Rusackas (ASF) <[email protected]> wrote: > > Hey all, > > Kicking off a new vote on an old SIP, that’s been largely implemented. Happy > to see it moving again, and would be stoked to see it merged as Superset is > *almost* fully translated nowadays! Let’s dive in... > > SIP-161 ("Translating Superset asset metadata"): > https://github.com/apache/superset/issues/32854 > > Quick background: > This SIP got extensive [DISCUSS] treatment on this list and in the issue back > in April 2025, and Max and I converged with the community on a minimal-core > direction. Namely, a deployment-configurable `TRANSLATION_HOOK` as the only > integration point, with Superset core never storing translations itself. > > The original proposer had to step away for funding reasons before we closed > the loop with a vote, and the issue sat until @alex-poor (GH handle) picked > it back up with a PR that implements this converged direction: > > https://github.com/apache/superset/pull/40679 > > *************** DETAILS *************** > > > What new things can be translated? > > • Chart names and dashboard titles, automatically — no author action needed. > • Home-page "Recents" item titles. > • Anything an author explicitly wraps in a new `{{ i18n('...') }}` Jinja > macro inside a templated field (axis labels, native filter names, etc.) > • This is opt-in per field, not automatic. > • Explicitly not covered: the actual chart data/values and localized > number/date formatting, which are the same exclusions the original SIP had. > > > How are translations maintained and loaded? > > • Superset core stores none of it, that's the design shift from the original > proposal. > • There's one hook: > • TRANSLATION_HOOK(text, locale, **context) -> str | None > • You implement it in config, and back it with whatever you want — a > static dict, an external MT API, gettext `.po` catalogs, or a database table, > whatever > • A `TRANSLATION_BATCH_HOOK` variant exists for anything where each > lookup is a query or network call. Superset prefetches through it wherever it > already holds a full collection (a dashboard's charts, the Recents list). > That means a 30-chart dashboard costs 1 hook call, not 30, and results are > memoized. The one place that still resolves per-row is the list views, since > FAB serializes each row independently. The docs tell you to cache your hook > if that matters. > • There's no export/import built into core; that's on whatever you build > behind the hook. > > > Effect on our `.pot`/`.po` effort? > > • None on the existing pipeline — UI chrome strings are unaffected, nothing > new gets added to Superset's own translatable-string extraction. > • One of the four reference hooks in the docs *does* show how a deployment > could reuse the gettext toolchain (Poedit/Transifex/Weblate) for asset > content. But that’s in a separate catalog domain (e.g. `assets`) so it can't > collide with or pollute our existing UI catalogs. Opt-in per deployment, zero > impact on Superset’s core. > > > Breaking? Nope… fully additive. > > • Feature flag + a multi-language `LANGUAGES` config are both required to > activate anything, so virtually every existing single-language install is > untouched. > • New optional config hooks (no-op if undefined), new dump-only REST fields > (`localized_name`/`localized_title`, nothing removed or renamed) > • One new Jinja macro > • No DB migration. > • Editing a name always shows/saves the canonical value, the edit workflow > doesn't change. > > > Summary of what you'd be voting on: > > > • A `TRANSLATION_HOOK(text, locale, **context) -> str | None` config hook > (plus an optional batch variant for query/API-backed stores), fully pluggable > — static map, external MT service, `.po` catalogs, a DB table, whatever a > deployment wants. > • A `{{ i18n('...') }}` Jinja macro for opt-in translation of templated > fields. > • - Gated behind `ENABLE_I18N_ASSET_TRANSLATIONS` + a multi-language > `LANGUAGES` config, so single-language deployments (the default) pay zero > cost. > • No new core dependencies, no DB migration, no translations stored in > Superset itself. Fully additive REST fields, editing always operates on the > canonical name. > • Automatically covers chart names and dashboard titles; anything else (axis > labels, native filter names, etc.) is opt-in via the macro. Search/filtering > on translated text is not addressed. Both are known, named gaps relative to > the original SIP's ambitions, not oversights. > > > Worth flagging from prior discussion / alternatives: > > • The original motivation explicitly called out *axis and metric labels* as > things to translate. This PR only auto-covers `slice_name`/`dashboard_title`. > Everything else needs manual `{{ i18n() }}` wrapping per field, per org, so > it’s a narrower scope > • "Search/filter by translated text" was an open question in the original SIP > and remains unaddressed — list search still matches canonical text only. > • The SIP's "markup vs. auto-wrap" contention is resolved as a hybrid option > (auto for the two title fields, manual macro for everything else) > • It was doubted that batch retrieval was feasible *through Jinja* but this > PR sidesteps that by prefetching outside the macro (dashboard-charts > endpoint, Recents), while the macro itself still resolves one string per call > site, consistent with rather than disproving the doubt. > > > The PR itself has already had thorough review already — worth an additional > pass if you want the engineering details > > *************** /END WALL OF DETAILS *************** > > > Please vote: > > [ ] +1 approve > [ ] +0 no opinion > [ ] -1 disapprove (please say why) > > Vote will stay open for at least 72 hours. > > Evan Rusackas > Preset, Inc > PMC, Apache Superset > Member, ASF
