Skip to content

Complete language support to all GUI tabs#873

Open
Ski90Moo wants to merge 18 commits into
openstudiocoalition:developfrom
Ski90Moo:develop
Open

Complete language support to all GUI tabs#873
Ski90Moo wants to merge 18 commits into
openstudiocoalition:developfrom
Ski90Moo:develop

Conversation

@Ski90Moo
Copy link
Copy Markdown

@Ski90Moo Ski90Moo commented May 10, 2026

Wraps user-facing string literals with tr() across all major tabs and adds a complete Spanish (es) translation file as proof of concept for multi-language support, addressing issue #680.

Tabs covered: Site/Weather Data, Construction Sets, Materials, Schedules, Thermal Zones, Space Types, Loads, Facility, HVAC Systems, Inspector panel IDD fields, Output Variables (1051 names), Simulation Settings, Measures, Run Simulation, and Results Summary.

Key patterns established:

  • tr() for compile-time strings in Q_OBJECT classes
  • QCoreApplication::translate(IDD/OutputVariables/TaxonomyCategories) for runtime strings from the OpenStudio SDK and taxonomy.xml
  • addItem(tr(Display), EnglishData) + currentData() for model-bound combo boxes where SDK values must stay in English
  • Bilingual display format for IDD fields and output variable names so engineers can cross-reference EnergyPlus documentation without switching the application language

translations/OpenStudioApp_es.ts grows from ~200 to 3017 entries.
New languages only require a new .ts file with no further C++ changes.

The exception is the Geometry tab HTML files (geometry_editor_start.html and geometry_preview.html) each contain a hardcoded JavaScript dictionary keyed by locale code. We could:

Option A — Keep the Geometry tab HTML as an exception requiring separate edits.

Option B — Improve the architecture (better): Have the C++ side inject the locale into the HTML page at load time via QWebEnginePage::runJavaScript(), and move the translations out of the HTML into the .ts file.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

Extra testing required

  • ScheduleFileInspector - especially the separator
  • VariablesTab

Ski90Moo and others added 4 commits May 4, 2026 15:21
Wraps all user-facing string literals in the three Schedules sub-tabs
(Schedule Sets, Schedules, Other Schedules) with Qt tr() calls to enable
multi-language support, addressing issue openstudiocoalition#680.

Files modified:
- ScheduleSetInspectorView: 12 section/field labels
- SchedulesView: 23 strings across ScheduleTabContent, ScheduleTabDefault,
  NewProfileView, DefaultScheduleDayView, SpecialScheduleDayView,
  ScheduleRuleView, ScheduleRulesetNameWidget, MonthView
- ScheduleFileInspectorView: 15 field labels and combo box items
- ScheduleDialog: 10 strings including runtime-appended values
- ScheduleDayView + .hpp: 6 button/label strings; adds
  Q_DECLARE_TR_FUNCTIONS to 3 QGraphicsItem subclasses for tooltip tr()
- ScheduleCompactInspectorView: 2 labels
- ScheduleConstantInspectorView: 2 labels
- ScheduleOthersController: 1 error message
- ScheduleOthersView: 3 sidebar type names via QCoreApplication::translate()
- MainRightColumnController: 9 sidebar nav strings via tr().toStdString()

Adds Spanish translations for all new strings to OpenStudioApp_es.ts.
Day-of-week single-letter buttons S/T marked unfinished pending source-level
disambiguation (tr("S", "Sunday") etc.).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…penstudiocoalition#680)

Wraps user-facing string literals with tr() across all major tabs and
adds a complete Spanish (es) translation file as proof of concept for
multi-language support, addressing issue openstudiocoalition#680.

Tabs covered: Site/Weather Data, Construction Sets, Materials, Schedules,
Thermal Zones, Space Types, Loads, Facility, HVAC Systems, Inspector panel
IDD fields, Output Variables (1051 names), Simulation Settings, Measures,
Run Simulation, and Results Summary.

