Open FrankYFTang opened 7 months ago
Two reasons:
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.:datetime
, rather than needing to be completely custom-built.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
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.
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.
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
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
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.
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 ?