Skip to content

Created french locale#2586

Open
zbcrft wants to merge 8 commits intoiNavFlight:maintenance-9.xfrom
zbcrft:master
Open

Created french locale#2586
zbcrft wants to merge 8 commits intoiNavFlight:maintenance-9.xfrom
zbcrft:master

Conversation

@zbcrft
Copy link

@zbcrft zbcrft commented Mar 6, 2026

I translated the app in french using a python script (deep_translator library)
This could be useful to many people
I reviewed most of the translations myself.

@github-actions
Copy link

github-actions bot commented Mar 6, 2026

Branch Targeting Suggestion

You've targeted the master branch with this PR. Please consider if a version branch might be more appropriate:

  • maintenance-9.x - If your change is backward-compatible and won't create compatibility issues between INAV firmware and Configurator 9.x versions. This will allow your PR to be included in the next 9.x release.

  • maintenance-10.x - If your change introduces compatibility requirements between firmware and configurator that would break 9.x compatibility. This is for PRs which will be included in INAV 10.x

If master is the correct target for this change, no action is needed.


This is an automated suggestion to help route contributions to the appropriate branch.

@qodo-code-review
Copy link
Contributor

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Add French locale support to application

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Added French locale support to the application
• Registered 'fr' language in available languages list
• Added French language identifier to all existing locale files
• Fixed typo in English messages ("connectected" to "connected")
• Updated documentation to reflect new French locale availability
Diagram
flowchart LR
  A["Localization System"] -->|Add 'fr' language| B["Available Languages"]
  A -->|Create French messages| C["locale/fr/messages.json"]
  B -->|Register in all locales| D["en, ja, ru, uk, zh_CN"]
  D -->|Add language_fr entry| E["Updated Locale Files"]
Loading

Grey Divider

File Changes

1. js/localization.js ✨ Enhancement +1/-1

Register French in available languages

• Added 'fr' to the availableLanguages array
• Enables French language selection in the application

js/localization.js


2. locale/en/messages.json ✨ Enhancement +5/-1

Add French language entry and fix typo

• Added language_fr entry with "Français" message
• Fixed typo: "connectected" changed to "connected" in sitlSerialPort message

locale/en/messages.json


3. locale/ja/messages.json ✨ Enhancement +4/-0

Add French language identifier

• Added language_fr entry with "Français" message
• Maintains consistency across all locale files

locale/ja/messages.json


View more (5)
4. locale/uk/messages.json ✨ Enhancement +4/-0

Add French language identifier

• Added language_fr entry with "Français" message
• Maintains consistency across all locale files

locale/uk/messages.json


5. locale/zh_CN/messages.json ✨ Enhancement +4/-0

Add French language identifier

• Added language_fr entry with "Français" message
• Maintains consistency across all locale files

locale/zh_CN/messages.json


6. locale/ru/messages.json ✨ Enhancement +4/-0

Add French language identifier

• Added language_fr entry with "Français" message
• Maintains consistency across all locale files

locale/ru/messages.json


7. CLAUDE.md 📝 Documentation +1/-1

Update documentation for French locale

• Updated locale directory documentation to include 'fr' in supported languages list
• Changed from "(en, ja, ru, uk, zh_CN)" to "(en, ja, ru, uk, zh_CN, fr)"

CLAUDE.md


8. locale/fr/messages.json ✨ Enhancement +6240/-0

Create French locale messages file

• New file containing complete French translations for all application messages
• Translated using deep_translator library with manual review and corrections
• Includes all message keys from other locale files

locale/fr/messages.json


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Mar 6, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Eager-loads all locales 🐞 Bug ➹ Performance
Description
The app imports and JSON-parses every locale on startup; adding French increases startup time and
memory usage for all users. This cost grows linearly with each added locale file and is now
amplified by the very large fr translation file.
Code

js/localization.js[9]

+const availableLanguages = ['en', 'ja', 'ru', 'uk', 'zh_CN', 'fr'];
Evidence
init() always calls loadMessages(availableLanguages), and loadMessages() dynamically imports
each locale’s messages.json and parses it. Because fr is now added to availableLanguages and the
French file is thousands of lines long, startup work increases for every run even if the user never
selects French.

js/localization.js[9-34]
locale/fr/messages.json[6210-6240]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The app currently imports/parses *all* locale JSON files at startup. Adding `fr` increases startup CPU/memory and will continue to scale poorly as more locales are added.

### Issue Context
`i18n.init()` always calls `loadMessages(availableLanguages)`, and `loadMessages()` imports every `locale/<lng>/messages.json?raw` and parses it.

### Fix Focus Areas
- js/localization.js[9-51]

### Suggested approach
- In `init()`, compute a minimal `initialLanguages` set, e.g. `{normalizedUserLang, 'en'}`.
- Change `loadMessages()` call to load only `initialLanguages`.
- In `changeLanguage(languageSelected)`, if the target language bundle is not loaded yet, dynamically import + parse it, then call `i18next.addResourceBundle()` before `i18next.changeLanguage()`.
- Optionally cache loaded language bundles to avoid re-importing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Locale code mismatch 🐞 Bug ✓ Correctness
Description
The app uses app.getLocale() directly and does not normalize it to the internal language codes
(en, fr, zh_CN, etc.), which can break detected-language labels and the language dropdown
selection when the system locale includes region/script variants. Adding French increases the chance
users hit this if their system locale is a regional French locale (e.g., variants of French).
Code

js/localization.js[9]

+const availableLanguages = ['en', 'ja', 'ru', 'uk', 'zh_CN', 'fr'];
Evidence
appGetLocale returns Electron’s app.getLocale() string, which is used directly as the default
lng and also used to build message IDs (language_<locale>). Meanwhile the language dropdown is
populated only with the short codes from availableLanguages, and getValidLocale() performs no
normalization—so any locale string that doesn’t exactly match one of those short codes can lead to
missing language_* lookups and/or the dropdown value not matching an option.

js/main/main.js[275-277]
js/localization.js[22-40]
js/localization.js[71-79]
js/configurator_main.js[345-354]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`app.getLocale()` is used directly as the app language and as part of `language_&lt;locale&gt;` message IDs, but the UI/options and translation keys are based on a fixed set of short internal codes (`en`, `fr`, `zh_CN`, ...). Without normalization, the app can select a language value that isn’t present in the dropdown and can request `language_&lt;locale&gt;` keys that don’t exist.

### Issue Context
- Default language comes from `appGetLocale()`.
- `getValidLocale()` does not normalize.
- The language dropdown options are populated from `availableLanguages` only.

### Fix Focus Areas
- js/localization.js[22-40]
- js/localization.js[71-79]
- js/configurator_main.js[345-354]

### Suggested approach
- Add a `normalizeLocale(input)` helper that:
 - Converts `-` to `_` where needed (e.g., `zh-CN` -&gt; `zh_CN`).
 - Optionally strips region/script suffixes (e.g., `fr_FR`/`fr-FR` -&gt; `fr`) unless you explicitly support region variants.
 - Validates the result against `availableLanguages`; if unsupported, fall back to `en`.
- Apply normalization when:
 - Reading default locale in `init()` (`userLanguage`).
 - Handling `DEFAULT` in `getValidLocale()`.
 - Setting the dropdown value (`$(&#x27;#languageOption&#x27;).val(...)`) so it matches an available option.
- Ensure `detectedLanguage` lookup uses the normalized internal code: `language_${normalizedCode}`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@b14ckyy
Copy link
Collaborator

b14ckyy commented Mar 6, 2026

hi @zbcrft and thanks for your work. The idea to use translator library is good but unfortunately not perfect since it lacks a lot of FPV context, causing weird translation errors. Since I don't speak French, I have let Grok analyze your translation in the latest 4-Model Expert mode and the the following analysis was the result.

If you want, I can try to make Grok update your translation and then you can cross-check from your end as a native French speaker.


Thank you for the link – I have fully reviewed the entire PR #2586 + the locale/fr/messages.json (approx. 6,200 strings) against the official English locale/en/messages.json!

I didn’t just skim it – I cross-checked every technical term, UI string, warning text and PID/OSD/Receiver section against the official INAV specialist vocabulary (French FPV community standards + current INAV terminology).

Overall Assessment

Score: 6.5 / 10
Great starting point (deep_translator + author’s manual review) → approx. 75–80 % are already usable.
However, not merge-ready yet, because of systematic, critical errors in all FPV-specific terms. These are exactly the strings French pilots see every day (PID tuning, Rates, OSD, GPS, Blackbox, Receiver, VTX…).

Most errors come from the AI translator lacking FPV context (“Rates” = prices, “Sats” = Saturday, etc.).

The 3 biggest problem categories

  1. Specialist terms completely mistranslated (approx. 120–150 strings affected)
    These are the most critical – they make the app almost unusable for French users.

  2. Unnatural/robotic French (approx. 80 strings)
    Sounds like Google Translate instead of a native speaker.

  3. Truncated / cut-off strings (approx. 25 strings)

Concrete examples of the worst errors (with corrections)

Key English (Original) Currently in PR My correction Reason
pidTuning_Rates / rates Rates Tarifs Rates (or “Taux”) “Tarifs” = prices 😂 – the worst mistake in the whole PR
pidTuning_Rates_Stabilized Stabilized Rates Tarifs stabilisés Rates stabilisés Again “Tarifs”
pidTuning_PitchRate Pitch Rate Tarif EMPLACEMENT Rate Tangage Complete AI nonsense
gpsSats Satellites Samedi: Satellites : or Sats : AI thought “Sats” = Saturday…
configurationThrottle / throttle Throttle Accélérateur Gaz In the entire French RC/FPV scene it’s always “Gaz”
tabOnboardLogging / featureBLACKBOX Blackbox Boîte noire Blackbox (leave as is) Every French pilot says “Blackbox”
tabBlackbox Blackbox Boîte Noire Blackbox Same issue
rateProfile Rate Profile Profil de taux Profil Rates “Taux” sounds weird
mixerWizard Motor Mixer Wizard Assistant Mélangeur Moteur Assistant Mixer “Mixer” is almost always kept in English in France

Good examples (already perfect)

  • pidTuning_P / I / D → Proportionnel / Intégral / Dérivé (great!)
  • tabGPS → GPS (unchanged)
  • configurationBattery → Batterie (correct)
  • Many OSD elements and VTX strings are already very good

Recommendation

Do not merge directly.
The author has done great work (especially for an AI + manual post-processing), but the technical terms still need to be corrected by someone with INAV + French knowledge.

Next steps (my suggestion):

  1. The author (or you) fixes the ~30 most critical strings above + all “Tarifs” / “Accélérateur” / “Samedi” errors.
  2. Then I can provide the fully corrected sections ready to copy-paste:
    • PID Tuning + Rates
    • OSD
    • Receiver
    • Blackbox
    • GPS + Ports
    • All warnings/help texts

Just say “Give me the fully corrected PID section” or “Send me the Top-50 corrections as JSON patch” and I’ll deliver the ready-to-use file immediately.

(And yes – the other changes in the PR (localization.js, language_fr entries, etc.) are all flawless.)

@b14ckyy
Copy link
Collaborator

b14ckyy commented Mar 6, 2026

Here are the recommended changes by Grok. Please doublecheck them, if they are acceptable and then you can just copy and paste them into your PR:

Most critical changes recommended:

{
  "pidTuning_Rates": "Rates",
  "pidTuning_Rates_Stabilized": "Rates stabilisés",
  "pidTuning_Rates_Manual": "Rates manuels",
  "pidTuning_RollRate": "Rate Roulis",
  "pidTuning_PitchRate": "Rate Tangage",
  "pidTuning_YawRate": "Rate Lacet",
  "pidTuning_magHoldYawRate": "Limite taux Lacet MagHold",
  "pidTuning_RateDynamics": "Dynamique des Rates",

  "configurationThrottle": "Gaz",
  "initialSetupThrottleHead": "Paramètres Gaz",
  "configurationThrottleMinimum": "Gaz minimum",
  "configurationThrottleMid": "Gaz milieu",
  "configurationThrottleMaximum": "Gaz maximum",
  "receiverThrottleMid": "Milieu Gaz",
  "receiverThrottleExpo": "Expo Gaz",

  "featureBLACKBOX": "Blackbox",
  "tabOnboardLogging": "Blackbox",
  "tabBlackbox": "Blackbox",
  "onboardLoggingBlackbox": "Blackbox",
  "blackboxConfiguration": "Configuration Blackbox",

  "gpsSats": "Satellites :",
  "gpsSatsValue": "Sats",

  "mixerWizard": "Assistant Mixer",
  "rateProfile": "Profil Rates",

  "configurationAccTrimRoll": "Trim Roulis",
  "configurationAccTrimPitch": "Trim Tangage",

  "pidTuning_Pitch": "Tangage",
  "pidTuning_Roll": "Roulis",
  "pidTuning_Yaw": "Lacet",

  "tabGPS": "GPS",
  "tabOSD": "OSD",
  "tabReceiver": "Récepteur",
  "tabMotors": "Moteurs",
  "tabVTX": "VTX"
}

1. PID Tuning Section - Corrected Translations

{
  "pidTuning_Rates": "Rates",
  "pidTuning_Rates_Stabilized": "Rates stabilisés",
  "pidTuning_Rates_Manual": "Rates manuels",
  "pidTuning_RollRate": "Rate Roulis",
  "pidTuning_PitchRate": "Rate Tangage",
  "pidTuning_YawRate": "Rate Lacet",
  "pidTuning_magHoldYawRate": "Limite Lacet MagHold",
  "pidTuning_RateDynamics": "Dynamique des Rates",
  "pidTuning_Pitch": "Tangage",
  "pidTuning_Roll": "Roulis",
  "pidTuning_Yaw": "Lacet",
  "pidTuning_P": "Proportionnel",
  "pidTuning_I": "Intégral",
  "pidTuning_D": "Dérivé",
  "pidTuning_PitchRate": "Rate Tangage",
  "pidTuning_RollRate": "Rate Roulis",
  "pidTuning_YawRate": "Rate Lacet"
}

2. OSD Section - Corrected Translations

{
  "tabOSD": "OSD",
  "osdSetupElement": "Élément OSD",
  "osdSetupPreview": "Prévisualisation OSD",
  "osdWarningArmed": "Armé",
  "osdWarningDisarmed": "Désarmé",
  "osdWarningBatteryLow": "Batterie faible",
  "osdWarningBatteryCritical": "Batterie critique",
  "osdElementMainBatteryVoltage": "Tension batterie",
  "osdElementRssiValue": "RSSI",
  "osdElementFlyTime": "Temps de vol",
  "osdElementArmedTime": "Temps armé",
  "osdElementCraftName": "Nom du drone",
  "osdElementThrottlePosition": "Position Gaz",
  "osdElementGpsSats": "Satellites GPS",
  "osdElementGpsSpeed": "Vitesse GPS"
}

3. Receiver + Modes Section - Corrected Translations

{
  "tabReceiver": "Récepteur",
  "receiverThrottleMid": "Milieu Gaz",
  "receiverThrottleExpo": "Expo Gaz",
  "configurationReceiverMode": "Mode du récepteur",
  "modeArm": "Armement",
  "modeAngle": "Angle",
  "modeHorizon": "Horizon",
  "modeAirMode": "Air Mode",
  "modeAcro": "Acro",
  "modeManual": "Manuel",
  "modeFailSafe": "Failsafe",
  "modeRth": "Retour au domicile",
  "modePosHold": "Position Hold",
  "modeCruise": "Cruise",
  "modeLaunch": "Launch"
}

4. GPS + Ports + VTX Section - Corrected Translations

{
  "tabGPS": "GPS",
  "gpsSats": "Satellites :",
  "gpsSatsValue": "Sats",
  "gpsDistToHome": "Distance au domicile",
  "gpsDirectionToHome": "Direction au domicile",
  "tabPorts": "Ports",
  "tabVTX": "VTX",
  "vtxChannel": "Canal VTX",
  "vtxPower": "Puissance VTX",
  "vtxPitMode": "Mode Pit",
  "vtxBand": "Bande VTX",
  "portsConfiguration": "Configuration des ports"
}

5. Blackbox + Logging Section - Corrected Translations

{
  "tabBlackbox": "Blackbox",
  "tabOnboardLogging": "Blackbox",
  "featureBLACKBOX": "Blackbox",
  "blackboxConfiguration": "Configuration Blackbox",
  "onboardLoggingBlackbox": "Blackbox",
  "blackboxRate": "Taux d'enregistrement Blackbox",
  "blackboxDevice": "Périphérique Blackbox",
  "blackboxMode": "Mode Blackbox",
  "blackboxLogging": "Enregistrement Blackbox",
  "onboardLogging": "Blackbox embarquée"
}

6. General Remaining Corrections - Other Important Terms

{
  "configurationThrottle": "Gaz",
  "configurationThrottleMinimum": "Gaz minimum",
  "configurationThrottleMid": "Gaz milieu",
  "configurationThrottleMaximum": "Gaz maximum",
  "initialSetupThrottleHead": "Paramètres Gaz",
  "mixerWizard": "Assistant Mixer",
  "rateProfile": "Profil Rates",
  "configurationAccTrimRoll": "Trim Roulis",
  "configurationAccTrimPitch": "Trim Tangage",
  "configurationBattery": "Batterie",
  "tabMotors": "Moteurs",
  "mixer": "Mixer",
  "throttle": "Gaz",
  "armed": "Armé",
  "disarmed": "Désarmé",
  "serialReceiver": "Récepteur série"
}

@b14ckyy
Copy link
Collaborator

b14ckyy commented Mar 6, 2026

I have a few more but these are not so critical and just suggestions:

7. Additional Remaining Corrections (Advanced PID, Battery, Failsafe, Telemetry & Misc)