Key patterns established:
- tr() for compile-time strings in Q_OBJECT classes
- QCoreApplication::translate(IDD/OutputVariables/TaxonomyCategories)
  for runtime strings from the OpenStudio SDK and taxonomy.xml
- addItem(tr(Display), EnglishData) + currentData() for model-bound
  combo boxes where SDK values must stay in English
- Bilingual display format for IDD fields and output variable names so
  engineers can cross-reference EnergyPlus documentation without switching
  the application language

translations/OpenStudioApp_es.ts grows from ~200 to 3017 entries.
New languages only require a new .ts file with no further C++ changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…#680)

Adds Translation_GTest.cpp to the OpenStudioApp test target, covering:

Translation_ts suite (no build-path dependency, uses .ts source file):
- ValidXml: verifies OpenStudioApp_es.ts parses as well-formed XML
- HasExpectedContexts: checks all new translation contexts are present
  (IDD, OutputVariables, TaxonomyCategories, SimSettingsView, RunView, etc.)
- TranslationCountIsSubstantial: guards against accidental file truncation
- IddContextHasEntries: IDD context has >50 field-name translations
- OutputVariablesContextHasEntries: OutputVariables context has >=1000 entries
- TaxonomyCategoriesContextHasEntries: taxonomy categories are present

Translation_qm suite (requires compiled .qm, skipped gracefully if absent):
- QmFileLoads: QTranslator::load() succeeds for OpenStudioApp_es.qm
- SpanishSimSettingsStringsTranslated: spot-checks Simulation Settings labels
- SpanishRunViewStringsTranslated: spot-checks Run Simulation labels
- TaxonomyCategoriesTranslated: spot-checks library sidebar category names
- OutputVariablesSampleTranslated: spot-checks output variable name translations
- EnglishStringsReturnedWithoutTranslator: verifies English fallback when no
  QTranslator is installed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@Ski90Moo
Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request May 10, 2026
@macumber
Copy link
Copy Markdown
Collaborator

This is awesome @Ski90Moo! I will check this out!

@Ski90Moo
Copy link
Copy Markdown
Author

Thank you @macumber. It is rough, but a good start. I would like your feedback on the html issue.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands internationalization across the OpenStudio Application UI by wrapping user-facing strings with Qt translation APIs and adding a significantly more complete Spanish translation as a proof of concept (Issue #680). It also introduces tests to validate the .ts file structure/content and (optionally) runtime .qm translation loading.

Changes:

  • Wrapped many GUI string literals in tr() / QCoreApplication::translate() across tabs, inspectors, and grid views.
  • Added bilingual display formatting for SDK-driven names (eg. Output Variables, IDD fields) to show Translated (English) when non-English.
  • Added a new translation-focused GTest suite and wired it into the app test target.

Reviewed changes

Copilot reviewed 98 out of 100 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/shared_gui_components/WorkflowView.cpp Translates “drop measure” placeholder text.
src/shared_gui_components/WorkflowController.cpp Translates section headers for measure categories.
src/shared_gui_components/OSGridController.cpp Translates “Custom” category label and apply-button text.
src/shared_gui_components/LocalLibraryView.cpp Translates tooltips/button labels in the local library footer.
src/shared_gui_components/LocalLibraryController.cpp Translates taxonomy category names at render time.
src/openstudio_lib/WindowMaterialSimpleGlazingSystemInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialShadeInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialScreenInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialGlazingRefractionExtinctionMethodInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialGlazingInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialGasMixtureInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialGasInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialDaylightRedirectionDeviceInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WindowMaterialBlindInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/WaterUseEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/VRFGraphicsItems.cpp Translates VRF drag/drop placeholder labels.
src/openstudio_lib/VariablesTabView.cpp Adds translated+bilingual output variable display and localized frequency display with English data values.
src/openstudio_lib/ThermalZonesTabView.cpp Translates main tab title.
src/openstudio_lib/ThermalZonesGridView.cpp Translates grid headers/categories via QCoreApplication::translate.
src/openstudio_lib/SteamEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/StandardsInformationMaterialWidget.cpp Translates standards/measure-tags labels.
src/openstudio_lib/StandardsInformationConstructionWidget.cpp Translates standards/measure-tags labels.
src/openstudio_lib/SpaceTypesTabView.cpp Translates main tab title.
src/openstudio_lib/SpaceTypesGridView.cpp Translates headers/categories/filter labels; some tooltips still hardcoded.
src/openstudio_lib/SpacesTabController.cpp Translates spaces sub-tab titles.
src/openstudio_lib/SpacesSurfacesGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SpacesSubtabGridView.cpp Translates filter labels; stores English keys in combo box data for SDK values.
src/openstudio_lib/SpacesSubsurfacesGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SpacesSpacesGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SpacesShadingGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SpacesLoadsGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SpacesInteriorPartitionsGridView.cpp Translates grid headers/categories.
src/openstudio_lib/SimSettingsTabController.cpp Translates “Simulation Settings” tab title.
src/openstudio_lib/ServiceWaterGridItems.cpp Translates tooltips and drop-zone placeholder text.
src/openstudio_lib/ScriptsTabView.cpp Translates “Measures” tab title and sync button strings.
src/openstudio_lib/SchedulesTabView.cpp Translates schedules sub-tab title.
src/openstudio_lib/SchedulesTabController.cpp Translates schedules sub-tab titles.
src/openstudio_lib/ScheduleSetInspectorView.cpp Translates schedule set inspector section labels.
src/openstudio_lib/ScheduleOthersView.cpp Translates “Schedule Others” type names returned to the list view.
src/openstudio_lib/ScheduleOthersController.cpp Translates unsupported-action message text.
src/openstudio_lib/ScheduleFileInspectorView.cpp Translates labels and attempts to translate separator choices (but bind() will overwrite).
src/openstudio_lib/ScheduleDialog.cpp Translates dialog labels and “None/unitless” strings.
src/openstudio_lib/ScheduleDayView.hpp Adds Q_DECLARE_TR_FUNCTIONS for QGraphicsItem subclasses to enable tr().
src/openstudio_lib/ScheduleDayView.cpp Translates schedule day UI strings/tooltips and keyboard prompt text.
src/openstudio_lib/ScheduleConstantInspectorView.cpp Translates labels (one includes leading whitespace in the source string).
src/openstudio_lib/ScheduleCompactInspectorView.cpp Translates labels.
src/openstudio_lib/RunTabView.cpp Translates run tab title, button/checkbox labels, and status text.
src/openstudio_lib/ResultsTabView.cpp Translates Results UI labels and some report names; “Custom Report N” uses concatenation.
src/openstudio_lib/ResultsTabController.cpp Translates “Results Summary” tab title.
src/openstudio_lib/RefrigerationGraphicsItems.cpp Translates refrigeration drop-zone placeholder text.
src/openstudio_lib/PeopleInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/OtherEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/OSItemSelectorButtons.cpp Translates toolbar button tooltips.
src/openstudio_lib/OSDropZone.hpp Changes default text arg to empty so ctor can apply translated default.
src/openstudio_lib/OSDropZone.cpp Applies translated default “Drag From Library” when text is empty.
src/openstudio_lib/OSDocument.cpp Translates left-side main tab button labels.
src/openstudio_lib/MaterialsView.cpp Translates materials category names returned to list view.
src/openstudio_lib/MaterialRoofVegetationInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/MaterialNoMassInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/MaterialInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/MaterialAirGapInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/LuminaireInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/LoopLibraryDialog.cpp Translates HVAC library dialog titles/buttons/system names.
src/openstudio_lib/LoadsView.cpp Translates loads category names returned to list view.
src/openstudio_lib/LightsInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/library/geometry_editor_start.html Adds an in-HTML Spanish translation dictionary + DOM rewrite for headings/paragraphs.
src/openstudio_lib/InternalMassInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/HVACSystemsTabView.cpp Translates main tab title.
src/openstudio_lib/HVACSystemsController.cpp Translates system selector entries and HVAC type labels; translates some drop-zone text.
src/openstudio_lib/HotWaterEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/GridItem.cpp Translates drop-zone placeholder and “Supply/Demand Equipment” labels.
src/openstudio_lib/GeometryTabController.cpp Translates geometry tab title and sub-tab titles.
src/openstudio_lib/GeometryPreviewView.cpp Injects locale into embedded web content; translates some UI strings.
src/openstudio_lib/GeometryEditorView.cpp Injects locale into embedded editor; translates most UI strings and some dialogs.
src/openstudio_lib/GasEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/FacilityTabView.cpp Translates facility tab title.
src/openstudio_lib/FacilityTabController.cpp Translates facility sub-tab titles.
src/openstudio_lib/FacilityStoriesGridView.cpp Translates grid headers/categories and filter label.
src/openstudio_lib/FacilityShadingGridView.cpp Translates grid headers/categories and uses English keys in filter combo data.
src/openstudio_lib/FacilityExteriorEquipmentGridView.cpp Translates grid headers/categories and view titles.
src/openstudio_lib/ElectricEquipmentInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/ConstructionsView.cpp Translates constructions category names returned to list view.
src/openstudio_lib/ConstructionsTabController.cpp Translates constructions sub-tab titles and main tab title.
src/openstudio_lib/ConstructionInternalSourceInspectorView.cpp Translates inspector labels and drop-zone text (and file gained a BOM).
src/openstudio_lib/ConstructionInspectorView.cpp Translates inspector labels and drop-zone text.
src/openstudio_lib/ConstructionFfactorGroundFloorInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/ConstructionCfactorUndergroundWallInspectorView.cpp Translates inspector labels (and file gained a BOM).
src/openstudio_lib/ConstructionAirBoundaryInspectorView.cpp Translates inspector labels and comments (and file gained a BOM).
src/openstudio_lib/BuildingInspectorView.cpp Translates building inspector labels.
src/openstudio_app/test/Translation_GTest.cpp Adds tests to validate .ts content and optionally .qm runtime translation.
src/openstudio_app/CMakeLists.txt Adds Translation_GTest.cpp to the test sources.
src/model_editor/InspectorGadget.cpp Adds bilingual IDD field display names with runtime translation lookup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/openstudio_lib/VariablesTabView.cpp
Comment thread src/openstudio_lib/ScheduleFileInspectorView.cpp
Comment on lines 1061 to 1064
checkbox->setToolTip(tr("Check to select all rows"));
connect(checkbox.data(), &OSSelectAllCheckBox::checkStateChanged, this, &SpaceTypesGridController::onSelectAllStateChanged);
connect(this, &SpaceTypesGridController::gridRowSelectionChanged, checkbox.data(), &OSSelectAllCheckBox::onGridRowSelectionChanged);
addSelectColumn(Heading(QString(SELECTED), false, false, checkbox), "Check to select this row", DataSource(allLoads, true));
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — all C++ hardcoded strings are now wrapped with tr():

  • SpaceTypesGridView.cpp tooltip was already tr()-wrapped earlier in the PR
  • GeometryEditorView.cpp "Debug" button label wrapped (commit d239658)
  • GeometryPreviewView.cpp Geometry Diagnostics checkbox tooltip wrapped (commit d239658)

The HTML geometry files (geometry_editor_start.html, geometry_preview.html) still contain untranslated JavaScript strings, but these require the QWebEnginePage::runJavaScript() injection approach — deferred to a follow-up PR by agreement with macumber.

Copy link
Copy Markdown
Collaborator

@macumber macumber May 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw some of tooltips translated

line 421: addSelectColumn(Heading(tr("All"), false, false, checkbox), tr("Check to select this row").toStdString());

but others not

line 1025: addSelectColumn(Heading(tr("All"), false, false, checkbox), "Check to select this row", DataSource(allLoads, true));

We should translate them all right?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I missed these, good catch. Spanish has some similarities to english, so I probably missed a few. I will go back through with something more obvious like Korean or Arabic.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — both instances now wrapped with tr(). The one macumber pointed out was corrected in commit 118457a1. Both uses now read tr("Check to select this row").toStdString().

Comment thread src/openstudio_lib/GeometryPreviewView.cpp Outdated
Comment thread src/openstudio_lib/GeometryEditorView.cpp Outdated
Comment thread src/openstudio_lib/ResultsTabView.cpp
Comment thread src/openstudio_lib/WindowMaterialSimpleGlazingSystemInspectorView.cpp Outdated
Comment thread src/openstudio_lib/ScheduleConstantInspectorView.cpp
Comment thread src/openstudio_lib/GeometryEditorView.cpp Outdated
//
// To add or refine translations: add entries to the IDD context in
// OpenStudioApp_<lang>.ts and recompile with lrelease — no C++ changes needed.
static QString iddFieldDisplayName(const std::string& englishName) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really cool, I just wonder how we will be able to maintain this. The Translation test could possibly loop over each IddObject and verify that there is an entry for each one?

Same concern for the OutputVariables

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was one my concerns as well. I did a handful of them, but I could imagine the list of these objects would be enormous and difficult to maintain. It also makes the .ts file huge; no small task for the language contributors to review. I envision it would be more of a reactionary process whereby the contributors review the general GUI stuff, but we would get feedback as users stumble upon poorly translated objects.

The OutputVariables should be complete though. I will look into modifying the Translation test.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. The OutputVariable gap is fixed — the original entries only had Zone X prefixed names, but outputVariableNames() returns bare names (e.g. Lights Electricity Energy). Added 359 bare-name entries auto-derived from the Zone translations, plus specific Site/Surface/People/Daylighting entries.

For IDD fields: all fields now have translations across all 18 language .ts files, generated via Claude API batch translation. Two complementary tools maintain coverage:

  • add_idd_skeleton.py — developer maintenance tool. Run after an SDK update to add skeleton entries for any new IDD fields, then run translate_skeleton.py to batch-translate them.
  • Translation_ts.IddCoverageAllLanguages GTest — uses IddFactory::instance() to enumerate every IddObject and its fields, then checks that each unique field name has a source entry in the IDD context of every OpenStudioApp_*.ts file. Fails with a per-language list of missing fields if any file is out of sync.

The test detects drift; the script fixes it. They run independently.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to add add_idd_skeleton.py and translate_skeleton.py to the pr?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in commit 44b3e7d7. The two scripts are now in the repo root:

  • add_idd_skeleton.py — scans OS_*_FieldEnums.hxx under the OpenStudio build tree to find field names not yet in the IDD context and inserts empty <message> skeleton entries. IDD directory is auto-detected by glob or passed as a CLI argument.
  • translate_skeleton.py — batch-translates those unfinished entries via the Anthropic Messages Batches API (reads ANTHROPIC_API_KEY from the environment).

The IddCoverageAllLanguages test added in this PR already provides the CI enforcement side: it loops over every IDD object's fields via IddFactory and fails if any field name is missing from the IDD context in a .ts file.

Comment thread src/openstudio_lib/library/geometry_editor_start.html Outdated
Comment thread translations/OpenStudioApp_es.ts Outdated
Comment thread src/openstudio_lib/MaterialsView.cpp Outdated
Comment thread src/openstudio_lib/ScheduleOthersView.cpp Outdated
Comment thread src/openstudio_lib/SchedulesView.cpp Outdated
Comment thread src/openstudio_lib/SpacesInteriorPartitionsGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesLoadsGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesShadingGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesSpacesGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesSubsurfacesGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesSubtabGridView.cpp Outdated
Comment thread src/openstudio_lib/SpacesSurfacesGridView.cpp Outdated
Comment thread src/openstudio_lib/SpaceTypesGridView.cpp Outdated
Comment thread src/openstudio_lib/ThermalZonesGridView.cpp Outdated
Comment thread src/openstudio_lib/library/geometry_preview.html Outdated
Comment thread src/openstudio_lib/ConstructionsView.cpp Outdated
Comment thread src/openstudio_lib/VariablesTabView.cpp Outdated
Comment thread src/openstudio_lib/VariablesTabView.cpp

auto* header = new DarkGradientHeader();
header->label->setText(item->name());
header->label->setText(QCoreApplication::translate("TaxonomyCategories", item->name().toUtf8().constData()));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be simplified?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The QCoreApplication::translate("TaxonomyCategories", ...) is required here because the translations are stored under the "TaxonomyCategories" context (not the class name). Even though LibraryTypeItemDelegate has Q_OBJECT, using plain tr() would resolve to context "openstudio::LibraryTypeItemDelegate" — a different bucket. Moving to tr() would require renaming all those context entries in every .ts file, which is out of scope here. We could add a Q_DECLARE_TR_FUNCTIONS(TaxonomyCategories) but that conflicts with the existing Q_OBJECT. Current verbosity is the correct trade-off.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mostly wondering if .toUtf8().constData() was needed?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, .toUtf8().constData() is required. QCoreApplication::translate() takes const char*, and item->name() returns a QString. The chain QString → .toUtf8() → QByteArray → .constData() → const char* is the standard Qt idiom — there is no shorter safe path (e.g. qPrintable() uses local-8-bit encoding rather than UTF-8, which can mangle non-ASCII taxonomy names on some systems).

To avoid repeating the pattern at every call site, it is now wrapped in a static helper (commit 251713b2):

static QString trTaxonomy(const QString& name) {
  return QCoreApplication::translate("TaxonomyCategories", name.toUtf8().constData());
}

The three call sites now read simply trTaxonomy(item->name()).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One additional note on the design: if either a new BCL taxonomy category or a new name under an existing category is added in the future, trTaxonomy() will still look up the name in the "TaxonomyCategories" context. If no entry exists in the .ts file for that name, Qt automatically falls back to displaying the English source string — so non-English users will see the untranslated name in plain English, which immediately signals that a new .ts entry is needed. No special detection logic is required; the gap is visible as soon as someone runs a non-English locale.

Comment thread src/shared_gui_components/OSGridController.cpp Outdated
@macumber
Copy link
Copy Markdown
Collaborator

This looks pretty good @Ski90Moo, thanks! I found a few anti-patterns I'd like to avoid, hopefully you can address those. I am also not sure if I like the approach for the html files, maybe we skip those for now?

I made an internal PR at #874 which seems to complete the build CI actions, maybe those are failing here because this is an external PR? In any case, you can fix the cppcheck and Clang Format failures on your PR.

@macumber
Copy link
Copy Markdown
Collaborator

One last question, did you get Claude to actually do the string translations, or just to add the tr wrappers throughout the app? Do you think Claude could do the string translations for all the languages?

Ski90Moo and others added 10 commits May 23, 2026 17:55
…penstudiocoalition#680)

- Expand language support from Spanish proof-of-concept to 18 languages:
  Arabic, Catalan, German, Greek, Persian, French, Hebrew, Hindi, Indonesian,
  Italian, Japanese, Korean, Polish, Portuguese, Turkish, Vietnamese,
  Simplified Chinese (new), plus Spanish
- Add Portuguese, Korean, Turkish, Indonesian to Preferences > Language menu
  with proper QAction wiring in MainMenu.cpp/.hpp
- Fix RTL layout direction: setLayoutDirection(RightToLeft) for ar/fa/he,
  reset to LeftToRight when switching away from RTL languages
- Enable Arabic in Language menu (was commented out)
- Translate ~7,000 strings per language via Claude Haiku Batches API:
  UI strings, IDD field names, and OutputVariable display names
- Fix apply_translations counter-shift bug: use same regex pattern as
  extract_unfinished so XML comments and <location/> tags don't cause
  wrong translations to be assigned to wrong source strings
- Escape HTML entities (bare <, >, & and named entities like &aacute;)
  in all translation files to produce valid XML for lrelease
- Add batch translation scripts: translate_all_languages.py,
  translate_new_languages.py, retranslate_stubborn.py, recover_batches.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oalition#680)

- Wrap hardcoded strings in GeometryEditorView.cpp (Debug button) and
  GeometryPreviewView.cpp (Geometry Diagnostics checkbox tooltip) with tr()
- Remove UTF-8 BOM from 27 inspector view .cpp files introduced by editor
- Run clang-format on all modified C++ files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Translation_ts.IddCoverageForAllFields GTest that loops over every
IddObject in the OpenStudio IDD (via IddFactory) and verifies each field
name has a corresponding source entry in the IDD translation context of
OpenStudioApp_es.ts.

When the SDK adds new IDD objects/fields and the .ts file is not updated,
the test fails with a list of missing field names. The fix is to run
add_idd_skeleton.py then translate_skeleton.py to restore coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…diocoalition#680)

Extend IddCoverageAllLanguages (renamed from IddCoverageForAllFields) to
iterate every OpenStudioApp_*.ts file in the translations directory rather
than only Spanish. For each language file the test independently extracts
the IDD context source strings and reports any field names missing from
that specific file, so drift after an SDK update is caught per-language.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion#680)

Adds translation_check.yml workflow that runs on every PR and push to
master/develop. After running lupdate6 with -locations none:

- git diff detects if any .ts file changed — meaning strings were added
  to or removed from the C++ source without the translation files being
  updated.
- ci/check_translations.py classifies the diff: new type="unfinished"
  stubs (new tr() calls needing translation) vs type="obsolete" entries
  (tr() calls removed from source). Reports actionable fix instructions
  for each case and exits 1 so CI fails.

If the diff is empty, all .ts files are in sync and CI passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Ski90Moo
Copy link
Copy Markdown
Author

All addressed:

  • Removed all #define MACRO tr(...) patterns across 13 grid view files — all column header strings are now inline tr() calls throughout
  • Changed return types in MaterialsView, ScheduleOthersView, and ConstructionsView to std::vector<std::pair<IddObjectType, QString>> with direct tr() calls
  • Reverted HTML geometry files — agreed to skip the in-HTML JavaScript approach for now and pursue the proper Qt injection approach in a follow-up PR
  • Copilot bugs fixed: signal connection order (VariablesTabView), dead pre-bind addItem() calls (ScheduleFileInspectorView), string concat → tr("Custom Report %1").arg(n) (ResultsTabView), leading space removed (ScheduleConstantInspectorView)
  • clang-format run on all 35 modified C++ files

@Ski90Moo
Copy link
Copy Markdown
Author

Yes — Claude did both the tr() wrapping and the translations. The batch API approach scales well: all 18 languages are now in this PR, generated via Claude Haiku Batches API at roughly $3–4 total cost. Each language gets ~7,000 translations covering UI strings, IDD field names, and OutputVariable display names. Adding a new language in the future is a one-command operation (translate_new_languages.py).

Languages added: Arabic, Catalan, German, Greek, Persian/Farsi, French, Hebrew, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Spanish, Turkish, Vietnamese, Simplified Chinese.

Ski90Moo and others added 3 commits May 23, 2026 22:20
…th tr()

- OSGridController: use tr() directly (class has Q_OBJECT, context matches)
- VariablesTabView: remove translate lambda, use QCoreApplication::translate
  with a named ctx string to avoid redefining tr in free function scope

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Explicit include required; cannot rely on transitive pulls from other Qt
headers on all build configurations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Not part of the project source; was accidentally committed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/openstudio_lib/ScheduleFileInspectorView.cpp
Comment thread src/openstudio_lib/HVACSystemsView.cpp Outdated

auto* singleZoneResetSPTitle = new QLabel(QString("Supply temperature is controlled by a <strong>%1</strong> setpoint manager.").arg(spmType));
auto* singleZoneResetSPTitle = new QLabel(
QCoreApplication::translate("openstudio::SingleZoneSPMView",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this, and the other instances in this file, be replaced by regular tr since it is already in class SingleZoneSPMView?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 251713b2. SingleZoneSPMView (and the 4 other view classes in that file — ScheduledSPMView, OAResetSPMView, AirLoopHVACUnitaryHeatPumpAirToAirControlView, NoSupplyAirTempControlView) are simple QWidget subclasses without signals/slots, so adding full Q_OBJECT would be unwarranted overhead. Instead, Q_DECLARE_TR_FUNCTIONS(openstudio::SingleZoneSPMView) was added to each class in HVACSystemsView.hpp — this macro provides tr() with the fully-qualified class name as context, matching the existing .ts file entries. All QCoreApplication::translate("openstudio::SingleZoneSPMView", ...) calls (and the equivalents for the other four classes) are now plain tr() in HVACSystemsView.cpp.

for (const auto& sst : subSurfacetypes) {
m_subSurfaceTypeFilter->addItem(sst.c_str());
QString key = sst.c_str();
m_subSurfaceTypeFilter->addItem(QCoreApplication::translate("openstudio::SpacesSubtabGridView", sst.c_str()), key);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this, and other instances in this file, be replaced by regular tr since they are in class SpacesSubtabGridView?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 251713b2. SpacesSubtabGridView has Q_OBJECT, so tr() resolves to context "openstudio::SpacesSubtabGridView" — matching the existing .ts entries. All five QCoreApplication::translate("openstudio::SpacesSubtabGridView", ...) calls are now plain tr(), and the now-unused #include <QCoreApplication> was removed.

@macumber
Copy link
Copy Markdown
Collaborator

Looks really good @Ski90Moo, I resolved all of my comments except for a couple, can you check them out?

Can you also run 'ci/clang-format.sh HEAD origin/develop to apply the clang format updates?

Finally, can you fix the cppcheck error [src/openstudio_app/test/Translation_GTest.cpp:47]:(style),[constVariable],Variable 'candidates' can be declared as const array?

I am going to do some testing, @jmarrec do you want to review and test before merging? My thought is that we can merge and then send out a link to test the next RC to all of the people who have shown interest in internationalization.

@Ski90Moo
Copy link
Copy Markdown
Author

Done — all three items addressed:

  • clang-format: ran ci/clang-format.sh HEAD origin/develop, corrected 20 files, committed in 251713b2.
  • cppcheck (candidates not const): fixed in 251713b2openstudio::path candidates[] is now const openstudio::path candidates[] at line 47 of Translation_GTest.cpp.
  • Unresolved review threads: checked and addressed all five — replies posted on each thread.

Ski90Moo added a commit to Ski90Moo/OpenStudioApplication that referenced this pull request May 26, 2026
Cross-referenced PR openstudiocoalition#874 (internal-branch duplicate of openstudiocoalition#873) and found
3 hardcoded strings not yet wrapped in our branch:

Source fixes:
- LocalLibraryView.cpp: QLabel("Measure") -> tr("Measure")
- LocalLibraryController.cpp: Python Measures Classic CLI tooltip -> tr()
- WorkflowController.cpp: same Python Measures Classic CLI tooltip -> tr()

Translation additions:
- 18 languages: new openstudio::LibraryItemView context (Measure),
  openstudio::LibraryItemDelegate and measuretab::MeasureStepItemDelegate
  contexts (Python CLI tooltip). "Measure" auto-filled by lupdate heuristic.

All 18 languages: 7209 finished translations, 0 unfinished, 0 vanished.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bring in tr() coverage for dialogs added since the last PR openstudiocoalition#873 update:
- Apply Measure Now, OSDialog buttons, Measure select prompt
- Online BCL / Find Measures, Find Components category tree (tid_api.xml)
- Component panel section headers and metadata row labels
- Sync Measures dialog, BCL taxonomy categories
- Change Default Libraries dialog
- Preferences > Change External Tools dialog
- Refrigeration, VRF, and other grid-view drop zone strings
- Measures sidebar labels, Python CLI tooltip
- Additional grid views across Facility, Spaces, Thermal Zones tabs

All 19 language .ts files updated; 0 unfinished entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants