Skip to content

Offer "Pseudo-English" (qps-ploc) as a UI language for i18n testing (BL-16748) - #8283

Draft
andrew-polk wants to merge 1 commit into
masterfrom
BL-16748-pseudo-english
Draft

Offer "Pseudo-English" (qps-ploc) as a UI language for i18n testing (BL-16748)#8283
andrew-polk wants to merge 1 commit into
masterfrom
BL-16748-pseudo-english

Conversation

@andrew-polk

@andrew-polk andrew-polk commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Problem

Nothing in Bloom shows which on-screen strings actually go through localization. A hard-coded string, a mangled placeholder, a label the layout will clip once the text grows — all of it looks fine in English, and only surfaces when a translator or a user in another language hits it.

What the PR does

On the developer and alpha channels, the UI Language menu now offers Pseudo-English (i18n test). L10NSharp 10.1.0-beta0001 transforms the live English at lookup time for the standard qps-ploc pseudo-locale — each vowel doubled and accented, the whole string bracketed, so Title Missing becomes [Tîitlée Mîissîing]. A tester then reads the problems straight off the screen: plain English means the string was never internationalized, a visible {0} or %0 means a broken placeholder, a missing ] means truncation, brackets mid-sentence mean the sentence is concatenated at runtime, and clipped layout means we can't absorb the ~30–40% growth real translations bring. No qps-* translation files exist or are ever written.

  • Program.SetUpLocalization turns the locale on for the developer and alpha channels only, and GetDesiredUiLanguage falls back to English if a build that doesn't offer the locale nonetheless finds qps-ploc stored, so nobody is left with a mangled UI and no menu entry to escape it.
  • WorkspaceView names the locale itself (Palaso's language-name lookup has nothing useful to say about a pseudo-locale) and puts it last in the menu rather than sorting it among real languages.
  • I18NApi pseudolocalizes the English fallback it returns for ids that aren't in the English XLIFF. Without this those come back as plain English and are indistinguishable from hard-coded text, which defeats the exercise.
  • The locale is excluded from the two places where the list of available localizations feeds book data rather than the UI: the pre-translated content TranslationGroupManager writes into a new book, and the hint-bubble language chooser.
  • Several UI strings mark their hyperlink words with [square brackets]. Because pseudo-localization brackets the whole string as well, the five parsers that took the first [ and the next ] swallowed the sentence into the link and ate the wrapper — making those strings look un-internationalized, which is the one thing the locale must never get wrong. A shared findLinkTextBrackets() now anchors on the first ] and takes the nearest [ before it (the innermost pair, correct in both plain and pseudo-localized text), and the markdown link regex no longer allows [ inside link text.
  • DistFiles/localization/README.md documents that the locale is runtime-derived, that no qps-* XLF should ever exist, and which surfaces stay plain English on purpose (the whole-file localizations — template readmes, help pages, xmatter descriptions), so the tester's rule stays exact. switchWorkspaceTab.mjs gets a label-independent fast path, since matching a tab by its visible English label fails under this locale.

Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-16748

Devin review


This change is Reviewable

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds the L10NSharp qps-ploc pseudo-locale as a developer/alpha-only UI language for finding internationalization and layout defects.

  • Gates pseudo-localization by release channel and normalizes carried-over settings to English on unsupported channels.
  • Adds pseudo-locale naming, menu placement, and fallback-string transformation.
  • Excludes the pseudo-locale from book-content translation generation and hint-language authoring.
  • Adds language-independent workspace-tab automation selectors, documentation, and focused tests.

Important Files Changed

Filename Overview
src/BloomExe/Program.cs Configures pseudo-localization before localization-manager initialization and safely falls back to English on channels where it is unavailable.
src/BloomExe/Workspace/WorkspaceView.cs Adds a stable pseudo-locale label and places it last in the language menu while preserving existing selection behavior.
src/BloomExe/web/I18NApi.cs Applies pseudo-localization to English fallback responses that bypass normal L10NSharp lookups, while excluding numeric IDs.
src/BloomExe/Book/TranslationGroupManager.cs Prevents the testing-only pseudo-locale from generating persisted translated content in books.
src/BloomExe/web/controllers/CommonApi.cs Excludes qps-ploc from the language chooser used to author persistent hint content.
src/BloomBrowserUI/react_components/TopBar/TopBar.tsx Adds a stable language-independent data attribute to workspace tabs for automation.
.github/skills/bloom-automation/switchWorkspaceTab.mjs Prefers the new stable workspace-tab selector while retaining legacy label-based fallbacks.
src/BloomTests/Workspace/PseudoLocalizationTests.cs Covers pseudo-locale naming/completeness and non-development channel gating, though not the I18N fallback branches.
src/BloomExe/BloomExe.csproj Upgrades L10NSharp to the beta version providing runtime pseudo-localization support.

Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/mas..." | Re-trigger Greptile

@andrew-polk

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5 (1M context) during preflight] Consulted Devin on 2026-09-02 18:29 UTC up to commit c64f5ade54ef2a5c3c2a23bc14a8d658319b37d7.

Clean: no bugs, no Investigate flags, no informational items. Nothing to mirror.

@andrew-polk
andrew-polk force-pushed the BL-16748-pseudo-english branch from c64f5ad to a436f8e Compare September 2, 2026 22:15
@andrew-polk
andrew-polk marked this pull request as ready for review September 2, 2026 22:16
@andrew-polk
andrew-polk force-pushed the BL-16748-pseudo-english branch 3 times, most recently from d9a2a3e to 41ba906 Compare September 11, 2026 17:58
@andrew-polk
andrew-polk marked this pull request as draft September 11, 2026 18:38
andrew-polk added a commit that referenced this pull request Sep 11, 2026
SetUpLocalization normalizes a stored qps-ploc to English on channels that
don't offer the locale, but it runs at Program.cs:228 and the previous
version's settings are migrated at :380 — and that migration ends in
Reload(), which throws the normalized value away. A tester who picked
Pseudo-English in an alpha would then hit the ungated
SetUILanguage(Settings.Default.UserInterfaceLanguage) further down and get a
release build with a mangled UI and no menu entry to escape it, which is the
exact outcome the guard exists to prevent.

Extract the guard as RefusePseudoLocaleWhereNotOffered and re-apply it right
after the migration, where it covers both later SetUILanguage calls. It is a
no-op when no migration happened or when the channel does offer the locale.

Found by Devin on PR #8283.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread src/BloomExe/Program.cs Outdated
Comment thread src/BloomExe/Program.cs
Comment thread src/BloomBrowserUI/react_components/TopBar/TopBar.tsx
@andrew-polk

andrew-polk commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5 (1M context) from Andrew Polk's machine during preflight] Consulted Devin on 2026-09-11 18:53 UTC up to commit db7c2aa9c1.

It raised one Bug and two Investigate flags, each its own resolved thread:

  • Release startup restores hidden pseudo-localenot an issue; the fix it prompted has been reverted. The finding assumes a Release build can inherit an Alpha's settings, and it cannot: settings are stored per Bloom<channel> product folder and the previous-version search never leaves the running build's own folder. Reasoning on the thread.
  • PR bypasses required release branch — not an issue; targeting master was already decided and is recorded on BL-16748. (thread)
  • Automation selector description is stale — correct, and the PR description was rewritten; the code was always right. (thread)

No Informational items either round. CI (pr-automation) is green.

Note the branch has since been collapsed to a single commit, so db7c2aa9c1 is no longer on it.

…BL-16748)

