Add French translation support ✅ - #1877
Conversation
- Création du fichier de traduction `fr.json` en se basant sur `en.json`. - Mise à jour de la configuration i18n pour inclure la langue française. - Modification du sélecteur de langue pour afficher l'option "Français" avec le drapeau correspondant.
- Création du fichier `README.fr.md` en se basant sur `README.en.md`.
WalkthroughAdds French localization: new Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Header as LanguageSelector
participant I18N as i18n
participant UI as App UI
User->>Header: open language menu
User->>Header: select "Français"
Header->>I18N: changeLanguage('fr')
I18N-->>Header: language changed (emit)
Header->>UI: re-render with 'fr' resources
UI-->>User: UI displayed in French
Note over I18N,UI: fallbackLng remains 'zh' for missing keys
sequenceDiagram
autonumber
participant Script as verify_translation.py
participant Browser as Chromium (headless)
participant App as http://localhost:5173
Script->>Browser: launch browser
Browser->>App: navigate to page
Script->>Browser: click language toggle (Chinese-labeled)
Script->>Browser: select "Français"
Browser->>App: apply i18n 'fr'
Script->>Browser: expect aria-label uses `common.changeLanguage`
Script->>Browser: take screenshot -> verification.png
Script->>Browser: close browser
Note over Script,Browser: uses explicit waits and a short sleep for UI update
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🔇 Additional comments (2)
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
web/src/components/layout/headerbar/LanguageSelector.jsx (2)
23-23: Prefer per-flag imports to minimize bundle risk.Named exports are usually tree-shaken, but single-file imports are safest across bundlers.
Apply this diff:
-import { CN, GB, FR } from 'country-flag-icons/react/3x2'; +import CN from 'country-flag-icons/react/3x2/CN'; +import GB from 'country-flag-icons/react/3x2/GB'; +import FR from 'country-flag-icons/react/3x2/FR';
55-58: Use stable i18n keys and add a test id for robust e2e selection.Avoid using a natural-language key ('切换语言') and expose a data-testid for Playwright.
Apply this diff:
- <Button - icon={<Languages size={18} />} - aria-label={t('切换语言')} + <Button + icon={<Languages size={18} />} + aria-label={t('common.changeLanguage')} + data-testid='language-selector' theme='borderless'Add translations for common.changeLanguage in all locales, for example:
- web/src/i18n/locales/zh.json:
{ "common": { "changeLanguage": "切换语言" } }
- web/src/i18n/locales/en.json:
{ "common": { "changeLanguage": "Change language" } }
- web/src/i18n/locales/fr.json:
{ "common": { "changeLanguage": "Changer de langue" } }jules-scratch/verification/verify_translation.py (1)
1-43: Make the test resilient to initial locale and remove fixed sleeps.Handle both Chinese/English initial states and rely on expect instead of time.sleep.
Apply this diff:
-from playwright.sync_api import sync_playwright, expect +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api import TimeoutError as PWTimeoutError @@ - # The aria-label is in Chinese in the source, so we use that. - language_button = page.get_by_role("button", name="切换语言") - - # Wait for the button to be visible - expect(language_button).to_be_visible() + # Locate the language button (support CN or EN initial states) + btn_cn = page.get_by_role("button", name="切换语言") + btn_en = page.get_by_role("button", name="Change language") + language_button = btn_cn if btn_cn.count() else btn_en + expect(language_button).to_be_visible() @@ - # Wait for the language switch to apply - time.sleep(2) # Wait for 2 seconds - - # Now the aria-label should be in French + # Now the aria-label should be in French (wait up to 10s) expect(page.get_by_role("button", name="Changer de langue")).to_be_visible(timeout=10000) + # Optional: verify i18next persisted language + try: + lang = page.evaluate("() => localStorage.getItem('i18nextLng')") + print("i18nextLng =", lang) + except PWTimeoutError: + passIf you adopt data-testid in LanguageSelector, prefer:
- language_button = page.get_by_test_id("language-selector")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
bun_output.logis excluded by!**/*.logpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
README.en.md(1 hunks)README.fr.md(1 hunks)README.md(1 hunks)jules-scratch/verification/verify_translation.py(1 hunks)web/src/components/layout/headerbar/LanguageSelector.jsx(2 hunks)web/src/i18n/i18n.js(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
web/src/components/layout/headerbar/LanguageSelector.jsx (1)
web/src/hooks/common/useHeaderBar.js (1)
currentLang(39-39)
🪛 markdownlint-cli2 (0.18.1)
README.fr.md
37-37: Blank line inside blockquote
(MD028, no-blanks-blockquote)
🔇 Additional comments (4)
README.en.md (1)
2-2: Add Français link — looks good.Verify the README.fr.md path resolves and the language order matches other READMEs.
README.fr.md (1)
1-216: Solid French localization added.Run markdownlint to ensure no MD028 (“no blank lines in blockquotes”) violations remain in this file.
README.md (1)
2-2: Français link added — consistent with other READMEs.Confirm the target file exists in main and the link isn’t broken post-merge.
web/src/components/layout/headerbar/LanguageSelector.jsx (1)
45-51: French option wiring — LGTM.Good use of FR flag and active state.
- Added `common.changeLanguage` key to `en.json`, `fr.json`, and `zh.json`. - Updated `LanguageSelector.jsx` to use the new shared key. - Completed `fr.json` with all keys from `en.json` and `zh.json`. - Added translations for `closeSidebar`, `pricing`, and `language`.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
web/src/components/layout/headerbar/LanguageSelector.jsx(2 hunks)web/src/i18n/locales/en.json(1 hunks)web/src/i18n/locales/zh.json(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
web/src/components/layout/headerbar/LanguageSelector.jsx (1)
web/src/hooks/common/useHeaderBar.js (1)
currentLang(39-39)
🔇 Additional comments (3)
web/src/components/layout/headerbar/LanguageSelector.jsx (3)
23-23: FR flag import aligns with new locale
ImportingFRalongsideCNandGBkeeps the flag set consistent with the supported languages.
45-51: French dropdown entry looks good
The new item mirrors the existing pattern, callsonLanguageChange('fr'), and uses the correct flag/title.
57-57: common.changeLanguage is present in all locale JSON files Confirmed the key exists in en.json, fr.json, and zh.json.
- Restructured the `common.changeLanguage` key to be nested under a `common` object in `en.json`, `fr.json`, and `zh.json`. - This change improves the organization of the translation files and aligns with best practices for i18next.
|
Closing this pull request as it has been superseded by #1889, which contains the same changes rebased on the latest main branch. |
This pull request adds French language support to the user interface:
fr.jsontranslation file based onen.jsonSummary by CodeRabbit
New Features
Documentation
Tests