Stage 1 Draft / July 25, 2024

Intl.MessageFormat

1 MessageFormat Objects

1.1 The Intl.MessageFormat Constructor

The MessageFormat constructor is the %MessageFormat% intrinsic object and a standard built-in property of the Intl object. Behaviour common to all service constructor properties of the Intl object is specified in 9.1.

1.1.1 Intl.MessageFormat ( locales, source [ , options ] )

When the Intl.MessageFormat function is called with arguments locales, source, and options, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let messageFormat be ? OrdinaryCreateFromConstructor(NewTarget, %MessageFormat.prototype%, « [[InitializedMessageFormat]], [[LocaleMatcher]], [[MessageData]], [[RequestedLocales]], [[Runtime]] »).
  3. Return ? InitializeMessageFormat(messageFormat, locales, source, options).

1.1.2 InitializeMessageFormat ( messageFormat, locales, source, options )

The abstract operation InitializeMessageFormat accepts the arguments messageFormat (which must be an object), locales, source, and options. It initializes messageFormat as a MessageFormat object. The following steps are taken:

  1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  2. If source is undefined, throw a TypeError exception.
  3. Let msgData be ? GetMessageData(source).
  4. Set options to ? GetOptionsObject(options).
  5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
  6. Let userFunctions be ? Get(options, "functions").
  7. Let functions be ? GetMessageFunctions(userFunctions).
  8. Set messageFormat.[[MessageData]] to msgData.
  9. Set messageFormat.[[RequestedLocales]] to requestedLocales.
  10. Set messageFormat.[[LocaleMatcher]] to matcher.
  11. Set messageFormat.[[Functions]] to functions.
  12. Return messageFormat.

1.2 Properties of the Intl.MessageFormat Constructor

The Intl.MessageFormat constructor has the following properties:

1.2.1 Intl.MessageFormat.prototype

The value of Intl.MessageFormat.prototype is %MessageFormat.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

1.2.2 Internal slots

Note
Unlike other Intl formatters, MessageFormat does not have a single list of locales that it supports, as it calls other formatters as necessary.

1.3 Properties of the Intl.MessageFormat Prototype Object

The Intl.MessageFormat prototype object is itself an ordinary object. %MessageFormat.prototype% is not an Intl.MessageFormat instance and does not have an [[InitializedMessageFormat]] internal slot or any of the other internal slots of Intl.MessageFormat instance objects.

1.3.1 Intl.MessageFormat.prototype.constructor

The initial value of Intl.MessageFormat.prototype.constructor is %MessageFormat%.

1.3.2 Intl.MessageFormat.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Intl.MessageFormat".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

1.3.3 Intl.MessageFormat.prototype.format ( [ values [ , onError ] ] )

When the format method is called with the optional arguments values and onError, the following steps are taken:

  1. Let mf be the this value.
  2. Perform ? RequireInternalSlot(mf, [[InitializedMessageFormat]]).
  3. Let ctx be ? CreateMessageFormatContext(mf, values, onError).
  4. Let msg be ? ResolveMessage(ctx).
  5. Let result be an empty String.
  6. For each element el of msg, do
    1. If Type(el) is String, then
      1. Let stringValue be el.
    2. Else if Type(el) is Object and el has a [[MessageValue]] internal slot, then
      1. Let mv be el.[[MessageValue]].
      2. Assert: Type(mv) is Object.
      3. Let toString be ? Get(mv, "toString").
      4. Let toStringResult be Completion(Call(toString, mv)).
      5. If toStringResult is a normal completion, then
        1. Let stringValue be toStringResult.[[Value]].
      6. Else,
        1. Perform ? HandleMessageFormatError(ctx, toStringResult).
        2. Let source be MessageValueSource(mv).
        3. Let stringValue be MessageFallbackString(source).
    3. Set result to the string-concatenation of result and stringValue.
  7. Return result.

1.3.4 Intl.MessageFormat.prototype.formatToParts ( [ values [ , onError ] ] )

When the formatToParts method is called with the optional arguments values and onError, the following steps are taken:

  1. Let mf be the this value.
  2. Perform ? RequireInternalSlot(mf, [[InitializedMessageFormat]]).
  3. Let ctx be ? CreateMessageFormatContext(mf, values, onError).
  4. Let msg be ? ResolveMessage(ctx).
  5. Let result be a new empty List.
  6. For each element mv of msg, do
    1. If Type(mv) is String, then
      1. Let textPart be OrdinaryObjectCreate(%Object.prototype%).
      2. Perform ! CreateDataPropertyOrThrow(textPart, "type", "text").
      3. Perform ! CreateDataPropertyOrThrow(textPart, "value", el).
      4. Append textPart to result.
    2. Else if Type(el) is Object and el has a [[MessageMarkup]] internal slot, then
      1. Let markup be ? FormatMarkupPart(ctx, el.[[MessageMarkup]]).
      2. Append markup to result
    3. Else,
      1. Assert: el has a [[MessageValue]] internal slot.
      2. Let mv be el.[[MessageValue]].
      3. Assert: Type(mv) is Object.
      4. Let toParts be ? Get(mv, "toParts").
      5. Let partResult be Completion(Call(toParts, mv)).
      6. If partResult is a normal completion, then
        1. Let parts be partResult.[[Value]].
        2. For each element part of parts, append part to result.
      7. Else,
        1. Perform ? HandleMessageFormatError(ctx, partResult).
        2. Let source be MessageValueSource(mv).
        3. Let fallbackPart be MessageFallbackPart(source).
        4. Append fallbackPart to result.
  7. Return CreateArrayFromList(result).

1.3.5 Intl.MessageFormat.prototype.resolvedOptions ( )

This function provides access to the locale and options computed during initialization of the object.

  1. Let mf be the this value.
  2. Perform ? RequireInternalSlot(mf, [[InitializedMessageFormat]]).
  3. Let options be OrdinaryObjectCreate(%Object.prototype%).
  4. For each row of Table 1, except the header row, in table order, do
    1. Let p be the Property value of the current row.
    2. Let v be the value of mf's internal slot whose name is the Internal Slot value of the current row.
    3. If v is not undefined, then
      1. Perform ! CreateDataPropertyOrThrow(options, p, v).
  5. Return options.
Table 1: Resolved Options of MessageFormat Instances
Internal Slot Property
[[Functions]] "functions"
[[LocaleMatcher]] "localeMatcher"

1.4 Properties of Intl.MessageFormat Instances

Intl.MessageFormat instances are ordinary objects that inherit properties from %MessageFormat.prototype%.

Intl.MessageFormat instances have an [[InitializedMessageFormat]] internal slot.

Intl.MessageFormat instances also have several internal slots that are computed by the constructor:

  • [[LocaleMatcher]] is one of the String values "lookup" or "best fit", identifying the locale matcher used.
  • [[MessageData]] is an Object conforming to the JSON Schema definition of the Unicode MessageFormat 2.0 specification.
  • [[RequestedLocales]] is a List of String values with the canonicalized language tags of the requested locales to use for message formatting.
  • [[Functions]] is an Object with function object values.

1.5 Abstract Operations for MessageFormat Objects

1.5.1 GetMessageData ( source )

The implementation-defined abstract operation GetMessageData takes argument source (a String or an Object) and returns an Object conforming to the JSON Schema definition of a message according to the Unicode MessageFormat 2.0 specification.

If source is a String, it returns the message data representation corresponding to the input source according to the Unicode MessageFormat 2.0 syntax. If source is an Object, it checks that source holds a valid message data representation, and returns an equivalent Object that is not affected by any further changes to source.

If source contains a syntax or data model error, this operation throws a SyntaxError.

1.5.2 HandleDateTimeInput ( input, opts )

The abstract operation HandleDateTimeInput takes arguments input (an ECMAScript value) and opts (an ECMAScript value) and returns a Date object. It accepts an input that could be a Date object, a number or a string and converts them into Date objects. It performs the following steps when called:

  1. If InstanceOfOperator(input, %Date%) is true, then
    1. If HasProperty(input, "options") is true, then
      1. Perform ? Call(Object.assign, undefined, « opts, Get(input, "options") »).
    2. Return input.
  2. If Type(input) is Object, then
    1. Let valueOf be ? Get(input, "valueOf").
    2. If IsCallable(valueOf) is true, let value be Call(valueOf, input).
    3. Else throw a TypeError exception.
    4. If HasProperty(input, "options") is true, then
      1. Perform ? Call(Object.assign, undefined, « opts, Get(input, "options") »).
  3. Else,
    1. Let value be input.
  4. If Type(value) is Number or String, then
    1. Return ? Construct(%Date%, « value »).
  5. If InstanceOfOperator(value, %Date%) is false, throw a TypeError exception.
  6. Return value.

1.5.3 DateTimeMessageValue ( value: a Date object, opts: an Object, funcCtx: an Object, ): an ECMAScript value

  1. Let locale be ! Get(funcCtx, "locale").
  2. Let source be ! Get(funcCtx, "source").
  3. Let dateTimeFormat be ? Construct(%Intl.DateTimeFormat%, « locale, opts »).
  4. Let toPartsClosure be a new Abstract Closure with no parameters that captures value, source, and dateTimeFormat and performs the following steps when called:
    1. Let parts be ? Call(Intl.DateTimeFormat.prototype.formatToParts, dateTimeFormat, « value »).
    2. Let result be OrdinaryObjectCreate(%Object.prototype%).
    3. Perform ! CreateDataPropertyOrThrow(result, "type", "datetime").
    4. Perform ! CreateDataPropertyOrThrow(result, "source", source).
    5. Perform ! CreateDataPropertyOrThrow(result, "locale", dateTimeFormat.[[Locale]]).
    6. Perform ! CreateDataPropertyOrThrow(result, "parts", parts).
    7. Return CreateArrayFromList(« result »).
  5. Let toParts be CreateBuiltinFunction(toPartsClosure, 0, "toParts", « »).
  6. Let toStringClosure be a new Abstract Closure with no parameters that captures value and dateTimeFormat and performs the following steps when called:
    1. Return ? Call(Intl.DateTimeFormat.prototype.format, dateTimeFormat, « value »).
  7. Let toString be CreateBuiltinFunction(toStringClosure, 0, "toString", « »).
  8. Let valueOfClosure be a new Abstract Closure with no parameters that captures value and performs the following steps when called:
    1. Return value.
  9. Let valueOf be CreateBuiltinFunction(valueOfClosure, 0, "valueOf", « »).
  10. Let mv be OrdinaryObjectCreate(%Object.prototype%).
  11. Perform ! CreateDataPropertyOrThrow(mv, "type", "datetime").
  12. Perform ! CreateDataPropertyOrThrow(mv, "source", source).
  13. Perform ! CreateDataPropertyOrThrow(mv, "locale", dateTimeFormat.[[Locale]]).
  14. Perform ! CreateDataPropertyOrThrow(mv, "options", opts).
  15. Perform ! CreateDataPropertyOrThrow(mv, "toParts", toParts).
  16. Perform ! CreateDataPropertyOrThrow(mv, "toString", toString).
  17. Perform ! CreateDataPropertyOrThrow(mv, "valueOf", valueOf).
  18. Return mv.

1.5.4 GetMessageFunctions ( userFunctions )

The abstract operation GetMessageFunctions takes argument userFunctions (an Object or undefined) and returns an Object. It determines the functions available during message formatting. It performs the following steps when called:

  1. Let numberSteps be the algorithm steps defined in 1.5.4.1.
  2. Let number be CreateBuiltinFunction(numberSteps, 3, "number", « »).
  3. Let stringSteps be the algorithm steps defined in 1.5.4.2.
  4. Let string be CreateBuiltinFunction(stringSteps, 3, "string", « »).
  5. Let dateTimeSteps be the algorithm steps defined in 1.5.4.3.
  6. Let dateTime be CreateBuiltinFunction(dateTimeSteps, 3, "datetime", « »).
  7. Let dateSteps be the algorithm steps defined in 1.5.4.4.
  8. Let date be CreateBuiltinFunction(dateSteps, 3, "date", « »).
  9. Let timeSteps be the algorithm steps defined in 1.5.4.5.
  10. Let time be CreateBuiltinFunction(timeSteps, 3, "time", « »).
  11. Let functions be OrdinaryObjectCreate(%Object.prototype%).
  12. Perform ! CreateDataPropertyOrThrow(functions, "number", number).
  13. Perform ! CreateDataPropertyOrThrow(functions, "string", string).
  14. Perform ! CreateDataPropertyOrThrow(functions, "datetime", dateTime).
  15. Perform ! CreateDataPropertyOrThrow(functions, "date", date).
  16. Perform ! CreateDataPropertyOrThrow(functions, "time", time).
  17. For each String name of ? EnumerableOwnProperties(userFunctions, key),
    1. Let func be ? Get(userFunctions, name).
    2. If IsCallable(func) is true, then
      1. Perform ! CreateDataPropertyOrThrow(functions, name, func).
    3. Else,
      1. Throw a TypeError exception.
  18. Return functions.

1.5.4.1 MessageFormat Number Functions

A MessageFormat number function is an anonymous built-in function.

When a MessageFormat number function is called with arguments funcCtx (an Object), options (an Object), and input (an ECMAScript language value), the following steps are taken:

  1. Let locale be ! Get(funcCtx, "locale").
  2. Let localeMatcher be ! Get(funcCtx, "localeMatcher").
  3. Let source be ! Get(funcCtx, "source").
  4. Let opts be OrdinaryObjectCreate(%Object.prototype%).
  5. Perform ! CreateDataPropertyOrThrow(opt, "localeMatcher", localeMatcher).
  6. If Type(input) is Object, then
    1. Let valueOf be ? Get(input, "valueOf").
    2. If IsCallable(valueOf) is true, then
      1. Let inputOptions be ? Get(input, "options").
      2. Perform ? Call(Object.assign, undefined, « opts, inputOptions »).
      3. Set input to ? Call(valueOf, input).
  7. If Type(input) is String, then
    1. Set input to ? Call(JSON.parse, %JSON%, « input »).
  8. If Type(input) is not Number or BigInt, throw a TypeError exception.
  9. Let numberOptions be « "minimumIntegerDigits", "minimumFractionDigits", "maximumFractionDigits", "minimumSignificantDigits", "maximumSignificantDigits", "roundingIncrement" ».
  10. Let booleanOptions be « "useGrouping" ».
  11. Let select be "cardinal".
  12. For each String optName of ? EnumerableOwnProperties(options, key),
    1. If optName is not "localeMatcher" and optName is not "type", then
      1. Let optValue be ? Get(options, optName).
      2. If Type(optValue) is Object, then
        1. Let optValueOf be ? Get(optValue, "valueOf").
        2. If IsCallable(optValueOf) is true, then
          1. Set optValue to ? Call(optValueOf, optValue).
      3. If optName is "select", then
        1. If optValue is "ordinal" or optValue is "exact", then
          1. Set select to optValue
        2. Else if optValue is not "plural", then
          1. Throw a RangeError exception.
      4. Else,
        1. If Type(optValue) is String, then
          1. If numberOptions contains optName, then
            1. Set optValue to ToNumber(optValue).
          2. Else if booleanOptions contains optName, then
            1. If optValue is "true", then
              1. Set optValue to true.
            2. Else if optValue is "false", then
              1. Set optValue to false.
        2. Perform ? Set(opts, optName, optValue, true).
  13. Let numberFormat be ? Construct(%Intl.NumberFormat%, « locale, opts »).
  14. If select is "exact", then
    1. Perform ? opts.[[Delete]]("type").
    2. Let pluralRules be undefined.
  15. Else,
    1. Perform ? Set(opts, "type", select, true).
    2. Let pluralRules be ? Construct(%Intl.PluralRules%, « locale, opts »).
  16. Let selectKeyClosure be a new Abstract Closure with parameters (keys) that captures input and pluralRules and performs the following steps when called:
    1. Let keyList be ? CreateListFromArrayLike(keys, « String »).
    2. Let str be ? ToString(input).
    3. If keyList contains str, return str.
    4. If pluralRules is not undefined, then
      1. Let category be ? Call(Intl.PluralRules.prototype.select, pluralRules, « input »).
      2. If keyList contains category, return category.
    5. Return null.
  17. Let selectKey be CreateBuiltinFunction(selectKeyClosure, 1, "selectKey", « »).
  18. Let toPartsClosure be a new Abstract Closure with no parameters that captures input, source, and numberFormat and performs the following steps when called:
    1. Let parts be ? Call(Intl.NumberFormat.prototype.formatToParts, numberFormat, « input »).
    2. Let result be OrdinaryObjectCreate(%Object.prototype%).
    3. Perform ! CreateDataPropertyOrThrow(result, "type", "number").
    4. Perform ! CreateDataPropertyOrThrow(result, "source", source).
    5. Perform ! CreateDataPropertyOrThrow(result, "locale", numberFormat.[[Locale]]).
    6. Perform ! CreateDataPropertyOrThrow(result, "parts", parts).
    7. Return CreateArrayFromList(« result »).
  19. Let toParts be CreateBuiltinFunction(toPartsClosure, 0, "toParts", « »).
  20. Let toStringClosure be a new Abstract Closure with no parameters that captures input and numberFormat and performs the following steps when called:
    1. Return ? Call(Intl.NumberFormat.prototype.format, numberFormat, « input »).
  21. Let toString be CreateBuiltinFunction(toStringClosure, 0, "toString", « »).
  22. Let valueOfClosure be a new Abstract Closure with no parameters that captures input and performs the following steps when called:
    1. Return input.
  23. Let valueOf be CreateBuiltinFunction(valueOfClosure, 0, "valueOf", « »).
  24. Let mv be OrdinaryObjectCreate(%Object.prototype%).
  25. Perform ! CreateDataPropertyOrThrow(mv, "type", "number").
  26. Perform ! CreateDataPropertyOrThrow(mv, "source", source).
  27. Perform ! CreateDataPropertyOrThrow(mv, "locale", numberFormat.[[Locale]]).
  28. Perform ! CreateDataPropertyOrThrow(mv, "options", opts).
  29. Perform ! CreateDataPropertyOrThrow(mv, "selectKey", selectKey).
  30. Perform ! CreateDataPropertyOrThrow(mv, "toParts", toParts).
  31. Perform ! CreateDataPropertyOrThrow(mv, "toString", toString).
  32. Perform ! CreateDataPropertyOrThrow(mv, "valueOf", valueOf).
  33. Return mv.

