Skip to content

Fix #5652 - Runtime i18n Loading for Theme Translations (no build-time merge for i18n files)#5653

Open
kanasznagyzoltan wants to merge 2 commits into
DSpace:mainfrom
qultoltd:QREPO-405-Runtime-i18n-Loading-for-Theme-Translations
Open

Fix #5652 - Runtime i18n Loading for Theme Translations (no build-time merge for i18n files)#5653
kanasznagyzoltan wants to merge 2 commits into
DSpace:mainfrom
qultoltd:QREPO-405-Runtime-i18n-Loading-for-Theme-Translations

Conversation

@kanasznagyzoltan
Copy link
Copy Markdown
Contributor

References

Description

Make the i18n TranslateLoader theme-aware: instead of relying on the build-time merge-i18n script, theme-specific translation overrides are now loaded and merged at runtime from each configured theme's assets/<theme>/i18n/<lang>.json5, following the theme extends chain. This allows a single Docker image to serve multiple customers/themes with their own translations.

Instructions for Reviewers

List of changes in this PR:

  • src/ngx-translate-loaders/translate-server.loader.ts — After reading the base i18n file (dist/.../assets/i18n/<lang>.<hash>.json), the loader now overlays every configured theme's dist/.../assets/<theme>/i18n/<lang>.json5 on top, in inheritance order (ancestor first, descendant last, so child theme keys win). The merged map is stored in NGX_TRANSLATE_STATE so the browser does not need to re-fetch theme overrides after SSR.
  • src/ngx-translate-loaders/translate-browser.loader.ts — When the TransferState is empty (CSR / dev mode), the browser loader now fetches the base i18n file plus each configured theme's override JSON5 file via HTTP and merges them client-side using JSON5.parse. Missing override files are tolerated via catchError.
  • Shared resolveThemeLoadOrder() helper added to both loaders. It walks each configured theme's extends chain (using NamedThemeConfig.extends) up to the root ancestor, then emits themes in ancestor → descendant order with deduplication and cycle protection. The algorithm mirrors the existing component-level inheritance resolution in src/app/shared/theme-support/themed.component.ts:resolveThemedComponent.
  • No API or configuration changes. Themes that do not ship assets/<theme>/i18n/*.json5 files are simply ignored (non-existing file → empty object → no effect on the merged result). Existing setups that still run merge-i18n continue to work unchanged.

How it works

Given a config like:

themes:
  - name: custom-child
    extends: custom-parent

…and i18n files at:

src/assets/i18n/hu.json5                       (base)
src/themes/custom-parent/assets/i18n/hu.json5          (parent overrides)
src/themes/custom-child/assets/i18n/hu.json5            (child overrides)

…the loader merges them at runtime in the order base → custom-parent→ custom-child, so custom-child keys override custom-parent keys, which override base keys. If custom-child does not define a key, the user falls back to custom-parent's value, then to base.

How to test

  1. Make sure src/assets/i18n/<lang>.json5 files contain only the upstream/base content (no merged theme content).
  2. Do not run npm run merge-i18n.
  3. Place theme-specific overrides in src/themes/<theme>/assets/i18n/<lang>.json5.
  4. Build and run:
  5. Open the home page and verify:
    • Theme-specific keys render the override value defined in the theme's i18n file.
    • Switching language still uses the theme override for that language.
    • Keys not overridden by the theme fall back to the base translation.
  6. Verify SSR: in DevTools Network, the initial HTML request should already contain the translated text; no extra request to /assets/<theme>/i18n/<lang>.json5 should fire on the first navigation (the merged map is hydrated from NGX_TRANSLATE_STATE).
  7. Verify CSR fallback: run npm run start:dev (no SSR) and confirm the loader fetches base + theme files via HTTP and merges them in the browser.
  8. Verify inheritance (optional): create a child theme that extends an existing one, override a key in the child, leave another key only in the parent — both should resolve correctly when the child theme is active.
  9. Verify no regression for setups without theme overrides: a project with no theme i18n files should behave identically to before this PR.

Checklist

This checklist provides a reminder of what we are going to look for when reviewing your PR. You do not need to complete this checklist prior creating your PR (draft PRs are always welcome).
However, reviewers may request that you complete any actions in this list if you have not done so. If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!

  • My PR is created against the main branch of code (unless it is a backport or is fixing an issue specific to an older branch).
  • My PR is small in size (e.g. less than 1,000 lines of code, not including comments & specs/tests), or I have provided reasons as to why that's not possible.
  • My PR passes ESLint validation using npm run lint
  • My PR doesn't introduce circular dependencies (verified via npm run check-circ-deps)
  • My PR includes TypeDoc comments for all new (or modified) public methods and classes. It also includes TypeDoc for large or complex private methods.
  • My PR passes all specs/tests and includes new/updated specs or tests based on the Code Testing Guide.
  • My PR aligns with Accessibility guidelines if it makes changes to the user interface.
  • My PR uses i18n (internationalization) keys instead of hardcoded English text, to allow for translations.
  • My PR includes details on how to test it. I've provided clear instructions to reviewers on how to successfully test this fix or feature.
  • If my PR includes new libraries/dependencies (in package.json), I've made sure their licenses align with the DSpace BSD License based on the Licensing of Contributions documentation.
  • If my PR includes new features or configurations, I've provided basic technical documentation in the PR itself.
  • If my PR fixes an issue ticket, I've linked them together.

@lgeggleston lgeggleston added improvement i18n / l10n Internationalisation and localisation, related to message catalogs code task themes labels May 13, 2026
@lgeggleston lgeggleston moved this to 🙋 Needs Reviewers Assigned in DSpace 10.0 Release May 13, 2026
@lgeggleston
Copy link
Copy Markdown

Hi @kanasznagyzoltan, thank you for this PR! Since this would probably qualify as an improvement to build process rather than a new user feature, I added it to the 10.0 project to start. However since we're close to the May 22 code freeze, this will likely go towards a later release unless reviews are very quick for it.

@lgeggleston lgeggleston added the needs documentation PR is missing documentation. All new features and config changes require documentation. label May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code task i18n / l10n Internationalisation and localisation, related to message catalogs improvement needs documentation PR is missing documentation. All new features and config changes require documentation. themes

Projects

Status: 🙋 Needs Reviewers Assigned

Development

Successfully merging this pull request may close these issues.

Runtime i18n Loading for Theme Translations (no build-time merge for i18n files)

2 participants