feat : implement extensible i18n support and remove hardcoded settings#94
Conversation
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughExpands the app's supported locales from ChangesMulti-locale i18n Expansion and Component Migration
Sequence Diagram(s)sequenceDiagram
participant Browser
participant Component
participant getDictionary
participant dictionaries
Browser->>Component: page load (lang prop)
Component->>getDictionary: getDictionary(locale)
getDictionary->>dictionaries: lookup dictionaries[locale]
alt Locale found
dictionaries-->>getDictionary: locale dictionary
else Locale missing
dictionaries-->>getDictionary: fallback to en dictionary
end
getDictionary-->>Component: Dictionary t
Component->>Browser: render with localized strings
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CONTRIBUTING.es.md`:
- Around line 42-43: Replace the file:// protocol URLs in the markdown links
with relative repository paths. Change the href values in the links for
src/i18n/config.ts and src/i18n/dictionaries/en.json from file:///src/i18n/...
format to relative paths like src/i18n/... or ./src/i18n/... so that the links
work properly when the markdown file is viewed in repository viewers.
In `@CONTRIBUTING.md`:
- Around line 41-42: Replace the file:// protocol URLs in the markdown links on
lines 41 and 42 with repository-relative paths. In both instances where you see
[src/i18n/config.ts](file:///src/i18n/config.ts) and
[src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json), remove
the file:/// prefix from the URL portion of the markdown link (keeping just the
relative path like src/i18n/config.ts and src/i18n/dictionaries/en.json
respectively) so the links work properly in GitHub and other markdown viewers.
In `@src/app/`[lang]/docs/[slug]/page.tsx:
- Line 55: The arrow glyphs on line 55 (← before prev.title) and line 70 (→
after next.title) are hardcoded for LTR languages and should be direction-aware
for RTL locales like Arabic. Determine if the current language (lang parameter)
is RTL, then conditionally render the appropriate arrow direction: for RTL
locales, reverse the arrows so the previous navigation shows → and next
navigation shows ←, while keeping the current LTR arrows for non-RTL languages.
This ensures navigation cues visually align with the reading direction of the
locale.
In `@src/components/layout/Header.tsx`:
- Line 107: The language dropdown component in Header.tsx is using
aria-haspopup="listbox" but the popup contains navigation links instead of
actual listbox options, creating a semantic mismatch that confuses assistive
technology. Change the aria-haspopup value from "listbox" to "menu" to
accurately reflect the menu pattern being rendered with navigation links. Also
apply this same ARIA semantic fix to all related instances mentioned (around
lines 123 and 128-140) to ensure consistent ARIA patterns throughout the
component. Verify that the overall component structure (button trigger and popup
content) follows the menu pattern semantics consistently.
In `@src/i18n/dictionaries.ts`:
- Around line 7-13: The catch block in the require statement for loading locale
dictionaries is currently catching all errors and silently falling back to
English, which masks real problems like syntax errors in JSON files. Modify the
catch block to discriminate between errors: only return the English fallback
when the error indicates a missing locale module (check the error code property
for MODULE_NOT_FOUND or similar), and rethrow all other errors so they surface
and aren't hidden. This ensures that actual issues with locale files are not
masked by the fallback mechanism.
In `@src/lib/docs.ts`:
- Line 14: The title field in the DocNavItem type definition on line 14 is
currently defined as Record<string, string>, which allows any locale keys but
does not guarantee that the "en" key exists. However, downstream code relies on
d.title["en"] always being present. Modify the title field type to require the
"en" key as mandatory while still allowing other optional locale keys. This can
be achieved by using an intersection type that combines Record<string, string>
with an object that explicitly requires the "en" property.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9e09a742-9c3d-4e6e-a3b0-1881646660cd
📒 Files selected for processing (19)
.gitignoreCONTRIBUTING.es.mdCONTRIBUTING.mdsrc/app/[lang]/docs/[slug]/page.tsxsrc/app/[lang]/docs/layout.tsxsrc/app/[lang]/layout.tsxsrc/components/docs/DocsSidebar.tsxsrc/components/layout/Header.tsxsrc/i18n/config.tssrc/i18n/dictionaries.tssrc/i18n/dictionaries/ar.jsonsrc/i18n/dictionaries/en.jsonsrc/i18n/dictionaries/es.jsonsrc/i18n/dictionaries/fr.jsonsrc/i18n/dictionaries/it.jsonsrc/i18n/dictionaries/pt.jsonsrc/i18n/i18n.test.tssrc/lib/docs.tsvitest.config.ts
| 1. Registra el nuevo código de locale (por ejemplo, `fr`) en [src/i18n/config.ts](file:///src/i18n/config.ts). | ||
| 2. Copia [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) a `src/i18n/dictionaries/<locale>.json` y traduce los valores. |
There was a problem hiding this comment.
Corrige enlaces file:// por rutas relativas del repositorio.
En la Line 42 y la Line 43, file:///... no funciona en visores Markdown del repositorio.
Proposed fix
-1. Registra el nuevo código de locale (por ejemplo, `fr`) en [src/i18n/config.ts](file:///src/i18n/config.ts).
-2. Copia [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) a `src/i18n/dictionaries/<locale>.json` y traduce los valores.
+1. Registra el nuevo código de locale (por ejemplo, `fr`) en [src/i18n/config.ts](src/i18n/config.ts).
+2. Copia [src/i18n/dictionaries/en.json](src/i18n/dictionaries/en.json) a `src/i18n/dictionaries/<locale>.json` y traduce los valores.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 1. Registra el nuevo código de locale (por ejemplo, `fr`) en [src/i18n/config.ts](file:///src/i18n/config.ts). | |
| 2. Copia [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) a `src/i18n/dictionaries/<locale>.json` y traduce los valores. | |
| 1. Registra el nuevo código de locale (por ejemplo, `fr`) en [src/i18n/config.ts](src/i18n/config.ts). | |
| 2. Copia [src/i18n/dictionaries/en.json](src/i18n/dictionaries/en.json) a `src/i18n/dictionaries/<locale>.json` y traduce los valores. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CONTRIBUTING.es.md` around lines 42 - 43, Replace the file:// protocol URLs
in the markdown links with relative repository paths. Change the href values in
the links for src/i18n/config.ts and src/i18n/dictionaries/en.json from
file:///src/i18n/... format to relative paths like src/i18n/... or
./src/i18n/... so that the links work properly when the markdown file is viewed
in repository viewers.
| 1. Register the new locale code (e.g., `fr`) in [src/i18n/config.ts](file:///src/i18n/config.ts). | ||
| 2. Copy [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) to `src/i18n/dictionaries/<locale>.json` and translate the values. |
There was a problem hiding this comment.
Replace file:// URLs with repository-relative links.
Line 41 and Line 42 use file:///..., which breaks in GitHub/Markdown viewers.
Proposed fix
-1. Register the new locale code (e.g., `fr`) in [src/i18n/config.ts](file:///src/i18n/config.ts).
-2. Copy [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) to `src/i18n/dictionaries/<locale>.json` and translate the values.
+1. Register the new locale code (e.g., `fr`) in [src/i18n/config.ts](src/i18n/config.ts).
+2. Copy [src/i18n/dictionaries/en.json](src/i18n/dictionaries/en.json) to `src/i18n/dictionaries/<locale>.json` and translate the values.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 1. Register the new locale code (e.g., `fr`) in [src/i18n/config.ts](file:///src/i18n/config.ts). | |
| 2. Copy [src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json) to `src/i18n/dictionaries/<locale>.json` and translate the values. | |
| 1. Register the new locale code (e.g., `fr`) in [src/i18n/config.ts](src/i18n/config.ts). | |
| 2. Copy [src/i18n/dictionaries/en.json](src/i18n/dictionaries/en.json) to `src/i18n/dictionaries/<locale>.json` and translate the values. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CONTRIBUTING.md` around lines 41 - 42, Replace the file:// protocol URLs in
the markdown links on lines 41 and 42 with repository-relative paths. In both
instances where you see [src/i18n/config.ts](file:///src/i18n/config.ts) and
[src/i18n/dictionaries/en.json](file:///src/i18n/dictionaries/en.json), remove
the file:/// prefix from the URL portion of the markdown link (keeping just the
relative path like src/i18n/config.ts and src/i18n/dictionaries/en.json
respectively) so the links work properly in GitHub and other markdown viewers.
| </span> | ||
| <span className="mt-1 block font-medium text-[#0f172a] transition-colors group-hover:text-[#4f46e5]"> | ||
| ← {prev.title[lang]} | ||
| ← {prev.title[lang] ?? prev.title["en"]} |
There was a problem hiding this comment.
Make prev/next arrow glyphs direction-aware for RTL locales.
Line 55 and Line 70 hardcode LTR arrows. In Arabic RTL pages, this can invert navigation cues visually.
Proposed fix
const Content = DOC_COMPONENTS[slug as DocSlug];
const prev = DOC_NAV[index - 1];
const next = DOC_NAV[index + 1];
+ const isRtl = lang === "ar";
@@
- ← {prev.title[lang] ?? prev.title["en"]}
+ {isRtl ? "→" : "←"} {prev.title[lang] ?? prev.title["en"]}
@@
- {next.title[lang] ?? next.title["en"]} →
+ {next.title[lang] ?? next.title["en"]} {isRtl ? "←" : "→"}Also applies to: 70-70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`[lang]/docs/[slug]/page.tsx at line 55, The arrow glyphs on line 55
(← before prev.title) and line 70 (→ after next.title) are hardcoded for LTR
languages and should be direction-aware for RTL locales like Arabic. Determine
if the current language (lang parameter) is RTL, then conditionally render the
appropriate arrow direction: for RTL locales, reverse the arrows so the previous
navigation shows → and next navigation shows ←, while keeping the current LTR
arrows for non-RTL languages. This ensures navigation cues visually align with
the reading direction of the locale.
| <button | ||
| onClick={() => setDropdownOpen(!dropdownOpen)} | ||
| aria-expanded={dropdownOpen} | ||
| aria-haspopup="listbox" |
There was a problem hiding this comment.
Fix ARIA popup semantics for the language dropdown.
Line 107 sets aria-haspopup="listbox", but the popup renders navigation links (not listbox/options). This mismatch can confuse assistive tech. Use a menu pattern (menu/menuitem) or a true listbox pattern consistently.
Suggested fix
- aria-haspopup="listbox"
+ aria-haspopup="menu"
+ aria-controls="language-menu"
@@
- <div
+ <div
+ id="language-menu"
+ role="menu"
className="absolute right-0 rtl:left-0 rtl:right-auto z-20 mt-2 w-36 rounded-xl border p-1 shadow-lg transition-all bg-white border-[`#e2e8f0`] dark:bg-[`#0b0d12`] dark:border-[`#232a36`]"
>
@@
- <Link
+ <Link
+ role="menuitem"Also applies to: 123-123, 128-140
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/layout/Header.tsx` at line 107, The language dropdown
component in Header.tsx is using aria-haspopup="listbox" but the popup contains
navigation links instead of actual listbox options, creating a semantic mismatch
that confuses assistive technology. Change the aria-haspopup value from
"listbox" to "menu" to accurately reflect the menu pattern being rendered with
navigation links. Also apply this same ARIA semantic fix to all related
instances mentioned (around lines 123 and 128-140) to ensure consistent ARIA
patterns throughout the component. Verify that the overall component structure
(button trigger and popup content) follows the menu pattern semantics
consistently.
| export type DocNavItem = { | ||
| slug: DocSlug; | ||
| title: Record<Locale, string>; | ||
| title: Record<string, string>; |
There was a problem hiding this comment.
Require en in DocNavItem.title while keeping locale flexibility.
Line 14 loosens the contract too much: Record<string, string> allows entries without "en", but downstream fallback relies on d.title["en"] always existing. Keep dynamic locale keys, but enforce English as required.
Suggested fix
+import type { Locale } from "`@/i18n/config`";
+
export type DocNavItem = {
slug: DocSlug;
- title: Record<string, string>;
+ title: { en: string } & Partial<Record<Locale, string>>;
};🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/docs.ts` at line 14, The title field in the DocNavItem type
definition on line 14 is currently defined as Record<string, string>, which
allows any locale keys but does not guarantee that the "en" key exists. However,
downstream code relies on d.title["en"] always being present. Modify the title
field type to require the "en" key as mandatory while still allowing other
optional locale keys. This can be achieved by using an intersection type that
combines Record<string, string> with an object that explicitly requires the "en"
property.
Restores the project's original import pattern. Typed Record<Locale, Dictionary> enforces at compile time that every configured locale has a dictionary, and stops silently swallowing load errors / hiding missing translations.
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
Pull Request: Extensible i18n Support & RTL Switcher
Description
This PR implements Issue #74 ("extensible i18n"), introducing a fully extensible internationalization architecture, removing hardcoded locale configurations, and adding full support for Portuguese (pt), French (fr), Italian (it), and Arabic (ar) (which includes dynamic RTL styling).
It also resolves conflicts with the recently merged light/dark mode theme toggles and updates the header menu with a path-preserving language switcher dropdown.
Key Changes
1. Extensible Locale Architecture
src/i18n/dictionaries.tsto dynamically resolve dictionaries without requiring hardcoded imports for new languages.pt,fr,it, andar) insrc/i18n/config.ts.dir="rtl"when the current locale is Arabic (ar), ensuring proper layout orientation.2. UI & Navigation Enhancements
src/components/layout/Header.tsx./docs/getting-startedredirects to/[new_lang]/docs/getting-startedinstead of reverting to the home page/).3. Localization Seeding
Added complete translation dictionaries matching the structure of
en.jsonfor:src/i18n/dictionaries/pt.jsonsrc/i18n/dictionaries/fr.jsonsrc/i18n/dictionaries/it.jsonsrc/i18n/dictionaries/ar.json4. Quality Assurance & CI Validation
src/i18n/i18n.test.tsusing Vitest to enforce structure validation. The test checks that all non-English JSON dictionaries exactly mirror the structure (keys and nesting) of the baselineen.jsonfile.src/lib/docs.tsto fallback elegantly when documents are not translated yet. Corrected Windows-specific file URL resolving invitest.config.ts.5. Contribution Guidelines
CONTRIBUTING.mdandCONTRIBUTING.es.md.Verification & Testing Results
pnpm testsuccessfully passed 43/43 tests (including dictionary schema matches).pnpm typecheckpassed with 0 errors.pnpm lintpassed with 0 warnings/errors.pnpm buildcompleted successfully, compiling all static subpages for the 6 locales without errors.Summary by CodeRabbit