> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/fr/development/i18n.md).

# i18n

MyIP est disponible en quatre langues, et les quatre sont au même niveau. Il n'existe pas de locale « principale » qui reçoive les fonctionnalités en premier.

| Code | Langue             | Fichier                    |
| ---- | ------------------ | -------------------------- |
| `en` | Anglais (de repli) | `frontend/locales/en.json` |
| `zh` | Chinois simplifié  | `frontend/locales/zh.json` |
| `fr` | Français           | `frontend/locales/fr.json` |
| `ru` | Russe              | `frontend/locales/ru.json` |

## Configuration

L'application utilise **vue-i18n** en mode API de composition. L'instance est créée dans `frontend/locales/i18n.js` avec `legacy: false` et `fallbackLocale: 'en'`, puis enregistrée dans `main.js`.

Dans un composant, vous récupérez `t()` depuis `useI18n()`:

```vue
<script setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>

<template>
  <p>{{ t('macchecker.Note') }}</p>
</template>
```

Rien d'affiché à l'utilisateur n'est codé en dur. Chaque chaîne passe par `t()`.

## Fichiers de locale

Chaque fichier de locale est un objet JSON, organisé par fonctionnalité. Les espaces de noms de niveau supérieur comprennent `nav`, `advancedtools`, `page`, `changelog`, et un par outil — `macchecker`, `whois`, `dnsresolver`, `censorshipcheck`, et ainsi de suite.

L'espace de noms d'un outil correspond normalement à son identifiant de registre :

{% code title="frontend/locales/en.json" %}

```json
"macchecker": {
  "Title": "Recherche MAC",
  "Note": "Interrogez le fabricant d'une adresse physique (adresse MAC)…",
  "Note2": "Veuillez saisir une adresse physique pour lancer la requête :",
  "Placeholder": "F0:2F:4B:01:0A:AA",
  "invalidMAC": "Adresse physique invalide",
  "fetchError": "Impossible de récupérer les résultats de la requête"
}
```

{% endcode %}

La description de la carte sur la page d'accueil se trouve séparément, dans le `advancedtools` espace de noms partagé, car c'est vers lui que pointe le registre des outils `noteKey` :

```json
"advancedtools": {
  "MacChecker": "Interroger les informations d'une adresse physique"
}
```

**Les noms des clés sont identiques dans les quatre fichiers. Seules les valeurs diffèrent.**

## Le chargement est à la demande

Les quatre packs ne sont jamais chargés ensemble. Les regrouper en amont coûtait environ 44 Ko compressés gzip de poids mort — trois locales inutilisées à chaque chargement de page.

À la place `frontend/locales/i18n.js` contient une carte d'importations dynamiques :

{% code title="frontend/locales/i18n.js" %}

```js
const localeLoaders = {
  en: () => import('./en.json'),
  zh: () => import('./zh.json'),
  fr: () => import('./fr.json'),
  ru: () => import('./ru.json'),
};
```

{% endcode %}

L'instance i18n commence avec **des messages** messages. `loadActiveLocaleMessages()` injecte la locale active ainsi que le `en` de secours (en parallèle, mémorisé), et `main.js` l'attend avant le montage — ainsi le premier rendu est déjà traduit. Changer de langue enregistre le choix et redémarre l'application, ce qui signifie qu'une seule locale est active par chargement de page.

### Comment la langue est choisie

`setLanguage()` dans `frontend/locales/i18n.js` se résout, dans l'ordre :

1. **Préférence enregistrée** dans `localStorage` — la clé de préférences actuelle, puis les clés héritées, de sorte qu'une clé tout juste mise à jour retrouve encore un ancien choix.
2. **`?hl=` paramètre de requête**, s'il désigne une locale prise en charge.
3. **Langue du navigateur** (`navigator.language`), comparée sur ses deux premiers caractères.
4. **`en`.**

Un plugin Vite au moment de la compilation (`localePreloadPlugin` dans `vite.config.js`) reproduit exactement cet ordre dans un petit `<head>` script inline et émet un `<link rel="modulepreload">` pour le pack choisi pendant que le HTML est encore en cours de diffusion — ainsi la locale se télécharge en parallèle avec le bundle principal au lieu de l'attendre après. Une mauvaise estimation ne gaspille qu'un seul préchargement ; le véritable import tranche toujours.

Une fois les messages chargés, `updateMeta()` définit `document.documentElement.lang` (avec `zh` déclaré comme `zh-CN`, puisque le pack est en chinois simplifié uniquement) et actualise les `titre`, `mots-clés`, et `description` balises meta à partir des `page.*` clés.

## Sous-packs

Deux jeux de données sont suffisamment volumineux pour rester hors du pack principal de locale et se charger à la demande uniquement pour la locale active :

<table><thead><tr><th width="300">Sous-pack</th><th>Chargé par</th></tr></thead><tbody><tr><td><code>frontend/locales/security-checklist/{en,zh,fr,ru}.json</code></td><td><code>SecurityChecklist.vue</code> — sa propre carte de chargeurs ; le jeu de données fait environ 30 Ko compressés gzip par langue et seul cet outil le lit.</td></tr><tr><td><code>frontend/locales/privacy/{en,zh,fr,ru}.json</code></td><td><code>PrivacyPolicy.vue</code> — fusionné dans i18n via <code>mergeLocaleMessage()</code> afin que <code>t()</code> et <code>tm()</code> résolve la copie normalement.</td></tr></tbody></table>

Les deux suivent le même schéma : une `{ en, zh, fr, ru }` carte d'importations dynamiques, avec retour à `en` pour une locale inconnue.

{% hint style="info" %}
**Quand ajouter un sous-pack :** un jeu de données volumineux, qui appartient à une seule vue chargée paresseusement et qui, sinon, se retrouverait dans le bundle du premier affichage de chaque visiteur. Les chaînes d'interface ordinaires vont toujours dans le pack principal.
{% endhint %}

## La règle des quatre locales

{% hint style="warning" %}
**Tout changement qui expose du texte est livré dans les quatre locales dans le même changement.** Pas une PR de suivi, pas un TODO.
{% endhint %}

Cela signifie :

* Une nouvelle clé va dans `en.json`, `zh.json`, `fr.json`, **et** `ru.json`.
* Une chaîne reformulée est reformulée dans les quatre.
* Une clé supprimée est supprimée des quatre.
* L'élément `changelog.json` associé contient les quatre traductions.

`fallbackLocale: 'en'` signifie qu'une clé manquante retombe sur l'anglais au lieu d'afficher un chemin de clé brut — ce qui explique précisément pourquoi une couverture partielle est facile à manquer en revue. Ne vous y fiez pas.

Si vous ne pouvez vraiment pas produire une traduction, dites-le dans la PR. Un mainteneur préférera corriger la formulation plutôt que découvrir une locale manquante après la publication.

## Le journal des modifications

Les notes de version se trouvent dans `frontend/data/changelog.json`, pas dans les fichiers de locale. Le fichier est un tableau de blocs de version, **du plus ancien au plus récent** — le panneau À propos l'affiche à l'envers, donc les nouvelles entrées sont ajoutées au dernier bloc.

{% code title="frontend/data/changelog.json" %}

```json
{
  "version": "v7.2.0",
  "date": "Bêta",
  "content": [
    {
      "type": "add",
      "change": {
        "en": "Refonte complète de la vérification de censure : voyez où un site est bloqué dans le monde",
        "zh": "全面重构封锁测试，可以查询一个网站在全球的封锁情况",
        "fr": "Refonte complète du test de censure : découvrez où un site est bloqué dans le monde",
        "ru": "Полностью переработана проверка цензуры: видно, где в мире сайт заблокирован"
      }
    }
  ]
}
```

{% endcode %}

Règles de forme :

| Champ     | Règle                                                                       |
| --------- | --------------------------------------------------------------------------- |
| `version` | Correspondance de chaînes `vX.Y…`                                           |
| `date`    | Chaîne — une date de publication, ou un espace réservé comme `"Bêta"`       |
| `contenu` | Tableau non vide d'éléments de changement                                   |
| `type`    | Exactement un des `add`, `improve`, `fix`                                   |
| `change`  | Objet avec **les quatre** clés de locale, chacune étant une chaîne non vide |

### Imposé par les tests

`tests/changelog.test.js` s'exécute à chaque `pnpm test` et fait échouer la compilation dans les cas suivants :

* une traduction manquante ou vide pour l'une de `en` / `zh` / `fr` / `ru`
* une `type` en dehors des trois autorisés
* un bloc de version manquant `version`, `date`, ou un `contenu` tableau
* un fichier de locale qui réintroduit `changelog.versions` (ces données ne vivent désormais que dans `changelog.json`)
* un fichier de locale qui a perdu `changelog.Title` / `add` / `improve` / `fix` Libellés de l'interface

Ce dernier duo mérite d'être retenu : **le texte des notes de version se trouve dans `changelog.json`; les libellés du badge et le titre du panneau autour restent dans les fichiers de locale** comme éléments ordinaires de l'interface.

## Ajouter une langue

Rien dans le codebase n'interdit une cinquième locale, mais c'est un véritable engagement — chaque future modification de texte demanderait alors cinq traductions, et `tests/changelog.test.js` impose en dur les quatre requises. Ouvrez une issue et discutez-en avec les mainteneurs avant de commencer.

## Suivant

* [Ajout d'un nouvel outil](/developer/fr/development/adding-a-new-tool.md) — où l'étape i18n s'insère dans une fonctionnalité complète.
* [Tests](/developer/fr/development/testing.md) — ce que d'autre `pnpm test` impose.
* [Comment contribuer](/developer/fr/contributing/how-to-contribute.md) — attentes en matière de PR.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/fr/development/i18n.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
