Pages Web mutlilingues avec UTF-8
Exemples turcs, indiens et arabes
Jean-François Perrot
Commentaires d'un informaticien sur le cours de Michel Jacobson à l'INaLCO du vendredi 5 novembre 2004
sur le codage des caractères.
- Observation des mécanismes fondamentaux (l'informatique sous-jacente)
- Application 1 : des pages franco-turques
- Application 2 : traitement des ligatures de l'écriture devanâgari
- Application 3 : traitement des différentes formes des caractères arabes et de leur combinaison
A. Mécanismes
-
Philosophie de la mécanique
- Rappel : il n'y a pas de caractères dans une machine, rien que des octets (= mots de 8 bits) !
Glose : ce qu'on trouve dans les mots de la mémoire centrale ou sur les pistes d'un disque,
ce qui circule sur le réseau, ce ne sont que des octets...
Ce que nous prenons pour des caractères est produit par une interprétation de ces octets.
Les octets demeurent, les interprétations varient...
Quand on transmet des octets d'une machine à l'autre,
l'interprétation par le récepteur est en général différente de celle de l'émetteur.
- Entrer & sortir :
les machines modernes avec écran et clavier nous laissent croire que lire et écrire ne font qu'un
c'est faux !
L'écriture (fabrication d'un fichier) et la lecture (interprétation)
sont deux processus dissymétriques.
Cette dissymétrie est masquée par la puissance des machines et par la bonne adéquation des outils (clavier - écran - logiciels)
Mais la puissance est relative et l'adéquation dépend du but poursuivi !
Il n'en a pas toujours été ainsi (à l'origine, cartes perforées et imprimantes...)
et actuellement l'exigence nouvelle de multilinguisme rend les outils inadéquats.
Nous sommes donc ramenés (provisoirement) à une situation analogue à celle des débuts de l'informatique.
-
Moyens d'observation
Comment observer la réalité des processus d'écriture et de lecture ?
- Principe : On ne voit jamais directement les octets,
ils sont toujours interprétés par le logiciel de visualisation.
- Cherchons donc l'interprète le plus fruste, celui qui "en fera le moins"
et qui nous révélera le fichier "tel qu'en lui-même".
- Avec le système Mac OS X.3 que j'utilise
- la commande cat
interprète complètement le format UTF-8 !
elle nous masque donc la réalité des octets.
- en revanche la commande more
n'interprète que l'ASCII 7 bits (voir plus loin)
et reproduit fidèlement tous les autres octets, en les écrivant en hexadécimal entre chevrons.
Hélas, ceci est une idiosyncrasie de la version de more en usage sur ce système
(qui est en fait less...).
- Dans le présent texte, j'utilise more
comme instrument d'observation de la matérialité des octets.
Cette solution commode ne peut malheureusement pas se généraliser...
Il faut recourir à des instruments plus compliqués comme hexdump ou od. Désolé !
Exemple :
le texte bien innocent : Ça, c'est mon frère René et ça c'est ma sœur Iñès.
se révèle être en fait (en codage MacRoman) :
<82>a, c'est mon fr<8F>re Ren<8E> et <8D>a c'est ma s<CF>ur I<96><8F>s.
- Observations préliminaires
nécessaires au déchiffrage des indications fournies (ici) par la commande more.
- La notation hexadécimale
On n'écrit jamais les chaînes de bits, elles sont illisibles.
En hexadécimal chaque chiffre représente 4 bits, un octet est donc représenté par deux chiffres.
Exemples : 09 = 0000 1001, 2F = 0010 1111
- Le code ASCII 7 bits - 128 caractères : un caractère = un octet (avec le premier bit à 0)
- Les extensions iso-8859-1 (iso-latin-1), Mac Roman et autres - 256 caractères :
- idem, un caractère = un octet (complet)
- mais différences incompatibles entre plateformes et entre langues
- Voici le même texte en deux codages Mac Roman et iso-8859-1 (Windows) :
On peut constater que, dans les deux cas, les caractères non-ASCII sont représentés
par un seul octet, mais qu'à chaque fois ce sont des octets différents !
- Ça, c'est mon frère René et ça c'est ma sœur Iñès.
- <82>a, c'est mon fr<8F>re Ren<8E> et <8D>a c'est ma s<CF>ur I<96><8F>s.
- <C7>a, c'est mon fr<E8>re Ren<E9> et <E7>a c'est ma s<9C>ur I<F1><E8>s.
-
Enfin Unicode vint...
et un caractère n'est plus un octet !!!
- Bien distinguer
- la désignation du caractère (nommer le caractère)
- par son n° (en décimal ou en hexa)
- en HTML/XML : &#lenumérodec; ou &#xlenumérohex;
- en Java : \ulenumérohex
- par son nom officiel (en Perl)
- Exemple : le caractère Unicode n° 304 = x0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
peut être désigné en HTML/XML par İ ou par İ et en Java par '\u0130'
- sa réalisation,
laquelle prend deux aspects (dissymétriques) :
- codage en octets (UTF-8)
Exemple : LATIN CAPITAL LETTER I WITH DOT ABOVE ==> sur 2 octets C4B0
- affichage via une police (à condition qu'elle soit présente sur la machine !)
Exemple :
LATIN CAPITAL LETTER I WITH DOT ABOVE ==>
İ
-
Pour marquer cette distinction, nous écrirons désormais les octets des réalisations en UTF-8
entre chevrons, comme ils sont produits par more :
Exemple : LATIN CAPITAL LETTER I WITH DOT ABOVE ==> en UTF-8 sur 2 octets <C4><B0>
- Exemple : le texte ci-dessus en UTF-8 :
<C3><87>a,
c'est mon fr<C3><A8>re Ren<C3><A9> et
<C3><A7>a c'est ma s<C5><93>ur
I<C3><B1><C3><A8>s.
- Mise en œuvre : où l'on voit bien que l'entrée et la sortie sont des processus dissymétriques !
- Côté entrée : deux étapes successives
- Écriture dans un outil d'édition par tout moyen à votre disposition
(ils sont nombreux : menu d'insertion,
donnée explicite du nom du caractère,
clavier,
palette, etc).
- Note technique : cette écriture fait entrer les caractères dans le buffer de l'outil,
qui loge en mémoire centrale en le recodant.
Notez que l'utilisateur n'est en général pas informé de ce codage interne,
(l'éditeur JEdit faisant exception : il déclare ouvertement
que sa représentation interne est UTF-16).
- Sauvegarde dans un fichier sur disque en spécifiant le codage UTF-8.
Notez que les modalités de cette spécification varient beaucoup avec le logiciel employé.
Par exemple, sur Mac OS X :
- L'éditeur de textes TextEdit répond à la commande Fichier>Enregistrer sous...
par une fenêtre de dialogue où la question du codage est posée clairement.
- L'éditeur HTML Netscape Composer en revanche distingue Fichier>Enregistrer sous...
de Enregistrer en changeant de codage
et il adopte un comportement diversifié suivant le choix de l'utilisateur.
L'analyse de ce comportement n'est pas sans intérêt...
- La version de Microsoft Word pour Mac OS X répond à la commande Fichier>Enregistrer sous...
par une fenêtre de dialogue où la question du codage est posée comme cas particulier de format
le choix de Texte unicode conduisant à une sauvegarde en format texte UTF-16.
- L'éditeur de textes JEdit distingue explicitement
- le buffer en mémoire centrale (où les caractères sont rerpésentés en UTF-16)
- du fichier sur disque, dont le codage courant est affiché au bord inférieur de la fenêtre
et peut être modifié par une commande adéquate (voir la documentation)
Il convient donc de se renseigner soigneusement sur l'usage du logiciel employé,
de préférence avant d'avoir à sauvegarder son travail en urgence,
car un mauvais choix de codage peut conduire à la perte irrémédiable de l'information acquise...
- Côté sortie : avertir le logiciel de traitement qu'il doit "lire" en UTF-8
- pour un éditeur prenant un fichier sur le disque,
à l'ouverture du fichier (en général, codage par défaut donné dans les préférences de l'outil).
Là aussi les mœurs des logiciels sont diverses, et il convient de chercher où l'information pertinente doit être fournie...
Tous n'ont pas la limpidité de TextEdit...
- pour un logiciel recevant le fichier par le réseau,
par un message spécifique avec un type MIME comme text/plain ou text/xml
assorti de la mention charset="UTF-8".
- Pour un courrier envoyé par SMTP, on dira dans un en-tête (header) :
Content-Type: text/xml; charset="UTF-8"
- Dans un fichier HTML, on va ajouter comme premier élément de la partie <head> un élément ainsi conçu:
<meta http-equiv="Content-Type" content="text/html; charset="UTF-8" />
en observant que tous les caractères précédents, à savoir <DOCTYPE....> <html xmlns:...><head>
sont de l'ASCII 7 bits, donc déchiffrables sans ambiguïté.
B. Un exemple de bilinguisme franco-turc : problème & solution
-
Problème à traiter
- Le turc s'écrit avec un alphabet latin étendu dont 4 caractères sont étrangers au français :
- le "i sans point" minuscule : ı (voyelle d'arrière)
Unicode n° 305 = x0131 LATIN SMALL LETTER DOTLESS I
En UTF-8 : <C4><B1>
- le "i majuscule avec point" İ (pour le distinguer du i sans point majuscule)
Unicode n° 304 = x0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
En UTF-8 : <C4><B0>
- le g "mou" (variante phonologique du g entre voyelles)
minuscule ğ Unicode n° 287 = x011F LATIN SMALL LETTER G WITH BREVE
majuscule Ğ Unicode n° 286 = x011E LATIN CAPITAL LETTER G WITH BREVE
En UTF-8 : <C4><9F> et <C4><9E>
- le s cédille (note la chuintante sourde, fr. "ch" - le c cédille du français note l'affriquée correspondante "tch")
minuscule ş Unicode n° 351 = x015F LATIN SMALL LETTER S WITH CEDILLA
majuscule Ş Unicode n° 350 =
x015E LATIN CAPITAL LETTER S WITH CEDILLA
En UTF-8 : <C5><9F> et <C5><9E>
- J'ai trouvé il y a plusieurs années une police de caractères dite international
permettant d'obtenir ces caractères sous Word par le procédé suivant :
- Le "i" sans point minuscule : taper ^ puis espace : garı
- Le "i" majuscule avec point : taper opt-shift-x après le "I" : İzmir
-
Le "g yumuşak" : taper opt-u après le "g" : oğlan
- pour la majuscule, taper opt-$ après le "G" : OĞLAN
- Le "c" et le "s" cédille : taper opt-< après la lettre : çicek, Çicek, paşa, PAŞA
- Le tréma : en minuscule, opt-shift-t après la lettre : Ben yürürüm yana yana
- en majuscule, opt-shift-r après la lettre : Ödemiş, Turgut Özal
- J'ai donc dans mes archives une collection de documents réalisés avec cette technique,
contenant des textes turcs annotés en français.
Les lettres turques y sont "codées" comme expliqué ci-dessus, avec la police international
et le logiciel de visualisation (en l'occurrence Word) interprète ce codage avec cette police
de manière à restituer les glyphes attendus.
-
Le problème est de transformer ces fichiers en pages Web bilingues, uniformément codées en UTF-8.
Exemple : une anecdote de Nasreddin Hodja
-
Solution (il y en a certainement d'autres !)
- Principe : (en Java) lire le fichier caractère par caractère et
- laisser intacts les caractères français (sous réserve qu'ils aient été lus correctement)
- décoder les constructions turques ci-dessus en les traduisant en Unicode.
Exemple : OG€LAN ==> OĞLAN
- Réalisation : 3 étapes à partir du fichier Word (contenant les balises HTML de mise en forme)
- Obtention du texte en Unicode UTF-16 (par dialogue avec Word).
Ceci fait disparaître au passage toutes les indications de mise en forme,
notamment celles qui mentionnent la police employée.
Cette perte d'information est sans conséquence car :
- la mise en forme sera confiée à HTML
- le codage des caractères turcs reste intact, puisque le rôle de la police international
était d'assurer leur interprétation par Word.
- Recodage en Mac Roman (via TextEdit) pour assurer la bonne lecture par Java sur Macintosh.
- Traduction par Java, sortie dans un fichier en UTF-8.
- Démonstration...
C. Mise en œuvre de la devanâgari : traitement des ligatures
-
Le problème
- L'écriture devanâgari considère que la voyelle a (bref) est inhérente à chaque consonne.
Elle ne l'écrit donc pas : क = ka
- Les autres voyelles en revanche sont écrites : कु = ku, को = ko, etc.
- Mais comment faire si on ne veut pas de voyelle, pour avoir un groupe de 2 ou 3 consonnes ?
On a alors recours à une ligature, qui peut prendre diverses formes (glyphes) :
क + व = क्व , क + म = क्म , क + ष = क्ष , क + र = क्र
- Mais les caractères correspondants ne figurent pas dans le catalogue Unicode !
- Comment va-t-on faire ?
-
La solution
- Il existe dans l'alphabet devanâgari une lettre spéciale (le virama, n° 2381 = x094D)
indiquant l'absence de voyelle.
Elle s'écrit comme une sorte de virgule souscrite : क् = k sans voyelle.
- Dans l'usage normal, cette lettre n'est employée qu'en fin de mot : महान् mahãn = grand
(comme dans mahãrãjã
et dans mahãtmã).
Elle apparaît également pour éviter aux typographes des ligatures particulièrement acrobatiques,
ou pour simplifier la lecture à l'intention des enfants :
-
dans un manuel de hindi pour classes élémentaires on trouve
दुपट्टा dupaṭṭã = écharpe, avec virama
- mais le dictionnaire donne दुपट्टा, avec ligature.
- Même si l'emploi du virama est assez restreint dans l'usage courant,
il offre la possibilité d'une écriture normalisée sans ligature.
- Le choix de réalisation avec Unicode est :
- on écrira (dans le fichier) sous forme normalisée,
avec virama
- et la réalisation des ligatures sera confiée au logiciel d'affichage.
- Il en résulte une exigence très forte à l'égard des éditeurs de texte, des navigateurs, entre autres !
Tous ne sont pas également performants...
Exemple : comparez le savoir-faire de différents outils sur le mantra गायत्री (Gâyatrî)
Comme votre instrument d'observation sera peut-être différent du mien,
je vous montre les images de ce que je vois sur Mac-OS X.3 :
- d'abord le contenu du fichier html tel que le révèle TextEdit.
- le travail impeccable du navigateur Safari,
- le travail beaucoup moins satisfaisant de Firefox 1.0.3, qui visiblement n'a pas investi sur ce point
-
Illustrations
- Il suffit d'examiner avec more des fichiers contenant de la devanâgari pour se convaincre :
la représentation du virama en UTF-8 est <E0><A5><8D>
- Sachant que क= <E0><A4><95>
et que व = <E0><A4><B5>
on trouve bien dans le fichier क्व = <E0><A4><95><E0><A5><8D><E0><A4><B5>
etc...
- Pour obtenir l'absence de ligature dans दुपट्टा,
il a fallu insérer un caractère supplémentaire après le virama,
à savoir le n° x200C antiliant sans chasse, alias ZWNJ (Zero-Width Non-Joiner), en UTF-8 : <E2><80><8C>.
(Merci à Y. Haralambous et à son excellent livre [Fontes et codages, chez O'Reilly] !)
Il y a donc à cet endroit dans le fichier :
<E0><A4><A6><E0><A5><81><E0><A4><AA><E0><A4><9F><E0><A5><8D><E2><80><8C><E0><A4><9F><E0><A4><BE>
et une ligne plus loin, avec un caractère de moins :
<E0><A4><A6><E0><A5><81><E0><A4><AA><E0><A4><9F><E0><A5><8D><E0><A4><9F><E0><A4><BE>
- Nombreux exemples dans la page de démonstration "Qu'est-ce qu'Unicode" en hindi.
-
Démonstration...
Écrire dans un éditeur comme TextEdit : on voit les ligatures se former à l'écran...
D. Formes des caractères arabes
-
Rappel : chaque lettre de l'alphabet arabe peut revêtir en principe quatre formes,
suivant qu'elle isolée, initiale, médiale ou finale.
Exemple 1 : les quatre formes de la lettre ha (x0647) :
- isolée : ه
- initiale : هـ
- médiale : ـهـ
- finale : ـه
Exemple 2 : les quatre formes de la lettre ayn (x0639) :
- isolée : ع
- initiale : عـ
- médiale : ـعـ
- finale : ـع
- Dans le répertoire Unicode, il n'y a qu'un code par caractère, et non pas quatre correspondant aux quatre formes.
Les formes liées sont engendrées par le logiciel de visualisation.
- Les
caractères sont toujours écrits de gauche à droite
dans le fichier, y compris les caractères arabes.
C'est le logiciel de visualisation qui les affiche de droite à gauche (bidirectional algorithm).
-
En UTF-8 les caractères arabes sont codés sur 2 octets (comme les lettres accentuées françaises),
tandis que les caractères indiens (devanâgari) sont codés sur 3 octets, comme on a pu le voir.
-
Exemple1 (allez voir le texte-source !) : عـنترة بن شداد
Exemple2 (idem) : &#
x0627;&# x0644;&# x0645;&# x064F;&# x0639;&#
x064E;&# x0644;&# x0651;&# x064E;&# x0642;&#
x064E;&# x0627;&# x062A;
À votre avis, pourquoi ces blancs bizarres entre "&#" et "x...." ?
Nombreux exemples dans la page de démonstration "Qu'est-ce qu'Unicode" en arabe.
ainsi que dans une excellente introduction à la littérature arabe (en espagnol).
- Adaptation au persan ( فارسی fârsi)
L'écriture du persan fait appel à trois lettres supplémentaires, le pé : پ (x067E), le tché : چ (x0686) et le jé : ژ (x0698),
qui suivent les mêmes règles que les autres.
En outre, elle emploie en position finale un ya sans points : ی (x06CC),
qu'il ne faut pas confondre aec l'alif maksura de l'arabe : ى (x0649).
Nombreux exemples dans la page de démonstration "Qu'est-ce qu'Unicode" en persan.
Pour quelques URL de sites proposant des textes persans, voyez mes notes sur Khayyâm.