Skip to content

fix(components): route UI text through the Flow string formatter - #3637

Open
ins0 wants to merge 2 commits into
mainfrom
fix/i18n-components-string-formatter
Open

ins0 wants to merge 2 commits into
mainfrom
fix/i18n-components-string-formatter

Conversation

@ins0

@ins0 ins0 commented Nov 4, 2026

Copy link
Copy Markdown
Member

Autocomplete, Notification, ProgressBar, LightBox, LightBoxGallery and LightBoxGalleryItem used react-aria's useLocalizedStringFormatter. It ignores TranslationProvider overrides and leaves ICU variables unevaluated. They now use Flow's hook from @/components/TranslationProvider.

  • Namespaces for TranslationProvider: Autocomplete, Notification, ProgressBar, LightBox. The gallery parts share the LightBox locale files, so they use LightBox too.
  • LightBoxGallery: aria-roledescription comes from the locale files (carousel / Karussell).
  • CodeEditor: the dotEnv lint diagnostics are localized (new CodeEditor/locales). Language loaders now receive the string formatter.
  • ProgressBar, DonutChart: without formatOptions, the value is formatted with the Intl unit percent in the active locale instead of `${value} %`. English reads 40%, German 40,5 %. ProgressBar had the same fallback as DonutChart, so it is fixed along with it.

FileCard's hard-coded en-US (also listed in #3423) is fixed in #3585, which is why FileSizeText is untouched here.

Visual changes

English renderings of ProgressBar and DonutChart lose the space before % (30 % → 30%). The baselines of the ProgressBar, DonutChart, SkeletonMode and IllustratedMessage scenarios need an update via update-screenshots.

Tests

All of them fail without the fix (checked by reverting the source changes):

  • TranslationProvider.browser.test.tsx › "a translation reaches the built-in text of" (one test per component)
  • CodeEditor.browser.test.tsx › "CodeEditor reports dotEnv diagnostics in the active locale"
  • LightBoxGallery.browser.test.tsx › "the gallery is announced as a carousel in the active locale"
  • ProgressBar.browser.test.tsx, DonutChart.browser.test.tsx › "the percentage follows the active locale", plus the updated English assertions

Closes #3423

Autocomplete, Notification, ProgressBar, LightBox, LightBoxGallery and
LightBoxGalleryItem used react-aria's useLocalizedStringFormatter, which
ignores TranslationProvider overrides and leaves ICU variables
unevaluated. They now use Flow's hook. Namespaces: Autocomplete,
Notification, ProgressBar and LightBox (the gallery parts share the
LightBox locale files).

LightBoxGallery's aria-roledescription comes from the locale files
("carousel" / "Karussell").

The dotEnv linter of CodeEditor reports its diagnostics in the active
locale (new CodeEditor locale files). Language loaders receive the
string formatter for that.

Without formatOptions, ProgressBar and DonutChart format their value
with the Intl unit "percent" in the active locale: "40%" in English,
"40,5 %" in German. The English output loses the space before "%".

FileCard's hard-coded en-US locale is fixed in #3585.

Closes #3423
@ins0
ins0 requested a review from a team November 4, 2026 07:30
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Coverage Report for ./packages/components/

Status Category Percentage Covered / Total
🔵 Lines 64.85% 1412 / 2177
🔵 Statements 64.31% 1451 / 2256
🔵 Functions 50.63% 318 / 628
🔵 Branches 58.94% 758 / 1286
File CoverageNo changed files found.
Generated in workflow #7549 for commit 72e43da by the Vitest Coverage Report Action

@ins0 ins0 added the update-screenshots Label a PR to update the screenshots used for visual regression testing label Nov 4, 2026
@github-actions github-actions Bot removed the update-screenshots Label a PR to update the screenshots used for visual regression testing label Nov 4, 2026
Co-authored-by: ins0 <2622534+ins0@users.noreply.github.com>
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

Preview environments are ready:

Type URL
docs pr-3637.docs.review.flow-components.de
storybook pr-3637.storybook.review.flow-components.de

Images:

  • docs: ghcr.io/mittwald/flow/docs:pr-3637
  • storybook: ghcr.io/mittwald/flow/storybook:pr-3637

@Lisa18289 Lisa18289 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The FileCard item of #3423 lands in #3585, which is still open and doesn't close the issue itself. If this merges first, #3423 closes with that item open. Could this say Part of #3423, and #3585 Closes #3423?

📐 Flow guideline: AGENTS.md › Development workflow · via /review-flow

Comment on lines +20 to +21
/** @internal */
export interface LocalizedStringFormatter {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

useLocalizedStringFormatter is public (public.ts → TranslationProvider/index.ts), but its new return type is @internal. With stripInternal: true in typescript-config/base.json, the published .d.ts references a type that isn't declared, so consumers get any (or TS2304 without skipLibCheck). test:compile stays green, so nothing catches it.

Suggested change
/** @internal */
export interface LocalizedStringFormatter {
export interface LocalizedStringFormatter {

showCodeIndentationMakers,
showLineNumbers,
showLinterMarkers,
stringFormatter,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

CodeEditor relies on extensions staying stable – a new array reconfigures CodeMirror. stringFormatter changes identity with the provider's translations/translate, so an app passing them inline (e.g. translations={{…}} at the root) now reconfigures the editor on every root render. Could the linter read the formatter from a ref instead, keeping it out of these deps?

This branch has not been deployed

No deployments
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.

i18n: components bypass the Flow string formatter or hard-code UI text

2 participants