Aller au contenu principal

Formatage de messages Intl

Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

Formate les chaînes de messages ICU avec des espaces réservés pour les nombres, dates, pluriels et sélections afin de créer des messages localisés.

npm Version intl-messageformat minzipped size

Vue d'ensemble

Objectifs

Ce package vise à fournir un moyen de gérer et formater les messages textuels de votre application JavaScript en chaînes localisées pour les utilisateurs. Il peut être utilisé dans le navigateur et sur le serveur via Node.js.

Cette implémentation est basée sur la proposition Strawman, mais présente quelques divergences.

Évolutions futures

L'API IntlMessageFormat pourra évoluer pour rester synchronisée avec ECMA-402, mais ce package respectera semver.

Fonctionnement

Les messages sont fournis au constructeur sous forme de chaîne String ou d'objet AST pré-analysé.

const msg = new IntlMessageFormat(message, locales, [formats], [opts])

La chaîne message est analysée puis stockée sous une forme compilée optimisée pour la méthode format(), qui génère la chaîne formatée destinée à l'utilisateur.

const output = msg.format(values)

Exemple d'utilisation courante

Un cas typique concerne le formatage de messages avec nombres et libellés de pluriel. Ce package garantit un formatage correct selon la locale de l'utilisateur, par exemple :

Live Editor
new IntlMessageFormat(
  `{numPhotos, plural,
      =0 {You have no photos.}
      =1 {You have one photo.}
      other {You have # photos.}
    }`,
  'en-US'
).format({numPhotos: 1000})
Result
Live Editor
new IntlMessageFormat(
  `{numPhotos, plural,
      =0 {Usted no tiene fotos.}
      =1 {Usted tiene una foto.}
      other {Usted tiene # fotos.}
    }`,
  'es-ES'
).format({numPhotos: 1000})
Result

Syntaxe des messages

La syntaxe utilisée n'est pas propriétaire : il s'agit d'un standard interlangages bien connu des traducteurs professionnels. Ce package utilise la syntaxe ICU Message et fonctionne pour toutes les langues CLDR disposant de règles de pluralisation.

Fonctionnalités

  • Utilise des standards industriels : syntaxe ICU Message et données locales CLDR.

  • Prend en charge les arguments de type plural, select et selectordinal.

  • Formate les nombres et dates/heures via Intl.NumberFormat et Intl.DateTimeFormat.

  • Optimisé pour les appels répétés à la méthode format() des instances IntlMessageFormat.

  • Permet de définir des styles/options de format personnalisés.

  • Gère les séquences d'échappement pour les caractères syntaxiques, ex. : "'{foo}'" produit "{foo}" plutôt que d'interpréter foo comme argument.

Utilisation

Dépendance Intl moderne

Ce package nécessite la présence globale de l'objet Intl dans l'environnement d'exécution. Intl est disponible dans tous les navigateurs modernes (IE11+) et Node.js (avec ICU complet). Les méthodes Intl utilisées sont :

  1. Intl.NumberFormat pour le formatage numérique (polyfillable via @formatjs/intl-numberformat)

  2. Intl.DateTimeFormat pour le formatage des dates et heures (peut être complété par @formatjs/intl-datetimeformat)

  3. Intl.PluralRules pour le formatage des pluriels et ordinaux (peut être complété par @formatjs/intl-pluralrules)

Chargement d'Intl MessageFormat dans un navigateur

<script src="intl-messageformat/intl-messageformat.min.js"></script>

Chargement d'Intl MessageFormat dans Node.js

Vous pouvez faire :

import IntlMessageFormat from 'intl-messageformat'
const IntlMessageFormat = require('intl-messageformat').default

REMARQUE : Votre Node doit inclure full ICU

API publique

Constructeur IntlMessageFormat

Pour créer un message à formater, utilisez le constructeur IntlMessageFormat. Il prend trois paramètres :

  • message: string | AST - Message sous forme de chaîne (ou AST pré-analysé) servant de modèle de formatage.

  • locales: string | string[] - Chaîne avec une balise de langue BCP 47, ou tableau de telles chaînes. Si aucune locale n'est fournie, la locale par défaut sera utilisée. Pour un tableau de locales, chaque élément et ses locales parentes sont vérifiés, et la première avec des données enregistrées est retenue. Voir : Résolution de locale pour plus de détails.

  • formats?: object - Objet optionnel contenant des options de format personnalisées.

  • opts?: { formatters?: Formatters, ignoreTag?: boolean } - Options facultatives.

    • formatters: Map contenant des formateurs mémoïsés pour la performance.
    • ignoreTag: Indique si les balises HTML/XML doivent être traitées comme des littéraux plutôt que comme des jetons. À false, seules les balises simples sans attributs sont autorisées.
const msg = new IntlMessageFormat('My name is {name}.', 'en-US')

Résolution de locale

IntlMessageFormat utilise Intl.NumberFormat.supportedLocalesOf() pour déterminer les données de locale à utiliser, basées sur la valeur locales passée au constructeur. Le résultat est consultable via la méthode prototype resolvedOptions().

Méthode resolvedOptions()

Cette méthode retourne un objet contenant les options résolues lors de la création de l'instance. Actuellement, seule la propriété locale est présente ; exemple :

Live Editor
new IntlMessageFormat('', 'en-us').resolvedOptions().locale
Result

Notez que la locale spécifiée en minuscules "en-us" a été résolue et normalisée en "en-US".

Méthode format(values)

Une fois le message créé, son formatage s'effectue en appelant format() sur l'instance avec une collection de values :

Live Editor
new IntlMessageFormat('My name is {name}.', 'en-US').format({name: 'Eric'})
Result
arguments

Une valeur doit être fournie pour chaque argument du modèle de message utilisé lors de la construction de l'instance.

Prise en charge du texte enrichi

Live Editor
new IntlMessageFormat('hello <b>world</b>', 'en').format({
  b: chunks => <strong>{chunks}</strong>,
})
Result

Nous prenons en charge les balises XML intégrées (ex: this is a <b>strong</b> tag). Ce n'est pas une méthode complète d'intégration HTML, mais un balisage contextuel pour la traduction. Restrictions :

  1. Les attributs des balises HTML sont ignorés.

  2. Les balises auto-fermantes sont traitées comme des littéraux et non prises en charge ; utilisez plutôt des paramètres ICU standard comme {placeholder}.

  3. Toutes les balises spécifiées doivent avoir des valeurs correspondantes, sinon une erreur est levée :

Live Editor
function () {
  try {
    return new IntlMessageFormat('a <foo>strong</foo>').format()
  } catch (e) {
    return String(e)
  }
}
Result
  1. Les balises XML/HTML sont échappées par apostrophe comme les autres constructions ICU. Exemple d'échappement :
Live Editor
new IntlMessageFormat("I '<'3 cats").format()
Result
Live Editor
new IntlMessageFormat("raw '<b>HTML</b>'").format()
Result
Live Editor
new IntlMessageFormat("raw '<b>HTML</b>' with '<a>'{placeholder}'</a>'").format(
  {placeholder: 'some word'}
)
Result
  1. L'intégration de balises HTML valides reste floue car nous ne supportons pas entièrement les spécifications HTML/XHTML/XML.

Méthode getAst

Retourne l'AST sous-jacent du message compilé.

Squelette Date/Heure/Nombre

Nous prenons en charge le squelette de nombre ICU et un sous-ensemble du squelette date/heure pour une personnalisation avancée des formats.

Squelette de nombre

Exemple :

Live Editor
new IntlMessageFormat(
  'The price is: {price, number, ::currency/EUR}',
  'en-GB'
).format({price: 100})
Result

Un ensemble complet d'options et de syntaxe est disponible ici

Squelette date/heure

ICU propose une large gamme de motifs pour personnaliser le format de date et d'heure. Cependant, tous ne sont pas disponibles via l'API Intl d'ECMA402. Par conséquent, notre analyseur ne prend en charge que les motifs suivants :

SymbolMeaningNotes
GEra designator
yyear
Mmonth in year
Lstand-alone month in year
dday in month
Eday of week
elocal day of weeke..eee is not supported
cstand-alone local day of weekc..ccc is not supported
aAM/PM marker
hHour [1-12]
HHour [0-23]
KHour [0-11]
kHour [1-24]
mMinute
sSecond
zTime Zone

Exemple :

Live Editor
new IntlMessageFormat('Today is: {now, date, ::yyyyMMdd}', 'en-GB').format({
  now: new Date(),
})
Result

Utilisation avancée

Passage d'AST

Vous pouvez passer un AST pré-analysé à IntlMessageFormat comme ceci :

new IntlMessageFormat('hello').format() // prints out hello

// is equivalent to

import IntlMessageFormat from 'intl-messageformat'
import {parse} from '@formatjs/icu-messageformat-parser'
new IntlMessageFormat(parse('hello')).format() // prints out hello

Cela améliore les performances dans des cas comme le SSR ou les plateformes supportant le préchargement/précompilation, car l'AST peut être mis en cache.

Si tous vos messages sont sous forme d'AST, vous pouvez définir un alias pour @formatjs/icu-messageformat-parser vers {default: undefined} pour économiser des octets lors du bundling.

Formateurs

Pour les messages complexes, l'initialisation des constructeurs Intl.* peut être coûteuse. Nous autorisons donc l'utilisateur à passer des formatters pour fournir des instances mémorisées de ces objets Intl. Cette option combinée avec le passage d'AST et fast-memoize peut accélérer les traitements jusqu'à 30x selon le benchmark ci-dessous.

Par exemple :

import IntlMessageFormat from 'intl-messageformat'
import {memoize} from '@formatjs/fast-memoize'
const formatters = {
getNumberFormat: memoize(
(locale, opts) => new Intl.NumberFormat(locale, opts)
),
getDateTimeFormat: memoize(
(locale, opts) => new Intl.DateTimeFormat(locale, opts)
),
getPluralRules: memoize((locale, opts) => new Intl.PluralRules(locale, opts)),
}
new IntlMessageFormat('hello {number, number}', 'en', undefined, {
formatters,
}).format({number: 3}) // prints out `hello, 3`

Benchmark

format_cached_complex_msg x 153,868 ops/sec ±1.13% (85 runs sampled)
format_cached_string_msg x 21,661,621 ops/sec ±4.06% (84 runs sampled)
new_complex_msg_preparsed x 719,056 ops/sec ±2.83% (78 runs sampled)
new_complex_msg x 12,844 ops/sec ±1.97% (85 runs sampled)
new_string_msg x 409,770 ops/sec ±2.57% (79 runs sampled)
complex msg format x 12,065 ops/sec ±1.66% (81 runs sampled)
complex msg w/ formatters format x 11,649 ops/sec ±2.05% (78 runs sampled)
complex preparsed msg w/ formatters format x 597,153 ops/sec ±1.46% (90 runs sampled)
complex preparsed msg w/ new formatters format x 684,263 ops/sec ±1.37% (89 runs sampled)