fix(swap): preload i18n messages before initial render#6969
fix(swap): preload i18n messages before initial render#6969crutch12 wants to merge 2 commits intocowprotocol:developfrom
Conversation
|
@crutch12 is attempting to deploy a commit to the cow Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThe changes implement preloaded locale message support for the i18n system by introducing dynamic message loading infrastructure, updating i18n providers to accept messages, and modifying the app initialization flow to load locale messages before rendering. Changes
Sequence DiagramsequenceDiagram
participant App as App Bootstrap
participant Init as initApp()
participant Loader as loadActiveLocaleMessages()
participant Activator as dynamicActivate()
participant Lib as i18n Library
participant UI as Main (React)
App->>Init: Start initialization
Init->>Loader: Load messages for active locale
Loader->>Lib: Import locale catalog (.po)
Lib-->>Loader: Return Messages object
Loader-->>Init: Return loaded messages
Init->>Activator: Activate locale with messages
Activator->>Lib: Load and activate catalog
Lib-->>Activator: Locale activated
Activator-->>Init: Activation complete
Init->>UI: Render Main(localeMessages)
UI->>UI: Pass messages to LanguageProvider
LanguageProvider->>Lib: Provider propagates messages
Lib-->>UI: i18n ready with locale strings
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Important Action Needed: IP Allowlist UpdateIf your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:
Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
||
| const catalog = await loadLocaleMessages(locale) | ||
|
|
||
| i18n.load(locale, catalog) |
There was a problem hiding this comment.
if there are no changes, it won't rerender the application
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cowswap-frontend/src/lib/i18n.tsx (1)
22-27:⚠️ Potential issue | 🟡 MinorRoute locale activation errors through the centralized logger.
console.errorshould be replaced with the shared logger for consistent formatting and routing.As per coding guidelines: Replace stray
console.log/debug/infowith the centralized logger unless intentionally scoped diagnostics (prefixed) are required; userg "console\\.(log|debug|info|warn|error)\\("to remove or route through the logger.
🤖 Fix all issues with AI agents
In `@apps/cowswap-frontend/src/lib/i18n.tsx`:
- Around line 30-35: Remove the render-time side effects by deleting the
conditional block that calls i18n.load(locale, messages) and
i18n.activate(locale) inside the I18nProvider render; instead rely on the
pre-render bootstrap call loadActiveLocaleMessages() (from cow-react/index.tsx)
or the existing dynamicActivate() in the useEffect to initialize i18n
before/after mount—ensure I18nProvider only reads i18n.locale/messages and does
not mutate global i18n during render so initialization is consolidated into the
bootstrap or the useEffect path.
In `@apps/cowswap-frontend/src/lib/localeMessages.ts`:
- Around line 12-20: loadActiveLocaleMessages currently always uses
getActiveLocale(), causing a flash when i18n is disabled; change
loadActiveLocaleMessages to accept a boolean isInternationalizationEnabled, and
if false use DEFAULT_LOCALE instead of getActiveLocale() before calling
loadLocaleMessages; update callers (notably LanguageProvider) to pass
isInternationalizationEnabled so the function gates locale preloading when i18n
is off and avoids loading non-default locales.
🧹 Nitpick comments (1)
apps/cowswap-frontend/src/lib/localeMessages.ts (1)
23-41: Route console.error through the centralized logger.This module now emits errors directly; please use the shared logger so logs are consistent and filterable.
As per coding guidelines, Use
rg "console\\.(log|debug|info|warn|error)\\("to remove or route through the logger.
| // if i18n is not activated (i18n.locale === ''), then I18nProvider renders null ("white screen") on initial render | ||
| // that's why we detect locale and load messages BEFORE initial render | ||
| if (!i18n.locale && messages) { | ||
| i18n.load(locale, messages) | ||
| i18n.activate(locale) // sets i18n.locale value, runs only one time | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's read the i18n.tsx file to see the full context
cat -n apps/cowswap-frontend/src/lib/i18n.tsxRepository: cowprotocol/cowswap
Length of output: 1700
🏁 Script executed:
# Find where createRoot and render are called
rg -n "createRoot|ReactDOM\.render\(" apps/cowswap-frontend/src --type ts --type tsxRepository: cowprotocol/cowswap
Length of output: 90
🏁 Script executed:
# Search for existing i18n initialization patterns
rg -n "dynamicActivate|loadActiveLocaleMessages|loadLocaleMessages" apps/cowswap-frontend/srcRepository: cowprotocol/cowswap
Length of output: 1248
🏁 Script executed:
# Check the initialization flow in cow-react/index.tsx around createRoot
sed -n '90,120p' apps/cowswap-frontend/src/cow-react/index.tsxRepository: cowprotocol/cowswap
Length of output: 883
🏁 Script executed:
# Look for createRoot and initial render
rg -n "createRoot|root.render\|ReactDOM" apps/cowswap-frontend/src/cow-react/index.tsx -A 5Repository: cowprotocol/cowswap
Length of output: 715
Move i18n initialization out of render—consolidate into pre-render bootstrap or useEffect.
The i18n.load and i18n.activate calls (lines 30–35) execute during component render, mutating global state. The guard condition !i18n.locale prevents re-execution within a render cycle, but does not eliminate the anti-pattern; in StrictMode or with concurrent rendering enabled, side effects during render remain unsafe and unreliable.
Since loadActiveLocaleMessages() already runs pre-render in cow-react/index.tsx (line 106) and dynamicActivate() already runs in useEffect (line 23), this render-time initialization is redundant and should be removed. Consolidate the initialization path: either pass fully-initialized i18n state before rendering, or defer to the existing useEffect pattern.
🤖 Prompt for AI Agents
In `@apps/cowswap-frontend/src/lib/i18n.tsx` around lines 30 - 35, Remove the
render-time side effects by deleting the conditional block that calls
i18n.load(locale, messages) and i18n.activate(locale) inside the I18nProvider
render; instead rely on the pre-render bootstrap call loadActiveLocaleMessages()
(from cow-react/index.tsx) or the existing dynamicActivate() in the useEffect to
initialize i18n before/after mount—ensure I18nProvider only reads
i18n.locale/messages and does not mutate global i18n during render so
initialization is consolidated into the bootstrap or the useEffect path.
There was a problem hiding this comment.
It's intended - i18n instance is a singleton
There was a problem hiding this comment.
@crutch12, understood. The synchronous initialization before I18nProvider renders is intentional to avoid the white screen issue. I appreciate the clarification!
🧠 Learnings used
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: apps/cowswap-frontend/AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:52.016Z
Learning: Use `yarn nx run cowswap-frontend:i18n` to manage i18n translations for cowswap-frontend
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Inline render factories used to dodge `react/no-unstable-nested-components` warnings are a red flag
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Stabilize hook dependencies and avoid recreating objects in render in React
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Avoid inline IIFEs/closures inside `.map()`; extract helpers outside render
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Never declare components inside render bodies or rely on `render*`/`get*` helpers that return JSX; hoist subcomponents to module scope
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Replace inline factories with extracted components or memoized callbacks; obey `react/no-unstable-nested-components`
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Hook dependency cascades are a red flag - verify control flow before tweaking dependency arrays
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Complicated JS logic to prevent visual glitches is a red flag - prioritize CSS-based solutions first
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : No side effects in render - use `useEffect`, `useCallback`, or event handlers instead
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Complex bespoke state managers are a red flag - investigate the trigger chain instead of layering abstractions
| export async function loadActiveLocaleMessages(): Promise<Messages | undefined> { | ||
| const activeLocale = getActiveLocale() | ||
| try { | ||
| const messages = await loadLocaleMessages(activeLocale) | ||
| return messages | ||
| } catch (error) { | ||
| console.error('Could not load locale file: ' + activeLocale, error) | ||
| return undefined | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
grep -R "initApp" -n apps/cowswap-frontend/srcRepository: cowprotocol/cowswap
Length of output: 214
🏁 Script executed:
cat -n apps/cowswap-frontend/src/initApp.tsRepository: cowprotocol/cowswap
Length of output: 131
🏁 Script executed:
rg -n "loadActiveLocaleMessages" -C3 -t ts apps/cowswap-frontend/srcRepository: cowprotocol/cowswap
Length of output: 2043
🏁 Script executed:
rg -n "i18nEnabled" -C3 -t ts apps/cowswap-frontend/srcRepository: cowprotocol/cowswap
Length of output: 45
🏁 Script executed:
cat -n apps/cowswap-frontend/src/providers/LanguageProvider.tsxRepository: cowprotocol/cowswap
Length of output: 151
🏁 Script executed:
cat -n apps/cowswap-frontend/src/lib/localeMessages.ts | sed -n '1,30p'Repository: cowprotocol/cowswap
Length of output: 1356
🏁 Script executed:
fd WithLDProvider -t f -I -p apps/cowswap-frontend/srcRepository: cowprotocol/cowswap
Length of output: 138
Gate locale preloading on the i18n feature flag
loadActiveLocaleMessages always loads getActiveLocale(), but when i18n is disabled LanguageProvider resets to DEFAULT_LOCALE, causing a flash of the non-default locale. Pass isInternationalizationEnabled into loadActiveLocaleMessages and fallback to DEFAULT_LOCALE:
🛠️ Suggested adjustment
-export async function loadActiveLocaleMessages(): Promise<Messages | undefined> {
- const activeLocale = getActiveLocale()
+export async function loadActiveLocaleMessages(
+ isInternationalizationEnabled = true,
+): Promise<Messages | undefined> {
+ const activeLocale = isInternationalizationEnabled ? getActiveLocale() : DEFAULT_LOCALE🤖 Prompt for AI Agents
In `@apps/cowswap-frontend/src/lib/localeMessages.ts` around lines 12 - 20,
loadActiveLocaleMessages currently always uses getActiveLocale(), causing a
flash when i18n is disabled; change loadActiveLocaleMessages to accept a boolean
isInternationalizationEnabled, and if false use DEFAULT_LOCALE instead of
getActiveLocale() before calling loadLocaleMessages; update callers (notably
LanguageProvider) to pass isInternationalizationEnabled so the function gates
locale preloading when i18n is off and avoids loading non-default locales.
There was a problem hiding this comment.
It's intended - we have no isInternationalizationEnabled value before initial render. This won't affect the application
There was a problem hiding this comment.
@crutch12, thank you for the clarification! That makes sense—since loadActiveLocaleMessages() runs in initApp() before the initial render, the feature flags (including isInternationalizationEnabled) haven't been initialized yet. I understand that this early loading is intentional to prevent the white screen and extra rerenders you're addressing in this PR.
✏️ Learnings added
Learnt from: crutch12
Repo: cowprotocol/cowswap PR: 6969
File: apps/cowswap-frontend/src/lib/localeMessages.ts:12-20
Timestamp: 2026-02-04T18:23:19.855Z
Learning: In apps/cowswap-frontend/src/lib/localeMessages.ts, the loadActiveLocaleMessages() function runs before initial render (in initApp()), at which point feature flags like isInternationalizationEnabled are not yet available. This early locale loading is intentional to avoid white screens and extra rerenders.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: apps/cowswap-frontend/AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:52.016Z
Learning: Use `yarn nx run cowswap-frontend:i18n` to manage i18n translations for cowswap-frontend
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 6234
File: libs/tokens/src/index.ts:1-4
Timestamp: 2025-09-11T08:25:51.460Z
Learning: In the cowprotocol/cowswap project, there is currently no SSR (Server-Side Rendering) support, so localStorage access at module import time does not cause SSR-related issues.
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6770
File: apps/cowswap-frontend/src/modules/tokensList/hooks/useAddListImport.ts:27-31
Timestamp: 2025-12-30T18:49:03.377Z
Learning: In apps/cowswap-frontend/src/modules/tokensList/hooks/useAddListImport.ts, when restrictedLists.isLoaded is false or geoStatus.isLoading is true, the code intentionally proceeds with the import immediately without blocking. This allows imports to proceed during loading states, deferring consent checks to trade time when necessary data isn't yet available.
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Hardcoded environment-specific lists/toggles when shared config/enums exist are a red flag
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Detect whether data originated locally or from the API and adapt derived values (e.g., bridge output tokens)
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Complicated JS logic to prevent visual glitches is a red flag - prioritize CSS-based solutions first
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 5768
File: apps/cow-fi/components/LearnPageComponent.tsx:184-185
Timestamp: 2025-05-28T16:50:12.273Z
Learning: In apps/cow-fi/components/LearnPageComponent.tsx, the user prefers to keep the inconsistent link behavior where featured articles always open in new tabs (target="_blank") while media coverage links conditionally open in new tabs based on the linkExternal flag. This inconsistency should not be flagged as an issue in future reviews.
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Use shared constants when referencing protocol names or disclaimers to keep copy consistent across the bridge UX
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Hook dependency cascades are a red flag - verify control flow before tweaking dependency arrays
Learnt from: CR
Repo: cowprotocol/cowswap PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-27T19:05:35.655Z
Learning: Applies to **/*.{ts,tsx} : Drive feature toggles from real data comparisons (e.g., compare chain IDs to determine bridging) instead of heuristics
Summary
<I18nProvider>rendersnull(white screen) if providedi18ninstance is not activated. Thus we loadmessagesand updatei18ninstance only after that "white screen" render.It leads to the following problems:
WithProviders) withoutwaitFor/waitForNextUpdateusageSolution:
activeLocaleand fetchlocaleMessagesbefore initial application renderTo Test
React Profiler Screenshot
Background
jotaiStore.get(featureFlagsAtom)value?