@@ -755,19 +755,57 @@ def set_title_description_tags(self, workspace_object: Any, translated: dict[str
755755 if workspace_object .tags :
756756 workspace_object .tags = [translated [x ] for x in workspace_object .tags ]
757757
758+ @staticmethod
759+ def _iter_dashboard_sections (content : dict ):
760+ """Yield all sections from a dashboard content dict.
761+
762+ Handles both the legacy flat layout (content.layout.sections) and the
763+ newer tabbed layout (content.tabs[*].layout.sections), including
764+ dashboards that contain both structures.
765+
766+ Args:
767+ content: Dashboard content dictionary
768+ """
769+ # Top-level layout sections (legacy / single-tab dashboards)
770+ layout = content .get ("layout" )
771+ if layout :
772+ yield from layout .get ("sections" , [])
773+
774+ # Tab-level layout sections (tabbed dashboards)
775+ for tab in content .get ("tabs" , []):
776+ tab_layout = tab .get ("layout" )
777+ if tab_layout :
778+ yield from tab_layout .get ("sections" , [])
779+
758780 def _extract_dashboard_date_filter_titles (self , to_translate : set [str ], dashboard_content : dict ) -> None :
759781 """Extract date filter titles from dashboard content for translation.
760782
783+ Handles both top-level and tab-level date filter configurations.
784+
761785 Args:
762786 to_translate: Set to collect translatable strings
763787 dashboard_content: Dashboard content dictionary containing date filter configurations
764788 """
789+ # Extract date filter titles from top-level content
790+ self ._extract_date_filter_titles_from_dict (to_translate , dashboard_content )
791+
792+ # Extract date filter titles from each tab
793+ for tab in dashboard_content .get ("tabs" , []):
794+ self ._extract_date_filter_titles_from_dict (to_translate , tab )
795+
796+ def _extract_date_filter_titles_from_dict (self , to_translate : set [str ], content_dict : dict ) -> None :
797+ """Extract date filter titles from a single content dictionary.
798+
799+ Args:
800+ to_translate: Set to collect translatable strings
801+ content_dict: Dictionary that may contain dateFilterConfig and dateFilterConfigs
802+ """
765803 # Extract implicit date filter title
766- implicit_date_filter_title = dashboard_content .get ("dateFilterConfig" , {}).get ("filterName" )
804+ implicit_date_filter_title = content_dict .get ("dateFilterConfig" , {}).get ("filterName" )
767805 self .add_title_description (to_translate , implicit_date_filter_title , None )
768806
769807 # Extract explicit date filter titles
770- for date_filter_config in dashboard_content .get ("dateFilterConfigs" , []):
808+ for date_filter_config in content_dict .get ("dateFilterConfigs" , []):
771809 explicit_date_filter_title = date_filter_config .get ("config" , {}).get ("filterName" )
772810 self .add_title_description (to_translate , explicit_date_filter_title , None )
773811
@@ -808,9 +846,15 @@ def get_texts_to_translate(
808846 to_translate .add (item ["measure" ]["alias" ])
809847 for dashboard in workspace_content .analytics .analytical_dashboards or []:
810848 self .add_title_description (to_translate , dashboard .title , dashboard .description )
811- # Extract date filter titles for translation
849+ # Extract date filter titles for translation (top-level + tabs)
812850 self ._extract_dashboard_date_filter_titles (to_translate , dashboard .content )
813- for section in dashboard .content ["layout" ]["sections" ]:
851+ # Extract tab titles for translation
852+ for tab in dashboard .content .get ("tabs" , []):
853+ tab_title = tab .get ("title" )
854+ if tab_title :
855+ to_translate .add (tab_title )
856+ # Iterate sections from both top-level layout and tabs
857+ for section in self ._iter_dashboard_sections (dashboard .content ):
814858 for item in section ["items" ]:
815859 widget = item ["widget" ]
816860 title = widget .get ("title" )
@@ -877,8 +921,12 @@ def set_translated_texts(
877921 item ["measure" ]["alias" ] = translated [item ["measure" ]["alias" ]]
878922 for dashboard in new_workspace_content .analytics .analytical_dashboards or []:
879923 self .set_title_description (dashboard , translated )
924+ # Translate tab titles
925+ for tab in dashboard .content .get ("tabs" , []):
926+ if "title" in tab and tab ["title" ]:
927+ tab ["title" ] = translated .get (tab ["title" ], tab ["title" ])
880928 # Hack: translate titles in free-form, which is not processed intentionally by this SDK
881- for section in dashboard .content [ "layout" ][ "sections" ] :
929+ for section in self . _iter_dashboard_sections ( dashboard .content ) :
882930 for item in section ["items" ]:
883931 if "title" in item ["widget" ]:
884932 item ["widget" ]["title" ] = translated .get (item ["widget" ]["title" ])
0 commit comments