We have no way to see which of Bloom's on-screen strings actually go through
localization. A hard-coded string, a mangled placeholder, a label the layout
clips once it grows -- all of it looks fine in English, and only surfaces when
a translator or a user in another language hits it.

On the developer and alpha channels the UI Language menu now offers
"Pseudo-English (i18n test)". L10NSharp 10.1.0-beta0001 transforms the live
English at lookup time for the standard qps-ploc pseudo-locale -- each vowel
doubled and accented, the whole string bracketed, so `Title Missing` becomes
`[Tiitlee Miissiing]`. A tester reads the problems straight off the screen:
plain English means the string was never internationalized, a visible {0} or
%0 means a broken placeholder, a missing ] means truncation, brackets
mid-sentence mean the sentence is concatenated at runtime, and clipped layout
means we cannot absorb the ~30-40% growth real translations bring. No qps-*
translation files exist or are ever written.

- Program.SetUpLocalization turns the locale on for the developer and alpha
  channels only, and GetDesiredUiLanguage falls back to English if a build
  that does not offer it nonetheless finds qps-ploc stored.
- WorkspaceView names the locale itself, since Palaso's language-name lookup
  has nothing useful to say about a pseudo-locale, and puts it last in the
  menu rather than sorting it among real languages.
- I18NApi pseudolocalizes the English fallback it returns for ids that are not
  in the English XLIFF. Without this those come back as plain English and are
  indistinguishable from hard-coded text, which defeats the exercise.
- The locale is excluded from the two places where the list of available
  localizations feeds book data rather than the UI: the pre-translated content
  TranslationGroupManager writes into a new book, and the hint-bubble language
  chooser.
- Several UI strings mark their hyperlink words with [square brackets].
  Because pseudo-localization brackets the whole string as well, the five
  parsers that took the first [ and the next ] swallowed the sentence into the
  link and ate the wrapper -- making those strings look un-internationalized,
  which is the one thing this locale must never get wrong. A shared
  findLinkTextBrackets() now anchors on the first ] and takes the nearest [
  before it, and the markdown link regex no longer allows [ inside link text.
- DistFiles/localization/README.md documents that the locale is runtime
  derived, that no qps-* XLF should ever exist, and which surfaces stay plain
  English on purpose, so the tester's rule stays exact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@andrew-polk
andrew-polk force-pushed the BL-16748-pseudo-english branch from db7c2aa to 469e556 Compare September 11, 2026 21:13
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.

1 participant