Skip to content

Add case selection specification #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Add case selection specification #170

wants to merge 1 commit into from

Conversation

eemeli
Copy link
Collaborator

@eemeli eemeli commented May 2, 2021

Closes #93
Closes #99
Closes #104
Closes #105
Closes #106

I'm not sure what the plan is on us actually producing spec text, so I figured I'd propose a start to it by adding the spec/ directory as a place to collect various parts of the specification as we agree on them. As with all our other work, it should be obvious that nothing is final until everything is final, and the contents of this directory may also change as our thinking changes and we take new aspects into consideration.

This PR adds a specification for the handling of case selection. This is an essential part of our Deliverable 4, "A specification for resolving translations at runtime, including interpolated data types and runtime errors."

A TypeScript implementation of the algorithm is provided here. Its functioning has been verified against some pretty complex MF1 & Fluent test cases.

The relatively high number of issues closed is due to our general silence on actually discussing this topic, at least so far. Previous to this, I'm only aware of #101 as a previously proposed algorithm (which this supersedes). While issue #99 is not directly about selector logic, the proposed algorithm relies on an answer "yes" to its question of allowing function references in the data model; this is supported by both proposed data models.

Discussion

This selector structure provides a superset of the functionality provided by the select, plural, and selectordinal selectors of MessageFormat 1, the Fluent selector, as well as all other selector methods currently in use.

The algorithm is highly reliant on the case order being correct (see prereq. 7). This is intentional, as it allows for the runtime logic to be relatively simple, and for case selection precedence to be easily deduced.

For a selector function such as plural, the order of the keys that it returns is not significant.

It is intentional that a key list may be shorter than its selector list. Such a key list may be considered to have the default value set for each of the not-defined selectors.

The only requirement this algorithm places on the function registry is that it may provide something like a "selector function" matching the above-defined signature. How the registry might be organised or structured and whether this differs somehow from a "formatter function" is explicitly left undefined here.

To use a plural category selector on a numerical value with non-default options and arguments, an explicit function reference may be used. This allows e.g. for ordinal and range plurals to be supported.

This algorithm special-cases numerical values to use a pre-defined default function. It would be possible to extend this logic to also cover e.g. number ranges and gender selectors, but those could easily be implemented using explicit selector functions.

An implementation could define a warning to be emitted if the algorithm reaches step 3. That situation should not be considered as an error, but it could (and possibly should?) be noted at least during development and linting, as it may indicate a missing variant case.

Open Questions

This algorithm does not define what a "number" is. It should be self-evident that a primitive number type would match this definition, but it is conceivable to also consider an object

{ type: "number", value: number, precision: number }

as a "number", and treat it accordingly (with an extension of the matching logic in steps 2.1-2.3).

The benefit of this would be an ability to express a value such as 1.0 as distinct from 1, which would allow for its correct handling for plural category selection.


1. The initial value `v` of the selector is resolved (see prereq. 2)
2. If `v` is a string value or a list of string and integer values, `s = v` is set.
3. Else if `v` is a number and a `plural` function is defined, `s = plural(v)` is set.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the data model to be more explicit, i.e. the selector should already encode that it will use the plural function for resolution.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intent with this is to handle cases where the data model representation does not make it clear whether the input value might or might not be a number. For instance, take the default message used by the Fluent Playground:

shared-photos =
    {$userName} {$photoCount ->
        [one] added a new photo
       *[other] added {$photoCount} new photos
    } to {$userGender ->
        [male] his stream
        [female] her stream
       *[other] their stream
    }.

Specifically, consider the $photoCount selector: at what point can it be known whether it represents a numeric value vs. e.g. the literal string 'one'? The implicit plural allows us to ask that question only when we actually have the value; any earlier, we'd need additional input on its data type, or we'd need to add an explicit plural wrapper on every single selector.

As I mention in the discussion, the algorithm does of course allow for explicit plural wrappers, and that is in fact required when doing anything other than simple cardinal plural selection.

@eemeli eemeli marked this pull request as draft September 11, 2021 16:23
@eemeli
Copy link
Collaborator Author

eemeli commented Sep 11, 2021

Converted back to draft, as this'll need to be rebased & refactored now that we have a spec.md in the repo.

@eemeli eemeli closed this Oct 17, 2022
@eemeli eemeli deleted the spec/case-selection branch October 17, 2022 17:18
@eemeli
Copy link
Collaborator Author

eemeli commented Oct 17, 2022

Closing, as the design moved in a slightly different direction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment