From 3615ebe3207ab65ed1d859286978a579bdf91a28 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Mon, 26 Oct 2026 09:01:27 -0700 Subject: [PATCH] Fix offering locales that are not shipped when there is no remote base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Choosing a language other than English or Chinese makes the frontend fetch `./locales/.json`, which React Native never ships: only `bundled_devtools_locales` (`en-US` and `zh`, set upstream in `config/gni/i18n.gni`) are packaged, and the rest are meant to come from Chrome's `remoteBase` CDN, which React Native never passes. The dev server logs `Error: ENOENT: no such file or directory, stat '…/core/i18n/locales/it.json'` on every launch, and the frontend falls back to English only once the failed request comes back. Users get there without looking for it: with the default setting, a system language that DevTools supports shows the "DevTools is now available in …" infobar on first launch, and both of its buttons pick a locale React Native can't load. The Settings language dropdown lists every one of about 80 locales too. When there is no remote base, build the supported-locale list from the bundled locales only. The language dropdown then offers English and Chinese, the infobar appears only for Chinese, and a stored unbundled locale (or "Browser UI language" on, say, an Italian system) resolves to `en-US` without a request. With a remote base, every locale is offered as before. Fixes react/react-native#52461 --- front_end/core/i18n/i18n.test.ts | 13 +++++++++++++ front_end/core/i18n/i18nImpl.ts | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/front_end/core/i18n/i18n.test.ts b/front_end/core/i18n/i18n.test.ts index 63d41ea9d782..d9b126d8f4ea 100644 --- a/front_end/core/i18n/i18n.test.ts +++ b/front_end/core/i18n/i18n.test.ts @@ -205,3 +205,16 @@ describe('fetchAndRegisterLocaleData', () => { `Actually called with ${fetchStub.args[0][0]}`); }); }); + +describe('supported locales without a remote base', () => { + it('offers only the bundled locales', () => { + const locales = i18n.i18n.getAllSupportedDevToolsLocales(); + assert.includeMembers(locales, ['en-US', 'zh']); + assert.notInclude(locales, 'it'); + }); + + it('resolves an unbundled locale to en-US', () => { + assert.strictEqual(i18n.i18n.lookupClosestSupportedDevToolsLocale('it-IT'), 'en-US'); + assert.strictEqual(i18n.i18n.lookupClosestSupportedDevToolsLocale('zh-CN'), 'zh'); + }); +}); diff --git a/front_end/core/i18n/i18nImpl.ts b/front_end/core/i18n/i18nImpl.ts index bb9d4e9443fe..7ac3eddd7c5a 100644 --- a/front_end/core/i18n/i18nImpl.ts +++ b/front_end/core/i18n/i18nImpl.ts @@ -16,7 +16,10 @@ import { REMOTE_FETCH_PATTERN, } from './locales.js'; -const i18nInstance = new I18n.I18n.I18n(LOCALES, DEFAULT_LOCALE); +// [RN] React Native ships only the bundled locales and has no remoteBase to fetch +// the rest from, so offer and resolve to the bundled locales only. +const i18nInstance = new I18n.I18n.I18n( + Root.Runtime.getRemoteBase()?.version ? LOCALES : BUNDLED_LOCALES_GENERATED, DEFAULT_LOCALE); // All the locales that are part of the DevTools bundle and should not be fetched // remotely.