unicode-org / message-format-wg

Developing a standard for localizable message strings
Other
229 stars 33 forks source link

Fix "function resolution" to handle selectors #626

Open aphillips opened 8 months ago

aphillips commented 8 months ago

In #621 around here I noticed, in response to @eemeli's comment, that Function Resolution has a bias towards formatting functions. We also have Resolve Selectors later, which wants to emit nomatch for these failures.

The problem with Function Resolution for a selection-only function is in this step:

Call the function implementation with the following arguments:

In the case of e.g. :plural, there is no function to call except for MatchSelectorKeys

eemeli commented 8 months ago

For any annotated expression being resolved (be its value used for formatting, selection, or as an operand or option value), some function needs to be provided that can return a value as defined in Function Resolution step 5. Note that at this point, no limits are placed on what that value looks like, because that's an implementation detail.

During selection that value is one of the arguments passed to MatchSelectorKeys. During formatting, we don't define so algorithmically how each resolved value is formatted, because the result of that formatting can be one thing (e.g. a string), a sequence of things (e.g. formatted parts), or a treelike structure.

Perhaps the one place where we should clarify this is this line: https://github.com/unicode-org/message-format-wg/blob/181ccde60ade749200a89b022ece7ce79b1598e3/spec/formatting.md?plain=1#L288

Would it be sufficient for disambiguation to qualify that as "The string representation of the fallback value depends on..."?

aphillips commented 7 months ago

I think the problem here is that "call the function" implies there is only one of these. The current text says:

Call the function implementation with the following arguments:

  • The current locale.
  • The resolved mapping of options.
  • If the expression includes an operand, its resolved value.

I think we would be better off with a tweak that allows the selector and formatter to be separated. Perhaps:

Using the following arguments, call the function's selector or formatting implementation as appropriate:

  • The current formatting context (which includes the locale) <-- notice change
  • The resolved mapping of options.
  • If the expression includes an operand, its resolved value.
eemeli commented 7 months ago

That looks fine, except that we really should not require passing the full formatting context to functions, given how it includes all of the raw input variable values and access to the function implementations.

catamorphism commented 7 months ago

That looks fine, except that we really should not require passing the full formatting context to functions, given how it includes all of the raw input variable values and access to the function implementations.

Perhaps it could be reworded to encourage the implementation to define its own "external context" that contains exactly what is needed for functions, separately from its "internal context" that will presumably be richer? Obviously it can't be required, but I agree that the spec shouldn't look like it's requiring the implementation to pass in all its internal data structures.

eemeli commented 7 months ago

That's pretty much what I ended up implementing; the MessageFunctionContext is a very restricted subset of the full Context.