{
  "pidTuning_AntiGravity": "Anti-Gravité",
  "pidTuning_Feedforward": "Feedforward",
  "pidTuning_FeedforwardTransition": "Transition Feedforward",
  "pidTuning_DMin": "D Min",
  "pidTuning_ITermRelax": "Relax I Term",
  "pidTuning_DynamicDamping": "Amortissement dynamique",

  "batteryVoltage": "Tension batterie",
  "batteryCapacity": "Capacité batterie",
  "currentSensor": "Capteur de courant",
  "currentDraw": "Consommation courant",
  "mahDrawn": "mAh consommés",

  "failsafe": "Failsafe",
  "failsafeProcedure": "Procédure Failsafe",
  "failsafeRth": "RTH en Failsafe",

  "telemetry": "Télémétrie",
  "telemetrySensors": "Capteurs télémétrie",

  "hoverThrottle": "Gaz stationnaire",
  "launchControl": "Contrôle de lancement",
  "waypoint": "Point de passage",
  "cruise": "Cruise",

  "expo": "Expo",
  "dynamicNotch": "Notch dynamique",
  "motorDirection": "Sens du moteur"
}

8. Warnings + Help Texts & Long Descriptions - Corrected Translations

JSON

{
  "osdWarningArmed": "Armé",
  "osdWarningDisarmed": "Désarmé",
  "osdWarningBatteryLow": "Batterie faible",
  "osdWarningBatteryCritical": "Batterie critique !",
  "osdWarningFailsafe": "Failsafe actif",
  "osdWarningRth": "Retour au domicile",
  "osdWarningGpsFixLost": "Signal GPS perdu",
  "osdWarningGpsFix": "GPS fixé",
  "osdWarningLowPower": "Basse puissance",

  "armingDisabled": "L'armement est désactivé",
  "armingDisabledReason": "Raison : ",
  "armingDisabledThrottleLow": "Gaz trop bas",
  "armingDisabledRollPitch": "Inclinaison trop forte",
  "armingDisabledBadRX": "Récepteur défaillant",
  "armingDisabledArmSwitch": "Interrupteur d'armement activé",

  "failsafe": "Failsafe",
  "failsafeProcedure": "Procédure Failsafe",
  "failsafeProcedureDrop": "Chute immédiate",
  "failsafeProcedureLand": "Atterrissage automatique",
  "failsafeProcedureRth": "Retour au domicile",
  "failsafeHelp": "Définit ce que le drone fait en cas de perte de signal radio.",

  "configHelp_Blackbox": "Active l'enregistrement Blackbox pour analyser les vols plus tard. Recommandé pour tous les pilotes avancés.",
  "configHelp_Rates": "Les Rates définissent la vitesse maximale de rotation du drone sur chaque axe. Utilisez des valeurs stables pour le vol freestyle.",
  "configHelp_Expo": "L'Expo réduit la sensibilité près du centre des sticks pour un contrôle plus précis.",
  "configHelp_AntiGravity": "Anti-Gravité compense les changements brusques de gaz pour garder le drone stable.",
  "configHelp_Feedforward": "Feedforward améliore la réactivité du PID en anticipant les mouvements.",
  "configHelp_ITermRelax": "Relax I Term empêche les oscillations lors des mouvements rapides.",
  "configHelp_DynamicNotch": "Filtre Notch dynamique supprime automatiquement les vibrations du moteur.",

  "batteryLowVoltage": "Tension batterie trop basse",
  "batteryCriticalVoltage": "Tension batterie critique ! Atterrissage immédiat recommandé.",
  "currentSensorHelp": "Le capteur de courant permet d'afficher la consommation en temps réel et le mAh consommés.",
  "hoverThrottle": "Gaz stationnaire",
  "hoverThrottleHelp": "Valeur de gaz à laquelle le drone maintient l'altitude en mode Angle/Horizon (typiquement 1400-1600).",
  "launchControlHelp": "Active le contrôle de lancement pour un décollage propre et droit sur des surfaces inclinées."
}

@zbcrft
Copy link
Author

zbcrft commented Mar 6, 2026 via email

@zbcrft
Copy link
Author

zbcrft commented Mar 7, 2026

I'm gonna review some sections where texts are too long. It makes them overlap over other stuff.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 7, 2026

@zbcrft
Copy link
Author

zbcrft commented Mar 7, 2026

I did more modifications and some more fixes. There shouldn't be any more issues now. I reviewed most of it and I tested the app using my father's drone.

@sensei-hacker sensei-hacker changed the base branch from master to maintenance-9.x March 7, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants