@fluent/bundle
Version:
Localization library for expressive translations.
139 lines (138 loc) • 3.91 kB
JavaScript
/**
* @overview
*
* The FTL resolver ships with a number of functions built-in.
*
* Each function take two arguments:
* - args - an array of positional args
* - opts - an object of key-value args
*
* Arguments to functions are guaranteed to already be instances of
* `FluentValue`. Functions must return `FluentValues` as well.
*/
import { FluentNone, FluentNumber, FluentDateTime, } from "./types.js";
function values(opts, allowed) {
const unwrapped = Object.create(null);
for (const [name, opt] of Object.entries(opts)) {
if (allowed.includes(name)) {
unwrapped[name] = opt.valueOf();
}
}
return unwrapped;
}
const NUMBER_ALLOWED = [
"unitDisplay",
"currencyDisplay",
"useGrouping",
"minimumIntegerDigits",
"minimumFractionDigits",
"maximumFractionDigits",
"minimumSignificantDigits",
"maximumSignificantDigits",
];
/**
* The implementation of the `NUMBER()` builtin available to translations.
*
* Translations may call the `NUMBER()` builtin in order to specify formatting
* options of a number. For example:
*
* pi = The value of π is {NUMBER($pi, maximumFractionDigits: 2)}.
*
* The implementation expects an array of {@link FluentValue | FluentValues} representing the
* positional arguments, and an object of named {@link FluentValue | FluentValues} representing the
* named parameters.
*
* The following options are recognized:
*
* unitDisplay
* currencyDisplay
* useGrouping
* minimumIntegerDigits
* minimumFractionDigits
* maximumFractionDigits
* minimumSignificantDigits
* maximumSignificantDigits
*
* Other options are ignored.
*
* @param args The positional arguments passed to this `NUMBER()`.
* @param opts The named argments passed to this `NUMBER()`.
*/
export function NUMBER(args, opts) {
let arg = args[0];
if (arg instanceof FluentNone) {
return new FluentNone(`NUMBER(${arg.valueOf()})`);
}
if (arg instanceof FluentNumber) {
return new FluentNumber(arg.valueOf(), {
...arg.opts,
...values(opts, NUMBER_ALLOWED),
});
}
if (arg instanceof FluentDateTime) {
return new FluentNumber(arg.toNumber(), {
...values(opts, NUMBER_ALLOWED),
});
}
throw new TypeError("Invalid argument to NUMBER");
}
const DATETIME_ALLOWED = [
"dateStyle",
"timeStyle",
"fractionalSecondDigits",
"dayPeriod",
"hour12",
"weekday",
"era",
"year",
"month",
"day",
"hour",
"minute",
"second",
"timeZoneName",
];
/**
* The implementation of the `DATETIME()` builtin available to translations.
*
* Translations may call the `DATETIME()` builtin in order to specify
* formatting options of a number. For example:
*
* now = It's {DATETIME($today, month: "long")}.
*
* The implementation expects an array of {@link FluentValue | FluentValues} representing the
* positional arguments, and an object of named {@link FluentValue | FluentValues} representing the
* named parameters.
*
* The following options are recognized:
*
* dateStyle
* timeStyle
* fractionalSecondDigits
* dayPeriod
* hour12
* weekday
* era
* year
* month
* day
* hour
* minute
* second
* timeZoneName
*
* Other options are ignored.
*
* @param args The positional arguments passed to this `DATETIME()`.
* @param opts The named argments passed to this `DATETIME()`.
*/
export function DATETIME(args, opts) {
let arg = args[0];
if (arg instanceof FluentNone) {
return new FluentNone(`DATETIME(${arg.valueOf()})`);
}
if (arg instanceof FluentDateTime || arg instanceof FluentNumber) {
return new FluentDateTime(arg, values(opts, DATETIME_ALLOWED));
}
throw new TypeError("Invalid argument to DATETIME");
}