diff --git a/spec/errors.md b/spec/errors.md
index a2ddd669d..b437be695 100644
--- a/spec/errors.md
+++ b/spec/errors.md
@@ -32,7 +32,7 @@ Some examples include throwing an exception,
returning an error code,
or providing a function or method for enumerating any errors.
-For all _messages_ without _Syntax Errors_ or _Data Model Errors_,
+For all _valid_ _messages_,
an implementation MUST enable a user to get a formatted result.
The formatted result might include _fallback values_
such as when a _placeholder_'s _expression_ produced an error
@@ -52,7 +52,7 @@ and a _Resolution Error_ or a _Message Function Error_ MUST be emitted.
## Syntax Errors
-**_Syntax Errors_** occur when the syntax representation of a message is not well-formed.
+**_Syntax Errors_** occur when the syntax representation of a message is not _well-formed_.
> Example invalid messages resulting in a _Syntax Error_:
>
@@ -74,7 +74,7 @@ and a _Resolution Error_ or a _Message Function Error_ MUST be emitted.
## Data Model Errors
-**_Data Model Errors_** occur when a message is invalid due to
+**_Data Model Errors_** occur when a message is not _valid_ due to
violating one of the semantic requirements on its structure.
### Variant Key Mismatch
diff --git a/spec/formatting.md b/spec/formatting.md
index 5e71d24a3..cbf6d4622 100644
--- a/spec/formatting.md
+++ b/spec/formatting.md
@@ -7,10 +7,19 @@ when formatting a message for display in a user interface, or for some later pro
To start, we presume that a _message_ has either been parsed from its syntax
or created from a data model description.
-If this construction has encountered any _Syntax Errors_ or _Data Model Errors_,
-an appropriate error MUST be emitted and a _fallback value_ MAY be used as the formatting result.
+If the resulting _message_ is not _well-formed_, a _Syntax Error_ is emitted.
+If the resulting _message_ is _well-formed_ but is not _valid_, a _Data Model Error_ is emitted.
-Formatting of a _message_ is defined by the following operations:
+The formatting of a _message_ is defined by the following operations:
+
+- **_Pattern Selection_** determines which of a message's _patterns_ is formatted.
+ For a message with no _selectors_, this is simple as there is only one _pattern_.
+ With _selectors_, this will depend on their resolution.
+
+- **_Formatting_** takes the resolved values of the selected _pattern_,
+ and produces the formatted result for the _message_.
+ Depending on the implementation, this result could be a single concatenated string,
+ an array of objects, an attributed string, or some other locally appropriate data type.
- **_Expression and Markup Resolution_** determines the value of an _expression_ or _markup_,
with reference to the current _formatting context_.
@@ -24,6 +33,15 @@ Formatting of a _message_ is defined by the following operations:
The resolution of _text_ is rather straightforward,
and is detailed under _literal resolution_.
+Implementations are not required to expose
+the _expression resolution_ and _pattern selection_ operations to their users,
+or even use them in their internal processing,
+as long as the final _formatting_ result is made available to users
+and the observable behavior of the _formatting_ matches that described here.
+
+_Attributes_ MUST NOT have any effect on the formatted output of a _message_,
+nor be made available to function implementations.
+
> [!IMPORTANT]
>
> **This specification does not require either eager or lazy _expression resolution_ of _message_
@@ -39,27 +57,6 @@ Formatting of a _message_ is defined by the following operations:
> have already been evaluated in the order in which the relevant _declarations_
> and _selectors_ appear in the _message_.
-- **_Pattern Selection_** determines which of a message's _patterns_ is formatted.
- For a message with no _selectors_, this is simple as there is only one _pattern_.
- With _selectors_, this will depend on their resolution.
-
- At the start of _pattern selection_,
- if the _message_ contains any _reserved statements_,
- emit an _Unsupported Statement_ error.
-
-- **_Formatting_** takes the resolved values of the selected _pattern_,
- and produces the formatted result for the _message_.
- Depending on the implementation, this result could be a single concatenated string,
- an array of objects, an attributed string, or some other locally appropriate data type.
-
-Formatter implementations are not required to expose
-the _expression resolution_ and _pattern selection_ operations to their users,
-or even use them in their internal processing,
-as long as the final _formatting_ result is made available to users
-and the observable behavior of the formatter matches that described here.
-
-_Attributes_ MUST NOT affect the processing or output of a _message_.
-
## Formatting Context
A message's **_formatting context_** represents the data and procedures that are required
@@ -82,8 +79,7 @@ At a minimum, it includes:
- The _function registry_,
providing the implementations of the functions referred to by message _functions_.
-- Optionally, a fallback string to use for the message
- if it contains any _Syntax Errors_ or _Data Model Errors_.
+- Optionally, a fallback string to use for the message if it is not _valid_.
Implementations MAY include additional fields in their _formatting context_.
@@ -192,8 +188,8 @@ If a _declaration_ exists for the _variable_, its resolved value is used.
Otherwise, the _variable_ is an implicit reference to an input value,
and its value is looked up from the _formatting context_ _input mapping_.
-The resolution of a _variable_ MAY fail if no value is identified for its _name_.
-If this happens, an _Unresolved Variable_ error MUST be emitted.
+The resolution of a _variable_ fails if no value is identified for its _name_.
+If this happens, an _Unresolved Variable_ error is emitted.
If a _variable_ would resolve to a _fallback value_,
this MUST also be considered a failure.
@@ -435,6 +431,17 @@ _Pattern selection_ is not supported for _fallback values_.
## Pattern Selection
+If the _message_ contains any _reserved statements_,
+emit an _Unsupported Statement_ error.
+
+If the _message_ being formatted is not _well-formed_ and _valid_,
+the result of pattern selection is a _pattern_ consisting of a single _fallback value_
+using the _message_'s fallback string defined in the _formatting context_
+or if this is not available or empty, the U+FFFD REPLACEMENT CHARACTER `�`.
+
+If the _message_ being formatted does not contain a _matcher_,
+the result of pattern selection is its _pattern_ value.
+
When a _message_ contains a _matcher_ with one or more _selectors_,
the implementation needs to determine which _variant_ will be used
to provide the _pattern_ for the formatting operation.
@@ -504,11 +511,6 @@ This selection method is defined in more detail below.
An implementation MAY use any pattern selection method,
as long as its observable behavior matches the results of the method defined here.
-If the message being formatted has any _Syntax Errors_ or _Data Model Errors_,
-the result of pattern selection MUST be a pattern resolving to a single _fallback value_
-using the message's fallback string defined in the _formatting context_
-or if this is not available or empty, the U+FFFD REPLACEMENT CHARACTER `�`.
-
### Resolve Selectors
First, resolve the values of each _selector_:
@@ -741,8 +743,8 @@ each _text_ and _placeholder_ part of the selected _pattern_ is resolved and for
Resolved values cannot always be formatted by a given implementation.
When such an error occurs during _formatting_,
-an implementation MUST emit an appropriate _Message Function Error_ and use a
-_fallback value_ for the _placeholder_ with the error.
+an appropriate _Message Function Error_ is emitted and
+a _fallback value_ is used for the _placeholder_ with the error.
Implementations MAY represent the result of _formatting_ using the most
appropriate data type or structure. Some examples of these include:
@@ -787,8 +789,9 @@ the _fallback value_ as a string,
and a U+007D RIGHT CURLY BRACKET `}`.
> For example,
-> a message with a _Syntax Error_ and no fallback string
-> defined in the _formatting context_ would format to a string as `{�}`.
+> a _message_ that is not _well-formed_ would format to a string as `{�}`,
+> unless a fallback string is defined in the _formatting context_,
+> in which case that string would be used instead.
### Handling Bidirectional Text
diff --git a/spec/syntax.md b/spec/syntax.md
index 76fc74502..80b704bcb 100644
--- a/spec/syntax.md
+++ b/spec/syntax.md
@@ -90,7 +90,7 @@ Attempting to parse a _message_ that is not _well-formed_ will result in a _Synt
A _message_ is **_valid_** if it is _well-formed_ and
**also** meets the additional content restrictions
and semantic requirements about its structure defined below for
-_declarations_, _matcher_, _options_, and _attributes_.
+_declarations_, _matcher_, and _options_.
Attempting to parse a _message_ that is not _valid_ will result in a _Data Model Error_.
## The Message
@@ -368,14 +368,18 @@ and at least one _variant_.
When the _matcher_ is processed, the result will be a single _pattern_ that serves
as the template for the formatting process.
-A _message_ can only be considered _valid_ if the following requirements are
-satisfied:
+A _message_ can only be considered _valid_ if the following requirements are satisfied;
+otherwise, a corresponding _Data Model Error_ will be produced during processing:
-- The number of _keys_ on each _variant_ MUST be equal to the number of _selectors_.
-- At least one _variant_ MUST exist whose _keys_ are all equal to the "catch-all" key `*`.
-- Each _selector_ MUST have an _annotation_,
+- _Variant Key Mismatch_:
+ The number of _keys_ on each _variant_ MUST be equal to the number of _selectors_.
+- _Missing Fallback Variant_:
+ At least one _variant_ MUST exist whose _keys_ are all equal to the "catch-all" key `*`.
+- _Missing Selector Annotation_:
+ Each _selector_ MUST have an _annotation_,
or contain a _variable_ that directly or indirectly references a _declaration_ with an _annotation_.
-- Each _variant_ MUST use a list of _keys_ that is unique from that
+- _Duplicate Variant_:
+ Each _variant_ MUST use a list of _keys_ that is unique from that
of all other _variants_ in the _message_.
_Literal_ _keys_ are compared by their contents, not their syntactical appearance.
@@ -587,7 +591,8 @@ Multiple _options_ are permitted in an _annotation_.
_Options_ are separated from the preceding _function_ _identifier_
and from each other by whitespace.
Each _option_'s _identifier_ MUST be unique within the _annotation_:
-an _annotation_ with duplicate _option_ _identifiers_ is not _valid_.
+an _annotation_ with duplicate _option_ _identifiers_ is not _valid_
+and will produce a _Duplicate Option Name_ error during processing.
The order of _options_ is not significant.
@@ -750,10 +755,10 @@ by an U+003D EQUALS SIGN `=` along with optional whitespace.
Multiple _attributes_ are permitted in an _expression_ or _markup_.
Each _attribute_ is separated by whitespace.
-Each _attribute_'s _identifier_ MUST be unique within the _expression_ or _markup_:
-an _expression_ or _markup_ with duplicate _attribute_ _identifiers_ is not _valid_.
-The order of _attributes_ is not significant.
+Each _attribute_'s _identifier_ SHOULD be unique within the _expression_ or _markup_:
+all but the last _attribute_ with the same _identifier_ are ignored.
+The order of _attributes_ is not otherwise significant.
```abnf
attribute = "@" identifier [[s] "=" [s] literal]