diff --git a/spec/formatting.md b/spec/formatting.md index 85ea0288d1..c8179ef12d 100644 --- a/spec/formatting.md +++ b/spec/formatting.md @@ -197,17 +197,28 @@ the following steps are taken: 1. If the _expression_ includes an _operand_, resolve its value. If this fails, use a _fallback value_ for the _expression_. -2. Based on the _function_ starting sigil and _name_, - find the appropriate function implementation from the _function registry_. - If the registry does not define an implementation for this _name_, +2. Resolve the _identifier_ of the _function_ and, based on the starting sigil, + find the appropriate function implementation to call. + If the implementation cannot find the function, + or if the _identifier_ includes a _namespace_ that the implementation does not support, emit an Unknown Function error and use a _fallback value_ for the _expression_. -3. Resolve the _option_ values to a mapping of string identifiers to values. + + Implementations are not required to implement _namespaces_ or installable + _function registries_. + +3. Resolve the _options_ to a mapping of string identifiers to values. + If _options_ is missing, the mapping will be empty. For each _option_: - - If its right-hand side successfully resolves to a value, - bind the _name_ of the _option_ to the resolved value in the mapping. - - Otherwise, do not bind the _name_ of the _option_ to any value in the mapping. -4. Call the function implementation with the following arguments: + - Resolve the _identifier_ of the _option_. + - If the _option_'s _identifier_ already exists in the resolved mapping of _options_, + emit a Duplicate Option Name error. + - If the _option_'s right-hand side successfully resolves to a value, + bind the _identifier_ of the _option_ to the resolved value in the mapping. + - Otherwise, bind the _identifier_ of the _option_ to an unresolved value in the mapping. + (Note that an Unresolved Variable error will have been emitted.) +4. Remove from the resolved mapping of _options_ any binding for which the value is an unresolved value. +5. Call the function implementation with the following arguments: - The current _locale_. - The resolved mapping of _options_. @@ -219,15 +230,20 @@ the following steps are taken: as long as reasonable precautions are taken to keep the function interface simple and minimal, and avoid introducing potential security vulnerabilities. - As implementations MAY allow custom functions to be defined by users, - their access to the _formatting context_ SHOULD be minimal and read-only, - and their execution time SHOULD be limited. + An implementation MAY define its own functions. + An implementation MAY allow custom functions to be defined by users. + + Function access to the _formatting context_ MUST be minimal and read-only, + and execution time SHOULD be limited. + + Implementation-defined _functions_ SHOULD use an implementation-defined _namespace_. 5. If the call succeeds, resolve the value of the _expression_ as the result of that function call. If the call fails or does not return a valid value, emit a Resolution error and use a _fallback value_ for the _expression_. + ### Fallback Resolution A **_fallback value_** is the resolved value emitted when an _expression_ cannot be resolved. @@ -255,13 +271,13 @@ The _fallback value_ depends on the contents of the _expression_: > Example: `$user` - _expression_ with no _operand_: - the _function_ starting sigil followed by its _name_ + the _function_ starting sigil followed by its _identifier_ > Examples: `:platform`, `+tag`, `-tag` - Otherwise: The U+FFFD REPLACEMENT CHARACTER `�` character -_Option_ names and values are not included in the _fallback value_. +_Option_ identifiers and values are not included in the _fallback value_. When an error occurs in an _expression_ with a _variable_ _operand_ and the _variable_ refers to a local _declaration_, @@ -817,7 +833,7 @@ These are divided into the following categories: > }} > ``` - - A **Duplicate Option Name error** occurs when the same _name_ + - A **Duplicate Option Name error** occurs when the same _identifier_ appears on the left-hand side of more than one _option_ in the same _expression_. diff --git a/spec/message.abnf b/spec/message.abnf index bd340fe9f2..f4b610fe5c 100644 --- a/spec/message.abnf +++ b/spec/message.abnf @@ -23,8 +23,8 @@ annotation = (function *(s option)) / reserved / private-use literal = quoted / unquoted variable = "$" name -function = (":" / "+" / "-") name -option = name [s] "=" [s] (literal / variable) +function = (":" / "+" / "-") identifier +option = identifier [s] "=" [s] (literal / variable) ; reserved keywords are always lowercase input = %s"input" @@ -45,13 +45,10 @@ quoted-char = %x0-5B ; omit \ / %x7D-D7FF ; omit surrogates / %xE000-10FFFF -; based on https://www.w3.org/TR/xml/#NT-Nmtoken, -; but cannot start with U+002D HYPHEN-MINUS or U+003A COLON ":" -unquoted = unquoted-start *name-char +unquoted = unquoted-start *(name-char / ":") unquoted-start = name-start / DIGIT / "." / %xB7 / %x300-36F / %x203F-2040 - ; reserve sigils for private-use by implementations private-use = private-start reserved-body private-start = "^" / "&" @@ -70,15 +67,17 @@ reserved-char = %x00-08 ; omit HTAB and LF / %x7E-D7FF ; omit surrogates / %xE000-10FFFF -; based on https://www.w3.org/TR/xml/#NT-Name, -; but cannot start with U+003A COLON ":" -name = name-start *name-char +; identifier matches https://www.w3.org/TR/REC-xml-names/#NT-QName +; name matches https://www.w3.org/TR/REC-xml-names/#NT-NCName +identifier = [namespace ":"] name +namespace = name +name = name-start *name-char name-start = ALPHA / "_" / %xC0-D6 / %xD8-F6 / %xF8-2FF / %x370-37D / %x37F-1FFF / %x200C-200D / %x2070-218F / %x2C00-2FEF / %x3001-D7FF / %xF900-FDCF / %xFDF0-FFFD / %x10000-EFFFF -name-char = name-start / DIGIT / "-" / "." / ":" +name-char = name-start / DIGIT / "-" / "." / %xB7 / %x300-36F / %x203F-2040 text-escape = backslash ( backslash / "{" / "}" ) diff --git a/spec/syntax.md b/spec/syntax.md index 1b68da8e60..9d2a3f9b94 100644 --- a/spec/syntax.md +++ b/spec/syntax.md @@ -169,7 +169,7 @@ external input value does not appear in a _declaration_. > [!Note] > These restrictions only apply to _declarations_. > A _placeholder_ or _selector_ can apply a different annotation to a _variable_ -> than one applied to the same _variable_ name in a _declaration_. +> than one applied to the same _variable_ named in a _declaration_. > For example, this message is _valid_: > ``` > {{ @@ -482,7 +482,7 @@ and vice versa. > {+button}Submit{-button} or {+link}cancel{-link}. > ``` -A _function_ consists of a prefix sigil followed by a _name_. +A _function_ consists of a prefix sigil followed by an _identifier_. The following sigils are used for _functions_: - `:` for a _standalone_ function @@ -497,8 +497,8 @@ _Options_ are not required. An **_option_** is a key-value pair containing a named argument that is passed to a _function_. -An _option_ has a _name_ and a _value_. -The _name_ is separated from the _value_ by an U+003D EQUALS SIGN `=` along with +An _option_ has an _identifier_ and a _value_. +The _identifier_ is separated from the _value_ by an U+003D EQUALS SIGN `=` along with optional whitespace. The value of an _option_ can be either a _literal_ or a _variable_. @@ -506,7 +506,7 @@ Multiple _options_ are permitted in an _annotation_. Each _option_ is separated by whitespace. ```abnf -option = name [s] "=" [s] (literal / variable) +option = identifier [s] "=" [s] (literal / variable) ``` > Examples of _functions_ with _options_ @@ -672,21 +672,65 @@ unquoted-start = name-start / DIGIT / "." / %xB7 / %x300-36F / %x203F-2040 ``` -### Names +### Names and Identifiers -A **_name_** is an identifier for a _variable_ (prefixed with `$`), +An **_identifier_** is a character sequence that +identifies a _function_ or _option_. +Each _identifier_ consists of a _name_ optionally preceeded by +a _namespace_. +When present, the _namespace_ is separated from the _name_ by a +U+003A COLON `:`. +Built-in _functions_ and their _options_ do not have a _namespace_ identifier. + +_Function_ _identifiers_ are prefixed with `:`, `+`, or `-`. +_Option_ _identifiers_ have no prefix. + +A **_name_** is a character sequence used in an _identifier_ +or as the name for for a _variable_. + +_Variable_ names are prefixed with `$`. for a _function_ (prefixed with `:`, `+` or `-`), -or for an _option_ (these have no prefix). -The namespace for _names_ is based on XML's [Name](https://www.w3.org/TR/xml/#NT-Name), -with the restriction that it MUST NOT start with `:`, -as that would conflict with the _function_ start character. -Otherwise, the set of characters allowed in names is large. + +Valid content for _names_ is based on Namespaces in XML 1.0's +[NCName](https://www.w3.org/TR/xml-names/#NT-NCName). +This is different from XML's [Name](https://www.w3.org/TR/xml/#NT-Name) +in that it MUST NOT contain a U+003A COLON `:`. +Otherwise, the set of characters allowed in a _name_ is large. + +> [!NOTE] +> _External variables_ can be passed in that are not valid _names_. +> Such variables cannot be referenced in a _message_, +> but are not otherwise errors. + +Examples: +> A variable: +>``` +>This has a {$variable} +>``` +>A function: +> ``` +> This has a {:function} +> ``` +> An add-on function from the `icu` namespace: +> ``` +> This has a {:icu:function} +> ``` +> An option and an add-on option: +> ``` +> This has {:options option=value icu:option=add_on} +> ``` + +Support for _namespaces_ and their interpretation is implementation-defined +in this release. ```abnf variable = "$" name -function = (":" / "+" / "-") name +function = (":" / "+" / "-") identifier +option = identifier [s] "=" [s] (literal / variable) -name = name-start *name-char +identifier = [namespace ":"] name +namespace = name +name = name-start *name-char name-start = ALPHA / "_" / %xC0-D6 / %xD8-F6 / %xF8-2FF / %x370-37D / %x37F-1FFF / %x200C-200D @@ -696,11 +740,6 @@ name-char = name-start / DIGIT / "-" / "." / ":" / %xB7 / %x300-36F / %x203F-2040 ``` -> [!NOTE] -> _External variables_ can be passed in that are not valid _names_. -> Such variables cannot be referenced in a _message_, -> but are not otherwise errors. - ### Escape Sequences An **_escape sequence_** is a two-character sequence starting with