@fluent/bundle
Advanced tools
Comparing version 0.17.1 to 0.18.0
867
CHANGELOG.md
# Changelog | ||
## [0.18.0](https://github.com/projectfluent/fluent.js/compare/@fluent/bundle@0.17.1...@fluent/bundle@0.18.0) (2023-03-13) | ||
- Drop Node.js v12 support, add v18 & latest to CI tests | ||
([#607](https://github.com/projectfluent/fluent.js/pull/607)) | ||
- Use `/** comments */` where appropriate | ||
## [@fluent/bundle 0.17.1](https://github.com/projectfluent/fluent.js/compare/@fluent/bundle@0.17.0...@fluent/bundle@0.17.1) (2021-12-21) | ||
- Add per locale Intl memoizer | ||
([#504](https://github.com/projectfluent/fluent.js/pull/504)) | ||
- The type of caught errors is validated at runtime | ||
([#575](https://github.com/projectfluent/fluent.js/pull/575)) | ||
- Add per locale Intl memoizer | ||
([#504](https://github.com/projectfluent/fluent.js/pull/504)) | ||
- The type of caught errors is validated at runtime | ||
([#575](https://github.com/projectfluent/fluent.js/pull/575)) | ||
## @fluent/bundle 0.17.0 (September 13, 2021) | ||
- Remove `"type": "commonjs"` from the package's root `package.json`, but add | ||
`"type": "module"` to the `esm/` directory. | ||
([#556](https://github.com/projectfluent/fluent.js/pull/556), | ||
[#567](https://github.com/projectfluent/fluent.js/pull/567)) | ||
- Set Node.js 12 as the minimum supported version ([#557](https://github.com/projectfluent/fluent.js/pull/557)) | ||
- Remove `"type": "commonjs"` from the package's root `package.json`, but add | ||
`"type": "module"` to the `esm/` directory. | ||
([#556](https://github.com/projectfluent/fluent.js/pull/556), | ||
[#567](https://github.com/projectfluent/fluent.js/pull/567)) | ||
- Set Node.js 12 as the minimum supported version ([#557](https://github.com/projectfluent/fluent.js/pull/557)) | ||
## @fluent/bundle 0.16.1 (April 9, 2021) | ||
- Separate FluentNumber/Datetime opts when used in DATETIME/NUMBER. (#526) | ||
- Separate FluentNumber/Datetime opts when used in DATETIME/NUMBER. (#526) | ||
## @fluent/bundle 0.16.0 (July 1, 2020) | ||
- Rename `FluentArgument` to `FluentVariable`. (#499) | ||
- Rename `FluentArgument` to `FluentVariable`. (#499) | ||
`FluentVariable` is a TypeScript-only type definition used to describe | ||
value types which can be passed as variables to translations. | ||
`FluentVariable` is a TypeScript-only type definition used to describe | ||
value types which can be passed as variables to translations. | ||
- Remove `compat.js` builds and compile everything to ES2018. (#472) | ||
- Remove `compat.js` builds and compile everything to ES2018. (#472) | ||
TypeScript source code is now compiled to ES2018 files in the `esm/` | ||
directory. These files are then bundled into a single `index.js` UMD file | ||
without any further transpilation. | ||
TypeScript source code is now compiled to ES2018 files in the `esm/` | ||
directory. These files are then bundled into a single `index.js` UMD file | ||
without any further transpilation. | ||
The `compat.js` build (available as `@fluent/bundle/compat`) was removed. | ||
Please use your own transpilation pipeline if ES2018 is too recent for | ||
your project. | ||
The `compat.js` build (available as `@fluent/bundle/compat`) was removed. | ||
Please use your own transpilation pipeline if ES2018 is too recent for | ||
your project. | ||
Refer to https://github.com/projectfluent/fluent.js/wiki/Compatibility | ||
for more information. | ||
Refer to https://github.com/projectfluent/fluent.js/wiki/Compatibility | ||
for more information. | ||
## @fluent/bundle 0.15.1 (April 7, 2020) | ||
- Allow only some formatting options to `NUMBER` and `DATETIME`. (#464) | ||
- Allow only some formatting options to `NUMBER` and `DATETIME`. (#464) | ||
The builtin functions available to translations were liberal in terms of | ||
the options they accepted. This could lead to undesired results, e.g. | ||
when for the same number value, a translation would specify a different | ||
currency than the source language. | ||
The builtin functions available to translations were liberal in terms of | ||
the options they accepted. This could lead to undesired results, e.g. | ||
when for the same number value, a translation would specify a different | ||
currency than the source language. | ||
The `NUMBER` builtin now only recognizes the following options: | ||
The `NUMBER` builtin now only recognizes the following options: | ||
unitDisplay | ||
currencyDisplay | ||
useGrouping | ||
minimumIntegerDigits | ||
minimumFractionDigits | ||
maximumFractionDigits | ||
minimumSignificantDigits | ||
maximumSignificantDigits | ||
unitDisplay | ||
currencyDisplay | ||
useGrouping | ||
minimumIntegerDigits | ||
minimumFractionDigits | ||
maximumFractionDigits | ||
minimumSignificantDigits | ||
maximumSignificantDigits | ||
The `DATETIME` builtin now only recognizes the following options: | ||
The `DATETIME` builtin now only recognizes the following options: | ||
dateStyle | ||
timeStyle | ||
fractionalSecondDigits | ||
dayPeriod | ||
hour12 | ||
weekday | ||
era | ||
year | ||
month | ||
day | ||
hour | ||
minute | ||
second | ||
timeZoneName | ||
dateStyle | ||
timeStyle | ||
fractionalSecondDigits | ||
dayPeriod | ||
hour12 | ||
weekday | ||
era | ||
year | ||
month | ||
day | ||
hour | ||
minute | ||
second | ||
timeZoneName | ||
All other options are ignored. | ||
All other options are ignored. | ||
## @fluent/bundle 0.15.0 (January 23, 2020) | ||
- Migrate to TypeScript. (#436) | ||
- Migrate to TypeScript. (#436) | ||
The source code of `@fluent/bundle` has been ported to TypeScript. There | ||
are no breaking changes to the public API. | ||
The source code of `@fluent/bundle` has been ported to TypeScript. There | ||
are no breaking changes to the public API. | ||
A new export has been added for TS consumers: `FluentValue` which is a | ||
union of the `FluentType` class and `string`. This reflects the | ||
implementation detail of `@fluent/bundle` which treats primitive strings | ||
as valid `FluentType` instances. | ||
A new export has been added for TS consumers: `FluentValue` which is a | ||
union of the `FluentType` class and `string`. This reflects the | ||
implementation detail of `@fluent/bundle` which treats primitive strings | ||
as valid `FluentType` instances. | ||
The ES module files are now published into the `esm` directory. It also | ||
contains the type definitions for TS consumers. The `src` directory has | ||
been removed from the published packages. | ||
The ES module files are now published into the `esm` directory. It also | ||
contains the type definitions for TS consumers. The `src` directory has | ||
been removed from the published packages. | ||
@@ -102,6 +108,6 @@ ## @fluent/bundle 0.14.1 (December 20, 2019) | ||
Expressions which resolved to strings over 2500 characters long used to be | ||
considered dangerous. This is no longer the case. Instead, there's a limit | ||
on how many placeable can be resolved during a single call to | ||
`formatPattern`, to protect from high CPU usage in deeply nested patterns. | ||
Expressions which resolved to strings over 2500 characters long used to be | ||
considered dangerous. This is no longer the case. Instead, there's a limit | ||
on how many placeable can be resolved during a single call to | ||
`formatPattern`, to protect from high CPU usage in deeply nested patterns. | ||
@@ -115,134 +121,133 @@ - Fix a bug which made it impossible to pass a variable called `hasOwnProperty` | ||
- Remove `FluentBundle.addMessages`. | ||
- Remove `FluentBundle.addMessages`. | ||
Use `FluentBundle.addResource` instead, combined with a `FluentResource` | ||
instance. | ||
Use `FluentBundle.addResource` instead, combined with a `FluentResource` | ||
instance. | ||
- Remove `FluentBundle.messages`. | ||
- Remove `FluentBundle.messages`. | ||
The list of messages in the bundle should not be inspected. If you need | ||
to do it, please use the tooling parser from `@fluent/syntax`. | ||
The list of messages in the bundle should not be inspected. If you need | ||
to do it, please use the tooling parser from `@fluent/syntax`. | ||
- Change the shape returned by `FluentBundle.getMessage`. | ||
- Change the shape returned by `FluentBundle.getMessage`. | ||
The method now returns the following shape: | ||
The method now returns the following shape: | ||
{value: Pattern | null, attributes: Record<string, Pattern>} | ||
{value: Pattern | null, attributes: Record<string, Pattern>} | ||
- The internal representtion of `Pattern` is private. | ||
- The internal representtion of `Pattern` is private. | ||
Raw messages returned from `getMessage` have their values and attributes | ||
stored in a `Pattern` type. The internal representation of this type is | ||
private and implementation-specific. It should not be inspected nor used | ||
for any purposes. The implementation may change without a warning in | ||
future releases. `Patterns` are black boxes and are meant to be used as | ||
arguments to `formatPattern`. | ||
Raw messages returned from `getMessage` have their values and attributes | ||
stored in a `Pattern` type. The internal representation of this type is | ||
private and implementation-specific. It should not be inspected nor used | ||
for any purposes. The implementation may change without a warning in | ||
future releases. `Patterns` are black boxes and are meant to be used as | ||
arguments to `formatPattern`. | ||
- Rename `FluentBundle.format` to `formatPattern`. | ||
- Rename `FluentBundle.format` to `formatPattern`. | ||
`formatPattern` only accepts valid `Patterns` as the first argument. In | ||
practice, you'll want to first retrieve a raw message from the bundle via | ||
`getMessage`, and then format the value (if present) and the attributes | ||
separately. | ||
`formatPattern` only accepts valid `Patterns` as the first argument. In | ||
practice, you'll want to first retrieve a raw message from the bundle via | ||
`getMessage`, and then format the value (if present) and the attributes | ||
separately. | ||
```js | ||
let message = bundle.getMessage("hello"); | ||
if (message.value) { | ||
bundle.formatPattern(message.value, {userName: "Alex"}); | ||
} | ||
``` | ||
```js | ||
let message = bundle.getMessage("hello"); | ||
if (message.value) { | ||
bundle.formatPattern(message.value, { userName: "Alex" }); | ||
} | ||
``` | ||
The list of all attributes defined in the message can be obtained with | ||
`Object.keys(message.attributes)`. | ||
The list of all attributes defined in the message can be obtained with | ||
`Object.keys(message.attributes)`. | ||
- Throw from `formatPattern` when `errors` are not passed as an argument. | ||
- Throw from `formatPattern` when `errors` are not passed as an argument. | ||
The old `format()` method would silence all errors if the thrid argument, | ||
the `errors` array was not given. `formatPattern` changes this behavior | ||
to throwing on the first encountered error and interrupting the | ||
formatting. | ||
The old `format()` method would silence all errors if the thrid argument, | ||
the `errors` array was not given. `formatPattern` changes this behavior | ||
to throwing on the first encountered error and interrupting the | ||
formatting. | ||
```js | ||
try { | ||
bundle.formatPattern(message.value, args); | ||
} catch (err) { | ||
// Handle the error yourself. | ||
} | ||
``` | ||
```js | ||
try { | ||
bundle.formatPattern(message.value, args); | ||
} catch (err) { | ||
// Handle the error yourself. | ||
} | ||
``` | ||
It's still possible to pass the `errors` array as the third argument to | ||
`formatPattern`. All errors encountered during the formatting will be | ||
then appended to the array. In this scenario, `formatPattern` is | ||
guaranteed to never throw because of errors in the translation. | ||
It's still possible to pass the `errors` array as the third argument to | ||
`formatPattern`. All errors encountered during the formatting will be | ||
then appended to the array. In this scenario, `formatPattern` is | ||
guaranteed to never throw because of errors in the translation. | ||
```js | ||
let errorrs = []; | ||
bundle.formatPattern(message.value, args, errors); | ||
for (let error of errors) { | ||
// Report errors. | ||
} | ||
``` | ||
```js | ||
let errorrs = []; | ||
bundle.formatPattern(message.value, args, errors); | ||
for (let error of errors) { | ||
// Report errors. | ||
} | ||
``` | ||
### `FluentResource` API | ||
- Remove the static `FluentResource.fromString` method. | ||
- Remove the static `FluentResource.fromString` method. | ||
Parse resources by using the constructor: `new FluentResource(text)`. | ||
Parse resources by using the constructor: `new FluentResource(text)`. | ||
- Do not extend `Map`. | ||
- Do not extend `Map`. | ||
`FluentResources` are now instances of their own class only. | ||
`FluentResources` are now instances of their own class only. | ||
- Add `FluentResource.body`. | ||
- Add `FluentResource.body`. | ||
The `body` field is an array storing the resource's parsed messages and | ||
terms. | ||
The `body` field is an array storing the resource's parsed messages and | ||
terms. | ||
### `FluentType` API | ||
- `FluentNumber` must be instantiated with a number. | ||
- `FluentNumber` must be instantiated with a number. | ||
The constructor doesn't call `parseFloat` on the passed value anymore. | ||
The constructor doesn't call `parseFloat` on the passed value anymore. | ||
- `FluentDateTime` must be instantiated with a number. | ||
- `FluentDateTime` must be instantiated with a number. | ||
The constructor doesn't call `new Date()` on the passed value anymore. | ||
The date is stored as the numerical timestamp, in milliseconds since the | ||
epoch. | ||
The constructor doesn't call `new Date()` on the passed value anymore. | ||
The date is stored as the numerical timestamp, in milliseconds since the | ||
epoch. | ||
### Formatting Changes | ||
- Report errors from instantiating Intl objects used for formatting. | ||
- Report errors from functions, including built-in functions. | ||
- Format numbers and dates to safe defaults in case or errors. (#410) | ||
- When a transform function is given, transform only `TextElements`. | ||
- Report errors from instantiating Intl objects used for formatting. | ||
- Report errors from functions, including built-in functions. | ||
- Format numbers and dates to safe defaults in case or errors. (#410) | ||
- When a transform function is given, transform only `TextElements`. | ||
## @fluent/bundle 0.13.0 (July 25, 2019) | ||
- Rename `fluent` to `@fluent/bundle`. | ||
- Rename `fluent` to `@fluent/bundle`. | ||
## fluent 0.13.0 (July 25, 2019) | ||
- Support Fluent Syntax 1.0. | ||
- Support Fluent Syntax 1.0. | ||
Syntax 1.0 is the same as Syntax 0.9, and the support for it in this | ||
release continues to be the same as in `fluent` 0.12. This note is meant | ||
to clearly indicate that `fluent` supports the first stable version of | ||
the Syntax specification. | ||
Syntax 1.0 is the same as Syntax 0.9, and the support for it in this | ||
release continues to be the same as in `fluent` 0.12. This note is meant | ||
to clearly indicate that `fluent` supports the first stable version of | ||
the Syntax specification. | ||
- Improve the fallback string in case of expression errors. | ||
- Improve the fallback string in case of expression errors. | ||
Unresolved expressions are now printed with braces around them, e.g. | ||
`{missing}` rather than `missing` (#368). References to missing message | ||
attributes now fall back to `{messageId.attributeName}` (#370). | ||
Unresolved expressions are now printed with braces around them, e.g. | ||
`{missing}` rather than `missing` (#368). References to missing message | ||
attributes now fall back to `{messageId.attributeName}` (#370). | ||
- Remove the `ftl` dedent helper. | ||
- Remove the `ftl` dedent helper. | ||
The `ftl` dedent helper has moved to its own package, `@fluent/dedent`. | ||
Note that its behavior has changed slightly, too. See the | ||
[README][dedent-readme] for details. | ||
The `ftl` dedent helper has moved to its own package, `@fluent/dedent`. | ||
Note that its behavior has changed slightly, too. See the | ||
[README][dedent-readme] for details. | ||
[dedent-readme]: https://www.npmjs.com/package/@fluent/dedent | ||
[dedent-readme]: https://www.npmjs.com/package/@fluent/dedent | ||
## fluent 0.12.0 (March 26, 2019) | ||
@@ -254,15 +259,15 @@ | ||
- Implement Fluent Syntax 0.9. | ||
- Implement Fluent Syntax 0.9. | ||
Most of the changes introduced in Syntax 0.9 affect the full tooling AST | ||
and thus do not apply to the `fluent` package which uses a different data | ||
structure for the result of the parsing, optimized for the runtime | ||
performance. | ||
Most of the changes introduced in Syntax 0.9 affect the full tooling AST | ||
and thus do not apply to the `fluent` package which uses a different data | ||
structure for the result of the parsing, optimized for the runtime | ||
performance. | ||
Syntax features deprecated in Syntax 0.8 have been removed in Syntax 0.9. | ||
The support for them have been removed in this release of `fluent` too. | ||
Syntax features deprecated in Syntax 0.8 have been removed in Syntax 0.9. | ||
The support for them have been removed in this release of `fluent` too. | ||
Consult the full Syntax 0.9 [changelog][chlog0.9] for details. | ||
Consult the full Syntax 0.9 [changelog][chlog0.9] for details. | ||
[chlog0.9]: https://github.com/projectfluent/fluent/releases/tag/v0.9.0 | ||
[chlog0.9]: https://github.com/projectfluent/fluent/releases/tag/v0.9.0 | ||
@@ -273,13 +278,11 @@ ### Backward-incompatible changes: | ||
## fluent 0.11.0 (February 15, 2019) | ||
- Add the `allowOverrides` option to `FluentBundle.addResource`. (#332) | ||
- Add the `allowOverrides` option to `FluentBundle.addResource`. (#332) | ||
`FluentBundle.addResource` and `FluentBundle.addMessages` now both accept | ||
an `options` object as the last argument. The `allowOverrides` option may | ||
be used to control whether it's allowed to override existing mesages or | ||
terms with new values. The default is `false`. | ||
`FluentBundle.addResource` and `FluentBundle.addMessages` now both accept | ||
an `options` object as the last argument. The `allowOverrides` option may | ||
be used to control whether it's allowed to override existing mesages or | ||
terms with new values. The default is `false`. | ||
## fluent 0.10.0 (December 13, 2018) | ||
@@ -291,60 +294,58 @@ | ||
- Implement Fluent Syntax 0.8. (#303) | ||
- Implement Fluent Syntax 0.8. (#303) | ||
This is only a quick summary of the spec changes in Syntax 0.8. Consult the | ||
full [changelog][chlog0.8] for details. | ||
This is only a quick summary of the spec changes in Syntax 0.8. Consult the | ||
full [changelog][chlog0.8] for details. | ||
[chlog0.8]: https://github.com/projectfluent/fluent/releases/tag/v0.8.0 | ||
[chlog0.8]: https://github.com/projectfluent/fluent/releases/tag/v0.8.0 | ||
In multiline `Patterns`, all common indent is now removed from each | ||
indented line in the final value of the pattern. | ||
In multiline `Patterns`, all common indent is now removed from each | ||
indented line in the final value of the pattern. | ||
```properties | ||
multiline = | ||
This message has 2 spaces of indent | ||
on the second line of its value. | ||
``` | ||
```properties | ||
multiline = | ||
This message has 2 spaces of indent | ||
on the second line of its value. | ||
``` | ||
`Terms` can now be parameterized via the call expression syntax. Only | ||
variables defined between the parentheses in the message a term is used in | ||
will be available inside of it. | ||
`Terms` can now be parameterized via the call expression syntax. Only | ||
variables defined between the parentheses in the message a term is used in | ||
will be available inside of it. | ||
```properties | ||
# A parametrized Term with a Pattern as a value. | ||
-thing = { $article -> | ||
*[definite] the thing | ||
[indefinite] a thing | ||
} | ||
```properties | ||
# A parametrized Term with a Pattern as a value. | ||
-thing = { $article -> | ||
*[definite] the thing | ||
[indefinite] a thing | ||
} | ||
this = This is { -thing(article: "indefinite") }. | ||
``` | ||
this = This is { -thing(article: "indefinite") }. | ||
``` | ||
`VariantLists` are now deprecated and will be removed from the Syntax | ||
before version 1.0. | ||
`VariantLists` are now deprecated and will be removed from the Syntax | ||
before version 1.0. | ||
All escapes sequences can only be used in `StringLiterals` now (see below). | ||
`\UHHHHHH` is a new escape sequence format suitable for codepoints above | ||
U+FFFF, e.g. `{"\U01F602"}`. | ||
All escapes sequences can only be used in `StringLiterals` now (see below). | ||
`\UHHHHHH` is a new escape sequence format suitable for codepoints above | ||
U+FFFF, e.g. `{"\U01F602"}`. | ||
### Backward-incompatible changes: | ||
- The backslash character (`\`) is now considered a regular character in | ||
`TextElements`. It's no longer possible to use escape sequences in | ||
`TextElements`. Please use `StringLiterals` instead, e.g. `{"\u00A0"}`. | ||
- The closing curly brace character (`}`) is not allowed in `TextElements` | ||
now. Please use `StringLiterals` instead: `{"}"}`. | ||
- The backslash character (`\`) is now considered a regular character in | ||
`TextElements`. It's no longer possible to use escape sequences in | ||
`TextElements`. Please use `StringLiterals` instead, e.g. `{"\u00A0"}`. | ||
- The closing curly brace character (`}`) is not allowed in `TextElements` | ||
now. Please use `StringLiterals` instead: `{"}"}`. | ||
## fluent 0.9.1 (October 23, 2018) | ||
- Forbid messages with `null` values and no attributes. (#299) | ||
- Forbid messages with `null` values and no attributes. (#299) | ||
Fix a parser behavior which caused it to parse messages without values | ||
nor attributes as `"message-id": null`. This skewed the return values of | ||
`FluentBundle.hasMessage` which would report `true` for messages which | ||
were `null`. This, in turn, would break code which assumed | ||
`FluentBundle.getMessage` would always return non-`null` values if it was | ||
guarded by a call to `hasMessage` first. | ||
Fix a parser behavior which caused it to parse messages without values | ||
nor attributes as `"message-id": null`. This skewed the return values of | ||
`FluentBundle.hasMessage` which would report `true` for messages which | ||
were `null`. This, in turn, would break code which assumed | ||
`FluentBundle.getMessage` would always return non-`null` values if it was | ||
guarded by a call to `hasMessage` first. | ||
## fluent 0.9.0 (October 23, 2018) | ||
@@ -356,79 +357,78 @@ | ||
- Implement Fluent Syntax 0.7. (#287) | ||
- Implement Fluent Syntax 0.7. (#287) | ||
The major new feature of Syntax 0.7 is the relaxation of the indentation | ||
requirement for all non-text elements of patterns. It's finally possible | ||
to leave the closing brace of select expressions unindented: | ||
The major new feature of Syntax 0.7 is the relaxation of the indentation | ||
requirement for all non-text elements of patterns. It's finally possible | ||
to leave the closing brace of select expressions unindented: | ||
emails = { $unread_email_count -> | ||
[one] You have one unread email. | ||
*[other] You have { $unread_email_count } unread emails. | ||
} | ||
emails = { $unread_email_count -> | ||
[one] You have one unread email. | ||
*[other] You have { $unread_email_count } unread emails. | ||
} | ||
Consult the [changelog](https://github.com/projectfluent/fluent/releases/tag/v0.7.0) | ||
to learn about other changes in Syntax 0.7. | ||
Consult the [changelog](https://github.com/projectfluent/fluent/releases/tag/v0.7.0) | ||
to learn about other changes in Syntax 0.7. | ||
- Re-write the runtime parser. (#289) | ||
- Re-write the runtime parser. (#289) | ||
Syntax 0.7 was an opportunity to completely re-write the runtime parser, | ||
which was originally created in the pre-0.1 era of Fluent. It's now less | ||
than a half of the code size of the old parser and also slightly faster. | ||
Syntax 0.7 was an opportunity to completely re-write the runtime parser, | ||
which was originally created in the pre-0.1 era of Fluent. It's now less | ||
than a half of the code size of the old parser and also slightly faster. | ||
The parser takes an optimistic approach to parsing. It focuses on | ||
minimizing the number of false negatives at the expense of increasing the | ||
risk of false positives. In other words, it aims at parsing valid Fluent | ||
messages with a success rate of 100%, but it may also parse a few invalid | ||
messages which the reference parser would reject. The parser doesn't | ||
perform strict validation of the all productions of the Fluent grammar. | ||
It may thus produce entries which wouldn't make sense in the real world. | ||
For best results users are advised to validate translations with the | ||
`fluent-syntax` parser pre-runtime (e.g. by using Pontoon or | ||
`compare-locales`). | ||
The parser takes an optimistic approach to parsing. It focuses on | ||
minimizing the number of false negatives at the expense of increasing the | ||
risk of false positives. In other words, it aims at parsing valid Fluent | ||
messages with a success rate of 100%, but it may also parse a few invalid | ||
messages which the reference parser would reject. The parser doesn't | ||
perform strict validation of the all productions of the Fluent grammar. | ||
It may thus produce entries which wouldn't make sense in the real world. | ||
For best results users are advised to validate translations with the | ||
`fluent-syntax` parser pre-runtime (e.g. by using Pontoon or | ||
`compare-locales`). | ||
### Backward-incompatible changes | ||
- Variant keys can now be either numbers (as previously) or identifiers. | ||
Variant keys with spaces in them produce syntax errors, e.g. `[New York]`. | ||
- `CR` is not a valid EOL character anymore. Please use `LF` or `CRLF`. | ||
- `Tab` is not recognized as syntax whitespace. It can only be used in | ||
translation content. | ||
- Variant keys can now be either numbers (as previously) or identifiers. | ||
Variant keys with spaces in them produce syntax errors, e.g. `[New York]`. | ||
- `CR` is not a valid EOL character anymore. Please use `LF` or `CRLF`. | ||
- `Tab` is not recognized as syntax whitespace. It can only be used in | ||
translation content. | ||
## fluent 0.8.1 (September 27, 2018) | ||
- Expose `FluentResource` as an export. (#286) | ||
- Expose `FluentResource` as an export. (#286) | ||
`FluentResource` is a data structure representing a parsed Fluent document. | ||
It can be used to cache resources which can then be added to `FluentBundle` | ||
via the `addResource` method. To create a `FluentResource` given a string | ||
of Fluent translations, use the static `FluentResource.fromString` method. | ||
`FluentResource` is a data structure representing a parsed Fluent document. | ||
It can be used to cache resources which can then be added to `FluentBundle` | ||
via the `addResource` method. To create a `FluentResource` given a string | ||
of Fluent translations, use the static `FluentResource.fromString` method. | ||
```js | ||
let resource = FluentResource.fromString(text); | ||
bundle.addResource(resource); | ||
``` | ||
```js | ||
let resource = FluentResource.fromString(text); | ||
bundle.addResource(resource); | ||
``` | ||
The undocumented `_parse` export was also removed in favor of | ||
`FluentResource.fromString`. | ||
The undocumented `_parse` export was also removed in favor of | ||
`FluentResource.fromString`. | ||
## fluent 0.8.0 (August 20, 2018) | ||
- Rename `MessageContext` to `FluentBundle`. (#222) | ||
- Rename `MessageContext` to `FluentBundle`. (#222) | ||
The following renames have been made to the public API: | ||
The following renames have been made to the public API: | ||
- Rename `MessageContext` to `FluentBundle`. | ||
- Rename `MessageArgument` to `FluentType`. | ||
- Rename `MessageNumberArgument` to `FluentNumber`. | ||
- Rename `MessageDateTimeArgument` to `FluentDateTime`. | ||
- Rename `MessageContext` to `FluentBundle`. | ||
- Rename `MessageArgument` to `FluentType`. | ||
- Rename `MessageNumberArgument` to `FluentNumber`. | ||
- Rename `MessageDateTimeArgument` to `FluentDateTime`. | ||
- Move `mapContext*` functions to [`fluent-sequence`][]. (#273) | ||
- Move `mapContext*` functions to [`fluent-sequence`][]. (#273) | ||
The `mapContextSync` and `mapContextAsync` functions previously exported | ||
by the `fluent` package have been moved to the new [`fluent-sequence`][] | ||
package. [`fluent-sequence`][] 0.1.0 corresponds to the exact | ||
implementation of these functions from `fluent` 0.7.0. | ||
The `mapContextSync` and `mapContextAsync` functions previously exported | ||
by the `fluent` package have been moved to the new [`fluent-sequence`][] | ||
package. [`fluent-sequence`][] 0.1.0 corresponds to the exact | ||
implementation of these functions from `fluent` 0.7.0. | ||
In later versions of [`fluent-sequence`][], these functions are called | ||
`mapBundleSync` and `mapBundleAsync`. | ||
In later versions of [`fluent-sequence`][], these functions are called | ||
`mapBundleSync` and `mapBundleAsync`. | ||
@@ -439,226 +439,223 @@ [`fluent-sequence`]: https://www.npmjs.com/package/fluent-sequence | ||
- Implement support for Fluent Syntax 0.6. | ||
- Implement support for Fluent Syntax 0.6. | ||
Syntax 0.6 keeps the syntax unchanged and makes many small changes to the | ||
previousl underspecified areas of the spec. The runtime parser now | ||
supports Unicode escapes and properly trims whitespace in TextElements. | ||
Syntax 0.6 keeps the syntax unchanged and makes many small changes to the | ||
previousl underspecified areas of the spec. The runtime parser now | ||
supports Unicode escapes and properly trims whitespace in TextElements. | ||
- Add `FluentResource`. (#244) | ||
- Add `FluentResource`. (#244) | ||
`FluentResource` is a class representing a parsed Fluent document. It was | ||
added with caching in mind. It's now possible to parse a Fluent document | ||
inton an instance of `FluentResouce` once and use it to construct new | ||
`MessageContexts`. For this end, `MessageContext` now has the | ||
`addResource` method which takes an instance of `FluentResource`. | ||
`FluentResource` is a class representing a parsed Fluent document. It was | ||
added with caching in mind. It's now possible to parse a Fluent document | ||
inton an instance of `FluentResouce` once and use it to construct new | ||
`MessageContexts`. For this end, `MessageContext` now has the | ||
`addResource` method which takes an instance of `FluentResource`. | ||
- Add the `transform` option to `MessageContext`. (#213) | ||
- Add the `transform` option to `MessageContext`. (#213) | ||
`MessageContext` now accepts a new option, `transform`, which may be a | ||
function. If passed it will be used to transform the string parts of | ||
patterns. This may be used to implement programmatic transformations of | ||
translations, e.g. to create pseudo-localizations. | ||
`MessageContext` now accepts a new option, `transform`, which may be a | ||
function. If passed it will be used to transform the string parts of | ||
patterns. This may be used to implement programmatic transformations of | ||
translations, e.g. to create pseudo-localizations. | ||
- Drop support for IE and old evergreen browsers. (#133) | ||
- Drop support for IE and old evergreen browsers. (#133) | ||
Currently supported are: Firefox 52+, Chrome 55+, Edge 15+, Safari 10.1+, | ||
iOS Safari 10.3+ and node 8.9+. | ||
Currently supported are: Firefox 52+, Chrome 55+, Edge 15+, Safari 10.1+, | ||
iOS Safari 10.3+ and node 8.9+. | ||
- Move `CachedSyncIterable` and `CachedAsyncIterable` to a dependency. | ||
- Move `CachedSyncIterable` and `CachedAsyncIterable` to a dependency. | ||
They are now available from the `cached-iterable` package. `fluent` | ||
depends on it for running tests. | ||
They are now available from the `cached-iterable` package. `fluent` | ||
depends on it for running tests. | ||
## fluent 0.6.4 (April 11, 2018) | ||
- Minor optimization to bidirectionality isolation | ||
- Added error logging when attempting an already registered message id | ||
- Minor optimization to bidirectionality isolation | ||
- Added error logging when attempting an already registered message id | ||
## fluent 0.6.3 (February 9, 2018) | ||
- Update sinon to 4.2.2 | ||
- Update sinon to 4.2.2 | ||
## fluent 0.6.2 (February 8, 2018) | ||
- Correctly parse empty comment lines. (#149) | ||
- Forbid null attribute and variant values. (part of #150) | ||
- Correctly parse empty comment lines. (#149) | ||
- Forbid null attribute and variant values. (part of #150) | ||
## fluent 0.6.0 (January 31, 2018) | ||
- Implement Fluent Syntax 0.5. | ||
- Implement Fluent Syntax 0.5. | ||
- Add support for terms. | ||
- Add support for `#`, `##` and `###` comments. | ||
- Remove support for tags. | ||
- Add support for `=` after the identifier in message and term | ||
defintions. | ||
- Forbid newlines in string expressions. | ||
- Allow trailing comma in call expression argument lists. | ||
- Add support for terms. | ||
- Add support for `#`, `##` and `###` comments. | ||
- Remove support for tags. | ||
- Add support for `=` after the identifier in message and term | ||
defintions. | ||
- Forbid newlines in string expressions. | ||
- Allow trailing comma in call expression argument lists. | ||
In fluent 0.6.x the new Syntax 0.5 is supported alongside the old Syntax | ||
0.4. This should make migrations easier. The parser will correctly parse | ||
Syntax 0.4 comments (prefixed with `//`), sections and message | ||
definitions without the `=` after the identifier. The one exception are | ||
tags which are no longer supported. Please use attributed defined on | ||
terms instead. | ||
In fluent 0.6.x the new Syntax 0.5 is supported alongside the old Syntax | ||
0.4. This should make migrations easier. The parser will correctly parse | ||
Syntax 0.4 comments (prefixed with `//`), sections and message | ||
definitions without the `=` after the identifier. The one exception are | ||
tags which are no longer supported. Please use attributed defined on | ||
terms instead. | ||
- Add `mapContextAsync`. (#125) | ||
- Add `mapContextAsync`. (#125) | ||
This is the async counterpart to mapContextSync. Given an async iterable | ||
of `MessageContext` instances and an array of ids (or a single id), it | ||
maps each identifier to the first `MessageContext` which contains the | ||
message for it. | ||
This is the async counterpart to mapContextSync. Given an async iterable | ||
of `MessageContext` instances and an array of ids (or a single id), it | ||
maps each identifier to the first `MessageContext` which contains the | ||
message for it. | ||
An ordered interable of `MessageContext` instances can represent the | ||
current negotiated fallback chain of languages. This iterable can be used | ||
to find the best existing translation for a given identifier. | ||
An ordered interable of `MessageContext` instances can represent the | ||
current negotiated fallback chain of languages. This iterable can be used | ||
to find the best existing translation for a given identifier. | ||
The iterable of `MessageContexts` can now be async, allowing code like | ||
this: | ||
The iterable of `MessageContexts` can now be async, allowing code like | ||
this: | ||
```js | ||
async formatString(id, args) { | ||
const bundle = await mapContextAsync(bundles, id); | ||
```js | ||
async formatString(id, args) { | ||
const bundle = await mapContextAsync(bundles, id); | ||
if (bundle === null) { | ||
return id; | ||
} | ||
if (bundle === null) { | ||
return id; | ||
} | ||
const msg = bundle.getMessage(id); | ||
return bundle.format(msg, args); | ||
} | ||
``` | ||
const msg = bundle.getMessage(id); | ||
return bundle.format(msg, args); | ||
} | ||
``` | ||
The iterable of `MessageContexts` should always be wrapped in | ||
`CachedIterable` to optimize subsequent calls to `mapContextSync` and | ||
`mapContextAsync`. | ||
The iterable of `MessageContexts` should always be wrapped in | ||
`CachedIterable` to optimize subsequent calls to `mapContextSync` and | ||
`mapContextAsync`. | ||
Because `mapContextAsync` uses asynchronous iteration you'll likely need | ||
the regenerator runtime provided by `babel-polyfill` to run the `compat` | ||
builds of `fluent`. | ||
Because `mapContextAsync` uses asynchronous iteration you'll likely need | ||
the regenerator runtime provided by `babel-polyfill` to run the `compat` | ||
builds of `fluent`. | ||
- Expose the `ftl` dedent helper. | ||
- Expose the `ftl` dedent helper. | ||
The `ftl` template literal tag can be used to conveniently include FTL | ||
snippets in other code. It strips the common indentation from the snippet | ||
allowing it to be indented on the level dictated by the current code | ||
indentation. | ||
The `ftl` template literal tag can be used to conveniently include FTL | ||
snippets in other code. It strips the common indentation from the snippet | ||
allowing it to be indented on the level dictated by the current code | ||
indentation. | ||
```js | ||
bundle.addMessages(ftl` | ||
foo = Foo | ||
bar = Bar | ||
); | ||
``` | ||
```js | ||
bundle.addMessages(ftl` | ||
foo = Foo | ||
bar = Bar | ||
); | ||
``` | ||
- Remove `MessageContext.formatToParts`. | ||
- Remove `MessageContext.formatToParts`. | ||
It's only use-case was passing React elements as arguments to | ||
translations which is now possible thanks to DOM overlays (#101). | ||
It's only use-case was passing React elements as arguments to | ||
translations which is now possible thanks to DOM overlays (#101). | ||
- Rename `FluentType.valueOf` to `FluentType.toString1. | ||
- Rename `FluentType.valueOf` to `FluentType.toString1. | ||
Without `MessageContext.formatToParts`, all use-cases for | ||
`FluentType.valueOf` boil down to stringification. | ||
Without `MessageContext.formatToParts`, all use-cases for | ||
`FluentType.valueOf` boil down to stringification. | ||
- Remove `FluentType.isTypeOf`. | ||
- Remove `FluentType.isTypeOf`. | ||
fluent-react's markup overlays (#101) removed the dependency on fluent's | ||
`FluentType` which was hardcoded as an import from fluent/compat. Without | ||
this dependency all imports from fluent are in the hands of developers | ||
again and they can decide to use the ES2015+ or the compat builds as they | ||
wish. As long as they do it consistently, regular instanceof checks will | ||
work well. | ||
fluent-react's markup overlays (#101) removed the dependency on fluent's | ||
`FluentType` which was hardcoded as an import from fluent/compat. Without | ||
this dependency all imports from fluent are in the hands of developers | ||
again and they can decide to use the ES2015+ or the compat builds as they | ||
wish. As long as they do it consistently, regular instanceof checks will | ||
work well. | ||
## fluent 0.4.2 (November 27, 2017) | ||
- Add touchNext to CachedIterable. | ||
- Add touchNext to CachedIterable. | ||
This allows the user of CachedIterable to trigger construction of an | ||
element yielded from the generator early. | ||
This allows the user of CachedIterable to trigger construction of an | ||
element yielded from the generator early. | ||
- Add the static FluentType.isTypeOf method. | ||
- Add the static FluentType.isTypeOf method. | ||
In some cases, bundlers such as Webpack would break the instanceof | ||
FluentType check. The new FluentType.isTypeOf static method can be used | ||
instead to guarantee the proper behavior. | ||
In some cases, bundlers such as Webpack would break the instanceof | ||
FluentType check. The new FluentType.isTypeOf static method can be used | ||
instead to guarantee the proper behavior. | ||
- Catch errors thrown by Intl formatters. | ||
- Catch errors thrown by Intl formatters. | ||
## fluent 0.4.1 (June 22, 2017) | ||
- Introduce mapContextSync and CachedIterable. | ||
- Introduce mapContextSync and CachedIterable. | ||
An ordered iterable of MessageContext instances can represent the | ||
current negotiated fallback chain of languages. This iterable can be | ||
used to find the best existing translation for a given identifier. | ||
An ordered iterable of MessageContext instances can represent the | ||
current negotiated fallback chain of languages. This iterable can be | ||
used to find the best existing translation for a given identifier. | ||
The mapContext* methods can be used to find the first MessageContext in | ||
the given iterable which contains the translation with the given | ||
identifier. If the iterable is ordered according to the result of | ||
a language negotiation the returned MessageContext contains the best | ||
available translation. | ||
The mapContext\* methods can be used to find the first MessageContext in | ||
the given iterable which contains the translation with the given | ||
identifier. If the iterable is ordered according to the result of | ||
a language negotiation the returned MessageContext contains the best | ||
available translation. | ||
A simple function which formats translations based on the identifier | ||
might be implemented as follows: | ||
A simple function which formats translations based on the identifier | ||
might be implemented as follows: | ||
getString(id, args) { | ||
const bundle = mapContextSync(bundles, id); | ||
getString(id, args) { | ||
const bundle = mapContextSync(bundles, id); | ||
if (bundle === null) { | ||
return id; | ||
} | ||
if (bundle === null) { | ||
return id; | ||
} | ||
const msg = bundle.getMessage(id); | ||
return bundle.format(msg, args); | ||
} | ||
const msg = bundle.getMessage(id); | ||
return bundle.format(msg, args); | ||
} | ||
In order to pass an iterator to mapContext*, wrap it in CachedIterable. | ||
This allows multiple calls to mapContext* without advancing and | ||
eventually depleting the iterator. | ||
In order to pass an iterator to mapContext*, wrap it in CachedIterable. | ||
This allows multiple calls to mapContext* without advancing and | ||
eventually depleting the iterator. | ||
function *generateMessages() { | ||
// Some lazy logic for yielding MessageContexts. | ||
yield *[bundle1, bundle2]; | ||
} | ||
function *generateMessages() { | ||
// Some lazy logic for yielding MessageContexts. | ||
yield *[bundle1, bundle2]; | ||
} | ||
const bundles = new CachedIterable(generateMessages()); | ||
const bundle = mapContextSync(bundles, id); | ||
const bundles = new CachedIterable(generateMessages()); | ||
const bundle = mapContextSync(bundles, id); | ||
## fluent 0.4.0 (May 17th, 2017) | ||
- Added MessageContext.hasMessage and MessageContext.getMessage methods. | ||
- Added MessageContext.hasMessage and MessageContext.getMessage methods. | ||
Using the MessageContext.messages map for getting raw messages is | ||
deprecated now. Instead, use the two dedicated methods: hasMessage and | ||
getMessage. | ||
Using the MessageContext.messages map for getting raw messages is | ||
deprecated now. Instead, use the two dedicated methods: hasMessage and | ||
getMessage. | ||
Before: | ||
Before: | ||
const msg = bundle.messages.get(id); | ||
const txt = bundle.format(msg); | ||
const msg = bundle.messages.get(id); | ||
const txt = bundle.format(msg); | ||
Now: | ||
Now: | ||
const msg = bundle.getMessage(id); | ||
const txt = bundle.format(msg); | ||
const msg = bundle.getMessage(id); | ||
const txt = bundle.format(msg); | ||
- The compat build is now transpiled using rollup-plugin-babel. | ||
- The compat build is now transpiled using rollup-plugin-babel. | ||
This ensures that the "use strict" pragma is scoped to the UMD wrapper. It | ||
also correctly parses the top-level "this" keyword (which the previous | ||
setup turned into "undefined"). | ||
This ensures that the "use strict" pragma is scoped to the UMD wrapper. It | ||
also correctly parses the top-level "this" keyword (which the previous | ||
setup turned into "undefined"). | ||
## fluent 0.3.1 | ||
- MessageContext takes one locale (a string) or an array of locales. | ||
- Add the "module" field to package.json for ES modules-compatible bundlers. | ||
- MessageContext takes one locale (a string) or an array of locales. | ||
- Add the "module" field to package.json for ES modules-compatible bundlers. | ||
## fluent 0.3.0 | ||
- Support Fluent Syntax 0.3 | ||
- Support Fluent Syntax 0.3 | ||
Added support for tags and indented multiline text. Removed quoted values. | ||
Added support for tags and indented multiline text. Removed quoted values. | ||
@@ -669,47 +666,47 @@ ## fluent 0.2.2 | ||
- (ef99a62) Remove the custom `Intl.PluralRules` polyfill | ||
- (ef99a62) Remove the custom `Intl.PluralRules` polyfill | ||
You'll need to provide your own polyfill or use `fluent-intl-polyfill`. | ||
You'll need to provide your own polyfill or use `fluent-intl-polyfill`. | ||
- (1a4f2a8) Make fluent and fluent-syntax separate packages | ||
- (1a4f2a8) Make fluent and fluent-syntax separate packages | ||
Install the `fluent-syntax` package to use the AST parser. | ||
Install the `fluent-syntax` package to use the AST parser. | ||
### New features | ||
- (73fbab8) Add `MessageContext.formatToParts` | ||
- (2f51e27) Export `FluentNumber` as `MessageArgument` | ||
- (de01c8b) Provide a compat version using babel-preset-latest | ||
- (73fbab8) Add `MessageContext.formatToParts` | ||
- (2f51e27) Export `FluentNumber` as `MessageArgument` | ||
- (de01c8b) Provide a compat version using babel-preset-latest | ||
Use it by importing from `fluent/compat' | ||
Use it by importing from `fluent/compat' | ||
### Other | ||
- (44fa872) Remove a special case for `FluentNumber` in `SelectExpression` | ||
- (7dfa787) Remove namespaces from keywords | ||
- (2fff487) Use `FluentNumber`'s value when matching `FluentKeywords` | ||
- (b4bcbdd) Remove tests which were causing parsing errors | ||
- (0f35313) Name the AMD module 'fluent' | ||
- (44fa872) Remove a special case for `FluentNumber` in `SelectExpression` | ||
- (7dfa787) Remove namespaces from keywords | ||
- (2fff487) Use `FluentNumber`'s value when matching `FluentKeywords` | ||
- (b4bcbdd) Remove tests which were causing parsing errors | ||
- (0f35313) Name the AMD module 'fluent' | ||
## fluent 0.2.1 | ||
- (d247e5d) npm install fluent | ||
- (d00fe3a) Remove `JunkEntries` from the RuntimeParser | ||
- (d247e5d) npm install fluent | ||
- (d00fe3a) Remove `JunkEntries` from the RuntimeParser | ||
## fluent 0.2.0 | ||
- (1f86c8f) Update the AST parser to Syntax 0.2 | ||
- (679ca3e) Update the Runtime parser to Syntax 0.2 | ||
- (d3681d7) Update the resolver to Syntax 0.2. | ||
- (bfea90e) Rename `Entity` to `Message` | ||
- (5efd0f9) Remove `FTLList` | ||
- (282cccb) Add `JunkEntry` to AST parser | ||
- (a78a32a) Add `lineNumber` and `columnNumber` to SyntaxErrors | ||
- (e0245f4) Always print JSON in tools/parse | ||
- (5d788b7) Move the AST parser to src/syntax | ||
- (1f86c8f) Update the AST parser to Syntax 0.2 | ||
- (679ca3e) Update the Runtime parser to Syntax 0.2 | ||
- (d3681d7) Update the resolver to Syntax 0.2. | ||
- (bfea90e) Rename `Entity` to `Message` | ||
- (5efd0f9) Remove `FTLList` | ||
- (282cccb) Add `JunkEntry` to AST parser | ||
- (a78a32a) Add `lineNumber` and `columnNumber` to SyntaxErrors | ||
- (e0245f4) Always print JSON in tools/parse | ||
- (5d788b7) Move the AST parser to src/syntax | ||
## fluent 0.1.0 | ||
- (0d38714) Fluent.js 0.1 | ||
- (0d38714) Fluent.js 0.1 | ||
The initial release based on l20n.js c3e35c4. | ||
The initial release based on l20n.js c3e35c4. |
@@ -1,2 +0,7 @@ | ||
export declare type Message = { | ||
/** | ||
* Raw messages are `{value, attributes}` shapes containing translation units | ||
* called `Patterns`. `Patterns` are implementation-specific; they should be | ||
* treated as black boxes and formatted with `FluentBundle.formatPattern`. | ||
*/ | ||
export type Message = { | ||
id: string; | ||
@@ -6,3 +11,3 @@ value: Pattern | null; | ||
}; | ||
export declare type Term = { | ||
export type Term = { | ||
id: string; | ||
@@ -12,7 +17,7 @@ value: Pattern; | ||
}; | ||
export declare type Pattern = string | ComplexPattern; | ||
export declare type ComplexPattern = Array<PatternElement>; | ||
export declare type PatternElement = string | Expression; | ||
export declare type Expression = SelectExpression | VariableReference | TermReference | MessageReference | FunctionReference | Literal; | ||
export declare type SelectExpression = { | ||
export type Pattern = string | ComplexPattern; | ||
export type ComplexPattern = Array<PatternElement>; | ||
export type PatternElement = string | Expression; | ||
export type Expression = SelectExpression | VariableReference | TermReference | MessageReference | FunctionReference | Literal; | ||
export type SelectExpression = { | ||
type: "select"; | ||
@@ -23,7 +28,7 @@ selector: Expression; | ||
}; | ||
export declare type VariableReference = { | ||
export type VariableReference = { | ||
type: "var"; | ||
name: string; | ||
}; | ||
export declare type TermReference = { | ||
export type TermReference = { | ||
type: "term"; | ||
@@ -34,3 +39,3 @@ name: string; | ||
}; | ||
export declare type MessageReference = { | ||
export type MessageReference = { | ||
type: "mesg"; | ||
@@ -40,3 +45,3 @@ name: string; | ||
}; | ||
export declare type FunctionReference = { | ||
export type FunctionReference = { | ||
type: "func"; | ||
@@ -46,7 +51,7 @@ name: string; | ||
}; | ||
export declare type Variant = { | ||
export type Variant = { | ||
key: Literal; | ||
value: Pattern; | ||
}; | ||
export declare type NamedArgument = { | ||
export type NamedArgument = { | ||
type: "narg"; | ||
@@ -56,8 +61,8 @@ name: string; | ||
}; | ||
export declare type Literal = StringLiteral | NumberLiteral; | ||
export declare type StringLiteral = { | ||
export type Literal = StringLiteral | NumberLiteral; | ||
export type StringLiteral = { | ||
type: "str"; | ||
value: string; | ||
}; | ||
export declare type NumberLiteral = { | ||
export type NumberLiteral = { | ||
type: "num"; | ||
@@ -64,0 +69,0 @@ value: number; |
@@ -13,3 +13,3 @@ /** | ||
*/ | ||
import { FluentNone, FluentNumber, FluentDateTime } from "./types.js"; | ||
import { FluentNone, FluentNumber, FluentDateTime, } from "./types.js"; | ||
function values(opts, allowed) { | ||
@@ -70,3 +70,3 @@ const unwrapped = Object.create(null); | ||
...arg.opts, | ||
...values(opts, NUMBER_ALLOWED) | ||
...values(opts, NUMBER_ALLOWED), | ||
}); | ||
@@ -76,3 +76,3 @@ } | ||
return new FluentNumber(arg.valueOf(), { | ||
...values(opts, NUMBER_ALLOWED) | ||
...values(opts, NUMBER_ALLOWED), | ||
}); | ||
@@ -140,3 +140,3 @@ } | ||
...arg.opts, | ||
...values(opts, DATETIME_ALLOWED) | ||
...values(opts, DATETIME_ALLOWED), | ||
}); | ||
@@ -146,3 +146,3 @@ } | ||
return new FluentDateTime(arg.valueOf(), { | ||
...values(opts, DATETIME_ALLOWED) | ||
...values(opts, DATETIME_ALLOWED), | ||
}); | ||
@@ -149,0 +149,0 @@ } |
@@ -5,5 +5,4 @@ import { FluentResource } from "./resource.js"; | ||
import { IntlCache } from "./memoizer.js"; | ||
export declare type TextTransform = (text: string) => string; | ||
declare type NativeValue = string | number | Date; | ||
export declare type FluentVariable = FluentValue | NativeValue; | ||
export type TextTransform = (text: string) => string; | ||
export type FluentVariable = FluentValue | string | number | Date; | ||
/** | ||
@@ -15,7 +14,13 @@ * Message bundles are single-language stores of translation resources. They are | ||
locales: Array<string>; | ||
/** @ignore */ | ||
_terms: Map<string, Term>; | ||
/** @ignore */ | ||
_messages: Map<string, Message>; | ||
/** @ignore */ | ||
_functions: Record<string, FluentFunction>; | ||
/** @ignore */ | ||
_useIsolating: boolean; | ||
/** @ignore */ | ||
_transform: TextTransform; | ||
/** @ignore */ | ||
_intls: IntlCache; | ||
@@ -25,31 +30,29 @@ /** | ||
* | ||
* The `locales` argument is used to instantiate `Intl` formatters used by | ||
* translations. The `options` object can be used to configure the bundle. | ||
* @example | ||
* ```js | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* | ||
* Examples: | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* ``` | ||
* | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* | ||
* Available options: | ||
* | ||
* - `functions` - an object of additional functions available to | ||
* translations as builtins. | ||
* | ||
* - `useIsolating` - boolean specifying whether to use Unicode isolation | ||
* marks (FSI, PDI) for bidi interpolations. Default: `true`. | ||
* | ||
* - `transform` - a function used to transform string parts of patterns. | ||
* @param locales - Used to instantiate `Intl` formatters used by translations. | ||
* @param options - Optional configuration for the bundle. | ||
*/ | ||
constructor(locales: string | Array<string>, { functions, useIsolating, transform }?: { | ||
constructor(locales: string | Array<string>, { functions, useIsolating, transform, }?: { | ||
/** Additional functions available to translations as builtins. */ | ||
functions?: Record<string, FluentFunction>; | ||
/** | ||
* Whether to use Unicode isolation marks (FSI, PDI) for bidi interpolations. | ||
* | ||
* Default: `true`. | ||
*/ | ||
useIsolating?: boolean; | ||
/** A function used to transform string parts of patterns. */ | ||
transform?: TextTransform; | ||
@@ -76,18 +79,20 @@ }); | ||
* | ||
* The translation resource must be an instance of `FluentResource`. | ||
* @example | ||
* ```js | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* ``` | ||
* | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* | ||
* Available options: | ||
* | ||
* - `allowOverrides` - boolean specifying whether it's allowed to override | ||
* an existing message or term with a new value. Default: `false`. | ||
* | ||
* @param res - FluentResource object. | ||
* @param options | ||
* @param res | ||
* @param options | ||
*/ | ||
addResource(res: FluentResource, { allowOverrides }?: { | ||
addResource(res: FluentResource, { allowOverrides, }?: { | ||
/** | ||
* Boolean specifying whether it's allowed to override | ||
* an existing message or term with a new value. | ||
* | ||
* Default: `false`. | ||
*/ | ||
allowOverrides?: boolean; | ||
@@ -106,20 +111,22 @@ }): Array<Error>; | ||
* | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* @example | ||
* ```js | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* ``` | ||
*/ | ||
formatPattern(pattern: Pattern, args?: Record<string, FluentVariable> | null, errors?: Array<Error> | null): string; | ||
} | ||
export {}; |
@@ -14,30 +14,23 @@ import { resolveComplexPattern } from "./resolver.js"; | ||
* | ||
* The `locales` argument is used to instantiate `Intl` formatters used by | ||
* translations. The `options` object can be used to configure the bundle. | ||
* @example | ||
* ```js | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* | ||
* Examples: | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* ``` | ||
* | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* | ||
* Available options: | ||
* | ||
* - `functions` - an object of additional functions available to | ||
* translations as builtins. | ||
* | ||
* - `useIsolating` - boolean specifying whether to use Unicode isolation | ||
* marks (FSI, PDI) for bidi interpolations. Default: `true`. | ||
* | ||
* - `transform` - a function used to transform string parts of patterns. | ||
* @param locales - Used to instantiate `Intl` formatters used by translations. | ||
* @param options - Optional configuration for the bundle. | ||
*/ | ||
constructor(locales, { functions, useIsolating = true, transform = (v) => v } = {}) { | ||
constructor(locales, { functions, useIsolating = true, transform = (v) => v, } = {}) { | ||
/** @ignore */ | ||
this._terms = new Map(); | ||
/** @ignore */ | ||
this._messages = new Map(); | ||
@@ -48,3 +41,3 @@ this.locales = Array.isArray(locales) ? locales : [locales]; | ||
DATETIME, | ||
...functions | ||
...functions, | ||
}; | ||
@@ -78,18 +71,14 @@ this._useIsolating = useIsolating; | ||
* | ||
* The translation resource must be an instance of `FluentResource`. | ||
* @example | ||
* ```js | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* ``` | ||
* | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* | ||
* Available options: | ||
* | ||
* - `allowOverrides` - boolean specifying whether it's allowed to override | ||
* an existing message or term with a new value. Default: `false`. | ||
* | ||
* @param res - FluentResource object. | ||
* @param options | ||
* @param res | ||
* @param options | ||
*/ | ||
addResource(res, { allowOverrides = false } = {}) { | ||
addResource(res, { allowOverrides = false, } = {}) { | ||
const errors = []; | ||
@@ -128,17 +117,20 @@ for (let i = 0; i < res.body.length; i++) { | ||
* | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* @example | ||
* ```js | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* ``` | ||
*/ | ||
@@ -145,0 +137,0 @@ formatPattern(pattern, args = null, errors = null) { |
@@ -9,4 +9,6 @@ /** | ||
*/ | ||
export type { Message } from "./ast.js"; | ||
export { FluentBundle, FluentVariable, TextTransform } from "./bundle.js"; | ||
export { FluentResource } from "./resource.js"; | ||
export { FluentValue, FluentType, FluentFunction, FluentNone, FluentNumber, FluentDateTime } from "./types.js"; | ||
export type { Scope } from "./scope.js"; | ||
export { FluentValue, FluentType, FluentFunction, FluentNone, FluentNumber, FluentDateTime, } from "./types.js"; |
@@ -11,2 +11,2 @@ /** | ||
export { FluentResource } from "./resource.js"; | ||
export { FluentType, FluentNone, FluentNumber, FluentDateTime } from "./types.js"; | ||
export { FluentType, FluentNone, FluentNumber, FluentDateTime, } from "./types.js"; |
@@ -1,2 +0,2 @@ | ||
export declare type IntlCache = Map<typeof Intl.NumberFormat | typeof Intl.DateTimeFormat | typeof Intl.PluralRules, Record<string, Intl.NumberFormat | Intl.DateTimeFormat | Intl.PluralRules>>; | ||
export type IntlCache = Map<typeof Intl.NumberFormat | typeof Intl.DateTimeFormat | typeof Intl.PluralRules, Record<string, Intl.NumberFormat | Intl.DateTimeFormat | Intl.PluralRules>>; | ||
export declare function getMemoizerForLocale(locales: string | string[]): IntlCache; |
@@ -27,2 +27,3 @@ /** | ||
import { ComplexPattern } from "./ast.js"; | ||
/** Resolve a pattern (a complex string with placeables). */ | ||
export declare function resolveComplexPattern(scope: Scope, ptn: ComplexPattern): FluentValue; |
@@ -25,11 +25,13 @@ /* global Intl */ | ||
*/ | ||
import { FluentType, FluentNone, FluentNumber, FluentDateTime } from "./types.js"; | ||
// The maximum number of placeables which can be expanded in a single call to | ||
// `formatPattern`. The limit protects against the Billion Laughs and Quadratic | ||
// Blowup attacks. See https://msdn.microsoft.com/en-us/magazine/ee335713.aspx. | ||
import { FluentType, FluentNone, FluentNumber, FluentDateTime, } from "./types.js"; | ||
/** | ||
* The maximum number of placeables which can be expanded in a single call to | ||
* `formatPattern`. The limit protects against the Billion Laughs and Quadratic | ||
* Blowup attacks. See https://msdn.microsoft.com/en-us/magazine/ee335713.aspx. | ||
*/ | ||
const MAX_PLACEABLES = 100; | ||
// Unicode bidi isolation characters. | ||
/** Unicode bidi isolation characters. */ | ||
const FSI = "\u2068"; | ||
const PDI = "\u2069"; | ||
// Helper: match a variant key to the given selector. | ||
/** Helper: match a variant key to the given selector. */ | ||
function match(scope, selector, key) { | ||
@@ -56,3 +58,3 @@ if (key === selector) { | ||
} | ||
// Helper: resolve the default variant from a list of variants. | ||
/** Helper: resolve the default variant from a list of variants. */ | ||
function getDefault(scope, variants, star) { | ||
@@ -65,3 +67,3 @@ if (variants[star]) { | ||
} | ||
// Helper: resolve arguments to a call expression. | ||
/** Helper: resolve arguments to a call expression. */ | ||
function getArguments(scope, args) { | ||
@@ -80,3 +82,3 @@ const positional = []; | ||
} | ||
// Resolve an expression to a Fluent type. | ||
/** Resolve an expression to a Fluent type. */ | ||
function resolveExpression(scope, expr) { | ||
@@ -88,3 +90,3 @@ switch (expr.type) { | ||
return new FluentNumber(expr.value, { | ||
minimumFractionDigits: expr.precision | ||
minimumFractionDigits: expr.precision, | ||
}); | ||
@@ -105,3 +107,3 @@ case "var": | ||
} | ||
// Resolve a reference to a variable. | ||
/** Resolve a reference to a variable. */ | ||
function resolveVariableReference(scope, { name }) { | ||
@@ -118,4 +120,4 @@ let arg; | ||
} | ||
else if (scope.args | ||
&& Object.prototype.hasOwnProperty.call(scope.args, name)) { | ||
else if (scope.args && | ||
Object.prototype.hasOwnProperty.call(scope.args, name)) { | ||
// We're in the top-level Pattern or inside a MessageReference. Missing | ||
@@ -149,3 +151,3 @@ // variables references produce ReferenceErrors. | ||
} | ||
// Resolve a reference to another message. | ||
/** Resolve a reference to another message. */ | ||
function resolveMessageReference(scope, { name, attr }) { | ||
@@ -171,3 +173,3 @@ const message = scope.bundle._messages.get(name); | ||
} | ||
// Resolve a call to a Term with key-value arguments. | ||
/** Resolve a call to a Term with key-value arguments. */ | ||
function resolveTermReference(scope, { name, attr, args }) { | ||
@@ -197,3 +199,3 @@ const id = `-${name}`; | ||
} | ||
// Resolve a call to a Function with positional and key-value arguments. | ||
/** Resolve a call to a Function with positional and key-value arguments. */ | ||
function resolveFunctionReference(scope, { name, args }) { | ||
@@ -220,3 +222,3 @@ // Some functions are built-in. Others may be provided by the runtime via | ||
} | ||
// Resolve a select expression to the member object. | ||
/** Resolve a select expression to the member object. */ | ||
function resolveSelectExpression(scope, { selector, variants, star }) { | ||
@@ -236,3 +238,3 @@ let sel = resolveExpression(scope, selector); | ||
} | ||
// Resolve a pattern (a complex string with placeables). | ||
/** Resolve a pattern (a complex string with placeables). */ | ||
export function resolveComplexPattern(scope, ptn) { | ||
@@ -275,4 +277,6 @@ if (scope.dirty.has(ptn)) { | ||
} | ||
// Resolve a simple or a complex Pattern to a FluentString (which is really the | ||
// string primitive). | ||
/** | ||
* Resolve a simple or a complex Pattern to a FluentString | ||
* (which is really the string primitive). | ||
*/ | ||
function resolvePattern(scope, value) { | ||
@@ -279,0 +283,0 @@ // Resolve a simple pattern. |
@@ -6,4 +6,5 @@ import { Message, Term } from "./ast.js"; | ||
export declare class FluentResource { | ||
/** @ignore */ | ||
body: Array<Message | Term>; | ||
constructor(source: string); | ||
} |
@@ -229,3 +229,3 @@ // This regex is used to iterate through the beginnings of messages and terms. | ||
selector, | ||
...variants | ||
...variants, | ||
}; | ||
@@ -262,3 +262,3 @@ } | ||
attr, | ||
args: [] | ||
args: [], | ||
}; | ||
@@ -295,3 +295,3 @@ } | ||
name: expr.name, | ||
value: parseLiteral() | ||
value: parseLiteral(), | ||
}; | ||
@@ -334,3 +334,3 @@ } | ||
type: "str", | ||
value: match1(RE_IDENTIFIER) | ||
value: match1(RE_IDENTIFIER), | ||
}; | ||
@@ -356,3 +356,3 @@ } | ||
value: parseFloat(value), | ||
precision | ||
precision, | ||
}; | ||
@@ -385,7 +385,7 @@ } | ||
return codepoint <= 0xd7ff || 0xe000 <= codepoint | ||
// It's a Unicode scalar value. | ||
? String.fromCodePoint(codepoint) | ||
// Lonely surrogates can cause trouble when the parsing result is | ||
// saved using UTF-8. Use U+FFFD REPLACEMENT CHARACTER instead. | ||
: "�"; | ||
? // It's a Unicode scalar value. | ||
String.fromCodePoint(codepoint) | ||
: // Lonely surrogates can cause trouble when the parsing result is | ||
// saved using UTF-8. Use U+FFFD REPLACEMENT CHARACTER instead. | ||
"�"; | ||
} | ||
@@ -392,0 +392,0 @@ throw new SyntaxError("Unknown escape sequence"); |
@@ -10,9 +10,15 @@ import { FluentBundle, FluentVariable } from "./bundle.js"; | ||
args: Record<string, FluentVariable> | null; | ||
/** The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. */ | ||
/** | ||
* The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. | ||
* @ignore | ||
*/ | ||
dirty: WeakSet<ComplexPattern>; | ||
/** A dict of parameters passed to a TermReference. */ | ||
params: Record<string, FluentVariable> | null; | ||
/** The running count of placeables resolved so far. Used to detect the | ||
* Billion Laughs and Quadratic Blowup attacks. */ | ||
/** | ||
* The running count of placeables resolved so far. | ||
* Used to detect the Billion Laughs and Quadratic Blowup attacks. | ||
* @ignore | ||
*/ | ||
placeables: number; | ||
@@ -19,0 +25,0 @@ constructor(bundle: FluentBundle, errors: Array<Error> | null, args: Record<string, FluentVariable> | null); |
export class Scope { | ||
constructor(bundle, errors, args) { | ||
/** The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. */ | ||
/** | ||
* The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. | ||
* @ignore | ||
*/ | ||
this.dirty = new WeakSet(); | ||
/** A dict of parameters passed to a TermReference. */ | ||
this.params = null; | ||
/** The running count of placeables resolved so far. Used to detect the | ||
* Billion Laughs and Quadratic Blowup attacks. */ | ||
/** | ||
* The running count of placeables resolved so far. | ||
* Used to detect the Billion Laughs and Quadratic Blowup attacks. | ||
* @ignore | ||
*/ | ||
this.placeables = 0; | ||
@@ -11,0 +17,0 @@ this.bundle = bundle; |
import { Scope } from "./scope.js"; | ||
export declare type FluentValue = FluentType<unknown> | string; | ||
export declare type FluentFunction = (positional: Array<FluentValue>, named: Record<string, FluentValue>) => FluentValue; | ||
export type FluentValue = FluentType<unknown> | string; | ||
export type FluentFunction = (positional: Array<FluentValue>, named: Record<string, FluentValue>) => FluentValue; | ||
/** | ||
@@ -5,0 +5,0 @@ * The `FluentType` class is the base of Fluent's type system. |
180
index.js
@@ -1,2 +0,2 @@ | ||
/* @fluent/bundle@0.17.1 */ | ||
/** @fluent/bundle@0.18.0 */ | ||
(function (global, factory) { | ||
@@ -118,10 +118,12 @@ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
/* global Intl */ | ||
// The maximum number of placeables which can be expanded in a single call to | ||
// `formatPattern`. The limit protects against the Billion Laughs and Quadratic | ||
// Blowup attacks. See https://msdn.microsoft.com/en-us/magazine/ee335713.aspx. | ||
/** | ||
* The maximum number of placeables which can be expanded in a single call to | ||
* `formatPattern`. The limit protects against the Billion Laughs and Quadratic | ||
* Blowup attacks. See https://msdn.microsoft.com/en-us/magazine/ee335713.aspx. | ||
*/ | ||
const MAX_PLACEABLES = 100; | ||
// Unicode bidi isolation characters. | ||
/** Unicode bidi isolation characters. */ | ||
const FSI = "\u2068"; | ||
const PDI = "\u2069"; | ||
// Helper: match a variant key to the given selector. | ||
/** Helper: match a variant key to the given selector. */ | ||
function match(scope, selector, key) { | ||
@@ -148,3 +150,3 @@ if (key === selector) { | ||
} | ||
// Helper: resolve the default variant from a list of variants. | ||
/** Helper: resolve the default variant from a list of variants. */ | ||
function getDefault(scope, variants, star) { | ||
@@ -157,3 +159,3 @@ if (variants[star]) { | ||
} | ||
// Helper: resolve arguments to a call expression. | ||
/** Helper: resolve arguments to a call expression. */ | ||
function getArguments(scope, args) { | ||
@@ -172,3 +174,3 @@ const positional = []; | ||
} | ||
// Resolve an expression to a Fluent type. | ||
/** Resolve an expression to a Fluent type. */ | ||
function resolveExpression(scope, expr) { | ||
@@ -180,3 +182,3 @@ switch (expr.type) { | ||
return new FluentNumber(expr.value, { | ||
minimumFractionDigits: expr.precision | ||
minimumFractionDigits: expr.precision, | ||
}); | ||
@@ -197,3 +199,3 @@ case "var": | ||
} | ||
// Resolve a reference to a variable. | ||
/** Resolve a reference to a variable. */ | ||
function resolveVariableReference(scope, { name }) { | ||
@@ -210,4 +212,4 @@ let arg; | ||
} | ||
else if (scope.args | ||
&& Object.prototype.hasOwnProperty.call(scope.args, name)) { | ||
else if (scope.args && | ||
Object.prototype.hasOwnProperty.call(scope.args, name)) { | ||
// We're in the top-level Pattern or inside a MessageReference. Missing | ||
@@ -241,3 +243,3 @@ // variables references produce ReferenceErrors. | ||
} | ||
// Resolve a reference to another message. | ||
/** Resolve a reference to another message. */ | ||
function resolveMessageReference(scope, { name, attr }) { | ||
@@ -263,3 +265,3 @@ const message = scope.bundle._messages.get(name); | ||
} | ||
// Resolve a call to a Term with key-value arguments. | ||
/** Resolve a call to a Term with key-value arguments. */ | ||
function resolveTermReference(scope, { name, attr, args }) { | ||
@@ -289,3 +291,3 @@ const id = `-${name}`; | ||
} | ||
// Resolve a call to a Function with positional and key-value arguments. | ||
/** Resolve a call to a Function with positional and key-value arguments. */ | ||
function resolveFunctionReference(scope, { name, args }) { | ||
@@ -312,3 +314,3 @@ // Some functions are built-in. Others may be provided by the runtime via | ||
} | ||
// Resolve a select expression to the member object. | ||
/** Resolve a select expression to the member object. */ | ||
function resolveSelectExpression(scope, { selector, variants, star }) { | ||
@@ -328,3 +330,3 @@ let sel = resolveExpression(scope, selector); | ||
} | ||
// Resolve a pattern (a complex string with placeables). | ||
/** Resolve a pattern (a complex string with placeables). */ | ||
function resolveComplexPattern(scope, ptn) { | ||
@@ -367,4 +369,6 @@ if (scope.dirty.has(ptn)) { | ||
} | ||
// Resolve a simple or a complex Pattern to a FluentString (which is really the | ||
// string primitive). | ||
/** | ||
* Resolve a simple or a complex Pattern to a FluentString | ||
* (which is really the string primitive). | ||
*/ | ||
function resolvePattern(scope, value) { | ||
@@ -380,9 +384,15 @@ // Resolve a simple pattern. | ||
constructor(bundle, errors, args) { | ||
/** The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. */ | ||
/** | ||
* The Set of patterns already encountered during this resolution. | ||
* Used to detect and prevent cyclic resolutions. | ||
* @ignore | ||
*/ | ||
this.dirty = new WeakSet(); | ||
/** A dict of parameters passed to a TermReference. */ | ||
this.params = null; | ||
/** The running count of placeables resolved so far. Used to detect the | ||
* Billion Laughs and Quadratic Blowup attacks. */ | ||
/** | ||
* The running count of placeables resolved so far. | ||
* Used to detect the Billion Laughs and Quadratic Blowup attacks. | ||
* @ignore | ||
*/ | ||
this.placeables = 0; | ||
@@ -480,3 +490,3 @@ this.bundle = bundle; | ||
...arg.opts, | ||
...values(opts, NUMBER_ALLOWED) | ||
...values(opts, NUMBER_ALLOWED), | ||
}); | ||
@@ -486,3 +496,3 @@ } | ||
return new FluentNumber(arg.valueOf(), { | ||
...values(opts, NUMBER_ALLOWED) | ||
...values(opts, NUMBER_ALLOWED), | ||
}); | ||
@@ -550,3 +560,3 @@ } | ||
...arg.opts, | ||
...values(opts, DATETIME_ALLOWED) | ||
...values(opts, DATETIME_ALLOWED), | ||
}); | ||
@@ -556,3 +566,3 @@ } | ||
return new FluentDateTime(arg.valueOf(), { | ||
...values(opts, DATETIME_ALLOWED) | ||
...values(opts, DATETIME_ALLOWED), | ||
}); | ||
@@ -582,30 +592,23 @@ } | ||
* | ||
* The `locales` argument is used to instantiate `Intl` formatters used by | ||
* translations. The `options` object can be used to configure the bundle. | ||
* @example | ||
* ```js | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* | ||
* Examples: | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(["en-US", "en"]); | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* ``` | ||
* | ||
* let bundle = new FluentBundle(locales, {useIsolating: false}); | ||
* | ||
* let bundle = new FluentBundle(locales, { | ||
* useIsolating: true, | ||
* functions: { | ||
* NODE_ENV: () => process.env.NODE_ENV | ||
* } | ||
* }); | ||
* | ||
* Available options: | ||
* | ||
* - `functions` - an object of additional functions available to | ||
* translations as builtins. | ||
* | ||
* - `useIsolating` - boolean specifying whether to use Unicode isolation | ||
* marks (FSI, PDI) for bidi interpolations. Default: `true`. | ||
* | ||
* - `transform` - a function used to transform string parts of patterns. | ||
* @param locales - Used to instantiate `Intl` formatters used by translations. | ||
* @param options - Optional configuration for the bundle. | ||
*/ | ||
constructor(locales, { functions, useIsolating = true, transform = (v) => v } = {}) { | ||
constructor(locales, { functions, useIsolating = true, transform = (v) => v, } = {}) { | ||
/** @ignore */ | ||
this._terms = new Map(); | ||
/** @ignore */ | ||
this._messages = new Map(); | ||
@@ -616,3 +619,3 @@ this.locales = Array.isArray(locales) ? locales : [locales]; | ||
DATETIME, | ||
...functions | ||
...functions, | ||
}; | ||
@@ -646,18 +649,14 @@ this._useIsolating = useIsolating; | ||
* | ||
* The translation resource must be an instance of `FluentResource`. | ||
* @example | ||
* ```js | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* ``` | ||
* | ||
* let res = new FluentResource("foo = Foo"); | ||
* bundle.addResource(res); | ||
* bundle.getMessage("foo"); | ||
* // → {value: .., attributes: {..}} | ||
* | ||
* Available options: | ||
* | ||
* - `allowOverrides` - boolean specifying whether it's allowed to override | ||
* an existing message or term with a new value. Default: `false`. | ||
* | ||
* @param res - FluentResource object. | ||
* @param options | ||
* @param res | ||
* @param options | ||
*/ | ||
addResource(res, { allowOverrides = false } = {}) { | ||
addResource(res, { allowOverrides = false, } = {}) { | ||
const errors = []; | ||
@@ -696,17 +695,20 @@ for (let i = 0; i < res.body.length; i++) { | ||
* | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* @example | ||
* ```js | ||
* let errors = []; | ||
* bundle.addResource( | ||
* new FluentResource("hello = Hello, {$name}!")); | ||
* | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* let hello = bundle.getMessage("hello"); | ||
* if (hello.value) { | ||
* bundle.formatPattern(hello.value, {name: "Jane"}, errors); | ||
* // Returns "Hello, Jane!" and `errors` is empty. | ||
* | ||
* If `errors` is omitted, the first encountered error will be thrown. | ||
* bundle.formatPattern(hello.value, undefined, errors); | ||
* // Returns "Hello, {$name}!" and `errors` is now: | ||
* // [<ReferenceError: Unknown variable: name>] | ||
* } | ||
* ``` | ||
*/ | ||
@@ -963,3 +965,3 @@ formatPattern(pattern, args = null, errors = null) { | ||
selector, | ||
...variants | ||
...variants, | ||
}; | ||
@@ -996,3 +998,3 @@ } | ||
attr, | ||
args: [] | ||
args: [], | ||
}; | ||
@@ -1029,3 +1031,3 @@ } | ||
name: expr.name, | ||
value: parseLiteral() | ||
value: parseLiteral(), | ||
}; | ||
@@ -1068,3 +1070,3 @@ } | ||
type: "str", | ||
value: match1(RE_IDENTIFIER) | ||
value: match1(RE_IDENTIFIER), | ||
}; | ||
@@ -1090,3 +1092,3 @@ } | ||
value: parseFloat(value), | ||
precision | ||
precision, | ||
}; | ||
@@ -1119,7 +1121,7 @@ } | ||
return codepoint <= 0xd7ff || 0xe000 <= codepoint | ||
// It's a Unicode scalar value. | ||
? String.fromCodePoint(codepoint) | ||
// Lonely surrogates can cause trouble when the parsing result is | ||
// saved using UTF-8. Use U+FFFD REPLACEMENT CHARACTER instead. | ||
: "�"; | ||
? // It's a Unicode scalar value. | ||
String.fromCodePoint(codepoint) | ||
: // Lonely surrogates can cause trouble when the parsing result is | ||
// saved using UTF-8. Use U+FFFD REPLACEMENT CHARACTER instead. | ||
"�"; | ||
} | ||
@@ -1186,4 +1188,2 @@ throw new SyntaxError("Unknown escape sequence"); | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
})); |
{ | ||
"name": "@fluent/bundle", | ||
"description": "Localization library for expressive translations.", | ||
"version": "0.17.1", | ||
"version": "0.18.0", | ||
"homepage": "https://projectfluent.org", | ||
@@ -48,3 +48,3 @@ "author": "Mozilla <l10n-drivers@mozilla.org>", | ||
"engines": { | ||
"node": ">=12.0.0", | ||
"node": ">=14.0.0", | ||
"npm": ">=7.0.0" | ||
@@ -51,0 +51,0 @@ }, |
@@ -6,5 +6,4 @@ # @fluent/bundle ![](https://github.com/projectfluent/fluent.js/workflows/test/badge.svg) | ||
[Project Fluent]: https://projectfluent.org | ||
[project fluent]: https://projectfluent.org | ||
## Installation | ||
@@ -18,3 +17,2 @@ | ||
## How to use | ||
@@ -26,3 +24,3 @@ | ||
```javascript | ||
import {FluentBundle, FluentResource} from "@fluent/bundle"; | ||
import { FluentBundle, FluentResource } from "@fluent/bundle"; | ||
@@ -37,3 +35,3 @@ let resource = new FluentResource(` | ||
if (errors.length) { | ||
// Syntax errors are per-message and don't break the whole resource | ||
// Syntax errors are per-message and don't break the whole resource | ||
} | ||
@@ -43,4 +41,4 @@ | ||
if (welcome.value) { | ||
bundle.formatPattern(welcome.value, {name: "Anna"}); | ||
// → "Welcome, Anna, to Foo 3000!" | ||
bundle.formatPattern(welcome.value, { name: "Anna" }); | ||
// → "Welcome, Anna, to Foo 3000!" | ||
} | ||
@@ -51,3 +49,2 @@ ``` | ||
## Compatibility | ||
@@ -57,12 +54,12 @@ | ||
- `Intl.DateTimeFormat` (standard, well-supported) | ||
- `Intl.NumberFormat` (standard, well-supported) | ||
- `Intl.PluralRules` (standard, new in ECMAScript 2018) | ||
- `Intl.DateTimeFormat` (standard, well-supported) | ||
- `Intl.NumberFormat` (standard, well-supported) | ||
- `Intl.PluralRules` (standard, new in ECMAScript 2018) | ||
`Intl.PluralRules` may already be available in some engines. In most cases, | ||
however, a polyfill will be required. We recommend [intl-pluralrules][]. | ||
`Intl.PluralRules` may already be available in some engines. In most cases, | ||
however, a polyfill will be required. We recommend [intl-pluralrules][]. | ||
```javascript | ||
import 'intl-pluralrules'; | ||
import {FluentBundle} from '@fluent/bundle'; | ||
import "intl-pluralrules"; | ||
import { FluentBundle } from "@fluent/bundle"; | ||
``` | ||
@@ -73,2 +70,2 @@ | ||
[intl-pluralrules]: https://www.npmjs.com/package/intl-pluralrules | ||
[Compatibility]: https://github.com/projectfluent/fluent.js/wiki/Compatibility | ||
[compatibility]: https://github.com/projectfluent/fluent.js/wiki/Compatibility |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2773
132050
64