Add createFixedFbt and FixedLocaleContext for locale-fixed translations#75
Open
bk-tho wants to merge 4 commits into
Open
Add createFixedFbt and FixedLocaleContext for locale-fixed translations#75bk-tho wants to merge 4 commits into
bk-tho wants to merge 4 commits into
Conversation
Adds a createFixedFbt(locale, gender?) function that returns { fbt, fbs }
runtimes bound to a specific locale and gender. Unlike the global fbt/fbs,
these runtimes are fully isolated — they do not read from or write to the
global Hooks singleton — making them safe for concurrent use in async
contexts like React Server Components.
Implementation:
- Extend createRuntime to accept optional getTranslatedInput,
getViewerContext, and getErrorListener overrides (defaulting to Hooks.*)
- Extract fbtParam/fbtPlural and fbsParam/fbsPlural as named exports so
they can be reused by createFixedFbt without duplication
- createFixedFbt creates closures over the fixed locale/gender and passes
them to createRuntime, producing isolated fbt and fbs instances
Adds <FixedLocaleContext locale="de_DE"> — a React context provider that transparently overrides the locale for all <fbt>, fbt(), <fbs>, and fbs() calls in descendant components. No call-site changes needed in children. Babel plugin changes: - Detects React components (/^[A-Z]/), hooks (/^use[A-Z0-9]/), and React.forwardRef/memo callbacks that contain fbt/fbs calls - Injects `const __fbtLocaleOverride = fbt.__locale?.() ?? null;` at the top of qualifying functions - Passes __fbtLocaleOverride as 4th argument to all fbt._() / fbs._() calls Runtime changes: - createRuntime gains __locale() method (reads from registered hook) and localeOverride 4th param on _() (delegates to fixed runtime when present) - FixedLocaleContext registers a React context hook via setLocaleOverrideHook and provides createFixedFbt(locale, gender) to descendants - Fully backward compatible: old plugin + new runtime and vice versa both work correctly (extra args are ignored, missing override defaults to null) Example app: - Adds Multi-Locale Preview section demonstrating <FixedLocaleContext> rendering the same string in 4 languages simultaneously
FixedLocaleContext now checks if translations for the requested locale are available. If not, it uses the loadLocale hook registered during setupLocaleContext to fetch them, suspending via React's use() until loaded. Translations are cached per locale and merged into the global FbtTranslations dictionary. Changes: - Hooks: add LoadLocaleFn type, loadLocale to Hooks, getLoadLocale() - setupLocaleContext: registers loadLocale in hooks during setup - FixedLocaleContext: useEnsureLocaleLoaded() suspends if translations need loading, caches promises per locale - Test: async loading with Suspense
Adds example/fixedLocale.html demonstrating FixedLocaleContext with: - Only en_US pre-loaded, all other locales loaded on demand via loadLocale - 1s simulated delay to make Suspense fallbacks visible - Test cases: basic fbt/fbs, functional calls, mixed, nested contexts, sibling contexts, and all available locales
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Disclaimer: This was written entirely by Opus 4.6 High. I believe I guided it thoroughly into the right direction. I reviewed and tested the result myself.
Summary
Adds locale-fixed translation support for fbtee — the equivalent of i18next's
getFixedT. Two complementary APIs:1.
<FixedLocaleContext>— React (transparent)A context provider that transparently overrides the locale for all
<fbt>,fbt(),<fbs>, andfbs()calls in descendant components. No call-site changes needed in children.On-demand translation loading: If translations for the requested locale are not yet loaded and a
loadLocalehook has been registered (viasetupLocaleContext),FixedLocaleContextwill suspend until translations are fetched. Wrap in<Suspense>to handle the loading state. Already-loaded locales render immediately.2.
createFixedFbt(locale, gender?)— Non-React (programmatic)Returns
{ fbt, fbs }runtimes bound to a specific locale. Shadow the globalfbt/fbsbinding and the babel plugin compiles calls normally:How it works
Babel plugin
The plugin detects React components (
/^[A-Z]/), hooks (/^use[A-Z0-9]/), andReact.forwardRef/React.memocallbacks that containfbt._()orfbs._()calls. For these functions, it:const __fbtLocaleOverride = fbt.__locale?.() ?? null;at the top__fbtLocaleOverrideas 4th argument to allfbt._()/fbs._()callsNon-component functions are left unchanged (use global locale).
Runtime
fbt.__locale()reads fromFbtLocaleOverrideContextvia a registered hookfbt._()checks the 4th argument: if present, delegates to the fixed runtime; otherwise uses global hooks as before<FixedLocaleContext>provides the fixed runtime (created bycreateFixedFbt) via React contextloadLocalehook + Reactuse()to suspend until loaded, then merges intoFbtTranslationscreateFixedFbtcreates isolated runtimes with their owngetTranslatedInputandgetViewerContextBackward compatibility
fbt._()with 3 args → 4th isundefined→ global hooksfbt._()with 4 args → extra arg ignored by JS<FixedLocaleContext>in tree__locale?.()returnsnull→ global hooksFixedLocaleContextnot importednullChanges
packages/babel-plugin-fbtee/src/index.tsx—injectLocaleOverrides()inProgram.exit: component/hook detection + hook injection + 4th arg additionpackages/fbtee/src/fbt.tsx—FbtLocaleOverridetype,__locale()method,localeOverride4th param on_(),runtimeKeyparam oncreateRuntimesrc/fbs.tsx—runtimeKey: "fbs"src/Hooks.tsx—LoadLocaleFntype,loadLocaleinHooks,getLoadLocale(),getLocaleOverrideHook()/setLocaleOverrideHook()src/setupLocaleContext.tsx— RegistersloadLocalein hooks during setupsrc/FixedLocaleContext.tsx— New: React context provider with on-demand translation loading viauseEnsureLocaleLoaded+ Suspensesrc/createFixedFbt.tsx— New: isolated runtime factorysrc/index-server.tsx— ExportscreateFixedFbtandFixedLocaleContextexample/fixedLocale.html+src/fixedLocale.tsx+src/example/FixedLocaleDemo.tsx— Comprehensive demo page with on-demand loading (1s simulated delay), Suspense fallbacks, all test casessrc/example/Example.tsx— Multi-Locale Preview sectionTests
FixedLocaleContexttests (fixed locale, isolation, nesting, global unaffected, fbs, async loading with Suspense)createFixedFbttests (locale, fbs, fallback, gender, concurrency, late registration)