Skip to content

feat: add project-wide i18n support - #209

Open
NAO-200 wants to merge 124 commits into
devfrom
feat-155-project-33-i18n
Open

feat: add project-wide i18n support#209
NAO-200 wants to merge 124 commits into
devfrom
feat-155-project-33-i18n

Conversation

@NAO-200

@NAO-200 NAO-200 commented May 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds UI internationalization (English + German): shared locale JSON, vue-i18n on the frontend, i18n error keys on the backend, and per-user UI language stored in the DB.

Also fixes #251 (users could override protected system settings via appSettingSet) and implements #250 (optional restriction of language selection per role).


Changes

  • utils/modules/i18n/ — EN/DE catalogs; i18n-bundles.js bundles namespaces for vue-i18n (renamed from messages.js); backend uses catalogs for logs.
  • Frontend: $t / i18n-t, resolveApiMessage, translateMaybeKey, formatLocalized* for dates
  • Backend: TranslatableError, structured { key, params } in socket responses
  • Backend English output: translateMaybeKey in backend/utils/i18n.js
  • Transform migrations: DB seed strings → i18n keys (settings, placeholders, templates, …)
  • UI language: app.locale in setting (default) + user_setting (per user); logged-in users read merged appSettings from server, with localStorage (locale) until settings load, fallback en; auth pages use browser language and clear cache when logged out; save via Preferences → appSettingSet + cache; App.vue applies locale on appSettings; helpers in locale.js + utils.js
  • Docs: docs/source/for_developers/i18n.rst with developer patterns and docs/source/for_researchers/interface_language.rst for researchers

Out of scope

Not fully done in this branch:

  • Workflows
  • Settings dashboard
  • Setup wizard (SetupWizard, components/wizard/*)
  • User rights UI (RoleManagementModal, …)
  • Some admin-only dashboards/modals
  • Assignments / Submissions cluster
  • Unify utils/modules/i18n/index.js and backend/utils/i18n.js — works as-is, duplication only in helper code

#250 — Restrict language selection

New right: frontend.preferences.disableLanguageSelection (default on Guest).

  • Hides language block in Preferences
  • Blocks saving app.locale via appSettingSet (non-admin)
  • Admins unaffected; can still set locale for users

#251 — Security: system settings override

Users could write any key to user_setting and shadow system setting values.

  • New column setting.allowUserOverride (default false; true only for allowed keys like app.locale, projects.default, …)
  • user_setting beforeCreate / beforeUpdate hooks reject protected keys
  • Admins bypass via bypassSystemSettingCheck when setting prefs for users

@NAO-200 NAO-200 self-assigned this May 18, 2026
@karimouf

Copy link
Copy Markdown
Collaborator

There were a lot of files changed, very hard to look at everything, but in general looks fine from my point of view. Don't forget to add docstrings and specify which files you said were incorrectly merged

NAO-200 added 5 commits July 28, 2026 00:32
Remove EN/DE keys with no frontend or backend references to shrink catalogs and reduce unused-key noise.
Rename setting:/users: to settingLabel/usersLabel for scanner-friendly keys, and remove unused modalTitle props that BasicCoordinator no longer accepts.
Pass localized copy/download/send labels via tooltip so icon-only buttons do not render title as visible text over the skill name.
Replace plain Error("ns.key") with TranslatableError so socket/HTTP errors go through the typed i18n path instead of legacy message keys.
@NAO-200
NAO-200 force-pushed the feat-155-project-33-i18n branch from 9a1f7fa to c201eaf Compare August 1, 2026 14:27
Comment thread backend/db/migrations/20260530150000-add-setting-app-locale-display.js Outdated
Comment thread backend/db/models/document.js Outdated
Comment thread backend/db/models/user_setting.js
Comment thread backend/webserver/sockets/document.js Outdated
Comment thread frontend/src/components/editor/sidebar/History.vue Outdated
Comment thread backend/utils/i18n.js
return result;
}

function loadTranslations() {

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.

flattenObject, interpolate, and hasKey are already implemented in utils/modules/i18n/index.js, the shared module this PR adds. Use it directly instead: const { t, hasKey, messages } = require('../../utils/modules/i18n');.

@NAO-200 NAO-200 Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, the duplication is real.
This split came from TPSE: shared JSON catalogs, frontend via Vite/ESM (i18n-bundles.js), backend via fs in backend/utils/i18n.js. utils/modules/i18n/index.js looks like an intended shared entry, but Node can’t require it as is because en/index.js is ESM, so the backend helper stayed separate. I’m not sure whether that was intentional or leftover.
Unifying the helpers needs a small refactor. I’d keep this PR on finishing the i18n port and track that in #273, unless you want it in scope here.

@NAO-200
NAO-200 requested a review from dennis-zyska August 8, 2026 20:59
return;
}

const systemSetting = await Setting.findOne({

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 think this should use the MetaModel.getByKey instead of findOne directly.


.. code-block:: javascript

const { TranslatableError } = require("../utils/TranslatableError");

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 think the brackets { TranslatableError } here will cause the import to be deconstructed which will cause the direct class export of TranslatableError.js:75 to be deconstructed which will return undefined and cause a TypeError when instantiated with new ...

As far as i can tell the import is done correctly in the actual code, but here in the docs the { } brackets are added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants