Kodokon kodokon.com

Internationalisation : lang, dir, charset et pièges Unicode

Exploitez lang, dir et la déclaration d'encodage à bon escient, et déjouez les pièges de normalisation et de directionnalité Unicode.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

L'attribut lang est bien plus qu'une métadonnée : il pilote la voix des lecteurs d'écran, la césure (hyphens: auto ne fonctionne pas sans lui), la sélection des glyphes CJK (un même idéogramme se dessine différemment en japonais et en chinois), les guillemets générés par <q> et le sélecteur CSS :lang(). Il s'hérite : déclarez-le sur <html> avec une étiquette BCP 47 (fr, fr-CA, ja) et surchargez-le localement à chaque changement de langue.

HTML
<html lang="fr">
  <p>Elle a dit : <q>bonjour</q>.</p>
  <p lang="en">She said: <q>hello</q>.</p>
</html>
Les guillemets de q suivent la langue : « bonjour » puis “hello”.

dir=rtl inverse l'alignement par défaut et l'ordre visuel des caractères à directionnalité neutre. Pour du contenu utilisateur imprévisible, dir=auto choisit la direction d'après le premier caractère fortement directionnel. L'élément <bdi> isole un fragment de l'algorithme bidirectionnel : sans lui, un pseudo arabe suivi de « : 12 points » voit sa ponctuation se réordonner de façon illisible.

HTML
<p dir="auto">مرحبا - direction déduite : RTL</p>
<ul>
  <li><bdi>مستخدم</bdi> : 12 points</li>
  <li><bdi>Alice</bdi> : 8 points</li>
</ul>
bdi protège la mise en page des pseudos bidirectionnels.

La déclaration <meta charset=utf-8> doit apparaître dans les 1024 premiers octets du document : le navigateur effectue un prescan limité à cette fenêtre avant de choisir un encodage. Sans déclaration ni en-tête HTTP, l'encodage par défaut dépend de la locale de l'utilisateur (souvent windows-1252 en Europe de l'Ouest) - jamais UTF-8. Un BOM en tête de fichier, lui, prime sur tout le reste, y compris l'en-tête HTTP.

JAVASCRIPT
const composed = "\u00e9";
const decomposed = "e\u0301";
console.log(composed === decomposed); // false
const nfc = decomposed.normalize("NFC");
console.log(composed === nfc);        // true
Deux « é » visuellement identiques, mais différents en mémoire.

macOS enregistre certains noms de fichiers en forme décomposée (NFD) : un « é » venu d'un upload peut donc différer de celui saisi au clavier. Normalisez systématiquement en NFC toute saisie utilisateur avant stockage ou comparaison. Enfin, .length compte des unités UTF-16, pas des caractères perçus : un emoji familial en combine plus de sept ; utilisez Intl.Segmenter pour compter de vrais graphèmes.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Où la déclaration <meta charset=utf-8> doit-elle impérativement se situer ?
    • N'importe où dans le <head>
    • Dans les 1024 premiers octets du document
    • Avant la déclaration DOCTYPE
    • Dans les 512 premiers octets du <body>
  2. Comment dir=auto détermine-t-il la direction d'un élément ?
    • Il examine le premier caractère fortement directionnel du contenu
    • Il applique la direction déclarée sur l'élément <html>
    • Il compte les caractères RTL et LTR et retient la majorité
  3. Pourquoi deux chaînes affichant toutes deux « é » peuvent-elles être différentes pour === ?
    • Parce que l'une est encodée en UTF-8 et l'autre en UTF-16
    • Parce que la casse Unicode diffère selon la locale
    • Parce que l'une utilise le caractère précomposé U+00E9 et l'autre la séquence décomposée e + U+0301