The "length" property of a MessageFormat number function is 3.

1.5.4.2 MessageFormat String Functions

A MessageFormat string function is an anonymous built-in function.

When a MessageFormat string function is called with arguments funcCtx (an Object), options (an Object), and input (an ECMAScript language value), the following steps are taken:

  1. Let str be ? ToString(input).
  2. Let selectKeyClosure be a new Abstract Closure with parameters (keys) that captures str and performs the following steps when called:
    1. Let keyList be ? CreateListFromArrayLike(keys, « String »).
    2. If keyList contains str, return str.
    3. Else, return null.
  3. Let selectKey be CreateBuiltinFunction(selectKeyClosure, 1, "selectKey", « »).
  4. Let toPartsClosure be a new Abstract Closure with no parameters that captures funcCtx and str and performs the following steps when called:
    1. Let source be ! Get(funcCtx, "source").
    2. Let locale be ! Get(funcCtx, "locale").
    3. Let locale0 be ! Get(locale, "0").
    4. Let result be OrdinaryObjectCreate(%Object.prototype%).
    5. Perform ! CreateDataPropertyOrThrow(result, "type", "string").
    6. Perform ! CreateDataPropertyOrThrow(result, "source", source).
    7. Perform ! CreateDataPropertyOrThrow(result, "locale", locale0).
    8. Perform ! CreateDataPropertyOrThrow(result, "value", str).
    9. Return CreateArrayFromList(« result »).
  5. Let toParts be CreateBuiltinFunction(toPartsClosure, 0, "toParts", « »).
  6. Let toStringClosure be a new Abstract Closure with no parameters that captures str and performs the following steps when called:
    1. Return str.
  7. Let toString be CreateBuiltinFunction(toStringClosure, 0, "toString", « »).
  8. Let valueOf be CreateBuiltinFunction(toStringClosure, 0, "valueOf", « »).
  9. Let mv be OrdinaryObjectCreate(%Object.prototype%).
  10. Perform ! CreateDataPropertyOrThrow(mv, "type", "number").
  11. Perform ! CreateDataPropertyOrThrow(mv, "source", source).
  12. Perform ! CreateDataPropertyOrThrow(mv, "locale", numberFormat.[[Locale]]).
  13. Perform ! CreateDataPropertyOrThrow(mv, "options", opts).
  14. Perform ! CreateDataPropertyOrThrow(mv, "selectKey", selectKey).
  15. Perform ! CreateDataPropertyOrThrow(mv, "toParts", toParts).
  16. Perform ! CreateDataPropertyOrThrow(mv, "toString", toString).
  17. Perform ! CreateDataPropertyOrThrow(mv, "valueOf", valueOf).
  18. Return mv.

The "length" property of a MessageFormat string function is 3.

1.5.4.3 MessageFormat DateTime Functions

A MessageFormat dateTime function is an anonymous built-in function.

When a MessageFormat dateTime function is called with arguments funcCtx (an Object), options (an Object), and input (an ECMAScript language value), the following steps are taken:

  1. Let opts be OrdinaryObjectCreate(%Object.prototype%).
  2. Let localeMatcher be ! Get(funcCtx, "localeMatcher").
  3. Perform ! CreateDataPropertyOrThrow(opts, "localeMatcher", localeMatcher).
  4. Let value be ? HandleDateTimeInput(input, opts).
  5. For each String optName of ? EnumerableOwnProperties(options, key),
    1. If optName is not "locale", then
      1. Let optValue be ? Get(options, optName).
      2. If Type(optValue) is Object, then
        1. Let optValueOf be ? Get(optValue, "valueOf").
        2. If IsCallable(optValueOf) is true, then
          1. Set optValue_ to ? Call(optValueOf, optValue).
      3. If optName is "fractionalSecondDigits", set optValue to ToNumber(optValue).
      4. Else if optName is "hour12", then
        1. If optValue is "true", then
          1. Set optValue to true.
        2. Else if optValue is "false", then
          1. Set optValue to false.
      5. Else, set optValue to ToString(optValue).
      6. Perform ? Set(opts, optName, optValue, "true").
  6. Return ? DateTimeMessageValue(value, opts, funcCtx).

The "length" property of a MessageFormat dateTime function is 3.

1.5.4.4 MessageFormat Date Functions

A MessageFormat date function is an anonymous built-in function.

When a MessageFormat date function is called with arguments funcCtx (an Object), options (an Object), and input (an ECMAScript language value), the following steps are taken:

  1. Let opts be OrdinaryObjectCreate(%Object.prototype%).
  2. Let localeMatcher be ! Get(funcCtx, "localeMatcher").
  3. Perform ! CreateDataPropertyOrThrow(opts, "localeMatcher", localeMatcher).
  4. Let value be ? HandleDateTimeInput(input, opts).
  5. Let dateStyle be ! Get(options, "style").
  6. If dateStyle is null or undefined, then
    1. Set dateStyle to ! Get(opts, "dateStyle").
    2. If dateStyle is null or undefined, then
      1. Set dateStyle to "short".
  7. For each String optName of ? EnumerableOwnProperties(opts, key),
    1. If optName is not "calendar", "localeMatcher", "hour12", "hourCycle", "numberingSystem", or "timeZone", then
      1. Perform ? DeletePropertyOrThrow(opts, optName).
  8. Perform ? Set(opts, "dateStyle", ToString(dateStyle)).
  9. Return ? DateTimeMessageValue(value, opts, funcCtx).

The "length" property of a MessageFormat date function is 3.

1.5.4.5 MessageFormat Time Functions

A MessageFormat time function is an anonymous built-in function.

When a MessageFormat time function is called with arguments funcCtx (an Object), options (an Object), and input (an ECMAScript language value), the following steps are taken:

  1. Let opts be OrdinaryObjectCreate(%Object.prototype%).
  2. Let localeMatcher be ! Get(funcCtx, "localeMatcher").
  3. Perform ! CreateDataPropertyOrThrow(opts, "localeMatcher", localeMatcher).
  4. Let value be ? HandleDateTimeInput(input, opts).
  5. Let timeStyle be ! Get(options, "style").
  6. If timeStyle is null or undefined, then
    1. Set timeStyle to ! Get(opts, "timeStyle").
    2. If timeStyle is null or undefined, then
      1. Set timeStyle to "short".
  7. For each String optName of ? EnumerableOwnProperties(opts, key),
    1. If optName is not "calendar", "localeMatcher", "hour12", "hourCycle", "numberingSystem", or "timeZone", then
      1. Perform ? DeletePropertyOrThrow(opts, optName).
  8. Perform ? Set(opts, "timeStyle", ToString(timeStyle)).
  9. Return ? DateTimeMessageValue(value, opts, funcCtx).

The "length" property of a MessageFormat time function is 3.

1.5.5 CreateMessageFormatContext ( mf, values, onError )

The abstract operation CreateMessageFormatContext takes arguments mf (an Object), values (an Object or undefined), and onError (a Function or undefined) and returns a MessageFormatContext Record. It initializes the MessageFormatContext Record used for pattern selection and formatting. It performs the following steps when called:

  1. Let localVars be OrdinaryObjectCreate(null).
  2. Let msgData be mf.[[MessageData]].
  3. Let declArray be ? Get(msgData, "declarations").
  4. Let declList be ? CreateListFromArrayLike(declArray).
  5. For each element decl of declList,
    1. Let declName be ? Get(decl, "name").
    2. Let declValue be OrdinaryObjectCreate(null, « [[UnresolvedDeclaration]] »).
    3. Set declValue.[[UnresolvedDeclaration]] to decl.
    4. Perform ? Set(localVars, declName, declValue, true).
  6. Let ctx be a new Record.
  7. Set ctx.[[LocalVariables]] to localVars.
  8. Set ctx.[[MessageFormat]] to mf.
  9. Set ctx.[[OnError]] to onError.
  10. Set ctx.[[Values]] to ? GetOptionsObject(values).
  11. Return ctx.

1.5.5.1 MessageFormatContext Records

A MessageFormatContext Record is used to hold the data required during the formatting of a message. It has the fields defined in Table 2.

Table 2: Record returned by CreateMessageContext
Field Name Value Type Description
[[LocalVariables]] Object Cache for local variables, which may be resolved during the formatting. The values in the cache are Objects, each of which will have either [[MessageValue]], [[ResolvedValue]], or [[UnresolvedDeclaration]] internal slots.
[[MessageFormat]] Intl.MessageFormat The MessageFormat instance on which the formatting is taking place.
[[OnError]] Function object or undefined. The onError argument of the formatter call.
[[Values]] Object The values argument of the formatter call.

1.5.6 ResolveMessage ( ctx )

The abstract operation ResolveMessage takes argument ctx (a MessageFormatContext Record) and returns a List of Strings and Objects. It resolves a message into a List of Strings and Objects with either [[MessageMarkup]] or [[MessageValue]] internal slots. It performs the following steps when called:

  1. Let result be an empty List.
  2. Let pattern be ? SelectPattern(ctx).
  3. For each element el of pattern,
    1. If Type(el) is String, then
      1. Append el to result.
    2. Else,
      1. Assert: Type(el) is Object.
      2. Let elType be ? Get(el, "type").
      3. If elType is "markup", then
        1. Let res be OrdinaryObjectCreate(null, « [[MessageMarkup]] »).
        2. Set res.[[MessageMarkup]] to el.
      4. Else,
        1. Assert: elType is "expression".
        2. Let res be ResolveExpression(ctx, el).
      5. Append res to result.
  4. Return result.

1.5.6.1 SelectPattern ( ctx )

The abstract operation SelectPattern takes argument ctx (a MessageFormatContext Record) and returns a List of Strings and Objects with an internal slot [[MessageValue]]. It selects the pattern to format from the message data model. It performs the following steps when called:

  1. Let msgData be ctx.[[MessageFormat]].[[MessageData]].
  2. Let msgType be ? Get(msgData, "type").
  3. If msgType is "message", then
    1. Let pattern be ? Get(msgData, "pattern").
  4. Else,
    1. Assert: msgType is "select".
    2. Let selectorsData be ? Get(msgData, "selectors").
    3. Let selectorExpressions be ? CreateListFromArrayLike(selectorsData, « Object »).
    4. Let selectors be an empty List.
    5. For each element selExp of selectorExpressions,
      1. Let sel be ResolveExpression(ctx, selExp).
      2. Let selectKey be ? Get(sel.[[MessageValue]], "selectKey").
      3. If IsCallable(selectKey) is true, then
        1. Append sel.[[MessageValue]] to selectors.
      4. Else,
        1. Let error be ThrowCompletion(TypeError).
        2. Perform ? HandleMessageFormatError(ctx, error).
        3. Append null to selectors.
    6. Let variantsArray be ? Get(msgData, "variants").
    7. Let variants be ? CreateListFromArrayLike(variantsArray, « Object »).
    8. Let selectedVariant be ? SelectVariant(ctx, selectors, variants).
  5. Return ? CreateListFromArrayLike(pattern, « String, Object »).

1.5.6.2 SelectVariant ( ctx, selectors, variants )

The implementation-defined abstract operation SelectVariant takes arguments ctx (a MessageFormatContext Record), selectors (a List of Object and Null values), and variants (a List of Objects) and returns an Object.

It applies the variant selection method defined by the "Resolve Preferences", "Filter Variants", and "Sort Variants" steps of the Pattern Selection section of the Unicode MessageFormat 2.0 specification.

For the selection, Null values in selectors indicate selectors for which selection will always fail. If any errors are encountered during the selection, the HandleMessageFormatError abstract operation must be called with ctx and an abrupt Completion Record containing an Error.

The value returned by this operation must be an Object matching the JSON Schema definition of a message pattern: https://github.com/unicode-org/message-format-wg/blob/main/spec/data-model/message.json#/$defs/pattern .

1.5.7 ResolveExpression ( ctx, expression )

The abstract operation ResolveExpression takes arguments ctx (a MessageFormatContext Record) and expression (an Object) and returns an Object with an internal slot [[MessageValue]]. It resolves the value of an expression for selection and formatting. It performs the following steps when called:

  1. Let source be ? GetSource(ctx, expression).
  2. Let arg be ? Get(expression, "arg").
  3. If arg is undefined, then
    1. Let resArg be undefined.
  4. Else,
    1. Let resArg be ResolveValue(ctx, arg).
    2. If resArg has a [[MessageFallback]] internal slot, return resArg.
  5. Let annotation be ? Get(expression, "annotation").
  6. If annotation is undefined, then
    1. Assert: resArg is not undefined.
    2. If Type(resArg) is Object and resArg has a [[MessageValue]] internal slot, then
      1. Return resArg.
    3. Else if Type(resArg) is Number or BigInt, then
      1. Set annotation to OrdinaryObjectCreate(null).
      2. Perform ! CreateDataPropertyOrThrow(annotation, "type", "function").
      3. Perform ! CreateDataPropertyOrThrow(annotation, "name", "number").
    4. Else if Type(resArg) is String, then
      1. Set annotation to OrdinaryObjectCreate(null).
      2. Perform ! CreateDataPropertyOrThrow(annotation, "type", "function").
      3. Perform ! CreateDataPropertyOrThrow(annotation, "name", "string").
    5. Else,
      1. Return ResolveUnknown(source, resArg).
  7. If ? Get(annotation, "type") is not "function", then
    1. Let error be ThrowCompletion(ReferenceError).
    2. Perform ? HandleMessageFormatError(ctx, error).
    3. Return ResolveFallback(source).
  8. Return ResolveFunction(ctx, source, resArg, annotation).

1.5.7.1 ResolveFunction ( ctx, source, resArg, annotation )

The abstract operation ResolveFunction takes arguments ctx (a MessageFormatContext Record), source (a String), resArg (an Object or undefined), and annotation (an Object) and returns an Object with an internal slot [[MessageValue]]. It resolves the value of an expression with a function annotation. It performs the following steps when called:

  1. Let name be ? Get(annotation, "name").
  2. Let function be ? Get(ctx.[[MessageFormat]].[[Functions]], name).
  3. If IsCallable(function) is false, then
    1. Let error be ThrowCompletion(ReferenceError).
    2. Perform ? HandleMessageFormatError(ctx, error).
    3. Return ResolveFallback(source).
  4. Let funcCtx be OrdinaryObjectCreate(%Object.prototype%).
  5. Let locales be CreateArrayFromList(ctx.[[MessageFormat]].[[RequestedLocales]]).
  6. Perform ! CreateDataPropertyOrThrow(funcCtx, "locale", locales).
  7. Perform ! CreateDataPropertyOrThrow(funcCtx, "localeMatcher", ctx.[[MessageFormat]].[[LocaleMatcher]]).
  8. Perform ! CreateDataPropertyOrThrow(funcCtx, "source", source).
  9. Let options be OrdinaryObjectCreate(%Object.prototype%).
  10. Let optArray be ? Get(annotation, "options").
  11. If optArray is not undefined, then
    1. Let optList be ? CreateListFromArrayLike(optArray).
    2. For each element opt of optList,
      1. Let optName be ? Get(opt, "name").
      2. Let optValue be ? Get(opt, "value").
      3. Let resValue be ResolveValue(ctx, optValue).
      4. If Type(resValue) is Object, then
        1. If resValue has a [[MessageFallback]] internal slot, then
          1. Set resValue to undefined.
        2. Else if resValue has a [[MessageValue]] internal slot, then
          1. Set resValue to resValue.[[MessageValue]].
      5. Perform ? CreateDataPropertyOrThrow(options, optName, resValue).
    3. Perform ! CreateDataPropertyOrThrow(part, "options", resOptions).
  12. Let funcArgs be « funcCtx, options ».
  13. If Type(resArg) is Object and resArg has a [[MessageValue]] internal slot, then
    1. Set resArg to resArg.[[MessageValue]].
  14. If resArg is not undefined, then
    1. Append resArg to funcArgs.
  15. Let funcRes be Completion(Call(function, undefined, funcArgs)).
  16. If funcRes is a normal completion, then
    1. Let mv be funcRes.[[Value]].
    2. If Type(mv) is Object and Type(? Get(mv, "type")) is String and Type(? Get(mv, "source")) is String, then
      1. Let result be OrdinaryObjectCreate(null, « [[MessageValue]] »).
      2. Set result.[[MessageValue]] to mv.
      3. Return result.
    3. Else,
      1. Let error be ThrowCompletion(TypeError).
      2. Perform ? HandleMessageFormatError(ctx, error).
      3. Return ResolveFallback(source).
  17. Else,
    1. Perform ? HandleMessageFormatError(ctx, funcRes).
    2. Return ResolveFallback(source).

1.5.7.2 ResolveUnknown ( source, value )

The abstract operation ResolveUnknown takes arguments source (a String) and value (an ECMAScript language value) and returns an Object with an internal slot [[MessageValue]]. It resolves an unknown value. It performs the following steps when called:

  1. Let toPartsClosure be a new Abstract Closure with no parameters that captures source and value and performs the following steps when called:
    1. Let part be OrdinaryObjectCreate(%Object.prototype%).
    2. Perform ! CreateDataPropertyOrThrow(part, "type", "unknown").
    3. Perform ! CreateDataPropertyOrThrow(part, "source", source).
    4. Perform ! CreateDataPropertyOrThrow(part, "value", value).
    5. Return CreateArrayFromList(« part »).
  2. Let toParts be CreateBuiltinFunction(toPartsClosure, 0, "toParts", « »).
  3. Let toStringClosure be a new Abstract Closure with no parameters that captures value and performs the following steps when called:
    1. Return ? ToString(value).
  4. Let toString be CreateBuiltinFunction(toStringClosure, 0, "toString", « »).
  5. Let valueOfClosure be a new Abstract Closure with no parameters that captures value and performs the following steps when called:
    1. Return value.
  6. Let valueOf be CreateBuiltinFunction(valueOfClosure, 0, "valueOf", « »).
  7. Let mv be OrdinaryObjectCreate(%Object.prototype%).
  8. Perform ! CreateDataPropertyOrThrow(mv, "type", "unknown").
  9. Perform ! CreateDataPropertyOrThrow(mv, "source", source).
  10. Perform ! CreateDataPropertyOrThrow(mv, "locale", "und").
  11. Perform ! CreateDataPropertyOrThrow(mv, "toParts", toParts).
  12. Perform ! CreateDataPropertyOrThrow(mv, "toString", toString).
  13. Perform ! CreateDataPropertyOrThrow(mv, "valueOf", valueOf).
  14. Let unknown be OrdinaryObjectCreate(null, « [[MessageValue]] »).
  15. Set unknown.[[MessageValue]] to mv.
  16. Return unknown.

1.5.8 FormatMarkupPart ( ctx, markup )

The abstract operation FormatMarkupPart takes arguments ctx (a MessageFormatContext Record) and markup (an Object) and returns an Object. It resolves the formatted part value of a markup placeholder. It performs the following steps when called:

  1. Let kind be ? Get(markup, "kind").
  2. Let name be ? Get(markup, "name").
  3. Let options be ? Get(markup, "options").
  4. Let part be OrdinaryObjectCreate(%Object.prototype%).
  5. Perform ! CreateDataPropertyOrThrow(part, "type", "markup").
  6. Perform ! CreateDataPropertyOrThrow(part, "kind", kind).
  7. Perform ! CreateDataPropertyOrThrow(part, "name", name).
  8. If kind is not "close" and options is not undefined, then
    1. Let len be ? LengthOfArrayLike(options).
    2. If len > 0, then
      1. Let opts be ? CreateListFromArrayLike(options).
      2. Let resOptions be OrdinaryObjectCreate(%Object.prototype%).
      3. For each element opt of opts,
        1. Let optName be ? Get(opt, "name").
        2. Let optValue be ? Get(opt, "value").
        3. Let resValue be ResolveValue(ctx, optValue).
        4. If Type(resValue) is Object, then
          1. If resValue has a [[MessageFallback]] internal slot, then
            1. Set resValue to undefined.
          2. Else,
            1. Let valueOf be ? Get(resValue, "valueOf").
            2. If IsCallable(valueOf) is true, then
              1. Let valueOfResult be Completion(Call(valueOf, resValue)).
              2. If valueOfResult is a normal completion, then
                1. Set resValue to valueOfResult.[[Value]].
              3. Else,
                1. Perform ? HandleMessageFormatError(ctx, valueOfResult).
                2. Set resValue to undefined.
        5. Perform ! CreateDataPropertyOrThrow(resOptions, optName, resValue).
      4. Perform ! CreateDataPropertyOrThrow(part, "options", resOptions).
  9. Return CreateArrayFromList(« part »).

1.5.9 GetSource ( ctx, value )

The abstract operation GetSource takes arguments ctx (a MessageFormatContext Record) and value (an Object) and returns a String. Determines the "source" value for a data model Object. It performs the following steps when called:

  1. Let type be ? Get(value, "type").
  2. If type is "literal", then
    1. Let strValue be ? Get(value, "value").
    2. Modify strValue such that all "\" characters are replaced with "\".
    3. Modify strValue such that all "|" characters are replaced with "|".
    4. Return the string-concatenation of "|", strValue, and "|".
  3. If type is "variable", then
    1. Let name be ? Get(value, "name").
    2. Let local be ! Get(ctx.[[LocalVariables]], name).
    3. If Type(local) is Object, then
      1. If local has an [[UnresolvedDeclaration]] internal slot, then
        1. Let decl be local.[[UnresolvedDeclaration]].
        2. If ? Get(decl, "type") is "local", then
          1. Let declValue be ? Get(decl, "value").
          2. Return ? GetSource(ctx, declValue).
      2. Else if local has a [[MessageValue]] internal slot, then
        1. Return MessageValueSource(local.[[MessageValue]]).
      3. Else,
        1. Assert: local has a [[ResolvedName]] internal slot.
        2. Assert: local has a [[ResolvedValue]] internal slot.
        3. Set name to local.[[ResolvedName]].
    4. Return the string-concatenation of "$" and name.
  4. If type is "markup", then
    1. Let kind be ? Get(value, "kind").
    2. Let name be ? Get(value, "name").
    3. If kind is "open", return the string-concatenation of "#" and name.
    4. If kind is "standalone", return the string-concatenation of "#", name, and "/".
    5. If kind is "close", return the string-concatenation of "/" and name.
  5. If type is "function", then
    1. Let name be ? Get(value, "name").
    2. Return the string-concatenation of ":" and name.
  6. If type is "unsupported-annotation", then
    1. Return ? Get(value, "sigil").
  7. If type is "expression", then
    1. Let arg be ? Get(value, "arg").
    2. If arg is not undefined, return ? GetSource(ctx, arg).
    3. Let annotation be ? Get(value, "annotation").
    4. If annotation is not undefined, return ? GetSource(ctx, annotation).
  8. Return "\uFFFD".

1.5.9.1 MessageValueSource ( mv )

The abstract operation MessageValueSource takes argument mv (an Object) and returns a String. It gets the source string representation of a resolved message value, which should be always available. On any error, it returns the Unicode replacement character � instead. It performs the following steps when called:

  1. Let source be Completion(Get(mv, "source")).
  2. If source is a normal completion, then
    1. Let str be source.[[Value]].
    2. If Type(str) is String, then
      1. Return str.
  3. Return "\uFFFD".

1.5.10 HandleMessageFormatError ( ctx, completionRecord )

The abstract operation HandleMessageFormatError takes arguments ctx (a MessageFormatContext Record) and completionRecord (a Completion Record). It handles errors during formatting. It performs the following steps when called:

  1. Assert: completionRecord is a Completion Record.
  2. Assert: completionRecord is an abrupt completion.
  3. Let onError be ctx.[[OnError]].
  4. Let error be completionRecord.[[Value]].
  5. If onError is not undefined, then
    1. Perform ? Call(onError, undefined, « error »).
  6. Else if an appropriate notification mechanism exists, then
    1. Issue a warning for error.

1.5.11 ResolveFallback ( source )

The abstract operation ResolveFallback takes argument source (a String) and returns an Object with internal slots [[MessageFallback]] and [[MessageValue]]. It resolves a fallback value. It performs the following steps when called:

  1. Let toPartsClosure be a new Abstract Closure with no parameters that captures source and performs the following steps when called:
    1. Let part be MessageFallbackPart(source).
    2. Return CreateArrayFromList(« part »).
  2. Let toParts be CreateBuiltinFunction(toPartsClosure, 0, "toParts", « »).
  3. Let toStringClosure be a new Abstract Closure with no parameters that captures source and performs the following steps when called:
    1. Return MessageFallbackString(source).
  4. Let toString be CreateBuiltinFunction(toStringClosure, 0, "toString", « »).
  5. Let mv be OrdinaryObjectCreate(%Object.prototype%).
  6. Perform ! CreateDataPropertyOrThrow(mv, "source", source).
  7. Perform ! CreateDataPropertyOrThrow(mv, "toParts", toParts).
  8. Perform ! CreateDataPropertyOrThrow(mv, "toString", toString).
  9. Let fallback be OrdinaryObjectCreate(null, « [[MessageFallback]], [[MessageValue]] »).
  10. Set fallback.[[MessageValue]] to mv.
  11. Return fallback.

1.5.11.1 MessageFallbackPart ( source )

The abstract operation MessageFallbackPart takes argument source (a String) and returns an Object. It gets the fallback formatted part representation. It performs the following steps when called:

  1. Let result be OrdinaryObjectCreate(%Object.prototype%).
  2. Perform ! CreateDataPropertyOrThrow(result, "type", "fallback").
  3. Perform ! CreateDataPropertyOrThrow(result, "source", source).
  4. Return result.

1.5.11.2 MessageFallbackString ( source )

The abstract operation MessageFallbackString takes argument source (a String) and returns a String. It gets the fallback formatted string representation. It performs the following steps when called:

  1. Return the string-concatenation of "{", source, and "}".

1.5.12 ResolveValue ( ctx, value )

The abstract operation ResolveValue takes arguments ctx (a MessageFormatContext Record) and value (an Object) and returns an ECMAScript language value. It resolves the value of a literal or variable reference. For literals, the returned value is always a String. For variable references, the returned value may be any ECMAScript language value. For unresolved variable references, the returned value is an Object with an internal slot [[MessageFallback]]. It performs the following steps when called:

  1. Let type be ? Get(value, "type").
  2. If type is "literal", then
    1. Return ? Get(value, "value").
  3. Assert: type is "variable".
  4. Let name be ? Get(value, "name").
  5. Let localVars be ctx.[[LocalVariables]].
  6. Let var be ! Get(localVars, name).
  7. If var is undefined, then
    1. Set var to ? Get(ctx.[[Values]], name).
    2. If var is undefined, then
      1. Let error be ThrowCompletion(ReferenceError).
      2. Perform ? HandleMessageFormatError(ctx, error).
      3. Let source be ? GetSource(value).
      4. Set var to ResolveFallback(source).
      5. Perform ! Set(localVars, name, var).
    3. Else,
      1. Let resolved be OrdinaryObjectCreate(null, « [[ResolvedName]], [[ResolvedValue]] »).
      2. Set resolved.[[ResolvedName]] to name.
      3. Set resolved.[[ResolvedValue]] to var.
      4. Perform ! Set(localVars, name, resolved).
  8. Else,
    1. Assert: Type(var) is Object.
    2. If var has a [[ResolvedValue]] internal slot, then
      1. Set var to var.[[ResolvedValue]].
    3. Else if var has an [[UnresolvedDeclaration]] internal slot, then
      1. Let decl be var.[[UnresolvedDeclaration]].
      2. Let declType be ? Get(decl, "type").
      3. If declType is "input", then
        1. Let expression be ? Get(decl, "value").
        2. Perform ! Set(localVars, name, undefined).
        3. Set var to ? ResolveExpression(ctx, expression).
      4. Else if declType is "local", then
        1. Let expression be ? Get(decl, "value").
        2. Set var to ? ResolveExpression(ctx, expression).
      5. Else,
        1. Let error be ThrowCompletion(ReferenceError).
        2. Perform ? HandleMessageFormatError(ctx, error).
        3. Let source be ? GetSource(value).
        4. Set var to ResolveFallback(source).
      6. Perform ! Set(localVars, name, var).
  9. Return var.

A Copyright & Software License

Copyright Notice

© 2024 Eemeli Aro

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.