fix(harmonia): print language dialog must always show for multiple templates#6129
Merged
Conversation
…mplates The multilingual feature made openPrint auto-print the configured Region & Language when a template for it exists. The locale store ALWAYS resolves to a value (en by default, even untouched), so with 2+ templates the language dialog became unreachable - uploading a bg template gave no way to pick it. Several templates now ALWAYS open the dialog; the configured language is only pre-sorted first as the suggested default. Single/zero template behavior unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pattern-less numeric fallback used the DecimalFormat literal '##0' inside the Velocity-rendered report.js.template. Velocity treats two hashes as a line comment, so it swallowed the rest of the line including the closing quote - the generated report.js carried an unterminated string, failed to parse, reportPage never registered, and every report page rendered blank with Alpine expression errors. '0' formats identically in displayNumber (0 decimals, no grouping) and carries no Velocity-significant characters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… Settings The picker previously existed only in each generated app's own Settings page (and only when that app's intent declares 2+ languages), so the shared application shell at /services/web/application/ had no visible place to switch the data language. The shell's Settings master pane now offers the same Region & Language select, backed by the shared locale store (localStorage codbex.harmonia.language, sent as Accept-Language by every app's fetch client). The offered codes are the union of the languages the embedded apps declare in their generated js/config.js (read with a targeted match - the config is a JS file); hidden while only one language is known. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… per module The Region & Language design was inverted: each module's intent declared what languages the picker offers, so an app declaring only 'en' hid the picker and a 5-language module next to an en-only one could not work. Corrected contract: - The PLATFORM defines the supported set: DIRIGIBLE_APPLICATION_LANGUAGES (DirigibleConfig + Configuration allow-list), default 'en,bg', served by the new platform-core/services/application-languages.js. - The shared locale store fetches that set; every Region & Language picker (shared application shell + generated per-app Settings) always offers exactly the platform set. - A module's intent 'languages:' only declares which languages it PROVIDES translations for (config.js semantics reworded accordingly). Untranslated content falls back to the default language naturally (the Translator overlays only existing _LANG rows). - The shared application shell's Settings lists every module missing a platform language as a visible warning - the developers' to-do list for adding translation content. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…th a detail page Instead of an inline picker above the settings list, Region & Language is now a built-in entry in the Settings master list (globe icon, selectable like the app-provided setting entities). Selecting it renders a local detail page in the right pane: description of the platform-wide language preference, the language select (the platform's supported set), and the missing-translations warnings per module. Deep-linkable as #/settings/region-language via the pseudo setting item. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generated Harmonia views baked English labels as literals, so
switching Region & Language translated only the data, never the UI.
Labels now translate by REUSING the AngularJS stack's i18n backbone
end-to-end - nothing new server-side:
- i18next (the existing webjar), the locales.js extension service that
aggregates every project's translations/<locale>/*.json from the
registry, the platform-locales + application-locales locale registry,
and the same catalogs/keys the 'translate' generation action already
emits (namespace = project, path = <tprefix>.t.<DATA_NAME> /
.defaults.* / .messages.*).
- New shared consumer application-core shell/js/services/i18n.js:
self-loads i18next, fetches the catalogs (all registered locales, own
project namespace), resolves the 2-letter platform code to a locale id
(en -> en-US), exposes a reactive Alpine 'i18n' store + global
T(key, fallback, options). In the default language the baked literal
always wins (it is the prettier authored label); in other languages a
missing key degrades per-key to the English literal. locale.set()
reloads the page so labels and data switch together.
- All generated view templates (manage list/form, document, master,
list, shell sidebar/dashboard/settings, detail registry metadata via
tkey) bind labels as T('<project>:<tprefix>...', 'Fallback') - keys
identical to the AngularJS stack, so one translations/<locale> folder
serves both stacks. translations.json.template gains the few keys the
Harmonia views need beyond the AngularJS set (new/retry/all/
clearFilters/previous/next/details/selectTitle/back/backToList,
noDataYet/getStarted/inputSelect, error.saving).
Verified by generating the multi-model sales-invoices model through the
updated templates: all 67 files render, every generated JS parses, keys
and fallbacks correct; the locales service returns the bg-BG catalogs
(project translations/bg-BG/*.json) with English (US) fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
integration-tests-postgresql failed DependsOnIT at PredefinedProjectIT.test:28 - the 'Published all projects in' toast was not found in any iframe. Same failure mode as the regenerate-toast flake fixed in EdmView (#6127): on slow CI runners the Selenide cross-frame text sweep outlasts the transient toast, and the sweep's timeout fallback reloads the page, destroying the toast for good while the publish itself succeeded. Workbench.publishAll now waits for the DURABLE effect - every workspace project appearing under /registry/public - via IRepository + Awaitility, then proceeds to the existing synchronization wait. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s, Dashboard, Settings
The generated per-project shell and the shared application shell now
translate their own chrome, completing the label-i18n story: sidebar
entries and section headings (Application/Entities/Reports/Other),
built-in Inbox / Documents / Dashboard / Settings / Reports / not-found
pages, notifications popover, user menu, and breadcrumb Create/Edit.
The platform ships its own catalog pair: application-core/translations/
{en-US,bg-BG}/shell.json (namespace 'application-core', root 'shell') -
the locales.js service aggregates any registry module's translations
folder, so no service change was needed. i18n.js now always requests the
'application-core' namespace alongside the hosting app's project
namespace. Adding a platform language = adding one shell.json file.
Backward safety: apps generated before label i18n load the shared views
(which now bind through T()) without services/i18n.js - the always-loaded
shared app.js defines a fallback-returning T() stub that i18n.js
overwrites, so old apps keep rendering English instead of throwing.
Verified: locales service returns the bg shell catalog (nav.inbox =
'Входящи'); smoke generation over the updated shell templates renders
all chrome keys with English fallbacks and every generated JS parses.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
delchev
added a commit
that referenced
this pull request
Jul 3, 2026
…es a busy cycle Two regressions from the publish-toast replacement (#6129) turned master red on the DB matrices: - StoreAPISampleProjectIT / ExtensionDecoratorSampleProjectIT: the durable-effect check only required the project COLLECTION to exist in /registry/public, but publish copies file by file - the check passed on half-published projects and the tests hit 'JS source could not be found, consider publishing it'. Workbench.publishAll now waits until every workspace file exists in the registry (dot-folders like a cloned project's .git excluded - synchronizers never read them). - DependsOnIT: SynchronizationUtil's 30s bound is too tight right after a full publish, when the synchronizer legitimately chews through the freshly copied projects for longer on the loaded PostgreSQL/MSSQL runners. Raised to 120s - an at-most bound only affects failing runs. Both previously failing tests pass locally with the fix (StoreAPISampleProjectIT 59.9s, DependsOnIT 60.9s, headless H2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Regression from #6125:
openPrintauto-printed the configured Region & Language when a template for it exists — but the locale store always resolves to a value (enby default, even if the Settings picker was never touched), so with 2+ templates the language dialog became unreachable. Uploading abgtemplate gave no way to select it.Fix: several templates → always open the dialog; the configured language is only pre-sorted first as the suggested default. Single-template direct print and the zero-template 404 path are unchanged.
🤖 Generated with Claude Code