# Formats numériques distincts par locale, avec les propriétés typées d’un thème

> Fiabiliser à l'écriture les formats numériques attendus par langue dans un thème qui gère sa propre internationalisation, sans extension dédiée.

- Auteur : Clément Hadrot
- Publié le : 2025-02-25
- Mis à jour le : 2025-02-25
- Catégorie : Multilingue
- URL : https://wpmoderne.dev.wordpress-developpement.fr/multilingue/formats-numeriques-locale-proprietes-typees-theme/

## L’essentiel

- Un tableau de configuration par locale centralise séparateurs et unités
- La validation à l'écriture évite un format incohérent en base
- La fonction reste indépendante de toute extension de traduction

Trois formats numériques différents devaient cohabiter sur le même thème : virgule décimale et espace insécable pour le français, point décimal et virgule pour l'anglais américain, virgule décimale et point pour l'allemand. Rien d'exotique en soi, mais le thème en question gérait sa propre couche d'internationalisation, sans extension de traduction dédiée, et laissait jusque-là chaque développeur formater les nombres à sa main, au gré des besoins — un terrain fertile pour des incohérences difficiles à repérer après coup.

## Le problème : un formatage dispersé, source d'incohérences

Avant cette recette, chaque template du thème appelait `number_format()` avec des paramètres saisis en dur, différents d'un fichier à l'autre. Un prix affiché sur une fiche produit utilisait une virgule comme séparateur décimal, tandis qu'un total de panier ailleurs sur la même page utilisait un point — une incohérence purement accidentelle, née de développeurs différents ayant travaillé sur ces deux zones à des moments différents.

## Le snippet : une configuration centralisée par locale

```
function get_locale_number_config( $locale = null ) {
    $locale = $locale ?: determine_locale();

    $configs = [
        'fr_FR' => [ 'decimals' => ',', 'thousands' => ' ', 'unit_position' => 'after' ],
        'en_US' => [ 'decimals' => '.', 'thousands' => ',', 'unit_position' => 'before' ],
        'de_DE' => [ 'decimals' => ',', 'thousands' => '.', 'unit_position' => 'after' ],
    ];

    return $configs[ $locale ] ?? $configs['en_US'];
}

function format_price_for_locale( $amount, $currency_symbol, $locale = null ) {
    $config = get_locale_number_config( $locale );

    $formatted = number_format(
        (float) $amount,
        2,
        $config['decimals'],
        $config['thousands']
    );

    return 'before' === $config['unit_position']
        ? $currency_symbol . $formatted
        : $formatted . ' ' . $currency_symbol;
}
```

Cette fonction unique remplace tous les appels dispersés à `number_format()` dans les templates. Elle s'appuie sur `determine_locale()`, la fonction native de WordPress qui résout la locale active pour la requête courante — pas besoin d'extension tierce pour connaître la langue en cours.

> L'essentiel à retenir : Un tableau de configuration par locale centralise séparateurs et unités ; La validation à l'écriture évite un format incohérent en base ; La fonction reste indépendante de toute extension de traduction

## Fiabiliser à l'écriture, pas seulement à l'affichage

Le vrai gain de cette recette ne vient pas seulement d'un affichage cohérent, mais d'une validation systématique au moment où un nombre est saisi ou importé, avant tout enregistrement en base. Un champ personnalisé de prix, par exemple, valide la saisie contre un format numérique strict avant de la convertir en valeur flottante stockée de façon uniforme :

```
function sanitize_locale_number_input( $raw_value, $locale = null ) {
    $config = get_locale_number_config( $locale );

    $normalized = str_replace( $config['thousands'], '', $raw_value );
    $normalized = str_replace( $config['decimals'], '.', $normalized );

    if ( ! is_numeric( $normalized ) ) {
        return new WP_Error( 'invalid_number', __( 'Format numérique invalide.', 'mon-theme' ) );
    }

    return (float) $normalized;
}
```

Cette étape de validation transforme systématiquement la saisie utilisateur, quelle que soit sa locale d'origine, vers une représentation interne unique (un flottant PHP standard), avant de la reformater à l'affichage selon la locale du visiteur. C'est cette séparation entre stockage neutre et affichage localisé qui évite les incohérences constatées au départ.

## Variantes possibles

### Variante 1 : unités de mesure conditionnelles

La même configuration par locale peut porter une clé supplémentaire pour basculer entre système métrique et système impérial, utile pour un catalogue technique vendu à la fois en Europe et en Amérique du Nord.

### Variante 2 : devise déduite de la locale plutôt que fixée

Sur un site multi-devises, la fonction peut être étendue pour déduire un symbole de devise par défaut selon la locale, tout en conservant la possibilité de le forcer explicitement quand la devise réelle diffère de la convention associée à la langue.

### Variante 3 : cache par locale pour les configurations lourdes

Si le tableau de configuration grossit avec de nombreuses locales et options, un appel à `wp_cache_get()` avec la locale comme clé évite de reconstruire ce tableau à chaque appel de fonction sur une page à fort volume d'affichage numérique.

- Centraliser tout formatage numérique dans une seule fonction, jamais dispersé dans les templates
- Valider systématiquement la saisie avant stockage, pas seulement à l'affichage
- Prévoir une valeur de repli explicite pour toute locale non configurée

> Un format numérique mal aligné avec la langue affichée reste l'un des détails les plus discrets d'un site multilingue — et l'un des plus agaçants pour un visiteur qui doit s'arrêter pour relire un prix deux fois.

## En résumé

Centraliser le formatage numérique par locale dans une fonction unique, testée et validée à l'écriture, évite la dispersion de règles ad hoc dans chaque template. Cette recette reste volontairement simple : pas d'extension supplémentaire, juste une convention de code appliquée avec discipline sur l'ensemble du thème.
