Skip to content
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

What is the use case of resolvedOptions().functions ? #54

Open
FrankYFTang opened this issue Apr 25, 2024 · 7 comments
Open

What is the use case of resolvedOptions().functions ? #54

FrankYFTang opened this issue Apr 25, 2024 · 7 comments

Comments

@FrankYFTang
Copy link
Contributor

Why do we need to return the functions in the resolvedOptions() object? What is the use case for providing such information. The caller should have it already, right? Why do we need to force the implementation to return a copy of that ?

@eemeli
Copy link
Member

eemeli commented Apr 26, 2024

Two reasons:

  1. I've understood that we have an expectation that the object returned by resolvedOptions() can be fed back into the corresponding constructor's options argument to get a second formatter with the same options. The functions are an important part of that.
  2. This is the only interface providing access to the implementations for the built-in functions. This allows e.g. for a formatter for custom date-like values to be built on top of the built-in :datetime, rather than needing to be completely custom-built.

@FrankYFTang
Copy link
Contributor Author

FrankYFTang commented Apr 29, 2024

I've understood that we have an expectation that the object returned by resolvedOptions() can be fed back into the corresponding constructor's options argument to get a second formatter with the same options. The functions are an important part of that.

ok, that I can see the motivation.

2. This is the only interface providing access to the implementations for the built-in functions. This allows e.g. for a formatter for custom date-like values to be built on top of the built-in :datetime, rather than needing to be completely custom-built.

ok, could you write some sample code to demostrate what this would look like for such use case

@eemeli
Copy link
Member

eemeli commented Apr 30, 2024

could you write some sample code to demostrate what this would look like for such use case

As an example, here's a sketch of what a Decimal128 formatter could look like:

const { number } = new Intl.MessageFormat('').resolvedOptions().functions;

/** @param {Decimal128} value */
function decimal(ctx, options, value) {
  const str = String(value);
  const dotPos = str.indexOf('.');
  const fd = dotPos === -1 ? 0 : str.length - dotPos - 1;
  const defaults = { minimumFractionDigits: fd, maximumFractionDigits: fd };
  return number(ctx, Object.assign(defaults, options), Number(value));
}

const mf = new Intl.MessageFormat(..., locale, { functions: { decimal } });

With the above, a function :decimal would be made available in messages, with the same options as :number, but with support for Decimal128 values, and with different defaults for the minimumFractionDigits and maximumFractionDigits options.

Without access to the built-in :number function implementation, the custom function implementation gets quite a bit more complicated, as it needs to handle formatting to a string, formatting to parts, selection, and use as a operand and option values. Here's the :number polyfill implementation, to give you some idea.

@FrankYFTang
Copy link
Contributor Author

so ... basically you are using
const { number } = new Intl.MessageFormat('').resolvedOptions().functions;
const { string } = new Intl.MessageFormat('').resolvedOptions().functions;
const { datetime } = new Intl.MessageFormat('').resolvedOptions().functions;

to get back the function for the built-in type "number", "string" and "datetime" right?
That looks so strange to me.
Why not just add 3 functions to the spec as Properties of the Intl.MessageFormat Constructor
get Intl.MessageFormat.numberFunction()
get Intl.MessageFormat.stringFunction()
get Intl.MessageFormat.datetimeFunction()

I think it is a bad programing style to ask the developer to construct a unused (new Intl.MessageFormat('')) just to call the resolvedOptions().functions.number to access that function. There are no reason this Intl.MessageFormat object should be created here.

@eemeli
Copy link
Member

eemeli commented May 6, 2024

If taking that approach is viable, then we probably should make the built-in functions directly callable properties:

const mv = Intl.MessageFormat.number({ locales: ['en'] }, { minimumFractionDigits: 2 }, 42);
mv.format(); // '42.00'

Is there any reason this might be a bad idea? The full set of MF2 built-in functions we'll need to support is:

:number
:integer
:datetime
:date
:time
:string

@FrankYFTang
Copy link
Contributor Author

FrankYFTang commented May 6, 2024

no, I do not think that is a good idea. What you need to think is if your have a message format which is needed to be called several times in a webpage, (say to format 100 items, each contains two varables (price and weight) in 100 rows, all following the same format) how could you consstruct a Intl.MessageFormat that internally you do not need to create the Intl.NumberFormat 100 times but only once. All these 100 invokations will share the same setting and only differ in the value, right? If you have two number variables in that message you may need to create two Intl.NumberFormat (since they may not share the same setting in the same message) but not 200 of them. If you pass in 42 to access that function, then you cannot share what it create internally across the 100 invokations

@eemeli
Copy link
Member

eemeli commented May 6, 2024

Could you help me connect the dots here? I don't see the connection between concerns about the internal memoization of NumberFormat instances with the public accessibility of the :number implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants