sadpandajoe commented on code in PR #37790: URL: https://github.com/apache/superset/pull/37790#discussion_r3827569222
########## superset/migrations/versions/2026-02-04_14-00_1af0da0adfec_add_translations_column.py: ########## @@ -0,0 +1,80 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Add translations column to dashboards and slices. + +The translations column stores user-generated content translations +in JSON format: + + { + "field_name": { + "locale": "translated_value" + } + } + +Example for dashboards: + + { + "dashboard_title": {"de": "Verkaufs-Dashboard", "fr": "Tableau de bord"}, + "description": {"de": "Monatlicher Verkaufsbericht"} + } + +Example for slices: + + { + "slice_name": {"de": "Umsatz nach Region", "fr": "Chiffre d'affaires"}, + "description": {"de": "Quartalsumsatz nach Vertriebsregion"} + } + +This enables localization of user-created content (dashboard titles, +chart names, filter labels) based on the viewer's UI language setting. +Controlled by ENABLE_CONTENT_LOCALIZATION feature flag. + +Revision ID: 1af0da0adfec +Revises: 9787190b3d89 +Create Date: 2026-02-04 14:00:00.000000 + +""" + +from sqlalchemy import Column, JSON + +from superset.migrations.shared.utils import add_columns, drop_columns + +# revision identifiers, used by Alembic. +revision = "1af0da0adfec" +down_revision = "9787190b3d89" Review Comment: This revision creates a second Alembic head: `2025_12_18_0220_create_tasks_table.py` already uses `9787190b3d89` as its `down_revision`. That makes `superset db upgrade` unable to resolve a single head, so deployments cannot create these columns. Should this be chained to the current head (or merged with the other branch)? ########## superset/localization/localizable_mixin.py: ########## @@ -0,0 +1,117 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" +LocalizableMixin for SQLAlchemy models. + +Provides content localization support for user-generated content fields. +Models that inherit this mixin can store and retrieve translations for +fields like titles and descriptions based on the viewer's locale. + +Translations are stored in a JSON column with the following structure: +{ + "field_name": { + "locale": "translated_value" + } +} + +Example: +{ + "dashboard_title": {"de": "Verkaufs-Dashboard", "fr": "Tableau de bord"}, + "description": {"de": "Monatlicher Verkaufsbericht"} +} +""" + +from typing import Any + +from superset.localization.locale_utils import get_translation + + +class LocalizableMixin: + """ + Mixin providing content localization for SQLAlchemy models. + + Requires the model to have a `translations` attribute (JSON column). + Provides methods for getting localized values with fallback support, + setting translations, and listing available locales. + """ + + translations: dict[str, dict[str, str]] | None + + def get_localized(self, field: str, locale: str) -> Any: + """ + Get localized value for a field with fallback support. + + Fallback chain: + 1. Exact locale match (e.g., "de-DE") + 2. Base language fallback (e.g., "de" from "de-DE") + 3. Original field value + + Args: + field: The field name to get localized value for + locale: The locale code (e.g., "de", "de-DE", "fr") + + Returns: + The localized value if translation exists, otherwise the original + field value. + """ + if not self.translations: + return getattr(self, field) + + field_translations = self.translations.get(field, {}) + + translated = get_translation(field_translations, locale) + if translated is not None: + return translated + + return getattr(self, field) + + def set_translation(self, field: str, locale: str, value: str) -> None: + """ + Set translation for a field and locale. + + Creates the translations dict and field dict if they don't exist. + + Args: + field: The field name to set translation for + locale: The locale code (e.g., "de", "fr") + value: The translated value + """ + if self.translations is None: + self.translations = {} + + if field not in self.translations: + self.translations[field] = {} + + self.translations[field][locale] = value Review Comment: After a model has persisted translations, this only mutates the nested JSON dictionary. Plain SQLAlchemy `JSON` columns do not mark nested in-place changes dirty, so adding a second locale can be lost on commit and reload. Should this reassign the column (or flag it modified) after updating the nested map? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
