Skip to content

Rework I18nManager: runtime forceRTL, no left / right swap - #59404

Open
zoontek wants to merge 14 commits into
react:mainfrom
zoontek:i18nmanager-relayout
Open

zoontek wants to merge 14 commits into
react:mainfrom
zoontek:i18nmanager-relayout

Conversation

@zoontek

@zoontek zoontek commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Summary:

This is a proposal to simplify / cleanup I18nManager. It contains multiple breaking changes, and it's obviously open to discussion.

I started working on it as the current API is messy / hard to grasp:

  • RTL support has two switches on Android (android:supportsRtl in the manifest and allowRTL at runtime) but only one on iOS (allowRTL), so the platforms do not match.
  • allowRTL, forceRTL and swapLeftAndRightInRTL are saved to disk and only take effect after a restart. They act as app configuration written from JS.
  • The left / right swap is on by default and has no equivalent on the web, where margin-left stays on the left in RTL and only logical properties (margin-inline-start) follow the direction.

This PR:

  • Makes forceRTL apply at runtime: surfaces relayout, and isRTL updates immediately (bridgeless only). The value is no longer persisted.
  • Removes the left / right swap. left / right are always physical, like on the web. Use start / end for direction-aware styles (already supported for a while).
  • Reads RTL support from app configuration: new RCTSupportsRTL in Info.plist on iOS, android:supportsRtl on Android (unchanged). true by default.
  • Deprecates allowRTL, swapLeftAndRightInRTL and doLeftAndRightSwapInRTL (no-ops with a warning).
  • Returns localeIdentifier on both platforms, in BCP 47 format (en-US) - same format as navigator.language on web.

Changelog:

[GENERAL] [BREAKING] - I18nManager: forceRTL applies at runtime and is no longer persisted, left / right styles are no longer swapped in RTL, allowRTL and swapLeftAndRightInRTL are deprecated
[IOS] [BREAKING] - RTL requires RCTSupportsRTL set to true in Info.plist
[ANDROID] [CHANGED] - I18nManager.getConstants().localeIdentifier uses BCP 47 format (en-US instead of en_US)

Test Plan:

Commands I ran, and their results:

  • yarn flow-check: 0 errors
  • yarn build-types && yarn test-generated-typescript: passed
  • yarn test packages/react-native/Libraries packages/jest-preset: passed
  • python -m scripts.cxx-api.parser --validate: all snapshots match
  • yarn format-check-cpp, yarn format-check-kotlin: clean

Videos:

RNTester's RTL example toggles forceRTL without a reload:

RTL.-.Android.mp4
RTL.-.iOS.mp4

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 23, 2026
@github-actions

Copy link
Copy Markdown

Warning

JavaScript API change detected

This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API.

  • Please include a clear changelog message.
  • This change will be subject to additional review.

This change was flagged as: POTENTIALLY_BREAKING

Comment thread packages/react-native/package.json Outdated
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 23, 2026

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

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Expo Partner: Expo Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants