mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
Merge pull request #1476 from bilawalsidhu/german/hal-638-fr
French in the language picker: the full catalog, French typography, one/many/ other plurals and the fr style guide. Voice plan steps join through a catalog string so French spaces its colon, and with nine languages the picker shows its search field. Based on the translation by @abiyeenzo (#907), checked against @meirm's French catalog (#312). Co-authored-by: Enzo Abyie <[email protected]> Co-authored-by: Meir Michanie <[email protected]>
This commit is contained in:
14 files changed
+3442
-9
No files matched your search
@@ -0,0 +1,4 @@
|
|||||||
|
- Add French (fr) to the language picker, with French typography and plural
|
||||||
|
forms. With nine languages the picker now shows its search field. Based on
|
||||||
|
the translation by @abiyeenzo (#907), checked against @meirm's French
|
||||||
|
catalog (#312) (German, @gekh, #1476).
|
||||||
@@ -3784,7 +3784,7 @@ test:track` 43 tracking invariants · headless QA harnesses under
|
|||||||
|
|
||||||
### Interface localization (October 2026)
|
### Interface localization (October 2026)
|
||||||
|
|
||||||
Shipped locales: **en** (source and fallback), **es**, **it**, **pt** (Brazilian Portuguese), **ru**, **uk**, **zh-CN** and **zh-Hant**. The code lives in
|
Shipped locales: **en** (source and fallback), **es**, **fr**, **it**, **pt** (Brazilian Portuguese), **ru**, **uk**, **zh-CN** and **zh-Hant**. The code lives in
|
||||||
`src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow:
|
`src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow:
|
||||||
[`docs/TRANSLATORS.md`](./TRANSLATORS.md).
|
[`docs/TRANSLATORS.md`](./TRANSLATORS.md).
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Translating God's Eye View
|
# Translating God's Eye View
|
||||||
|
|
||||||
Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Italian** (`it`), **Brazilian Portuguese** (`pt`), **Russian** (`ru`), **Ukrainian** (`uk`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`).
|
Shipped languages: **English** (source and fallback), **Spanish** (`es`), **French** (`fr`), **Italian** (`it`), **Brazilian Portuguese** (`pt`), **Russian** (`ru`), **Ukrainian** (`uk`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`).
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
@@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth
|
|||||||
|
|
||||||
## Language notes
|
## Language notes
|
||||||
|
|
||||||
Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/<code>.md`: [Spanish](./translations/es.md), [Italian](./translations/it.md), [Brazilian Portuguese](./translations/pt.md), [Russian](./translations/ru.md), [Ukrainian](./translations/uk.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one.
|
Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/<code>.md`: [Spanish](./translations/es.md), [French](./translations/fr.md), [Italian](./translations/it.md), [Brazilian Portuguese](./translations/pt.md), [Russian](./translations/ru.md), [Ukrainian](./translations/uk.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one.
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# French (`fr`)
|
||||||
|
|
||||||
|
Catalog: `src/i18n/locales/fr.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md).
|
||||||
|
|
||||||
|
Translation source: abiyeenzo (#907); the French part of meirm's #312 was used for comparison.
|
||||||
|
|
||||||
|
## Style
|
||||||
|
|
||||||
|
- Standard French that reads naturally in France, Belgium, Switzerland and Canada; avoid regionalisms.
|
||||||
|
- Address the user with "vous" imperatives: « Cliquez », « Activez », « Réessayez ». Tooltips that name an action use the infinitive: « Réduire le panneau », « Réinitialiser la caméra ». UPPERCASE HUD instructions also use the infinitive: « CLIQUER SUR UNE CAMÉRA POUR L'ACTIVER ».
|
||||||
|
- Sentence case, not Title Case: "Live Flights" → « Vols en direct ». UPPERCASE English stays UPPERCASE, accents included: « ÉTAT », « PRÉC. ».
|
||||||
|
- Typography: a narrow no-break space (U+202F) goes before `:` `;` `?` `!` and `%`, and inside « » quotes: `Supprimer le plan « {shot} » ?`. It keeps the sign on the same line as the word before it. Do not type a plain space there. The same narrow no-break space separates thousands in a number written into the text: « 1 000 km ». Ellipsis is `…`, not `...`. Dashes keep their spaces: « flux indisponible — réessayez ».
|
||||||
|
- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: PRÉC., SUIV., RÉINIT., ENREG., INDISP., DIST.
|
||||||
|
- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD and ALT stay in English everywhere, as in cockpit avionics. Words are translated: RANGE → « PORTÉE », heading in a sentence → « cap », ground-track course → « route » (« ROUTE 270° »).
|
||||||
|
- ON and OFF stay as they are on HUD toggles and chips (« CCTV ON », « PROJECTION OFF »); in a sentence use « activé » / « désactivé ».
|
||||||
|
- Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 (« Maintenez Space pour parler », « ESC pour fermer »).
|
||||||
|
- Units: km, m, km/h, m/s, nd (knots), ft (feet), h, min, s, with a space before the unit: « 250 km », « il y a 5 min »; in UPPERCASE text KM, KM/S, ND, FT, MIN. MW, dBZ, hPa and `°` stay. Decimal comma in fixed numbers: « 28,2710° N », « M4,4 ». Money: « 12 k$ », « 3 M$ », « 2 Md$ ».
|
||||||
|
- "ago" goes before the time: « il y a {count} min ». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add « il y a » again.
|
||||||
|
- Round-about exit ordinals: 1re, 2e, 3e… (« prenez la 1re sortie »).
|
||||||
|
|
||||||
|
## Plurals
|
||||||
|
|
||||||
|
A `tn()` entry needs three forms. `Intl.PluralRules('fr')` picks:
|
||||||
|
|
||||||
|
| Form | Counts | Example |
|
||||||
|
| ------- | -------------------------------------- | -------------------- |
|
||||||
|
| `one` | 0 and 1, fractions below 2 (1,5) | 1 caméra, 0 caméra |
|
||||||
|
| `many` | 1 000 000, 2 000 000… (exact millions) | 1 000 000 de caméras |
|
||||||
|
| `other` | everything else: 2–999 999, 2,5… | 3 caméras |
|
||||||
|
|
||||||
|
The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». The same goes for a layer name whose gender and number vary: « Couche activée : {label} », not « {label} activé », or a tool name: « Outil actif : {name} », not « {name} est actif ».
|
||||||
|
|
||||||
|
## Glossary
|
||||||
|
|
||||||
|
| English | Français |
|
||||||
|
| ------------------------------------------------------------ | ----------------------------------------------------------------------- |
|
||||||
|
| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES |
|
||||||
|
| feed / source / data source | flux / source / source de données |
|
||||||
|
| LIVE (status) / live data | DIRECT / données en direct |
|
||||||
|
| SIMULATED | SIMULÉ |
|
||||||
|
| stale / degraded / unavailable | obsolète / dégradé / indisponible |
|
||||||
|
| retry / retrying (status: RETRYING X) | nouvel essai / réessayez (NOUVEL ESSAI : X) |
|
||||||
|
| rate-limited | limite de requêtes atteinte |
|
||||||
|
| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ |
|
||||||
|
| Provider Settings | paramètres des fournisseurs |
|
||||||
|
| enable / disable | activer / désactiver |
|
||||||
|
| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte |
|
||||||
|
| tile (map) | tuile |
|
||||||
|
| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires |
|
||||||
|
| vessel, ship / tanker (AIS type) | navire / navire-citerne |
|
||||||
|
| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE |
|
||||||
|
| launch / launch site / space mission | lancement / site de lancement / mission spatiale |
|
||||||
|
| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance au sol (DIST. SOL) |
|
||||||
|
| contact / tracking / track (HUD) | contact / suivi / piste |
|
||||||
|
| brackets (HUD corner brackets around contacts) | cadres de ciblage |
|
||||||
|
| installation / site | installation / site |
|
||||||
|
| mapped / observed | cartographié / observé |
|
||||||
|
| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI |
|
||||||
|
| earthquake | séisme |
|
||||||
|
| active fire (FIRMS detection) / wildfire | feu actif / incendie |
|
||||||
|
| contained / containment (wildfire) | circonscrit / part circonscrite (not « maîtrisé », which is controlled) |
|
||||||
|
| advisory (NHC/CPHC cyclone) | bulletin |
|
||||||
|
| forecast / lead hours / valid / issued | prévision / échéances / valide / émise |
|
||||||
|
| AQHI (Canada) | CQAS (cote air santé) |
|
||||||
|
| radio station / tune | station / régler |
|
||||||
|
| bikeshare / transit | vélos partagés / transports en commun |
|
||||||
|
| route (directions) / turn (maneuver) | itinéraire / manœuvre |
|
||||||
|
| scene / shot / scene recipe | scène / plan / recette de scène |
|
||||||
|
| bundle / data pack / anchor | archive / paquet de données / ancre |
|
||||||
|
| import / export (noun: file, scene, project) | importation / exportation (not « import » / « export ») |
|
||||||
|
| capture camera as anchor / set move start (scene editor) | ancre à la position de la caméra / vue actuelle comme départ |
|
||||||
|
| story beat | étape du récit |
|
||||||
|
| briefing / panel / dock | briefing / panneau / dock |
|
||||||
|
| cockpit | cockpit |
|
||||||
|
| preset / visual preset | préréglage / préréglage visuel |
|
||||||
|
| Scope (circular viewport mask) / keyhole | lunette / ouverture |
|
||||||
|
| detection overlay | surcouche de détection |
|
||||||
|
| Clean UI | vue épurée |
|
||||||
|
| Street Level (layer) / Street View (Google) | Niveau rue / Street View |
|
||||||
|
| Recent Imagery / box | imagerie récente / zone |
|
||||||
|
| Daily overview / overview (Recent Imagery VIIRS product) | vue quotidienne (one name for the product, not « vue d'ensemble ») |
|
||||||
|
| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler |
|
||||||
|
| Cyber (HUD layout, effect) | Cyber |
|
||||||
|
| heading / course (ground track) / altitude / ground speed | cap / route / altitude / vitesse sol |
|
||||||
|
| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged |
|
||||||
|
| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. |
|
||||||
|
| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. |
|
||||||
|
| Previous / Next (button text) | Précédent / Suivant |
|
||||||
|
| L / R (relative bearing) | G / D |
|
||||||
|
| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL |
|
||||||
|
| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO |
|
||||||
|
| NOT AN ALL-CLEAR | PAS UN FEU VERT |
|
||||||
|
| AI agent | agent IA |
|
||||||
|
| share (a view or link) | partager |
|
||||||
|
| click / click to … | cliquez / cliquer pour … |
|
||||||
|
| map heading (compass, north-up control) | orientation (de la carte) |
|
||||||
|
| subject (cockpit / shared contact) | cible |
|
||||||
|
| cloud cover / CLOUD (briefing readout) | nébulosité / NÉBULOSITÉ |
|
||||||
|
| LEVEL (cockpit horizon guide) | HORIZON |
|
||||||
|
| CALIBRATED / CURATED / RAW PRIOR (CCTV pose) | CALIBRÉE / VÉRIFIÉE / ESTIM. INITIALE |
|
||||||
|
| DATASHEET / SPEC FOV (CCTV lens range) | FICHE TECHNIQUE / FOV CONSTRUCTEUR |
|
||||||
|
| PORT TENDER (AIS type) | SERVITUDE PORT. (navire de servitude portuaire) |
|
||||||
|
| ChatGPT sign-in (action) / opening sign-in / sign-in expired | connexion / page de connexion / la session a expiré |
|
||||||
|
| authored shot (scene) | plan scénarisé |
|
||||||
|
| report / record (USGS event card) / readout, reading | rapport / relevé (a measured value only) |
|
||||||
@@ -440,6 +440,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -482,6 +483,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -515,6 +517,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -540,6 +543,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -560,6 +564,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -583,6 +588,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -613,6 +619,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -651,6 +658,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -671,6 +679,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -832,6 +841,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -958,6 +968,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1030,6 +1041,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1082,6 +1094,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1148,6 +1161,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1181,6 +1195,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1215,6 +1230,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1249,6 +1265,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1286,6 +1303,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1332,6 +1350,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1372,6 +1391,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1426,6 +1446,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1459,6 +1480,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1511,6 +1533,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1578,6 +1601,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1611,6 +1635,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1655,6 +1680,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1681,6 +1707,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1741,6 +1768,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -1807,6 +1835,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -2693,6 +2722,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3282,6 +3312,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3396,6 +3427,7 @@
|
|||||||
"src/data/cameraArrival.js",
|
"src/data/cameraArrival.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3423,6 +3455,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3462,6 +3495,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3493,6 +3527,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3588,6 +3623,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3647,6 +3683,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3905,6 +3942,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -3952,6 +3990,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -4009,6 +4048,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -4029,6 +4069,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -4092,6 +4133,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
@@ -4294,6 +4336,7 @@
|
|||||||
"src/i18n/index.js",
|
"src/i18n/index.js",
|
||||||
"src/i18n/locale.js",
|
"src/i18n/locale.js",
|
||||||
"src/i18n/locales/es.json",
|
"src/i18n/locales/es.json",
|
||||||
|
"src/i18n/locales/fr.json",
|
||||||
"src/i18n/locales/it.json",
|
"src/i18n/locales/it.json",
|
||||||
"src/i18n/locales/pt.json",
|
"src/i18n/locales/pt.json",
|
||||||
"src/i18n/locales/ru.json",
|
"src/i18n/locales/ru.json",
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () =>
|
|||||||
assert.equal(normalizeLocale('uk'), 'uk');
|
assert.equal(normalizeLocale('uk'), 'uk');
|
||||||
assert.equal(normalizeLocale('uk-UA'), 'uk');
|
assert.equal(normalizeLocale('uk-UA'), 'uk');
|
||||||
assert.equal(normalizeLocale('en_GB'), 'en');
|
assert.equal(normalizeLocale('en_GB'), 'en');
|
||||||
|
assert.equal(normalizeLocale('fr'), 'fr');
|
||||||
|
assert.equal(normalizeLocale('fr-CA'), 'fr');
|
||||||
|
assert.equal(normalizeLocale('FR_be'), 'fr');
|
||||||
assert.equal(normalizeLocale('pt-BR'), 'pt');
|
assert.equal(normalizeLocale('pt-BR'), 'pt');
|
||||||
assert.equal(normalizeLocale('pt_PT'), 'pt');
|
assert.equal(normalizeLocale('pt_PT'), 'pt');
|
||||||
assert.equal(normalizeLocale('xx'), null);
|
assert.equal(normalizeLocale('xx'), null);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
writeStoredLocale,
|
writeStoredLocale,
|
||||||
} from './locale.js';
|
} from './locale.js';
|
||||||
import es from './locales/es.json' with { type: 'json' };
|
import es from './locales/es.json' with { type: 'json' };
|
||||||
|
import fr from './locales/fr.json' with { type: 'json' };
|
||||||
import it from './locales/it.json' with { type: 'json' };
|
import it from './locales/it.json' with { type: 'json' };
|
||||||
import pt from './locales/pt.json' with { type: 'json' };
|
import pt from './locales/pt.json' with { type: 'json' };
|
||||||
import ru from './locales/ru.json' with { type: 'json' };
|
import ru from './locales/ru.json' with { type: 'json' };
|
||||||
@@ -26,6 +27,7 @@ import zhHant from './locales/zh-Hant.json' with { type: 'json' };
|
|||||||
|
|
||||||
const CATALOGS = Object.freeze({
|
const CATALOGS = Object.freeze({
|
||||||
es,
|
es,
|
||||||
|
fr,
|
||||||
it,
|
it,
|
||||||
pt,
|
pt,
|
||||||
ru,
|
ru,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const DEFAULT_LOCALE = 'en';
|
|||||||
export const LOCALES = Object.freeze([
|
export const LOCALES = Object.freeze([
|
||||||
'en',
|
'en',
|
||||||
'es',
|
'es',
|
||||||
|
'fr',
|
||||||
'it',
|
'it',
|
||||||
'pt',
|
'pt',
|
||||||
'ru',
|
'ru',
|
||||||
@@ -23,6 +24,7 @@ export const LOCALES = Object.freeze([
|
|||||||
export const LOCALE_NAMES = Object.freeze({
|
export const LOCALE_NAMES = Object.freeze({
|
||||||
en: 'English',
|
en: 'English',
|
||||||
es: 'Español',
|
es: 'Español',
|
||||||
|
fr: 'Français',
|
||||||
it: 'Italiano',
|
it: 'Italiano',
|
||||||
pt: 'Português (Brasil)',
|
pt: 'Português (Brasil)',
|
||||||
ru: 'Русский',
|
ru: 'Русский',
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -124,6 +124,185 @@
|
|||||||
"ΔN",
|
"ΔN",
|
||||||
"▲ {frp} MW"
|
"▲ {frp} MW"
|
||||||
],
|
],
|
||||||
|
"fr": [
|
||||||
|
"1090 MHz",
|
||||||
|
"978 MHz UAT",
|
||||||
|
"ALTITUDE",
|
||||||
|
"ALTITUDE · FT",
|
||||||
|
"ANIME",
|
||||||
|
"AUTO",
|
||||||
|
"Action",
|
||||||
|
"Allocation",
|
||||||
|
"Altitude {altitude}",
|
||||||
|
"Ambient",
|
||||||
|
"Anime",
|
||||||
|
"Austin",
|
||||||
|
"Aviation / Marine",
|
||||||
|
"BRG {value}°",
|
||||||
|
"BRG —",
|
||||||
|
"Bloom",
|
||||||
|
"Blues",
|
||||||
|
"Bus",
|
||||||
|
"CAL {value}",
|
||||||
|
"CAL · {badge}",
|
||||||
|
"CALIBRATION",
|
||||||
|
"CARGO",
|
||||||
|
"CAUSE",
|
||||||
|
"CCTV",
|
||||||
|
"CCTV OFF",
|
||||||
|
"CCTV ON",
|
||||||
|
"COCKPIT",
|
||||||
|
"COMMERCIAL",
|
||||||
|
"CONTACT",
|
||||||
|
"CONTACTS",
|
||||||
|
"CONTACTS · 250 KM",
|
||||||
|
"CRS {value}°",
|
||||||
|
"CRT",
|
||||||
|
"Country",
|
||||||
|
"Cyan",
|
||||||
|
"Cyber",
|
||||||
|
"Cyclones · NHC / CPHC",
|
||||||
|
"DENSE",
|
||||||
|
"DENSE ···",
|
||||||
|
"DENSE ✕",
|
||||||
|
"DEST ---°",
|
||||||
|
"DEST {bearing}",
|
||||||
|
"DESTINATION",
|
||||||
|
"Dance",
|
||||||
|
"Drone",
|
||||||
|
"ENE",
|
||||||
|
"ESE",
|
||||||
|
"EUROPE",
|
||||||
|
"FLIR",
|
||||||
|
"FM MHZ",
|
||||||
|
"FOV",
|
||||||
|
"FOV {value}°",
|
||||||
|
"FT",
|
||||||
|
"Ferry",
|
||||||
|
"Folk",
|
||||||
|
"Funk",
|
||||||
|
"GAIN",
|
||||||
|
"GEO",
|
||||||
|
"GOOGLE STREET VIEW",
|
||||||
|
"Gain",
|
||||||
|
"Google Street View",
|
||||||
|
"Grain",
|
||||||
|
"HDG",
|
||||||
|
"HDG {value}°",
|
||||||
|
"Hip-Hop",
|
||||||
|
"House",
|
||||||
|
"IMAGE",
|
||||||
|
"Indie",
|
||||||
|
"Ironbow",
|
||||||
|
"Jazz",
|
||||||
|
"LOCAL",
|
||||||
|
"Landsat 8/9",
|
||||||
|
"Landsat 8/9 via HLS",
|
||||||
|
"Los Angeles",
|
||||||
|
"MIC",
|
||||||
|
"MIL",
|
||||||
|
"MINI",
|
||||||
|
"MISSION",
|
||||||
|
"MM",
|
||||||
|
"MSG/S",
|
||||||
|
"Metal",
|
||||||
|
"Minimal",
|
||||||
|
"Minutes",
|
||||||
|
"Mode",
|
||||||
|
"NAV",
|
||||||
|
"NE",
|
||||||
|
"NNE",
|
||||||
|
"NOIR",
|
||||||
|
"NORMAL",
|
||||||
|
"NVG",
|
||||||
|
"New York",
|
||||||
|
"Noir",
|
||||||
|
"Normal",
|
||||||
|
"OFF",
|
||||||
|
"OK",
|
||||||
|
"ON",
|
||||||
|
"ON/OFF",
|
||||||
|
"Oldies",
|
||||||
|
"PAUSE",
|
||||||
|
"POSITION {age}",
|
||||||
|
"PROJ OFF",
|
||||||
|
"PROJECTION OFF",
|
||||||
|
"PROJECTION ON",
|
||||||
|
"PROPAGATION",
|
||||||
|
"Paris",
|
||||||
|
"Pause",
|
||||||
|
"Plan",
|
||||||
|
"Pop",
|
||||||
|
"Punk",
|
||||||
|
"RADIO",
|
||||||
|
"REC",
|
||||||
|
"Radio",
|
||||||
|
"Reggae",
|
||||||
|
"Rock",
|
||||||
|
"S2 GhostMaps",
|
||||||
|
"SAR",
|
||||||
|
"SE",
|
||||||
|
"SIG",
|
||||||
|
"SOURCE",
|
||||||
|
"SQUAWK {code} · {status}",
|
||||||
|
"SRC {value}",
|
||||||
|
"SSE",
|
||||||
|
"STANDARD",
|
||||||
|
"STATION",
|
||||||
|
"STD",
|
||||||
|
"San Francisco",
|
||||||
|
"Satellites",
|
||||||
|
"Saturation",
|
||||||
|
"Sonar",
|
||||||
|
"Soul",
|
||||||
|
"Source",
|
||||||
|
"Station",
|
||||||
|
"Station {id}",
|
||||||
|
"Style",
|
||||||
|
"TAGS · {tags}",
|
||||||
|
"TEMP",
|
||||||
|
"TYPE",
|
||||||
|
"Tallinn",
|
||||||
|
"Techno",
|
||||||
|
"Tokyo",
|
||||||
|
"Train",
|
||||||
|
"Trance",
|
||||||
|
"USB {rate} msg/s",
|
||||||
|
"VOLUME",
|
||||||
|
"VS",
|
||||||
|
"WHOT/BHOT",
|
||||||
|
"audio {state}",
|
||||||
|
"dB",
|
||||||
|
"ft",
|
||||||
|
"hPa",
|
||||||
|
"image",
|
||||||
|
"installation class|BASE",
|
||||||
|
"installation class|INSTALLATION",
|
||||||
|
"km",
|
||||||
|
"km/h",
|
||||||
|
"max {value} MW",
|
||||||
|
"min",
|
||||||
|
"mini",
|
||||||
|
"mph",
|
||||||
|
"nominal",
|
||||||
|
"satellite",
|
||||||
|
"standard",
|
||||||
|
"station",
|
||||||
|
"voice|OFF",
|
||||||
|
"{count} MSGS",
|
||||||
|
"{count} SOURCES",
|
||||||
|
"{count} messages",
|
||||||
|
"{n} cyclones",
|
||||||
|
"{n} satellites",
|
||||||
|
"{rate} msg/s",
|
||||||
|
"{value} KM",
|
||||||
|
"{value} KM/H",
|
||||||
|
"{value} KM/S",
|
||||||
|
"ΔE",
|
||||||
|
"ΔN",
|
||||||
|
"Ⅱ PAUSE",
|
||||||
|
"▲ {frp} MW"
|
||||||
|
],
|
||||||
"it": [
|
"it": [
|
||||||
"1090 MHz",
|
"1090 MHz",
|
||||||
"978 MHz UAT",
|
"978 MHz UAT",
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// The CCTV HUD summary shows the CAL badge, source kind and view band in the
|
||||||
|
// UI language; English keeps its codes, and unknown source codes stay codes.
|
||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { setLocale } from '../../i18n/index.js';
|
||||||
|
import { createPresentation } from './presentation.js';
|
||||||
|
|
||||||
|
function summary(sourceKind) {
|
||||||
|
const camera = {
|
||||||
|
id: 'c1',
|
||||||
|
city: 'Austin',
|
||||||
|
name: 'Cam',
|
||||||
|
rangeM: 100,
|
||||||
|
fovDeg: 60,
|
||||||
|
feedType: 'image',
|
||||||
|
};
|
||||||
|
const record = { camera };
|
||||||
|
const presentation = createPresentation({
|
||||||
|
state: {
|
||||||
|
_records: [record],
|
||||||
|
_healthById: new Map(sourceKind ? [['c1', { sourceKind }]] : []),
|
||||||
|
_showProjection: false,
|
||||||
|
_coverageMode: 'sector',
|
||||||
|
},
|
||||||
|
services: {},
|
||||||
|
parts: {
|
||||||
|
selection: { getActiveRecord: () => record },
|
||||||
|
model: {
|
||||||
|
sectorAreaKm2: () => 1,
|
||||||
|
currentViewContext: () => 'street:1:2',
|
||||||
|
},
|
||||||
|
geometry: { coverageNeighborCount: () => 0 },
|
||||||
|
calibration: { deriveCalBadge: () => 'raw-prior' },
|
||||||
|
},
|
||||||
|
source: {},
|
||||||
|
});
|
||||||
|
return presentation.buildSummaryText();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('en: CAL, SRC and CONTEXT keep their English codes', () => {
|
||||||
|
setLocale('en');
|
||||||
|
assert.match(summary('upstream'), /CAL RAW PRIOR · SRC UPSTREAM/);
|
||||||
|
assert.match(summary(null), /SRC IMAGE · STREET CONTEXT/);
|
||||||
|
assert.match(summary('upstream-image'), /SRC UPSTREAM-IMAGE/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fr: CAL, SRC and CONTEXT values are translated', () => {
|
||||||
|
setLocale('fr');
|
||||||
|
try {
|
||||||
|
assert.match(
|
||||||
|
summary('upstream'),
|
||||||
|
/CAL ESTIM\. INITIALE · SRC AMONT · CONTEXTE RUE/,
|
||||||
|
);
|
||||||
|
assert.match(summary('upstream-image'), /SRC UPSTREAM-IMAGE/);
|
||||||
|
} finally {
|
||||||
|
setLocale('en');
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -31,6 +31,9 @@ const MANY = Object.keys(NAMES);
|
|||||||
|
|
||||||
const codes = (rows) => rows.map((row) => row.code);
|
const codes = (rows) => rows.map((row) => row.code);
|
||||||
|
|
||||||
|
// Few enough languages that the picker has no search field.
|
||||||
|
const UNSEARCHED = ['en', 'es', 'ru', 'uk', 'zh-CN', 'zh-Hant'];
|
||||||
|
|
||||||
test('the current language comes first, the rest by their own names', () => {
|
test('the current language comes first, the rest by their own names', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
codes(
|
codes(
|
||||||
@@ -40,7 +43,7 @@ test('the current language comes first, the rest by their own names', () => {
|
|||||||
nativeNames: LOCALE_NAMES,
|
nativeNames: LOCALE_NAMES,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
['ru', 'uk', 'en', 'es', 'it', 'pt', 'zh-CN', 'zh-Hant'],
|
['ru', 'uk', 'en', 'es', 'fr', 'it', 'pt', 'zh-CN', 'zh-Hant'],
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
codes(
|
codes(
|
||||||
@@ -50,7 +53,7 @@ test('the current language comes first, the rest by their own names', () => {
|
|||||||
nativeNames: LOCALE_NAMES,
|
nativeNames: LOCALE_NAMES,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
['es', 'en', 'it', 'pt', 'ru', 'uk', 'zh-CN', 'zh-Hant'],
|
['es', 'en', 'fr', 'it', 'pt', 'ru', 'uk', 'zh-CN', 'zh-Hant'],
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
codes(
|
codes(
|
||||||
@@ -60,7 +63,7 @@ test('the current language comes first, the rest by their own names', () => {
|
|||||||
nativeNames: LOCALE_NAMES,
|
nativeNames: LOCALE_NAMES,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
['en', 'es', 'it', 'pt', 'ru', 'uk', 'zh-CN', 'zh-Hant'],
|
['en', 'es', 'fr', 'it', 'pt', 'ru', 'uk', 'zh-CN', 'zh-Hant'],
|
||||||
);
|
);
|
||||||
const rows = buildLocaleOptions({
|
const rows = buildLocaleOptions({
|
||||||
locales: MANY,
|
locales: MANY,
|
||||||
@@ -95,6 +98,7 @@ test('each row gets the interface-language name for search, unless it only repea
|
|||||||
const byCode = Object.fromEntries(rows.map((row) => [row.code, row]));
|
const byCode = Object.fromEntries(rows.map((row) => [row.code, row]));
|
||||||
assert.equal(byCode.en.localName, 'английский');
|
assert.equal(byCode.en.localName, 'английский');
|
||||||
assert.equal(byCode.es.localName, 'испанский');
|
assert.equal(byCode.es.localName, 'испанский');
|
||||||
|
assert.equal(byCode.fr.localName, 'французский');
|
||||||
assert.equal(byCode.ru.localName, '', 'русский only repeats Русский');
|
assert.equal(byCode.ru.localName, '', 'русский only repeats Русский');
|
||||||
const english = buildLocaleOptions({
|
const english = buildLocaleOptions({
|
||||||
locales: LOCALES,
|
locales: LOCALES,
|
||||||
@@ -103,6 +107,7 @@ test('each row gets the interface-language name for search, unless it only repea
|
|||||||
localName: createLocalNameReader('en'),
|
localName: createLocalNameReader('en'),
|
||||||
});
|
});
|
||||||
assert.equal(english.find((row) => row.code === 'es').localName, 'Spanish');
|
assert.equal(english.find((row) => row.code === 'es').localName, 'Spanish');
|
||||||
|
assert.equal(english.find((row) => row.code === 'fr').localName, 'French');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('without Intl.DisplayNames the interface-language name is simply left out', () => {
|
test('without Intl.DisplayNames the interface-language name is simply left out', () => {
|
||||||
@@ -165,7 +170,10 @@ test('search folds case and diacritics, and matches either name or the code', ()
|
|||||||
|
|
||||||
test('the search field appears only above the threshold', () => {
|
test('the search field appears only above the threshold', () => {
|
||||||
assert.equal(LOCALE_SEARCH_THRESHOLD, 8);
|
assert.equal(LOCALE_SEARCH_THRESHOLD, 8);
|
||||||
assert.equal(createLocalePickerModel({ current: 'en' }).searchable, false);
|
assert.equal(
|
||||||
|
createLocalePickerModel({ current: 'en' }).searchable,
|
||||||
|
LOCALES.length > LOCALE_SEARCH_THRESHOLD,
|
||||||
|
);
|
||||||
const eight = MANY.slice(0, 8);
|
const eight = MANY.slice(0, 8);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
createLocalePickerModel({
|
createLocalePickerModel({
|
||||||
@@ -250,6 +258,7 @@ test('type-ahead cycles by first letter and refines with more letters', () => {
|
|||||||
|
|
||||||
test('keyboard model: open on the current language, move, choose, close', () => {
|
test('keyboard model: open on the current language, move, choose, close', () => {
|
||||||
const model = createLocalePickerModel({
|
const model = createLocalePickerModel({
|
||||||
|
locales: UNSEARCHED,
|
||||||
current: 'ru',
|
current: 'ru',
|
||||||
localName: createLocalNameReader('ru'),
|
localName: createLocalNameReader('ru'),
|
||||||
});
|
});
|
||||||
@@ -293,7 +302,11 @@ test('keyboard model: open on the current language, move, choose, close', () =>
|
|||||||
|
|
||||||
test('keyboard model: type-ahead resets after a pause and ignores shortcuts', () => {
|
test('keyboard model: type-ahead resets after a pause and ignores shortcuts', () => {
|
||||||
let clock = 0;
|
let clock = 0;
|
||||||
const model = createLocalePickerModel({ current: 'en', now: () => clock });
|
const model = createLocalePickerModel({
|
||||||
|
locales: UNSEARCHED,
|
||||||
|
current: 'en',
|
||||||
|
now: () => clock,
|
||||||
|
});
|
||||||
model.openList();
|
model.openList();
|
||||||
assert.deepEqual(model.keydown({ key: 'e' }), { handled: true });
|
assert.deepEqual(model.keydown({ key: 'e' }), { handled: true });
|
||||||
assert.equal(model.activeOption.code, 'es');
|
assert.equal(model.activeOption.code, 'es');
|
||||||
|
|||||||
+4
-1
@@ -963,7 +963,10 @@ export function progressStepLabel(step, label) {
|
|||||||
: step
|
: step
|
||||||
? spokenLabel(step, 24)
|
? spokenLabel(step, 24)
|
||||||
: t('Working');
|
: t('Working');
|
||||||
return label ? `${base}: ${spokenLabel(label, 32)}` : base;
|
// The join is a catalog string so each language spaces its colon.
|
||||||
|
return label
|
||||||
|
? t('{name}: {state}', { name: base, state: spokenLabel(label, 32) })
|
||||||
|
: base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
spokenLabel,
|
spokenLabel,
|
||||||
} from './speech.js';
|
} from './speech.js';
|
||||||
import { countWords, findHedges } from './speechLint.js';
|
import { countWords, findHedges } from './speechLint.js';
|
||||||
|
import { setLocale } from '../i18n/index.js';
|
||||||
|
|
||||||
function envelope(name, result, args) {
|
function envelope(name, result, args) {
|
||||||
return attachVoiceResult(name, result, args);
|
return attachVoiceResult(name, result, args);
|
||||||
@@ -459,3 +460,15 @@ test('labels are bounded and cleaned before they are spoken', () => {
|
|||||||
'background steps stay on screen',
|
'background steps stay on screen',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('progress step labels join through the catalog colon', () => {
|
||||||
|
setLocale('fr');
|
||||||
|
try {
|
||||||
|
assert.equal(
|
||||||
|
progressStepLabel('resolve', 'Capitol'),
|
||||||
|
'Recherche de lieux\u202f: Capitol',
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setLocale('en');
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in new issue
Block a user