Internationalisation: rendre le Web accessible à tous

Ecma International, Technical Committee 39, ou simplement TC39, est un groupe de développeurs JavaScript, de développeurs de technologies, d'universitaires et d'autres parties intéressées qui, avec la communauté, soutiennent et développent JavaScript en tant que plateforme.

Les participants au TC39 partagent généralement quelque chose d'intéressant en utilisant leur profonde compréhension de JavaScript. Mais certaines personnes pensent qu'elles sont allées trop loin des problèmes des développeurs ordinaires. Où est le développeur de langage et où est la personne qui écrit chaque jour des frontends dans la pratique?

Faisons connaissance avec le rapport, qui combine à la fois la profondeur de la compréhension et une grande applicabilité pratique . Découvrez la nouvelle histoire de Romulo Cintra sur les problèmes d'internationalisation qui seront traités par la nouvelle API, qui apparaîtra bientôt en JavaScript.



Romulo Cintra - Délégué TC39, travaille dans le développement et l'architecture depuis plus de 10 ans, spécialisé dans le web, le développement mobile et le cloud. Dans ce rapport, vous apprendrez de première main le coprésident du groupe de travail MessageFormat , quelles options sont déjà disponibles pour résoudre les problèmes existants, et sous quelle forme ils vont être résolus en utilisant la nouvelle API dans JavaScript lui-même.

Sous la coupe, la transcription textuelle complète du rapport Romulo et un lien vers la vidéo. Si vous aimez lire - cet article a tout pour plaire, vous ne manquerez de rien. Si vous avez le temps de démarrer l'enregistrement vidéo, vous aurez environ une heure de bon enregistrement vidéo avec des diapositives intéressantes et un anglais compréhensible.

Nouvelle narration au nom de l'orateur.


Il y a trois choses que vous devez savoir sur l'état de l'internationalisation et de la localisation: tout est très, très, très mauvais. Je m’appelle Romulo Cintra et je suis en charge de l’architecture applicative en finance. Je parle beaucoup avec des gens de TC39 et je vois comment ils essaient de rendre le monde JavaScript meilleur. De plus, je suis un fervent partisan de l'open source, et pendant mon temps libre, je suis professeur à l'École de technologie de Barcelone.

La question de l'internationalisation est très importante. Il se trouve que sur notre Terre, il existe de nombreux peuples et langues différents. Le monde compte aujourd'hui environ 195 pays et 6 000 langues. Cela rend notre tâche extrêmement difficile. Pensez à autre chose: j'écris des articles et je lis des rapports en anglais, pas en russe; nous avons déjà un problème d'internationalisation. Si quelqu'un ne parle pas anglais, il sera exclu de notre conversation avec vous. Pour éviter que cela ne se produise, l'internationalisation a été inventée.

L'internationalisation en anglais est abrégée en i18n. Le nombre 18 est le nombre de caractères entre les lettres i et n dans ce mot. En bref, l'internationalisation est la conception de logiciels afin de simplifier au maximum la localisation. Grâce à l'internationalisation, le logiciel peut prendre en charge les paramètres locaux, la langue, la devise, etc. L'internationalisation rend le Web plus accessible à tous. Ici, vous pouvez faire un parallèle avec le développement par le biais de tests (développement piloté par les tests): là d'abord, le test est écrit, puis le code; avec l'internationalisation, il est nécessaire de faire de même. Habituellement, les gens pensent à l'internationalisation une fois le code écrit, mais c'est faux.

Semblable à i18n, l10n est l'abréviation de localisation, et 10 est le nombre de caractères entre le premier l et le dernier n. La localisation est l'adaptation d'un produit à l'environnement linguistique et culturel dans lequel il est distribué. Autrement dit, vous devez non seulement traduire "Bonjour" en "Bonjour", mais également utiliser la devise locale, le séparateur décimal, etc., c'est-à-dire rendre le logiciel plus familier à l'utilisateur. C'est plus qu'une simple traduction.

Combien de langues vos projets Web prennent-ils en charge? Beaucoup en ont plus de deux. Y a-t-il quelqu'un qui en a plus de cinq? Et 15? Nous prenons en charge environ 25 langues. Nous n'avons pas un très bon soutien, car l'internationalisation n'est pas organisée de la meilleure façon. Au cours du rapport, je vais expliquer comment améliorer l'internationalisation et parler des mesures que nous prenons.

Donc, je le répète encore une fois: l'internationalisation signifie simplifier la localisation, la soutenir au niveau de l'architecture. Et la localisation est l'adaptation des logiciels aux réalités locales. La traduction ne correspond pas très souvent à l'original - prenons un exemple de l'industrie cinématographique, où le nom du film «Pain and Gain» a été traduit par «Blood and Sweat: Anabolics».



Ou un autre exemple: une publicité pour un bain russe, dans laquelle la traduction anglaise dit «crématorium russe» (crématorium russe).



Je doute que cela attirera des clients, au moins vivants. L'internationalisation et la localisation sont si importantes précisément parce qu'elles nous permettent de transmettre exactement ce que nous voulons dire à l'utilisateur. En substance, l'internationalisation est la fourniture d'accessibilité, car si vous ne comprenez pas le logiciel avec lequel vous travaillez, vos options sont en fait limitées. Il est avantageux pour tout le monde que le logiciel soit plus accessible, car il offre un plus large éventail d'utilisateurs, et donc un revenu plus élevé; cela améliore également le Web.

Format du message


Considérez les exemples de code:

'es-ES': { 
    HELLO_WORLD: '¡Hola mundo!' 
}, 
'en-GB': { 
    HELLO_WORLD: 'Hello world!'

Nous devons traduire nos objets chaîne. Nous avons une variable HELLO_WORLDavec des lignes correspondantes dans chaque langue. Pour une telle traduction dans de nombreuses langues (par exemple, Java), le format MessageFormat existe . Essayons de comprendre ce que c'est. Tout d'abord, un peu sur certaines technologies de base - commençons par Unicode. Il s'agit d'une norme qui crée un espace unique pour les caractères de différentes langues. Tirons une analogie avec les échecs: chaque type de pièces peut avoir une forme différente, mais nous savons toujours exactement où elles devraient être sur le plateau. Bien sûr, il existe différents formats Unicode avec différents nombres d'octets: UTF-8, UTF-16 et UTF-32. Désormais, la balise META la plus utilisée est UTF-8. Avec Unicode, le navigateur peut afficher des caractères spéciaux, si cette balise`metaoubliez, personne ne comprendra quel type de symboles nous avons sur la page.

En plus d'Unicode, deux autres technologies importantes sont CLDR et ICU. CLDR est une sorte de base de données d'alphabets, de pays, de devises, de fuseaux horaires, etc., stockée dans différentes langues du monde. Les 6 000 langues du monde n'y sont pas toutes présentes, des travaux sont toujours en cours sur cette base de données. La dernière mise à jour date d'octobre dernier. Un autre projet important est l'ICU. Il s'agit d'une énorme base de données de mots, nombres et symboles de différents langages, qui sont fournis sous forme de méthodes de tri, de normalisation, de formatage, etc. Ces bibliothèques sont utilisées dans de nombreux langages de programmation. En JavaScript, ICU est au cœur de l'API Intl. Mais il existe tellement de matériaux divers dans les langues du monde qui doivent être affichés dans les navigateurs que le travail de les inclure dans ces normes est loin d'être terminé.

MessageFormat est un format qui vous permet d'associer une clé spécifique à un message spécifique dans une langue spécifique. Dans certains cas, des variables peuvent être transmises à MessageFormat , il les définit et les entre dans la ligne finale. Le même problème a été résolu d'une manière légèrement différente dans d'autres langues. Sous Android, MessageFormat est implémenté en Java. Là, pour travailler avec ce format, une bibliothèque spéciale n'est pas nécessaire; Android est capable d'interagir avec lui-même. Dans iOS, il existe une API très similaire à celle de JavaScript. Il est intégré au système, il n'y a pas besoin de télécharger quoi que ce soit là non plus, il suffit de passer la ligne nécessaire à la méthode de cette API.

Comment ce problème a-t-il été résolu en JavaScript? Pas encore. Mais nous avons de nombreuses bibliothèques qui offrent une solution.



Il montre le nombre de téléchargements des plus populaires d'entre eux (et deux moins populaires, couramment Mozilla et fbt de Facebook). Près de deux millions de téléchargements ont lieu chaque semaine, il y a donc un besoin de bibliothèques pour l'internationalisation.

Bibliothèques


Nous allons brièvement présenter certaines de ces bibliothèques et commencer par i18next. Ses développeurs ont apporté de nombreuses modifications à MessageFormat , et il ne suit pas entièrement l'ICU. Cependant, c'est une très bonne bibliothèque. Son implémentation de MessageFormat présente de nombreux avantages, par exemple, la possibilité d'utiliser l'interpolation de chaînes (qui n'est pas disponible au format ICU). Cependant, il y a aussi des inconvénients, par exemple, plusieurs messages ne peuvent pas être placés sur la même ligne que le seul, comme cela peut être fait en USI. Intl-messageformat

est l'une des bibliothèques d'internationalisation les plus célèbres. Chaque semaine, il est téléchargé plus de 700 000 fois. Son soutien est géré par ma collègue, Long Hu. Sa popularité s'explique par le fait que react-intl est créé par-dessus. Donc, si vous utilisez React, vous avez probablement cette bibliothèque. Son développeur participe également à ECMA-402, et donc il essaie de se conformer à la norme ICU.

var MESSAGES = { 
    'en-US': { 
        NUM_PHOTOS: 'You have {numPhotos, plural, ' +
            '=0 {no photos.}' +
            '=1 {one photo.}' +
            'other {# photos.}}'
}, 
    'es-MX': {
        NUM_PHOTOS: 'Usted {numPhotos, plural, ' +
            '=0 {no tiene fotos.}' + 
            '=1 {tiene una foto.}' 
            +'other {tiene # fotos.}}' 
    } 
};

Son implémentation est très similaire à MessageFormat . Ici, vous pouvez passer des variables et indiquer la nécessité du pluriel.

Avant de passer aux exemples de code, je vais parler de deux nouvelles bibliothèques qui sont maintenant à la mode, elles ont été créées par Facebook et Mozilla.



L'ensemble de l'API ne peut pas être montré dans son ensemble, mais croyez-moi: les développeurs de ces bibliothèques ont fait de leur mieux, il y a exactement ce qui nous manque en ce moment. Certes, Facebook l'a fait dans son propre style: son propre balisage, la possibilité de s'exécuter pendant la mise en page, l'extraction de cartes de hachage à partir de chaînes qui peuvent être automatiquement traduites. Le problème est que tout cela se concentre sur l'échelle avec laquelle le programmeur moyen travaille rarement. Le projet est très jeune, et ils veulent l'intégrer à d'autres bibliothèques bien connues, par exemple, avec React. À l'avenir, il devrait gagner en popularité.

Tous les éléments ci-dessus sont des bibliothèques qui doivent être téléchargées en plus, elles ne sont pas intégrées au navigateur. Avec un seul navigateur, nous n'irons pas loin, donc tout va mal avec la localisation. MessageFormat peut nous aider à changer cet état de fait . Bien que nous ne pouvons pas l'utiliser, mais croyez-moi: l'avenir lui appartient. Maintenant, nous y travaillons activement, établissons des parties prenantes, recherchons de nouvelles idées pour le nouveau MessageFormat . Dans sa version originale, ce format est déjà dépassé, les besoins des développeurs ont considérablement évolué depuis sa création. Le nouveau format doit être de haute qualité et facile à utiliser.

Intl.DateTimeFormat


Les navigateurs disposent déjà de nombreux mécanismes intégrés pour l'internationalisation et la localisation, la plupart d'entre eux ne les connaissent tout simplement pas et ne les utilisent pas. Avez-vous entendu parler d'Intl.DateTimeFormat? Dans ce projet, nous créons constamment de nouvelles API. Il est probable qu'il n'y ait plus besoin de Moment.js , Day.js , date-fns .

const myDate = new Date(); 
new Intl.DateTimeFormat('ru', { timeStyle : 'short'}).format(myDate); 
// short → 19:49 
// medium → 19:49:17 
// long → 19:49:17 GMT+2
// full → 19:49:17  ,  

Il y a timeStyle, il a été créé il y a quelques mois et il vous permet de formater la date et l'heure sans avoir recours à Moment.js. De plus, il existe une méthode formatRange . Toute tâche associée au choix d'une plage de dates (comme sur les sites avec une fonction de réservation) est toujours difficile. Mais la méthode pour cela existe déjà dans le navigateur. Et, plus important encore, cette méthode prend en charge l'internationalisation, tout en éliminant la nécessité de télécharger des bibliothèques supplémentaires.

Intl.RelativeTimeFormat


J'ai travaillé sur la documentation de la deuxième partie de ce projet, et si vous souhaitez également participer, nous avons besoin d'aide pour la traduction en russe et dans le respect des normes. RelativeTimeFormat est nécessaire lorsque vous devez effectuer un compte à rebours.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(2 , 'quarter'); 
//Style Narrow : +2 . → in 2 qtrs. → dentro de 2 trim. 
//Style Long :  2  → in 2 quarters → dentro de 2 trimestres

Maintenant, c'est assez simple de le faire, vous pouvez spécifier l'heure en deux jours, deux semaines, un quart, etc. Auparavant, une telle mise en forme sur le Web n'existait pas.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(2 , 'day'); 
//Style Narrow : +2 . → in 2 days → dentro de 2 días 
//Style Long :  2  → dentro de 2 días myTime.format(-1 , 'day');
//Style Narrow : -1 . → 1 day ago → hace 1 día 
//Style Long : 1   → 1 day ago → hace 1 día //Numeric(auto) :  → yesterday → ayer 

Voici un exemple en russe. Vous pouvez vous-même tester le fonctionnement de ce code, car il est déjà dans votre navigateur.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(20 , 'seconds'); 
//Style Narrow : +20  → in 20 sec. → dentro de 20 s 
//Style Long :  20  → in 20 seconds → dentro de 20 segundos

Cette méthode est très utile, elle peut donner du temps dans le format court que vous voyez ci-dessus. Je souligne que pour tout cela, vous n'avez pas besoin d'utiliser de bibliothèques tierces.

Intl.NumberFormat


La prochaine chose que je voulais partager est Intl.NumberFormat . Je vais parler de la troisième étape, mais seule la seconde est présentée dans les exemples, car certains changements sont encore en discussion. Intl.NumberFormat fonctionne avec des unités et des formulaires d'enregistrement. Il vaut la peine de faire attention à ce qu'il fait avec les unités: il vous permet de travailler avec différents styles.

new Intl.NumberFormat("ru", { 
style: "unit", 
unit: "liter", unitDisplay: "long" 
}).format(16); 
// → 16  → 16 liters → 16 litros

Toutes les unités proviennent de l'UTC 35, et il y en a beaucoup. Au total, environ 140 unités de formatage sont présentées ici. L'internationalisation est donc plus facile que jamais. Il vous suffit de traduire vos lignes, et toute la dynamique nécessaire est déjà contenue dans le navigateur.

const nbr = 987654321; 
new Intl.NumberFormat('ru', { notation: 'scientific' }).format(nbr); 
// → 9,877E8 → 9.877E8 (en-US) 
new Intl.NumberFormat('ru', { notation: 'engineering' }).format(nbr); 
// → 987,654E6 → 987.654E6 (en-US) 
new Intl.NumberFormat('ru', { notation: 'compact' }).format(nbr); 
// → 988  → 988M (en-US) → 9.9亿 (zn-CN) 
new Intl.NumberFormat('ru', { notation: 'compact', compactDisplay: 'long' }).format(nbr); 
// → 988  → 988 millions (fr)

Maintenant, pour les formulaires d'enregistrement. Pour être honnête, je ne les utilise pas trop souvent, car je n'utilise pas le formulaire d'enregistrement avec l'exposant (dossier scientifique), et je n'ai pas besoin de présenter de grands nombres. Mais si vous en avez besoin, il existe une API correspondante spécialement pour vous.

Intl.ListFormat


Une autre API utile est Intl.ListFormat , qui est déjà à la troisième étape et vous permet de formater les listes de deux manières différentes. Supposons que je doive dire la phrase «Je vais à HolyJS». Nous pouvons faire une liste qui comprend les lignes «Moscou» et «St. Petersburg », spécifiez le paramètre« conjonction », et les lignes seront combinées par l'union de la langue russe« et ». Il s'agit d'une fonctionnalité complètement nouvelle et très utile.



Si vous spécifiez "disjonction", alors nous obtenons l'union "ou".



Enfin, la fonction peut déterminer automatiquement la langue et l'alphabet utilisés et trier les éléments de la liste en conséquence.

Intl.PluralRules


Une autre API importante est Intl.PluralRules . Cette API est la plus ancienne de toutes, mais pour une raison quelconque, personne ne l'utilise.



Quand je vois les listes des finalistes dans les courses ou dans le football, les numéros sont toujours indiqués à côté des noms: "1", "2", "3", etc. Mais cela ne correspond pas à la façon dont nous disons que ce serait beaucoup plus proche pour la parole, écrivez «1er», «2e», «3e». Et pour cela, il existe des API spéciales, qui ne sont pas si difficiles à utiliser.



Par exemple, nous pouvons écrire les phrases «1 chat», «0 chat», «0,5 chat», «1,5 chat», et l'API sélectionnera automatiquement la terminaison plurielle correcte.

Intl.DisplayNames


C'est l'une des API les plus populaires, car nous devons très souvent afficher des listes de pays. Supposons que nous ayons une liste de pays - par exemple, dans une base de données ou dans JSON. Ensuite, chaque fois que vous changez de langue, nous devons charger un JSON distinct avec une nouvelle liste de pays, de devises, etc. Il y a trop de ces JSON et comment cela se termine-t-il? Nous créons un microservice dans lequel une base de données avec plusieurs langues est intégrée, et nous en extrayons toutes les données. Bien sûr, dans l'exemple avec la liste des pays, nous avons eu de la chance et nous devons mettre à jour les données rarement - mais ce ne sera pas toujours comme ça, non? Nous ne pouvons pas résoudre tous les problèmes à la fois, mais DisplayNames résout certains d'entre eux. Vous disposez de l'API comme dans l'exemple ci-dessous, et vous ne pouvez demander qu'une liste de devises ou seulement une liste de pays:

const currencyNames = new Intl.DisplayNames(['en'], {type: 'currency'}); currencyNames.of('USD'); // "US Dollar" 
currencyNames.of('EUR'); // "Euro" 
currencyNames.of('TWD'); // "New Taiwan Dollar" 
currencyNames.of('CNY'); // "Chinese Yuan"


const languageNames = new Intl.DisplayNames(['en'], {type: 'language'}); languageNames.of('fr'); // "French" 
languageNames.of('de'); // "German" 
languageNames.of('fr-CA'); // "Canadian French" 
languageNames.of('zh-Hant'); // "Traditional Chinese"

C'est une chose très utile. Cela ne fonctionne pas seulement avec les pays et les devises: de la même manière, vous pouvez travailler avec des mois, des jours de la semaine et bien d'autres choses dont vous avez besoin en tant que développeur.

Résultats et plans pour l'avenir


Jusqu'à présent, nous avons parlé des API existantes. Passons à nos plans pour l'avenir. Ma langue maternelle est le portugais. Donc, sur mes sites, je dois prendre en charge au moins le portugais et l'anglais. Et comme nous sommes très proches de l'Espagne, l'espagnol est également utile. Le Portugal est un très petit pays, et la France n'est pas loin non plus, il serait donc bien d'ajouter le français à cette liste.

Pour nous MessageFormattrès pertinent, et il apparaîtra bientôt. Il y a des bibliothèques et il y a des développeurs qui y travaillent. Tous ces développeurs travaillent sur des problèmes connexes. La plupart des créateurs des bibliothèques les plus populaires et des plus grandes entreprises (Netflix, Amazon, Facebook) s'accordent sur au moins une chose: il y a maintenant un besoin urgent d'internationalisation. Ceci est également indiqué par deux millions de téléchargements par semaine. Alors maintenant, nous pouvons nous permettre d'écrire à nouveau MessageFormat et de le faire de manière qualitative.

Qui bénéficiera d'une bonne internationalisation? Tout le Web: toutes les entreprises, tous les projets, toutes les bibliothèques. Des bibliothèques comme Intl.MessageFormatne disparaîtra nulle part, mais commencera à fonctionner d'une nouvelle manière. Vous n'aurez pas besoin de télécharger de données, car toutes les données seront déjà dans le navigateur. Très probablement, vous n'aurez pas besoin de passer à une nouvelle bibliothèque. Certaines de ces bibliothèques fonctionnent déjà comme polyfills pour certaines implémentations. Certaines implémentations que j'ai mentionnées sont dans la troisième étape et ne sont pas implémentées dans tous les navigateurs. Mais des bibliothèques comme Intl.MessageFormat fournissent des polyfillings pour cette fonctionnalité. De manière générale, un nouveau chapitre de l'histoire du Web arrive - une véritable révolution. Le Web deviendra accessible et compréhensible pour tous. C'est extrêmement important.

Je pense qu'il est très important de garantir l'unicité de notre projet. S'il existe un format qui peut être utilisé en C ++, Java et JavaScript, alors pourquoi ne pas utiliser ce format partout? Lorsque nous écrivons des pages Web, nous devons souvent en créer des versions mobiles, auquel cas nous devons faire beaucoup de travail deux fois. Si nous avions un seul format pour tout, nous pourrions simplement utiliser les ressources et l'API existantes. Nous avons besoin d'un nouveau niveau d'intégration avec les outils. L'internationalisation n'est pas seulement assurée par le travail des développeurs directement impliqués. Pour elle, la modularité est extrêmement importante, car il est souvent pratique d'utiliser vos propres outils de formatage, votre propre code. Par conséquent, vous ne devez pas fermer l'API, elles doivent être ouvertes pour pouvoir connecter ce que la situation requiert.Autre point important: ces API doivent être natives. Les CLDR fournissent les données dont l'API d'internationalisation a besoin. Si vous utilisez Windows ou MacOS, vous téléchargez déjà des données depuis le CLDR. CLDR est un référentiel unique; personne ne duplique sa fonction. Cela signifie que les données ne peuvent être téléchargées qu'une seule fois et rendues communes à l'ensemble du système d'exploitation. Si toutes les données de l'API Intl sont déjà chargées dans le système d'exploitation, alors pourquoi ne pas les fournir pour tous les logiciels de ce système?Si toutes les données de l'API Intl sont déjà chargées dans le système d'exploitation, alors pourquoi ne pas les fournir pour tous les logiciels de ce système?Si toutes les données de l'API Intl sont déjà chargées dans le système d'exploitation, alors pourquoi ne pas les fournir pour tous les logiciels de ce système?

Notre expérience nous a appris à nous rappeler que nous ne sommes pas seuls, que non seulement les programmeurs travaillent à l'internationalisation. Nous sommes des développeurs, pas des traducteurs. Supposons que nous ayons besoin de faire un saut de ligne dans notre interface, nous les envoyons à la société de traduction. Mais les traducteurs n'ont souvent aucun contexte pour ces lignes. Cela est également absent dans MessageFormat . Parfois, cela conduit à des erreurs, comme nous l'avons déjà vu dans l'exemple mentionné avec le crématorium russe.

Enfin, je pense que les API pour l'internationalisation devraient être faciles à utiliser et que tout le monde devrait pouvoir faire l'internationalisation - cela ne devrait pas prendre trop de temps et d'efforts. Lorsque vous écrivez du code pour l'internationalisation, vous devez être guidé dès le début. Après tout, avec TDD, ils écrivent d'abord un test, puis codent; Commençons nos projets Web sur ce principe avec la bonne internationalisation et localisation. Cela nous permettra de créer des sites pratiques et accessibles à tous.
HolyJS 2020 Piter «Speak my language %app%». , , : . HolyJS 2020 Piter . , .

All Articles