Feat/i18n complete french locale - #1878
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 language support across the UI and i18n resources, updates README language links and introduces a new French README. Implements a Playwright-based verification script that automates switching the UI language to French and captures a screenshot. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant QA as Playwright Script
participant B as Headless Browser
participant App as Web App (localhost:5173)
participant I18N as i18n Engine
QA->>B: Launch Chromium (headless)
B->>App: GET /
App->>I18N: Initialize with available locales (en, zh, fr)
QA->>B: Click Language Selector ➜ Français
B->>App: Dispatch onLanguageChange('fr')
App->>I18N: Set language = fr
I18N-->>App: Provide fr translations
App-->>B: Render UI with French strings
QA->>B: Wait for French label visible
QA->>B: Capture screenshot
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/layout/headerbar/LanguageSelector.jsx (1)
57-57: Use the new i18n key for aria-label to enable FR translationCurrent key t('切换语言') won’t translate to “Changer de langue” unless fr.json duplicates that Chinese key. Use common.changeLanguage to match the new locale entries and the verification script.
Apply:
- aria-label={t('切换语言')} + aria-label={t('common.changeLanguage')}Ensure fr.json contains: "common": { "changeLanguage": "Changer de langue" } (or a flat "common.changeLanguage": "Changer de langue").
🧹 Nitpick comments (5)
web/src/i18n/i18n.js (1)
31-48: Harden language detection and supported languagesRecommend constraining detected languages and persisting to localStorage for stability (especially for tests) without changing UX.
Apply:
.init({ load: 'languageOnly', + supportedLngs: ['zh', 'en', 'fr'], + nonExplicitSupportedLngs: true, + detection: { + order: ['localStorage', 'navigator'], + caches: ['localStorage'], + }, resources: {jules-scratch/verification/verify_translation.py (4)
42-43: Avoid side effects on import; gate execution with mainTop-level execution runs whenever imported. Wrap with a main guard.
Apply:
-with sync_playwright() as playwright: - run(playwright) +if __name__ == "__main__": + with sync_playwright() as playwright: + run(playwright)
29-34: Remove arbitrary sleep; wait for translated aria-label insteadPrefer deterministic waits to avoid flakiness and speed up runs.
Apply:
- # Wait for the language switch to apply - time.sleep(2) # Wait for 2 seconds - - # Now the aria-label should be in French - expect(page.get_by_role("button", name="Changer de langue")).to_be_visible(timeout=10000) + # Wait until the button's accessible name reflects French + expect(page.get_by_role("button", name="Changer de langue")).to_be_visible(timeout=10000)
9-15: Stabilize initial locale for the testLanguageDetector may pick browser locale; explicitly set i18nextLng to zh before navigation so the button query works reliably in all environments.
Apply:
- page.goto("http://localhost:5173", wait_until="networkidle") + context.add_init_script("localStorage.setItem('i18nextLng','zh')") + page.goto("http://localhost:5173", wait_until="networkidle")
40-40: Close context explicitly (minor hygiene)Close the context before closing the browser.
Apply:
- browser.close() + context.close() + browser.close()
📜 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 (8)
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)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)
🪛 markdownlint-cli2 (0.18.1)
README.fr.md
37-37: Blank line inside blockquote
(MD028, no-blanks-blockquote)
🔇 Additional comments (7)
README.en.md (1)
2-2: Header language link addition looks goodFrançais link correctly added; anchors render as expected.
README.md (1)
2-2: Header language link addition looks goodFrançais link added consistently with other READMEs.
web/src/i18n/i18n.js (1)
24-27: Registering French translations: LGTMfr locale import is correct and aligns with resources registration below.
web/src/components/layout/headerbar/LanguageSelector.jsx (2)
45-51: French option UI: LGTMDropdown item mirrors existing ones with correct active-state and flag.
23-23: country-flag-icons declared in package.json
Declared at ^1.5.19 in web/package.json; 'country-flag-icons/react/3x2' import will resolve correctly.web/src/i18n/locales/zh.json (1)
35-36: New key added: OK"common.changeLanguage" matches intended usage and value is correct in zh.
web/src/i18n/locales/en.json (1)
2127-2129: common.changeLanguage key is present in fr.json
| > [!NOTE] | ||
| > Il s'agit d'un projet open-source développé sur la base de [One API](https://github.com/songquanpeng/one-api) | ||
|
|
||
| > [!IMPORTANT] | ||
| > - Ce projet est uniquement destiné à des fins d'apprentissage personnel, sans garantie de stabilité ni de support technique. | ||
| > - Les utilisateurs doivent se conformer aux [Conditions d'utilisation](https://openai.com/policies/terms-of-use) d'OpenAI et aux **lois et réglementations applicables**, et ne doivent pas l'utiliser à des fins illégales. | ||
| > - Conformément aux [《Mesures provisoires pour la gestion des services d'intelligence artificielle générative》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm), veuillez ne fournir aucun service d'IA générative non enregistré au public en Chine. | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Fix markdownlint MD028: remove blank line inside blockquote
markdownlint flagged a blank line within the blockquote/admonition. Ensure consecutive lines in the NOTE/IMPORTANT blocks are all prefixed with > and avoid blank lines inside the blockquote.
Run markdownlint to confirm:
🏁 Script executed:
#!/bin/bash
npx -y markdownlint-cli2 README.fr.md || trueLength of output: 9488
Remove blank line in blockquote
At README.fr.md (lines 35–42), delete the empty line between the [!NOTE] and [!IMPORTANT] blocks so that every line in the blockquote is prefixed with >.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
37-37: Blank line inside blockquote
(MD028, no-blanks-blockquote)
🤖 Prompt for AI Agents
In README.fr.md around lines 35 to 42, there is an extra blank line inside the
blockquote separating the [!NOTE] and [!IMPORTANT] blocks; remove that empty
line and ensure every line in the blockquote is prefixed with ">" so the two
blocks are contiguous and consistently formatted as a single blockquote.
Summary by CodeRabbit
New Features
Documentation
Tests