# CHAPITRE 21 — Gérer le multilingue (pages sœurs)

Dolibarr Website propose deux modèles multilingues différents. Identifier le modèle que vous utilisez est une étape préalable à toute écriture de code. Ce chapitre vous présente les deux options et la manière dont le module s'y intègre.

### <span style="color: rgb(35, 111, 161);">Les deux modèles multilingues</span>

<table id="bkmrk-mod%C3%A8lecaract%C3%A9ristiqu" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.95em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Modèle

</th><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Caractéristique

</th></tr><tr><td style="padding: 0.6rem 1rem; border: 1px solid rgb(229, 231, 235);">**A. Slot par langue**

<span style="white-space: pre-wrap;"> (recommandé)</span>

</td><td style="padding: 0.6rem 1rem; border: 1px solid rgb(229, 231, 235);">Un seul fichier tpl.php sert toutes les langues. Les slots disposent de surcharges par langue.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.6rem 1rem; border: 1px solid rgb(229, 231, 235);">**B. Pages sœurs**

<span style="white-space: pre-wrap;"> (legacy)</span>

</td><td style="padding: 0.6rem 1rem; border: 1px solid rgb(229, 231, 235);">Un fichier tpl.php par langue (

`<span class="editor-theme-code">about.php</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">about-en.php</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">about-de.php</span>`

). Modèle hérité des sites Dolibarr Website classiques.

</td></tr></tbody></table>

<p class="callout info">**Recommandé —**<span style="white-space: pre-wrap;"> Adoptez le modèle A pour tout nouveau site. Le modèle B reste pris en charge pour la migration progressive de sites existants. Le module fournit un outil de consolidation B vers A.</span></p>

### <span style="color: rgb(35, 111, 161);">Modèle A — Slot par langue (le standard moderne)</span>

##### **Fonctionnement**

<span style="white-space: pre-wrap;">Une seule page Dolibarr Website existe par concept (par exemple </span>`<span class="editor-theme-code">about</span>`<span style="white-space: pre-wrap;">). Le fichier tpl.php est unique. Les slots possèdent leur valeur canonique (FR par défaut) et des surcharges par langue stockées dans </span>`<span class="editor-theme-code">llx_infrasstudio_slot</span>`.

```
<!-- about.tpl.php — UN SEUL fichier pour FR/EN/DE/ES/IT/PT/NL/PL -->
<h1>{{slot:about_title|type=text|default=À propos de nous|label=Titre About}}</h1>
<p>{{slot:about_lead|type=textarea|default=Notre histoire en quelques mots.|label=Accroche}}</p>
```

##### **Récupérer la langue du visiteur dans le gabarit**

Le module résout les slots automatiquement selon la langue détectée. Pour vos propres traitements PHP (afficher la date dans la bonne langue, choisir une image différente par langue), récupérez la langue via :

```
<?php
// helpers fournis par le module
$iso2 = infrasstudio_current_lang();         // 'fr', 'en', 'de', ...
$locale = infrasstudio_current_locale();     // 'fr_FR', 'en_US', 'de_DE', ...
?>
```

##### **Cascade de détection**

<span style="white-space: pre-wrap;">La fonction </span>`<span class="editor-theme-code">infrasstudio_current_lang()</span>`<span style="white-space: pre-wrap;"> détecte la langue dans cet ordre :</span>

1. <span style="white-space: pre-wrap;">Constante </span>`<span class="editor-theme-code">INFRASSTUDIO_LANG_ISO</span>`<span style="white-space: pre-wrap;"> définie par le site (souvent dans </span>`<span class="editor-theme-code">lang.inc.php</span>`).
2. <span style="white-space: pre-wrap;">Paramètre URL </span>`<span class="editor-theme-code">?lang=xx</span>`.
3. Suffixe sur le slug (`<span class="editor-theme-code">about-en.php</span>`<span style="white-space: pre-wrap;"> donne en).</span>
4. Cookie de persistance (`<span class="editor-theme-code">INFRASSTUDIO_LANG_COOKIE</span>`).
5. <span style="white-space: pre-wrap;">Valeur de </span>`<span class="editor-theme-code">$langs->defaultlang</span>`.
6. <span style="white-space: pre-wrap;">En-tête HTTP </span>`<span class="editor-theme-code">Accept-Language</span>`<span style="white-space: pre-wrap;"> du visiteur.</span>

### <span style="color: rgb(35, 111, 161);">Modèle B — Pages sœurs (legacy)</span>

Il s'agit du modèle Dolibarr Website classique : pour chaque page, vous créez un fichier tpl.php par langue.

```
about.php           # FR (canonique)
about-en.php        # EN
about-de.php        # DE
about-es.php        # ES
...
```

Si vous reprenez un site existant qui suit ce modèle, deux options s'offrent à vous :

1. Conserver le modèle avec des stubs du module.
2. Migrer vers le modèle A grâce à l'outil de consolidation en ligne de commande.

### <span style="color: rgb(35, 111, 161);">Conserver le modèle B avec des stubs</span>

<span style="white-space: pre-wrap;">Le module fournit un helper </span>`<span class="editor-theme-code">sister_stub.tpl.php</span>`<span style="white-space: pre-wrap;"> qui réduit chaque page sœur à trois lignes et permet de partager le HTML avec la canonique.</span>

##### **Procédure**

La page canonique reste un tpl.php classique :

```
// page5.tpl.php — canonique FR
<?php // bootstrap dolibarr ... ?>
<html>...<h1>{{slot:about_title|type=text|default=À propos|...}}</h1>...</html>
```

Chaque page sœur devient un stub :

```
<?php
// page42.tpl.php — sister EN
$_infrasstudio_sister_canonical = 'page5.tpl.php';
$_infrasstudio_sister_lang      = 'en';
include dol_buildpath('/infrasstudio/core/tpl/sister_stub.tpl.php', 0);
```

<span style="white-space: pre-wrap;">Le stub force </span>`<span class="editor-theme-code">$_GET['lang'] = 'en'</span>`<span style="white-space: pre-wrap;"> puis délègue le rendu à la canonique. Les surcharges EN sont automatiquement utilisées pour résoudre les slots.</span>

### <span style="color: rgb(35, 111, 161);">Migrer du modèle B vers A en ligne de commande</span>

Un script consolide une famille de pages sœurs en une page canonique et plusieurs stubs :

```
php htdocs/custom/infrasstudio/scripts/consolidate_sister_pages.php <ref-site> \
    [--entity=N] \
    [--base-slug=about] \
    [--dry-run] \
    [--extractor=/path/to/extractor.php]
```

##### **Ce que fait le script**

1. Détecte les groupes de pages sœurs parmi les codes ISO2 pris en charge (en, de, es, it, pt, nl, pl).
2. Pour chaque groupe :
    - Conserve la page tpl FR comme canonique.
    - Extrait les valeurs traduites depuis chaque page sœur (par expression régulière ou via un extracteur personnalisé).
    - <span style="white-space: pre-wrap;">Insère les surcharges dans </span>`<span class="editor-theme-code">llx_infrasstudio_slot</span>`.
    - <span style="white-space: pre-wrap;">Réécrit la canonique avec des slots </span>`<span class="editor-theme-code">{{slot:...}}</span>`.
    - Remplace chaque page sœur par un stub de trois lignes.
3. <span style="white-space: pre-wrap;">Sauvegarde de chaque tpl original avec l'extension </span>`<span class="editor-theme-code">.bak</span>`.

<p class="callout info">**Conseil —**<span style="white-space: pre-wrap;"> Lancez d'abord avec </span>`<span class="editor-theme-code">--dry-run</span>`<span style="white-space: pre-wrap;"> pour visualiser ce que le script va faire sans rien écrire. Lancez en mode réel uniquement après vérification.</span></p>

### <span style="color: rgb(35, 111, 161);">hreflang : déclarer les alternates au navigateur</span>

<span style="white-space: pre-wrap;">Pour que Google sache que vos pages sont des traductions les unes des autres, vous devez émettre des balises </span>`<span class="editor-theme-code"><link rel="alternate" hreflang="..."></span>`<span style="white-space: pre-wrap;"> dans l'en-tête HTML.</span>

Le module fournit un helper qui les génère automatiquement :

```
<head>
    ...
    <?php echo infrasstudio_hreflang_tags($website, $WEBSITE_PAGE); ?>
    ...
</head>
```

Sortie type :

```
<link rel="alternate" hreflang="fr" href="https://exemple.com/about.php" />
<link rel="alternate" hreflang="en" href="https://exemple.com/about-en.php" />
<link rel="alternate" hreflang="de" href="https://exemple.com/about-de.php" />
<link rel="alternate" hreflang="x-default" href="https://exemple.com/about.php" />
```

<p class="callout info">**Compatibilité avec les deux modèles —**<span style="white-space: pre-wrap;"> Pour le modèle A, le helper émet une seule URL canonique avec les langues différenciées par </span>`<span class="editor-theme-code">?lang=</span>`. Pour le modèle B, il émet une URL par page sœur.</p>

### <span style="color: rgb(35, 111, 161);">Sélecteur de langue côté gabarit</span>

<span style="white-space: pre-wrap;">Pour permettre au visiteur de changer de langue, vous devez exposer un sélecteur. Le helper </span>`<span class="editor-theme-code">infrasstudio_translated_url($iso2)</span>`<span style="white-space: pre-wrap;"> génère l'URL équivalente de la page courante dans une autre langue :</span>

```
<nav class="lang-switcher">
    <?php foreach (array('fr', 'en', 'de', 'es') as $iso): ?>
        <a href="<?php echo infrasstudio_translated_url($iso); ?>">
            <?php echo strtoupper($iso); ?>
        </a>
    <?php endforeach; ?>
</nav>
```

### <span style="color: rgb(35, 111, 161);">Charger les fichiers de langue du site</span>

<span style="white-space: pre-wrap;">Si votre site utilise des fichiers </span>`<span class="editor-theme-code">.lang</span>`<span style="white-space: pre-wrap;"> Dolibarr (par exemple pour les libellés de menu), chargez-les en début de tpl :</span>

```
<?php
require_once __DIR__ . '/lang.inc.php';
$langs->loadLangs(array('website_main', 'website_blog'));
?>
```

<span style="white-space: pre-wrap;">Et utilisez les clés via </span>`<span class="editor-theme-code">$langs->trans('Key')</span>`<span style="white-space: pre-wrap;"> ou via le slot avec </span>`<span class="editor-theme-code">default=@lang:Key</span>`.

### <span style="color: rgb(35, 111, 161);">Récapitulatif</span>

**Vous savez désormais :**

- Distinguer le modèle A (slot par langue, recommandé) du modèle B (pages sœurs, legacy).
- <span style="white-space: pre-wrap;">Récupérer la langue du visiteur via </span>`<span class="editor-theme-code">infrasstudio_current_lang()</span>`.
- <span style="white-space: pre-wrap;">Convertir un site existant utilisant le modèle B en utilisant le helper </span>`<span class="editor-theme-code">sister_stub.tpl.php</span>`.
- <span style="white-space: pre-wrap;">Migrer en bloc B vers A grâce à l'outil </span>`<span class="editor-theme-code">consolidate_sister_pages.php</span>`.
- <span style="white-space: pre-wrap;">Émettre les balises hreflang automatiquement avec </span>`<span class="editor-theme-code">infrasstudio_hreflang_tags</span>`.
- <span style="white-space: pre-wrap;">Construire un sélecteur de langue avec </span>`<span class="editor-theme-code">infrasstudio_translated_url</span>`.

</body></html>