Date de publication du RFC : Octobre 2017
Auteur(s) du RFC : N. Tomkinson, N. Borenstein (Mimecast)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF slim
Première rédaction de cet article le 10 octobre 2017
Dernière mise à jour le 20 mars 2018
La norme MIME permet d'étiqueter un
message en
indiquant la langue, avec l'en-tête
Content-Language:
(RFC 4021). Mais
comment faire si on veut envoyer le même message en plusieurs
langues, pour s'adapter à une audience variée, ou bien si on n'est
pas sûr des langues parlées par le destinataire ? C'est ce que
permet le nouveau type de
message multipart/multilingual
qui permet d'étiqueter les messages multilingues.
C'est le premier RFC du groupe de travail SLIM, chargé de créer des normes pour indiquer la langue utilisée dans le courrier et pour les communications synchrones (téléphonie sur IP, par exemple, couverte depuis par le RFC 8373), dans le cas où plusieurs langues sont en présence.
Le type de premier niveau multipart/
(RFC 2046, section 5.1, enregistré à
l'IANA) permet d'indiquer un message (ou une partie de
message, en cas de récursivité) composé de plusieurs
parties. Ainsi, multipart/mixed
(RFC 2046, section 5.1.3) indique un message dont
les dfférentes parties sont indépendantes (un texte et une image,
par exemple). Alors que multipart/alternative
(RFC 2046, section 5.1.4) est utilisé pour
le cas où les différentes parties veulent dire la même chose, mais
avec des formats différentes (une version texte
seul et une version HTML, par
exemple, ou bien une image en JPEG et la
même en PNG). Normalement, le lecteur de courrier ne va afficher qu'une
seule des parties d'une
multipart/alternative
, celle qui convient le
mieux, selon les capacités du logiciel de lecture et les
préférences de l'utilisateur. Ce sera la même chose avec ce
nouveau multipart/multilingual
: l'émetteur
enverra le message en plusieurs langues, le logiciel de lecture
n'affichera que celle qui colle le mieux aux choix de
l'utilisateur. Ce type est désormais enregistré
à l'IANA (section 9 du RFC).
Rappelez-vous que MIME est
récursif : un
multipart/
peut contenir un autre
multipart/
. Voici, par exemple, vu par le
MUA mutt, un
multipart/mixed
, dont la première partie est
un multipart/alternative
et la seconde un
fichier PDF :
I 1 <no description> [multipart/alternative, 7bit, 45K] I 2 ├─><no description> [text/plain, 8bit, utf-8, 1,8K] I 3 └─><no description> [text/html, 8bit, utf-8, 43K] A 4 35378031645-672029836-registration.pdf [application/pdf, base64, 84K]
Cette première partie du corps du message, de type
multipart/alternative
, a à son tour deux
parties, une en texte brut et l'autre en HTML. Comme ma
configuration mutt inclut la directive alternative_order
text/plain
, seule la version texte sera affichée, le
HTML étant ignoré.
Revenons aux messages multilingues. Avant ce RFC 8255, la solution la plus fréquente, quand on envoyait un message à quelqu'un dont on n'était pas sûr des préférences linguistiques, était de mettre toutes les versions dans un même message. Du genre :
(English translation at the end) Bonjour, ceci est un message. Hello, this is a message.
(La première ligne ayant pour but d'éviter que le lecteur anglophone se décourage en ne voyant au début que du français.) Cette solution n'est pas satisfaisante : elle passe mal à l'échelle dès qu'il y a plus de deux langues. Et elle ne permet pas la sélection automatique de la langue par le logiciel du destinataire.
Le type MIME d'un message est mis dans un en-tête
Content-Type:
. Par exemple, un message de
plusieurs parties représentant le même contenu serait :
Content-Type: multipart/alternative; boundary="------------E6043EF6F3B557567F3B18F4"
Où boundary
indique le texte qui sera le
séparateur entre les parties (RFC 2046,
section 5.1). La section 2 du RFC décrit ce qu'on peut désormais
mettre dans le Content-Type:
, avec le nouveau
type multipart/multilingual
.
Il ressemble beaucoup au
multipart/alternative
et, comme tous les
multipart/quelquechose
(RFC 2046, section 5.1.1), a une chaîne de
caractères qui indique le passage d'une partie à une autre :
Content-Type: multipart/multilingual; boundary=01189998819991197253
Chacune des parties d'un message en plusieurs langues doit
indiquer la langue de la partie, avec l'en-tête
Content-Language:
. Mais attention, comme il
faut tenir compte des vieux clients de messagerie qui ne
connaissent pas ce RFC, la première partie ne doit
pas avoir de
Content-Language:
, elle sert de solution de
repli, car c'est elle qui sera affichée en premier par les logiciels qui ne
connaissent pas multipart/multilingual
. Comme
elle sert de secours, il est recommandé qu'elle soit dans le
format le plus simple, donc text/plain
, en
UTF-8 (car il faut pouvoir représenter
diverses langues). Cette partie se nomme la préface. En la
lisant, l'utilisateur pourra donc comprendre qu'il doit mettre à
jour vers un logiciel plus récent.
Les parties suivantes, après la préface, vont être écrites dans des langues différentes. Le RFC recommande de les mettre dans l'ordre, avec celles qui ont le plus de chance d'être pertinentes en premier. (Ainsi, une société française ayant une activité européenne, avec une majorité de clients français, et envoyant un message en anglais, allemand et français, mettra sans doute le français en premier, suivi de l'anglais.)
Chacune de ces parties aura un en-tête
Content-Language:
, pour indiquer la langue,
et Content-Type:
pour indiquer le type
MIME. (Rappelez-vous toujours que MIME est récursif.) Il est
recommandé que chaque partie soit un message complet (avec
notamment le champ Subject:
, qui a besoin
d'être traduit, lui aussi, et le champ From:
,
dont une partie peut être utilement traduite). Le type conseillé est donc
message/rfc822
(RFC 2046, section 5.2.1), mais on peut aussi utiliser le
plus récent message/global
(RFC 6532).
Notez bien que ce RFC ne spécifie évidemment pas comment se fera la traduction : il ne s'occupe que d'étiqueter proprement le résultat.
Le message peut se terminer par une section « indépendante de
la langue » (par exemple une image ne comportant pas de
texte, si le message peut être porté par une image). Dans ce cas, son Content-Language:
doit indiquer zxx
, ce qui veut dire
« information non pertinente » (RFC 5646,
section 4.1). C'est elle qui sera sélectionnée si aucune partie ne
correspond aux préférences de l'utilisateur.
Maintenant, que va faire le client de
messagerie qui reçoit un tel message multilingue ? La
section 4 de notre RFC décrit les différents cas. D'abord, avec
les logiciels actuels, le client va afficher les différentes
parties de multipart/multilingual
dans
l'ordre où elles apparaissent (donc, en commençant par la
préface).
Mais le cas le plus intéressant est évidemment celui d'un client plus récent, qui connait les messages multilingues. Il va dans ce cas sauter la préface (qui n'a pas de langue indiquée, rappelez-vous) et sélectionner une des parties, celle qui convient le mieux à l'utilisateur.
Un moment. Arrêtons-nous un peu. C'est quoi, la « meilleure » version ? Imaginons un lecteur francophone, mais qui parle anglais couramment. Il reçoit un message multilingue, en français et en anglais. S'il choisissait manuellement, il prendrait forcément le français, non ? Eh bien non, car cela dépend de la qualité du texte. Comme peut le voir n'importe quel utilisateur du Web, les différentes versions linguistiques d'un site Web ne sont pas de qualité égale. Il y a le texte original, les traductions faites par un professionnel compétent, les traductions faites par le stagiaire, et celles faites par un programme (en général, les plus drôles). Sélectionner la meilleure version uniquement sur la langue n'est pas une bonne idée, comme le montre la mauvaise expérience de HTTP. Ici, pour reprendre notre exemple, si la version en anglais est la version originale, et que le français est le résultat d'une mauvaise traduction par un amateur, notre francophone qui comprend bien l'anglais va sans doute préférer la version en anglais.
Il est donc crucial d'indiquer le type de traduction effectuée,
ce que permet le Content-Translation-Type:
exposé plus loin, en section 6. (Les premières versions du projet
qui a mené à ce RFC, naïvement, ignoraient complètement ce
problème de la qualité de la traduction, et de la version
originale.)
Donc, le mécanisme de sélection par le MUA de la « meilleure » partie dans un message multilingue n'est pas complètement spécifié. Mais il va dépendre des préférences de l'utilisateur, et sans doute des règles du RFC 4647.
Si aucune partie ne correspond aux choix de l'utilisateur, le RFC recommande que le MUA affiche la partie indépendante de la langue, ou, si elle n'existe pas, la partie après la préface. Le MUA peut également proposer le choix à l'utilisateur (« Vous n'avez indiqué qu'une langue, le français. Ce message est disponible en anglais et en chinois. Vous préférez lequel ? »)
La section 5 du RFC présente en détail l'utilisation de l'en-tête
Content-Language:
. Il doit suivre la norme
existante de cet en-tête, le RFC 3282, et sa valeur doit
donc être une étiquette de langue du RFC 5646. Des exemples (en pratique, il ne faut
évidemment en mettre qu'un) :
Content-Language: fr Content-Language: sr-Cyrl Content-Language: ay Content-Language: aaq
Le premier exemple concerne le français, le second le serbe écrit en alphabet cyrillique, le troisième l'aymara et le quatrième l'abénaqui oriental.
La section décrit le nouvel en-tête
Content-Translation-Type:
qui indique le type
de traduction réalisé. Il peut prendre trois valeurs,
original
(la version originale),
human
(traduit par un humain) et
automated
(traduit par un programme). Notez
que les humains (les programmes aussi, d'ailleurs) varient
considérablement dans leurs compétences de traducteur. J'aurais
personnellement préféré qu'on distingue un traducteur
professionnel d'un amateur, mais la traduction fait partie des
métiers mal compris, où beaucoup de gens croient que si on parle
italien et allemand, on peut traduire de l'italien en allemand
correctement. C'est loin d'être le cas. (D'un autre côté, comme
pour tous les étiquetages, si on augmente le nombre de choix, on
rend l'étiquetage plus difficile et il risque d'être incorrect.)
Voici un exemple complet, tel qu'il apparait entre deux logiciels de messagerie. Il est fortement inspiré du premier exemple de la section 8 du RFC, qui comprend également des exemples plus complexes. Dans ce message, l'original est en anglais, mais une traduction française a été faite par un humain.
From: jeanne@example.com To: jack@example.com Subject: Example of a message in French and English Date: Thu, 7 Apr 2017 21:28:00 +0100 MIME-Version: 1.0 Content-Type: multipart/multilingual; boundary="01189998819991197253" --01189998819991197253 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit This is a message in multiple languages. It says the same thing in each language. If you can read it in one language, you can ignore the other translations. The other translations may be presented as attachments or grouped together. Ce message est disponible en plusieurs langues, disant la même chose dans toutes les langues. Si vous le lisez dans une des langues, vous pouvez donc ignorer les autres. Dans votre logiciel de messagerie, ces autres traductions peuvent se présenter comme des pièces jointes, ou bien collées ensemble. --01189998819991197253 Content-Type: message/rfc822 Content-Language: en Content-Translation-Type: original Content-Disposition: inline From: Manager <jeanne@example.com> Subject: Example of a message in French and English Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 Hello, this message content is provided in your language. --01189998819991197253 Content-Type: message/rfc822 Content-Language: fr Content-Translation-Type: human Content-Disposition: inline From: Directrice <jeanne@example.com> Subject: =?utf-8?q?Message_d=27exemple=2C_en_fran=C3=A7ais_et_en_anglais?= Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit MIME-Version: 1.0 Bonjour, ce message est disponible dans votre langue. --01189998819991197253--
On note qu'il y a une préface (la première partie, celle qui
commence par « This is a message in multiple languages »), que
chacun des deux parties étiquetées a un
From:
(pour pouvoir adapter le titre de
l'expéditrice) et un sujet (celui en français étant encodé selon
le RFC 2047). Les deux dernières parties
ont un Content-Translation-Type:
.
Actuellement, il ne semble pas qu'il existe de
MUA qui gère cette nouvelle norme. Si vous
voulez envoyer des messages à ce format, vous pouvez copier/coller
l'exemple ci-dessus, ou bien utiliser le programme Python send-multilingual.py
.
Voici le message d'exemple cité plus haut affiché par mutt (version NeoMutt 20170113 (1.7.2)) :
Thunderbird affiche à peu près la même chose.
Gmail a stupidement décidé de mettre ce message dans le dossier Spam. Une fois le message sorti de ce purgatoire, voici ce que ça donnait :
Notez l'existence d'une FAQ sur ce format.
Une mise en œuvre dans
mutt a été faite au hackathon
de la réunion IETF 101 par Alexandre Simon. Elle a été soumise en tant que pull
request à mutt. Outre ce travail sur un
MUA, le même auteur a écrit un réflecteur de
courrier permettant de tester ce RFC. Vous envoyez un
message ordinaire en français à
reflector+sl_fr+tl_zh@rfc8255.as-home.fr
(sl
= Source Language, tl = Target
Language, ici, on dit que le message est en français, et
on veut une réponse en chinois), et il répond avec
un message conforme au RFC 8255, traduit par Google Translate. Voici par exemple une demande :
To: reflector+sl_fr+tl_zh@rfc8255.as-home.fr MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: NeoMutt/20170113 (1.7.2) Subject: Test je parle la France From: Stephane Bortzmeyer <stephane@bortzmeyer.org> Alors, ça donne quoi ? Surtout s'il y a plusieurs lignes.
Et sa réponse :
Content-Type: multipart/multilingual; boundary="----------=_1521485603-32194-0" Content-Transfer-Encoding: binary MIME-Version: 1.0 To: Stephane Bortzmeyer <stephane@bortzmeyer.org> Sender: <reflector@idummy.as-home.fr> Subject: Test je parle la France From: Stephane Bortzmeyer <stephane@bortzmeyer.org> This is a multi-part message in MIME format... ------------=_1521485603-32194-0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: binary Alors, ça donne quoi ? Surtout s'il y a plusieurs lignes. ------------=_1521485603-32194-0 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: binary Content-Language: fr Content-Translation-Type: original Content-Type: text/plain; charset=utf-8 From: Stephane Bortzmeyer <stephane@bortzmeyer.org> Subject: Test je parle la France Alors, ça donne quoi ? Surtout s'il y a plusieurs lignes. ------------=_1521485603-32194-0 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: binary Content-Language: zh Content-Translation-Type: automated Content-Type: text/plain; charset=utf-8 From: Stephane Bortzmeyer <stephane@bortzmeyer.org> Subject: =?UTF-8?B?5rWL6K+V5oiR6K6y5rOV5Zu9?= 那么,这给了什么? 特别是如果有几条线。 ------------=_1521485603-32194-0 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: binary Content-Language: zxx Content-Translation-Type: human Content-Type: text/plain; charset=utf-8 /////| ///// | ///// | |~~~| M | |===| U | | | L | | R | T | | F | I | | C | L | | 8 | I | | 2 | N | | 5 | G | | 5 | U | | | A | | | L | | | | | | / | | / |===|/ '---' ------------=_1521485603-32194-0--
On notera la dernière partie, qui utilise la langue
zxx
, code qui veut dire « non spécifiée », et
qui sert à mettre du texte qui sera affiché dans tous les
cas. Notez aussi que le message originel est inclus.
Ce message est ainsi affiché par un mutt actuel :
Et par le mutt patché pendant le hackathon :
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)