Skip to content

Feat/profile switch language#1172

Merged
mwojtyczka merged 22 commits into
databrickslabs:mainfrom
lfbraz:feat/profile_switch_language
Jun 9, 2026
Merged

Feat/profile switch language#1172
mwojtyczka merged 22 commits into
databrickslabs:mainfrom
lfbraz:feat/profile_switch_language

Conversation

@lfbraz

@lfbraz lfbraz commented May 11, 2026

Copy link
Copy Markdown
Contributor

Changes

Linked issues

#1171

Tests

  • manually tested
  • added unit tests
  • added integration tests
  • added end-to-end tests
  • added performance tests

Documentation and Demos

Adds in-app language switching to DQX Studio, surfaced from the user's Profile page. The studio now ships with four locales (English, Portuguese-BR, Italian, Spanish) and persists the user's choice per-browser without touching server-side state.

Frontend — i18n infrastructure

  • Add i18next + react-i18next + i18next-browser-languagedetector to app/package.json.
  • New app/src/databricks_labs_dqx_app/ui/lib/i18n/index.ts bootstraps i18next with fallbackLng: "en", supportedLngs whitelist, and a detector chain of localStorage → navigator (cached under dqx.language).
  • Wire the bootstrap into app/src/databricks_labs_dqx_app/ui/main.tsx so translations are initialized before the router mounts.
  • Add four locale files under app/src/databricks_labs_dqx_app/ui/lib/i18n/locales/ (en.json, pt-BR.json, it.json, es.json) — keys mirror the existing UI copy across header, sidebar, profile, runs, rules, profiler, discovery, config, and labels surfaces.

Frontend — UI

  • New app/src/databricks_labs_dqx_app/ui/components/apx/LanguageSelector.tsx: shadcn Select showing each language by native label (with English label as secondary hint); on change it calls i18n.changeLanguage and updates document.documentElement.lang.
  • New Preferences card on app/src/databricks_labs_dqx_app/ui/routes/_sidebar/profile.tsx hosts the selector.
  • Replace hard-coded strings with t(...) calls across the sidebar routes (config.tsx, discovery.tsx, home.tsx, profile.tsx, profiler.tsx, rules.active.tsx, rules.create.tsx, rules.create-sql.tsx, rules.drafts.tsx, rules.import.tsx, rules.single-table.tsx, runs.tsx, runs-history.tsx, route.tsx) and shared components (HeaderUserMenu, PageBreadcrumb, SidebarLayout, SidebarUserFooter, mode-toggle, AICheckGenerator, AuthGuard, CatalogBrowser, ColumnDiscoveryPanel, CommentThread, DryRunResults, Labels, RoleManagement, RulesReview).
  • Behaviour preserved: this is a string-extraction refactor — no logic, routes, RBAC, or API contracts changed.

Docs

  • Add a Profile preferences → Language section to docs/dqx/docs/guide/dqx_studio.mdx covering supported locales, persistence behavior, scope (per-user, UI only), and a caution note that non-English translations are AI-generated and not yet reviewed by native speakers.

Notes for reviewers

  • Persistence is browser-local (localStorage); no backend or table changes.
  • No new dependencies in the Python wheel — frontend-only.
  • Non-English copy was AI-assisted; native-speaker review welcome (as I'm a Portuguese native speaker, I already reviewed all the PT-BR sections).

Images

profile-language-switch

main-page-dqx

  • added/updated demos
  • added/updated docs
  • added/updated agent skills

@lfbraz lfbraz requested a review from a team as a code owner May 11, 2026 20:39
@lfbraz lfbraz requested review from grusin-db and removed request for a team May 11, 2026 20:39

@ghanse ghanse left a comment

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.

Solid i18n landing — clean key parity across en/es/it/pt-BR, JSON validates, and every route I spot-checked routes user-facing strings through t(). Two functional gotchas to address before merge: (1) <html lang> is never synchronized when LanguageDetector picks a non-English locale on first load (a11y / screen-reader regression), and (2) rulesSingleTable.summary / duplicateChecksExist_* interpolate a hard-coded English "s" via {{tablesPlural}}/{{checksPlural}}/{{rulesPlural}} placeholders, which the non-English translators correctly dropped — producing a placeholder-count divergence and defeating proper pluralization.

Smaller items addressed inline: t in AuthGuard's effect deps, all four locales bundled eagerly (~262 KB raw), ~50 unused common.* keys. Recommend adding a make app-check script that asserts placeholder-set parity across locales to prevent this class of bug going forward.

Two follow-ups on pre-existing code that this PR makes newly relevant (not anchorable to the diff, hence here in the summary):

  • app/src/databricks_labs_dqx_app/ui/routes/_sidebar/config.tsx ~ lines 60 and 66Intl.DateTimeFormat("en-US", …) is hard-coded for two timezone-label formatters. Every user (including pt-BR / es / it) sees timezone short names (PST, CET) and offset formatting in English. Pass undefined (browser default) or i18n.language so this matches the rest of the UI. format-utils.ts already uses undefined, so this is the only outlier.
  • app/src/databricks_labs_dqx_app/ui/routes/_sidebar/rules.drafts.tsx:7 (also rules.active.tsx:54,148, runs-history.tsx:243) — the synthetic catalog label "Cross-table rules" is used both as an internal filter id and rendered to the user. With i18n in this PR, it should be translated at render time while keeping the internal id stable, e.g. cat === CROSS_TABLE_CATALOG ? t("common.crossTableRules") : cat. Most visible untranslated remnant.

Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/index.ts
Comment thread app/src/databricks_labs_dqx_app/ui/routes/_sidebar/rules.single-table.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/components/AuthGuard.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/components/apx/LanguageSelector.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/components/apx/LanguageSelector.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/index.ts Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/locales/en.json
Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/locales/en.json
@ghanse ghanse added the under-review This PR is currently being reviewed by one of DQX maintainers. label May 21, 2026
@CLAassistant

CLAassistant commented May 22, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
3 out of 4 committers have signed the CLA.

✅ lfbraz
✅ mwojtyczka
✅ ghanse
❌ berrybluecode
You have signed the CLA already but the status is still pending? Let us recheck it.

@lfbraz

lfbraz commented May 22, 2026

Copy link
Copy Markdown
Contributor Author

Hi @ghanse . Thanks for your review. I've tried to apply all the suggestions. Please let me know if they are OK or if there are any missing issues. I really appreciate your support!

@lfbraz lfbraz requested a review from ghanse May 26, 2026 14:08
@mwojtyczka mwojtyczka requested review from laurencewells and removed request for grusin-db June 2, 2026 16:26
Comment thread app/src/databricks_labs_dqx_app/ui/main.tsx
Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/index.ts
Comment thread app/src/databricks_labs_dqx_app/ui/components/apx/LanguageSelector.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/components/apx/LanguageSelector.tsx Outdated
Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/locales/it.json Outdated
@mwojtyczka

Copy link
Copy Markdown
Contributor

Hi @ghanse . Thanks for your review. I've tried to apply all the suggestions. Please let me know if they are OK or if there are any missing issues. I really appreciate your support!

@lfbraz thank you for the PR. I posted additional comments.

Comment thread app/package.json
@mwojtyczka mwojtyczka added the needs-changes Changes required after review label Jun 5, 2026
@mwojtyczka

Copy link
Copy Markdown
Contributor

Hi @lfbraz , could you please give me permission to push code to your folk as I would like to resolve the conflicts. Also, are there only three language added? We need to add more languages for the next step image

I think this is fine. We can have follow up PRs to add more languages

@mwojtyczka mwojtyczka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed after the latest round — thanks for the thorough fixes. Verified and resolved 13 of the 14 threads (a11y <html lang> sync, AuthGuard t ref, lazy-loading, useId/aria-label, locale-switch .catch, the blank-page .catch, the common.* cleanup, the Italian discovery translation, and the CLAUDE.md i18n section all check out; locale key sets are now at full parity — 1142 keys in each of the 4 files). Left the CI placeholder-parity-check thread open since that's a pending follow-up rather than a code fix.

One residual instance of the same plural anti-pattern from the (now-fixed) rules.single-table.tsx thread — flagged inline.

Comment thread app/src/databricks_labs_dqx_app/ui/lib/i18n/locales/en.json Outdated
@berrybluecode

berrybluecode commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

resolved the conflicts

Replace the {{tablesPlural}}/{{checksPlural}} placeholders in
rulesActive.tablesAndChecks and checksAcrossTables with native i18next
_one/_other fragment keys (tablesCount/checksCount) composed via nested
t() calls, matching the existing rulesSingleTable.summary pattern. This
fixes broken plurals in es/it/pt-BR (e.g. 'verificacións' -> proper
'verificaciones'). Keys added to all four locales; parity preserved.

Co-authored-by: Isaac
New pytest (runs under `make app-test`, no JS toolchain needed) asserts,
with en.json as source of truth, that every locale has:
  - the same key set (catches keys that silently fall back to English), and
  - the same {{placeholder}} set per key (catches missing/extra interpolation
    that triggers i18next missingInterpolation),
and that no locale uses a hard-coded {{*Plural}} placeholder (use native
_one/_other + {{count}} instead) — the anti-pattern fixed in 9830447, which
placeholder-set parity alone would not catch since all locales shared it.

Co-authored-by: Isaac

@mwojtyczka mwojtyczka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@mwojtyczka mwojtyczka added Approved to Merge When PR is reviewed and approved. To be merged once all tests pass and removed under-review This PR is currently being reviewed by one of DQX maintainers. needs-changes Changes required after review labels Jun 8, 2026
@lfbraz

lfbraz commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews, guys. Please let me know if you need anything else from my side at this time.

Fixes TS6133 'formatLabel is declared but its value is never read'
that broke the Build and Check App TypeScript compilation in CI.

Co-authored-by: Isaac
@mwojtyczka mwojtyczka merged commit 0ef9589 into databrickslabs:main Jun 9, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Approved to Merge When PR is reviewed and approved. To be merged once all tests pass

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants