├── .editorconfig
├── .gitignore
├── .npmrc
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs
└── index.md
├── elm.json
├── example.986e475a.js
├── example.986e475a.js.map
├── example
├── common
│ └── resources.js
├── elm
│ ├── Example.elm
│ ├── example.js
│ └── index.html
├── svelte
│ ├── public
│ │ ├── global.css
│ │ └── index.html
│ └── src
│ │ ├── App.svelte
│ │ └── main.js
└── vanillajs
│ ├── index.html
│ └── index.js
├── index.html
├── package.json
├── rollup.config.js
├── rollup.svelte.js
├── screen_shot_en-us.png
├── screen_shot_pl.png
├── src.19911aa5.js
├── src.19911aa5.js.map
├── src
└── index.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org/
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 | indent_style = space
10 | indent_size = 2
11 | trim_trailing_whitespace = true
12 |
13 | [*.{elm}]
14 | indent_size = 4
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .cache
4 | dist
5 | commonjs
6 | elm-stuff
7 | node_modules
8 | example/svelte/public/build/
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wolfadex/fluent-web/18bd925344eefbc2fcc8714b6db7cc65eeb14a08/.prettierrc
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [Unreleased]
8 | - Nothing
9 |
10 | ## [4.0.0] - 2020-05-01
11 | ### Changed
12 | - `messageId` is now `messageid` ***note the lower case 'i'***. Changed to match HTML naming conventions
13 |
14 | ## [3.0.0] - 2020-04-26
15 | ### Added
16 | - Added `unsafeArgs`
17 |
18 | ### Changed
19 | - `args` are now sanatized to prevent XSS
20 | - Better handling of blank messages
21 |
22 | ## [2.1.0] - 2020-04-21
23 | ### Added
24 | - `` as a way to simplifying adding bundles
25 |
26 | ### Changed
27 | - Improve checking and setting for bundles
28 |
29 | ## [2.0.0] - 2020-04-19
30 | ### Changed
31 | - Instead of the user passing in a `FluentResource` the now pass in an array of `FluentBundle`
32 |
33 | ## [1.0.1] - 2020-04-18
34 | ### Changed
35 | - Fixed formatting of attributes
36 |
37 | ## [1.0.0] - 2020-04-15
38 | ### Added
39 | - Initial commit
40 | - See docs at v1.0.0
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Wolfgang Schuster
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fluent-web
2 |
3 | A web component that uses [Fluent](https://projectfluent.org/) for localization.
4 |
5 | [Interactive example](https://wolfadex.github.io/fluent-web/).
6 |
7 | | Locale en-US | Locale pl |
8 | | ------------------------------------------------------- | ------------------------------------------------- |
9 | |  |  |
10 |
11 | ## Basic Usage:
12 |
13 | `yarn add @wolfadex/fluent-web` or `npm install @wolfadex@fluent-web`
14 |
15 |
16 | ```js
17 | import "@wolfadex/fluent-web"
18 | import { FluentResource, FluentBundle } from "@fluent/bundle";
19 |
20 | const resource = new FluentResource(`
21 | hello = Hello, Fluent!
22 | `);
23 | const bundle = new FluentBundle("en-US");
24 | bundles.addResource(resource);
25 |
26 | const textEl = document.getElementById("my-text-element");
27 |
28 | textEl.bundles = [bundle];
29 | ```
30 |
31 | HTML:
32 |
33 | ```html
34 |
35 | ```
36 |
37 | Result:
38 |
39 | ```
40 | Hello, Fluent!
41 | ```
42 |
43 | For how to build messages, see the [Fluent docs](https://github.com/projectfluent/fluent/wiki).
44 |
45 | ## Examples:
46 |
47 | - [Elm](https://github.com/wolfadex/fluent-web/tree/master/example/elm), this is used for the interactive demo
48 | - [Svelte](https://github.com/wolfadex/fluent-web/tree/master/example/svelte)
49 | - [Vanilla HTML & JS](https://github.com/wolfadex/fluent-web/tree/master/example/vanillajs)
50 |
51 | ## Docs:
52 |
53 | See the [Docs](https://github.com/wolfadex/fluent-web/blob/master/docs/index.md) for more details.
54 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Basics
2 |
3 | Under the hood, fluent-web uses the libraries provided by the Fluent team for doing the actual localization. All you need to do is provide the component with an array of bundles. See the [Fluent docs](https://projectfluent.org/fluent.js/bundle/) for how to build a bundle of resources.
4 |
5 | Once you have 1 or more bundles, you can send the one(s) you want to the web component as a property
6 |
7 | ```html
8 |
9 |
10 | ```
11 |
12 | ```js
13 | // index.js
14 | document.getElementById("helloEl").bundles = yourBundles;
15 | ```
16 |
17 | Results in
18 |
19 | ```
20 | Witaj, FLuent!
21 | ```
22 |
23 | # Complex Text
24 |
25 | Fluent also supports passing arguments, please see [their docs](https://projectfluent.org/) for more information about how arguments work.
26 |
27 | Once you have a bundle with arguments setup, they're easy to use.
28 |
29 | ```html
30 |
31 |
32 | ```
33 |
34 | ```js
35 | // index.js
36 | import "@wolfadex/fluent-web";
37 | import { FluentResource, FluentBundle } from "@fluent/bundle";
38 |
39 | const enUSResource = new FluentResource(`
40 | hello-name = Hello, { $name }!
41 | `);
42 | const enUSBundle = new FluentBundle("en-US");
43 | enUSBundle.addResource(enUSResource);
44 |
45 | const helloEl = document.getElementById("helloPersonEl");
46 |
47 | helloEl.args = { name: "Wolfgang" };
48 | helloEl.bundles = [enUSBundle];
49 | ```
50 |
51 | Results in
52 |
53 | ```
54 | Hello, Wolfgang!
55 | ```
56 |
57 | # Localization with Properties
58 |
59 | Another feature of Fluent is support for localized properties. For example, you may want `placeholder` text on your input like so
60 |
61 | ```html
62 |
63 | ```
64 |
65 | Since this is more than just text, it's also an element, you'll need to specify the child element which you want the attributes applied to. This looks like
66 |
67 | ```html
68 |
69 |
70 |
71 |
72 | ```
73 |
74 | ```js
75 | // index.js
76 | import "@wolfadex/fluent-web";
77 | import { FluentResource, FluentBundle } from "@fluent/bundle";
78 |
79 | const enUSResource = new FluentResource(`
80 | name =
81 | .placeholder = Your name
82 | `);
83 | const enUSBundle = new FluentBundle("en-US");
84 | enUSBundle.addResource(enUSResource);
85 |
86 | const nameInput = document.getElementById("nameInput");
87 |
88 | nameInput.attributeWhitelist = ["placeholder"];
89 | nameInput.enUSBundle = [enUSBundle];
90 | ```
91 |
92 | ***Note:*** Don't forget to whitelist the attributes you want localized!
93 |
94 | Results in a text input with placeholder text of `Your Name`.
95 |
96 | # Provider
97 |
98 | Assigning bundles to large numbers of elements can sometimes be inconvenient. `fluent-provider` can do this for you: set only the provider's bundles, and the provider will keep its children up to date.
99 |
100 | ```html
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | ```
109 |
110 | ```js
111 | // index.js
112 | document.getElementsByTagName("fluent-provider")[0].bundles = yourBundles;
113 | ```
114 |
115 | Bundles assigned to a single element will take priority over those assigned by a provider.
116 |
117 | # Errors
118 |
119 | If there are any errors encountered while localizing, a event named `fluent-web-error` is dispatched. If the error arises while running Fluent's `bundle.formatPattern()`, the `event.detail` will look like
120 |
121 | ```js
122 | {
123 | messageid, // The message id passed in
124 | args, // Any args passed in, or null
125 | message, // The message object returned by Fluent
126 | errors, // A list of errors populated by Fluent
127 | }
128 | ```
129 |
130 | If the error is due to the message not being found, you'll get
131 |
132 | ```js
133 | {
134 | messageid, // The message id passed in
135 | args, // Any args passed in, or null
136 | errors: [new Error("Message object not found")],
137 | }
138 | ```
139 |
140 | If you try to pass a set of bundles that isn't iterable, you'll get
141 |
142 | ```js
143 | {
144 | bundles,
145 | errors: [new Error("bundles property must be iterable or null")],
146 | }
147 | ```
148 |
149 | # Saftey
150 |
151 | By default, `args` are sanatized to prevent XSS and other vulnerabilities. If you'd like your args to not be sanatized you can instead use `unsafeArgs`. ***Don't forget***, if you decide to switch from `args` to `unsafeArgs` at runtime to clear out `args` by setting it to `null`.
152 |
153 | # Framework Support
154 |
155 | The great thing about fluent-web being a web component is that we can use it in any front end framework or language that supports web components. The [demo](https://wolfadex.github.io/fluent-web/) is written in [Elm](https://elm-lang.org/), and there are additional [examples](https://github.com/wolfadex/fluent-web/tree/master/example) built in [Svelte](https://svelte.dev/) and vanilla html & javascript.
156 |
157 | I hope that this project can help to reduce the amount of time spent re-implementing localization across every front end framework.
158 |
159 | # Known Issues
160 |
161 | - Users of React should look at using [@fluent/react](https://github.com/projectfluent/fluent.js/tree/master/fluent-react) as React has some compatability issues with web components. In this case the issue is that React isn't able to set properties on web components. Another option would be to wrap fluent-web in a specialized React component. I do not have experience in this so I won't be making any recommendations.
162 | - Chromium (Chrome, Brave, Edge, etc.) and Safari browsers don't update the current value of a `select` element when the translation changes. They do update as soon as you interact with the `select`, such as changing its focus. FireFox updates as expected.
163 |
--------------------------------------------------------------------------------
/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": ["example/elm"],
4 | "elm-version": "0.19.1",
5 | "dependencies": {
6 | "direct": {
7 | "avh4/elm-beautiful-example": "2.0.1",
8 | "avh4/elm-color": "1.0.0",
9 | "elm/browser": "1.0.2",
10 | "elm/core": "1.0.5",
11 | "elm/html": "1.0.0",
12 | "elm/json": "1.1.3",
13 | "elm/time": "1.0.0"
14 | },
15 | "indirect": {
16 | "elm/svg": "1.0.1",
17 | "elm/url": "1.0.0",
18 | "elm/virtual-dom": "1.0.2"
19 | }
20 | },
21 | "test-dependencies": {
22 | "direct": {},
23 | "indirect": {}
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/example.986e475a.js:
--------------------------------------------------------------------------------
1 | parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;cvoid 0!==i).join("-")}clearVariants(){this.variant=void 0}clearRegion(){this.region=void 0}addLikelySubtags(){const t=(0,i.getLikelySubtagsMin)(this.toString().toLowerCase());return!!t&&(this.language=t.language,this.script=t.script,this.region=t.region,this.variant=t.variant,!0)}}exports.Locale=n;
5 | },{"./subtags":"D7wF"}],"HsHF":[function(require,module,exports) {
6 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.filterMatches=o;var e=require("./locale");function o(o,r,t){const n=new Set,i=new Map;for(let f of r){new e.Locale(f).isWellFormed&&i.set(f,new e.Locale(f))}e:for(const f of o){const o=f.toLowerCase(),r=new e.Locale(o);if(void 0!==r.language){for(const e of i.keys())if(o===e.toLowerCase()){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}for(const[e,o]of i.entries())if(o.matches(r,!0,!1)){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}if(r.addLikelySubtags())for(const[e,o]of i.entries())if(o.matches(r,!0,!1)){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}r.clearVariants();for(const[e,o]of i.entries())if(o.matches(r,!0,!0)){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}if(r.clearRegion(),r.addLikelySubtags())for(const[e,o]of i.entries())if(o.matches(r,!0,!1)){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}r.clearRegion();for(const[e,o]of i.entries())if(o.matches(r,!0,!0)){if(n.add(e),i.delete(e),"lookup"===t)return Array.from(n);if("filtering"===t)continue;continue e}}}return Array.from(n)}
7 | },{"./locale":"KnUO"}],"KmJp":[function(require,module,exports) {
8 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.negotiateLanguages=t;var e=require("./matches");function t(t,r,{strategy:o="filtering",defaultLocale:a}={}){const n=(0,e.filterMatches)(Array.from(Object(t)).map(String),Array.from(Object(r)).map(String),o);if("lookup"===o){if(void 0===a)throw new Error("defaultLocale cannot be undefined for strategy `lookup`");0===n.length&&n.push(a)}else a&&!n.includes(a)&&n.push(a);return n}
9 | },{"./matches":"HsHF"}],"JAgC":[function(require,module,exports) {
10 | "use strict";function e(e=""){if("string"!=typeof e)throw new TypeError("Argument must be a string");return e.split(",").map(e=>e.trim()).filter(e=>""!==e).map(e=>e.split(";")[0])}Object.defineProperty(exports,"__esModule",{value:!0}),exports.acceptedLanguages=e;
11 | },{}],"SVcC":[function(require,module,exports) {
12 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"negotiateLanguages",{enumerable:!0,get:function(){return e.negotiateLanguages}}),Object.defineProperty(exports,"acceptedLanguages",{enumerable:!0,get:function(){return t.acceptedLanguages}});var e=require("./negotiate_languages"),t=require("./accepted_languages");
13 | },{"./negotiate_languages":"KmJp","./accepted_languages":"JAgC"}],"NveG":[function(require,module,exports) {
14 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.FluentDateTime=exports.FluentNumber=exports.FluentNone=exports.FluentType=void 0;class t{constructor(t){this.value=t}valueOf(){return this.value}}exports.FluentType=t;class e extends t{constructor(t="???"){super(t)}toString(t){return`{${this.value}}`}}exports.FluentNone=e;class r extends t{constructor(t,e={}){super(t),this.opts=e}toString(t){try{return t.memoizeIntlObject(Intl.NumberFormat,this.opts).format(this.value)}catch(e){return t.reportError(e),this.value.toString(10)}}}exports.FluentNumber=r;class s extends t{constructor(t,e={}){super(t),this.opts=e}toString(t){try{return t.memoizeIntlObject(Intl.DateTimeFormat,this.opts).format(this.value)}catch(e){return t.reportError(e),new Date(this.value).toISOString()}}}exports.FluentDateTime=s;
15 | },{}],"uYv6":[function(require,module,exports) {
16 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.resolveComplexPattern=m;var e=require("./types.js");const r=100,n="",t="";function o(r,n,t){if(t===n)return!0;if(t instanceof e.FluentNumber&&n instanceof e.FluentNumber&&t.value===n.value)return!0;if(n instanceof e.FluentNumber&&"string"==typeof t){if(t===r.memoizeIntlObject(Intl.PluralRules,n.opts).select(n.value))return!0}return!1}function u(r,n,t){return n[t]?w(r,n[t].value):(r.reportError(new RangeError("No default")),new e.FluentNone)}function a(e,r){const n=[],t=Object.create(null);for(const o of r)"narg"===o.type?t[o.name]=s(e,o.value):n.push(s(e,o));return{positional:n,named:t}}function s(r,n){switch(n.type){case"str":return n.value;case"num":return new e.FluentNumber(n.value,{minimumFractionDigits:n.precision});case"var":return l(r,n);case"mesg":return i(r,n);case"term":return c(r,n);case"func":return f(r,n);case"select":return p(r,n);default:return new e.FluentNone}}function l(r,{name:n}){let t;if(r.params){if(!Object.prototype.hasOwnProperty.call(r.params,n))return new e.FluentNone(`$${n}`);t=r.params[n]}else{if(!r.args||!Object.prototype.hasOwnProperty.call(r.args,n))return r.reportError(new ReferenceError(`Unknown variable: $${n}`)),new e.FluentNone(`$${n}`);t=r.args[n]}if(t instanceof e.FluentType)return t;switch(typeof t){case"string":return t;case"number":return new e.FluentNumber(t);case"object":if(t instanceof Date)return new e.FluentDateTime(t.getTime());default:return r.reportError(new TypeError(`Variable type not supported: $${n}, ${typeof t}`)),new e.FluentNone(`$${n}`)}}function i(r,{name:n,attr:t}){const o=r.bundle._messages.get(n);if(!o)return r.reportError(new ReferenceError(`Unknown message: ${n}`)),new e.FluentNone(n);if(t){const u=o.attributes[t];return u?w(r,u):(r.reportError(new ReferenceError(`Unknown attribute: ${t}`)),new e.FluentNone(`${n}.${t}`))}return o.value?w(r,o.value):(r.reportError(new ReferenceError(`No value: ${n}`)),new e.FluentNone(n))}function c(r,{name:n,attr:t,args:o}){const u=`-${n}`,s=r.bundle._terms.get(u);if(!s)return r.reportError(new ReferenceError(`Unknown term: ${u}`)),new e.FluentNone(u);if(t){const n=s.attributes[t];if(n){r.params=a(r,o).named;const e=w(r,n);return r.params=null,e}return r.reportError(new ReferenceError(`Unknown attribute: ${t}`)),new e.FluentNone(`${u}.${t}`)}r.params=a(r,o).named;const l=w(r,s.value);return r.params=null,l}function f(r,{name:n,args:t}){let o=r.bundle._functions[n];if(!o)return r.reportError(new ReferenceError(`Unknown function: ${n}()`)),new e.FluentNone(`${n}()`);if("function"!=typeof o)return r.reportError(new TypeError(`Function ${n}() is not callable`)),new e.FluentNone(`${n}()`);try{let s=a(r,t);return o(s.positional,s.named)}catch(u){return r.reportError(u),new e.FluentNone(`${n}()`)}}function p(r,{selector:n,variants:t,star:a}){let l=s(r,n);if(l instanceof e.FluentNone)return u(r,t,a);for(const e of t){if(o(r,l,s(r,e.key)))return w(r,e.value)}return u(r,t,a)}function m(o,u){if(o.dirty.has(u))return o.reportError(new RangeError("Cyclic reference")),new e.FluentNone;o.dirty.add(u);const a=[],l=o.bundle._useIsolating&&u.length>1;for(const e of u)if("string"!=typeof e){if(o.placeables++,o.placeables>r)throw o.dirty.delete(u),new RangeError(`Too many placeables expanded: ${o.placeables}, `+`max allowed is ${r}`);l&&a.push(n),a.push(s(o,e).toString(o)),l&&a.push(t)}else a.push(o.bundle._transform(e));return o.dirty.delete(u),a.join("")}function w(e,r){return"string"==typeof r?e.bundle._transform(r):m(e,r)}
17 | },{"./types.js":"NveG"}],"SlPp":[function(require,module,exports) {
18 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Scope=void 0;class e{constructor(e,t,s){this.dirty=new WeakSet,this.params=null,this.placeables=0,this.bundle=e,this.errors=t,this.args=s}reportError(e){if(!this.errors)throw e;this.errors.push(e)}memoizeIntlObject(e,t){let s=this.bundle._intls.get(e);s||(s={},this.bundle._intls.set(e,s));let r=JSON.stringify(t);return s[r]||(s[r]=new e(this.bundle.locales,t)),s[r]}}exports.Scope=e;
19 | },{}],"MWbQ":[function(require,module,exports) {
20 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.NUMBER=i,exports.DATETIME=u;var e=require("./types.js");function n(e,n){const t=Object.create(null);for(const[i,r]of Object.entries(e))n.includes(i)&&(t[i]=r.valueOf());return t}const t=["unitDisplay","currencyDisplay","useGrouping","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits"];function i(i,r){let u=i[0];if(u instanceof e.FluentNone)return new e.FluentNone(`NUMBER(${u.valueOf()})`);if(u instanceof e.FluentNumber||u instanceof e.FluentDateTime)return new e.FluentNumber(u.valueOf(),{...u.opts,...n(r,t)});throw new TypeError("Invalid argument to NUMBER")}const r=["dateStyle","timeStyle","fractionalSecondDigits","dayPeriod","hour12","weekday","era","year","month","day","hour","minute","second","timeZoneName"];function u(t,i){let u=t[0];if(u instanceof e.FluentNone)return new e.FluentNone(`DATETIME(${u.valueOf()})`);if(u instanceof e.FluentNumber||u instanceof e.FluentDateTime)return new e.FluentDateTime(u.valueOf(),{...u.opts,...n(i,r)});throw new TypeError("Invalid argument to DATETIME")}
21 | },{"./types.js":"NveG"}],"TptV":[function(require,module,exports) {
22 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.FluentBundle=void 0;var e=require("./resolver.js"),s=require("./scope.js"),t=require("./types.js"),r=require("./builtins.js");class i{constructor(e,{functions:s,useIsolating:t=!0,transform:i=(e=>e)}={}){this._terms=new Map,this._messages=new Map,this._intls=new WeakMap,this.locales=Array.isArray(e)?e:[e],this._functions={NUMBER:r.NUMBER,DATETIME:r.DATETIME,...s},this._useIsolating=t,this._transform=i}hasMessage(e){return this._messages.has(e)}getMessage(e){return this._messages.get(e)}addResource(e,{allowOverrides:s=!1}={}){const t=[];for(let r=0;r\s*/y,S=/\s*:\s*/y,m=/\s*,?\s*/y,b=/\s+/y;class A{constructor(A){this.body=[],e.lastIndex=0;let $=0;for(;;){let t=e.exec(A);if(null===t)break;$=e.lastIndex;try{this.body.push(j(t[1]))}catch(K){if(K instanceof SyntaxError)continue;throw K}}function Z(e){return e.lastIndex=$,e.test(A)}function F(e,t){if(A[$]===e)return $++,!0;if(t)throw new t(`Expected ${e}`);return!1}function U(e,t){if(Z(e))return $=e.lastIndex,!0;if(t)throw new t(`Expected ${e.toString()}`);return!1}function k(e){e.lastIndex=$;let t=e.exec(A);if(null===t)throw new SyntaxError(`Expected ${e.toString()}`);return $=e.lastIndex,t}function z(e){return k(e)[1]}function j(e){let r=O(),n=function(){let e=Object.create(null);for(;Z(t);){let r=z(t),n=O();if(null===n)throw new SyntaxError("Expected attribute value");e[r]=n}return e}();if(null===r&&0===Object.keys(n).length)throw new SyntaxError("Expected message value or attributes");return{id:e,value:r,attributes:n}}function O(){let e;if(Z(l)&&(e=z(l)),"{"===A[$]||"}"===A[$])return _(e?[e]:[],1/0);let t=G();return t?e?_([e,t],t.length):(t.value=H(t.value,f),_([t],t.length)):e?H(e,y):null}function _(e=[],t){for(;;){if(Z(l)){e.push(z(l));continue}if("{"===A[$]){e.push(M());continue}if("}"===A[$])throw new SyntaxError("Unbalanced closing brace");let r=G();if(!r)break;e.push(r),t=Math.min(t,r.length)}let r=e.length-1,n=e[r];"string"==typeof n&&(e[r]=H(n,y));let u=[];for(let a of e)a instanceof I&&(a=a.value.slice(0,a.value.length-t)),a&&u.push(a);return u}function M(){U(w,SyntaxError);let e=P();if(U(x))return e;if(U(v)){let t=function(){let e,t=[],n=0;for(;Z(r);){F("*")&&(e=n);let r=q(),u=O();if(null===u)throw new SyntaxError("Expected variant value");t[n++]={key:r,value:u}}if(0===n)return null;if(void 0===e)throw new SyntaxError("Expected default variant");return{variants:t,star:e}}();return U(x,SyntaxError),{type:"select",selector:e,...t}}throw new SyntaxError("Unclosed placeable")}function P(){if("{"===A[$])return M();if(Z(a)){let[,e,t,r=null]=k(a);if("$"===e)return{type:"var",name:t};if(U(E)){let n=function(){let e=[];for(;;){switch(A[$]){case")":return $++,e;case void 0:throw new SyntaxError("Unclosed argument list")}e.push(R()),U(m)}}();if("-"===e)return{type:"term",name:t,attr:r,args:n};if(o.test(t))return{type:"func",name:t,args:n};throw new SyntaxError("Function names must be all upper-case")}return"-"===e?{type:"term",name:t,attr:r,args:[]}:{type:"mesg",name:t,attr:r}}return C()}function R(){let e=P();return"mesg"!==e.type?e:U(S)?{type:"narg",name:e.name,value:C()}:e}function q(){let e;return U(d,SyntaxError),e=Z(n)?B():{type:"str",value:z(u)},U(g,SyntaxError),e}function C(){if(Z(n))return B();if('"'===A[$])return function(){F('"',SyntaxError);let e="";for(;;){if(e+=z(i),"\\"!==A[$]){if(F('"'))return{type:"str",value:e};throw new SyntaxError("Unclosed string literal")}e+=D()}}();throw new SyntaxError("Invalid expression")}function B(){let[,e,t=""]=k(n),r=t.length;return{type:"num",value:parseFloat(e),precision:r}}function D(){if(Z(s))return z(s);if(Z(c)){let[,e,t]=k(c),r=parseInt(e||t,16);return r<=55295||57344<=r?String.fromCodePoint(r):"�"}throw new SyntaxError("Unknown escape sequence")}function G(){let e=$;switch(U(b),A[$]){case".":case"[":case"*":case"}":case void 0:return!1;case"{":return J(A.slice(e,$))}return" "===A[$-1]&&J(A.slice(e,$))}function H(e,t){return e.replace(t,"")}function J(e){let t=e.replace(p,"\n"),r=h.exec(e)[1].length;return new I(t,r)}}}exports.FluentResource=A;class I{constructor(e,t){this.value=e,this.length=t}}
25 | },{}],"bNFF":[function(require,module,exports) {
26 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"FluentBundle",{enumerable:!0,get:function(){return e.FluentBundle}}),Object.defineProperty(exports,"FluentResource",{enumerable:!0,get:function(){return t.FluentResource}}),Object.defineProperty(exports,"FluentType",{enumerable:!0,get:function(){return r.FluentType}}),Object.defineProperty(exports,"FluentNumber",{enumerable:!0,get:function(){return r.FluentNumber}}),Object.defineProperty(exports,"FluentDateTime",{enumerable:!0,get:function(){return r.FluentDateTime}});var e=require("./bundle.js"),t=require("./resource.js"),r=require("./types.js");
27 | },{"./bundle.js":"TptV","./resource.js":"Dfkb","./types.js":"NveG"}],"Y9sf":[function(require,module,exports) {
28 | !function(n){"use strict";function e(n,e,r){return r.a=n,r.f=e,r}function r(n){return e(2,n,function(e){return function(r){return n(e,r)}})}function t(n){return e(3,n,function(e){return function(r){return function(t){return n(e,r,t)}}})}function u(n){return e(4,n,function(e){return function(r){return function(t){return function(u){return n(e,r,t,u)}}}})}function a(n){return e(5,n,function(e){return function(r){return function(t){return function(u){return function(a){return n(e,r,t,u,a)}}}}})}function i(n,e,r){return 2===n.a?n.f(e,r):n(e)(r)}function o(n,e,r,t){return 3===n.a?n.f(e,r,t):n(e)(r)(t)}function f(n,e,r,t,u){return 4===n.a?n.f(e,r,t,u):n(e)(r)(t)(u)}function c(n,e,r,t,u,a){return 5===n.a?n.f(e,r,t,u,a):n(e)(r)(t)(u)(a)}var l=t(function(n,e,r){for(var t=[],u=0;n>u;u++)t[u]=r(e+u);return t}),s=r(function(n,e){for(var r=[],t=0;n>t&&e.b;t++)r[t]=e.a,e=e.b;return r.length=t,m(r,e)});function v(n){throw Error("https://github.com/elm/core/blob/1.0.0/hints/"+n+".md")}function d(n,e){for(var r,t=[],u=b(n,e,0,t);u&&(r=t.pop());u=b(r.a,r.b,0,t));return u}function b(n,e,r,t){if(n===e)return!0;if("object"!=typeof n||null===n||null===e)return"function"==typeof n&&v(5),!1;if(r>100)return t.push(m(n,e)),!0;for(var u in 0>n.$&&(n=re(n),e=re(e)),n)if(!b(n[u],e[u],r+1,t))return!1;return!0}function p(n,e,r){if("object"!=typeof n)return n===e?0:e>n?-1:1;if(void 0===n.$)return(r=p(n.a,e.a))?r:(r=p(n.b,e.b))?r:p(n.c,e.c);for(;n.b&&e.b&&!(r=p(n.a,e.a));n=n.b,e=e.b);return r||(n.b?1:e.b?-1:0)}var h=0;function m(n,e){return{a:n,b:e}}function g(n,e){var r={};for(var t in n)r[t]=n[t];for(var t in e)r[t]=e[t];return r}var x=r($);function $(n,e){if("string"==typeof n)return n+e;if(!n.b)return e;var r=y(n.a,e);n=n.b;for(var t=r;n.b;n=n.b)t=t.b=y(n.a,e);return r}var w={$:0};function y(n,e){return{$:1,a:n,b:e}}var k=r(y);function E(n){for(var e=w,r=n.length;r--;)e=y(n[r],e);return e}var j=Math.ceil,A=Math.floor,P=Math.round,L=Math.log,T=isNaN,_=r(function(n,e){return e.join(n)});function N(n){return n+""}function H(n){return{$:2,b:n}}H(function(n){return"number"!=typeof n?I("an INT",n):n>-2147483647&&2147483647>n&&(0|n)===n?ce(n):!isFinite(n)||n%1?I("an INT",n):ce(n)}),H(function(n){return"boolean"==typeof n?ce(n):I("a BOOL",n)}),H(function(n){return"number"==typeof n?ce(n):I("a FLOAT",n)});var z=H(function(n){return ce(J(n))}),C=H(function(n){return"string"==typeof n?ce(n):n instanceof String?ce(n+""):I("a STRING",n)}),F=r(function(n,e){return{$:6,d:n,b:e}});var B=r(function(n,e){return{$:10,b:e,h:n}}),D=r(function(n,e){return function(n,e){return{$:9,f:n,g:e}}(n,[e])}),S=r(function(n,e){return O(n,G(e))});function O(n,e){switch(n.$){case 2:return n.b(e);case 5:return null===e?ce(n.c):I("null",e);case 3:return U(e)?M(n.b,e,E):I("a LIST",e);case 4:return U(e)?M(n.b,e,q):I("an ARRAY",e);case 6:var r=n.d;if("object"!=typeof e||null===e||!(r in e))return I("an OBJECT with a field named `"+r+"`",e);var t=O(n.b,e[r]);return ze(t)?t:ae(i(oe,r,t.a));case 7:var u=n.e;return U(e)?e.length>u?(t=O(n.b,e[u]),ze(t)?t:ae(i(fe,u,t.a))):I("a LONGER array. Need index "+u+" but only see "+e.length+" entries",e):I("an ARRAY",e);case 8:if("object"!=typeof e||null===e||U(e))return I("an OBJECT",e);var a=w;for(var o in e)if(e.hasOwnProperty(o)){if(t=O(n.b,e[o]),!ze(t))return ae(i(oe,o,t.a));a=y(m(o,t.a),a)}return ce(he(a));case 9:for(var f=n.f,c=n.g,l=0;c.length>l;l++){if(t=O(c[l],e),!ze(t))return t;f=f(t.a)}return ce(f);case 10:return t=O(n.b,e),ze(t)?O(n.h(t.a),e):t;case 11:for(var s=w,v=n.g;v.b;v=v.b){if(t=O(v.a,e),ze(t))return t;s=y(t.a,s)}return ae(le(he(s)));case 1:return ae(i(ie,n.a,J(e)));case 0:return ce(n.a)}}function M(n,e,r){for(var t=e.length,u=[],a=0;t>a;a++){var o=O(n,e[a]);if(!ze(o))return ae(i(fe,a,o.a));u[a]=o.a}return ce(r(u))}function U(n){return Array.isArray(n)||"undefined"!=typeof FileList&&n instanceof FileList}function q(n){return i(He,n.length,function(e){return n[e]})}function I(n,e){return ae(i(ie,"Expecting "+n,J(e)))}function W(n,e){if(n===e)return!0;if(n.$!==e.$)return!1;switch(n.$){case 0:case 1:return n.a===e.a;case 2:return n.b===e.b;case 5:return n.c===e.c;case 3:case 4:case 8:return W(n.b,e.b);case 6:return n.d===e.d&&W(n.b,e.b);case 7:return n.e===e.e&&W(n.b,e.b);case 9:return n.f===e.f&&R(n.g,e.g);case 10:return n.h===e.h&&W(n.b,e.b);case 11:return R(n.g,e.g)}}function R(n,e){var r=n.length;if(r!==e.length)return!1;for(var t=0;r>t;t++)if(!W(n[t],e[t]))return!1;return!0}function J(n){return n}function G(n){return n}var X=t(function(n,e,r){return r[n]=G(e),r});function V(n){return{$:0,a:n}}function Q(n){return{$:2,b:n,c:null}}J(null);var Y=r(function(n,e){return{$:3,b:n,d:e}}),K=0;function Z(n){var e={$:0,e:K++,f:n,g:null,h:[]};return rn(e),e}var nn=!1,en=[];function rn(n){if(en.push(n),!nn){for(nn=!0;n=en.shift();)tn(n);nn=!1}}function tn(n){for(;n.f;){var e=n.f.$;if(0===e||1===e){for(;n.g&&n.g.$!==e;)n.g=n.g.i;if(!n.g)return;n.f=n.g.b(n.f.a),n.g=n.g.i}else{if(2===e)return void(n.f.c=n.f.b(function(e){n.f=e,rn(n)}));if(5===e){if(0===n.h.length)return;n.f=n.f.b(n.h.shift())}else n.g={$:3===e?0:1,b:n.f.b,i:n.g},n.f=n.f.d}}}var un={};function an(n,e){var r={g:e,h:void 0},t=n.c,u=n.d,a=n.e,c=n.f;function l(n){return i(Y,l,{$:5,b:function(e){var i=e.a;return 0===e.$?o(u,r,i,n):a&&c?f(t,r,i.i,i.j,n):o(t,r,a?i.i:i.j,n)}})}return r.h=Z(i(Y,l,n.b))}var on=r(function(n,e){return Q(function(r){n.g(e),r(V(h))})});function fn(n){return function(e){return{$:1,k:n,l:e}}}var cn=[],ln=!1;function sn(n,e,r){if(cn.push({p:n,q:e,r:r}),!ln){ln=!0;for(var t;t=cn.shift();)vn(t.p,t.q,t.r);ln=!1}}function vn(n,e,r){var t,u={};for(var a in dn(!0,e,u,null),dn(!1,r,u,null),n)(t=n[a]).h.push({$:"fx",a:u[a]||{i:w,j:w}}),rn(t)}function dn(n,e,r,t){switch(e.$){case 1:var u=e.k,a=function(n,r,t){function u(n){for(var e=t;e;e=e.t)n=e.s(n);return n}return i(n?un[r].e:un[r].f,u,e.l)}(n,u,t);return void(r[u]=function(n,e,r){return r=r||{i:w,j:w},n?r.i=y(e,r.i):r.j=y(e,r.j),r}(n,a,r[u]));case 2:for(var o=e.m;o.b;o=o.b)dn(n,o.a,r,t);return;case 3:return void dn(n,e.o,r,{s:e.n,t:t})}}function bn(n){un[n]&&v(3)}var pn=r(function(n,e){return e});function hn(n){var e=[],r=un[n].u,u=(0,Q(function(n){var e=setTimeout(function(){n(V(h))},0);return function(){clearTimeout(e)}}));return un[n].b=u,un[n].c=t(function(n,t){for(;t.b;t=t.b)for(var a=e,i=G(r(t.a)),o=0;a.length>o;o++)a[o](i);return u}),{subscribe:function(n){e.push(n)},unsubscribe:function(n){var r=(e=e.slice()).indexOf(n);0>r||e.splice(r,1)}}}var mn,gn=r(function(n,e){return function(r){return n(e(r))}});var xn="undefined"!=typeof document?document:{};function $n(n,e){n.appendChild(e)}function wn(n){return{$:0,a:n}}var yn=r(function(n,e){return r(function(r,t){for(var u=[],a=0;t.b;t=t.b){var i=t.a;a+=i.b||0,u.push(i)}return a+=u.length,{$:1,c:e,d:_n(r),e:u,f:n,b:a}})}),kn=yn(void 0);r(function(n,e){return r(function(r,t){for(var u=[],a=0;t.b;t=t.b){var i=t.a;a+=i.b.b||0,u.push(i)}return a+=u.length,{$:2,c:e,d:_n(r),e:u,f:n,b:a}})})(void 0);var En,jn=r(function(n,e){return{$:"a0",n:n,o:e}}),An=r(function(n,e){return{$:"a1",n:n,o:e}}),Pn=r(function(n,e){return{$:"a2",n:n,o:e}}),Ln=r(function(n,e){return{$:"a3",n:n,o:e}});function Tn(n){return/^\s*(javascript:|data:text\/html)/i.test(n)?"":n}function _n(n){for(var e={};n.b;n=n.b){var r=n.a,t=r.$,u=r.n,a=r.o;if("a2"!==t){var i=e[t]||(e[t]={});"a3"===t&&"class"===u?Nn(i,u,a):i[u]=a}else"className"===u?Nn(e,u,G(a)):e[u]=G(a)}return e}function Nn(n,e,r){var t=n[e];n[e]=t?t+" "+r:r}function Hn(n,e){var r=n.$;if(5===r)return Hn(n.k||(n.k=n.m()),e);if(0===r)return xn.createTextNode(n.a);if(4===r){for(var t=n.k,u=n.j;4===t.$;)"object"!=typeof u?u=[u,t.j]:u.push(t.j),t=t.k;var a={j:u,p:e};return(i=Hn(t,a)).elm_event_node_ref=a,i}if(3===r)return zn(i=n.h(n.g),e,n.d),i;var i=n.f?xn.createElementNS(n.f,n.c):xn.createElement(n.c);mn&&"a"==n.c&&i.addEventListener("click",mn(i)),zn(i,e,n.d);for(var o=n.e,f=0;o.length>f;f++)$n(i,Hn(1===r?o[f]:o[f].b,e));return i}function zn(n,e,r){for(var t in r){var u=r[t];"a1"===t?Cn(n,u):"a0"===t?Dn(n,e,u):"a3"===t?Fn(n,u):"a4"===t?Bn(n,u):("value"!==t&&"checked"!==t||n[t]!==u)&&(n[t]=u)}}function Cn(n,e){var r=n.style;for(var t in e)r[t]=e[t]}function Fn(n,e){for(var r in e){var t=e[r];void 0!==t?n.setAttribute(r,t):n.removeAttribute(r)}}function Bn(n,e){for(var r in e){var t=e[r],u=t.f,a=t.o;void 0!==a?n.setAttributeNS(u,r,a):n.removeAttributeNS(u,r)}}function Dn(n,e,r){var t=n.elmFs||(n.elmFs={});for(var u in r){var a=r[u],i=t[u];if(a){if(i){if(i.q.$===a.$){i.q=a;continue}n.removeEventListener(u,i)}i=Sn(e,a),n.addEventListener(u,i,En&&{passive:2>Oe(a)}),t[u]=i}else n.removeEventListener(u,i),t[u]=void 0}}try{window.addEventListener("t",null,Object.defineProperty({},"passive",{get:function(){En=!0}}))}catch(n){}function Sn(n,e){function r(e){var t=r.q,u=O(t.a,e);if(ze(u)){for(var a,i=Oe(t),o=u.a,f=i?3>i?o.a:o.o:o,c=1==i?o.b:3==i&&o.T,l=(c&&e.stopPropagation(),(2==i?o.b:3==i&&o.P)&&e.preventDefault(),n);a=l.j;){if("function"==typeof a)f=a(f);else for(var s=a.length;s--;)f=a[s](f);l=l.p}l(f,c)}}return r.q=e,r}function On(n,e){return n.$==e.$&&W(n.a,e.a)}function Mn(n,e,r,t){var u={$:e,r:r,s:t,t:void 0,u:void 0};return n.push(u),u}function Un(n,e,r,t){if(n!==e){var u=n.$,a=e.$;if(u!==a){if(1!==u||2!==a)return void Mn(r,0,t,e);e=function(n){for(var e=n.e,r=e.length,t=[],u=0;r>u;u++)t[u]=e[u].b;return{$:1,c:n.c,d:n.d,e:t,f:n.f,b:n.b}}(e),a=1}switch(a){case 5:for(var i=n.l,o=e.l,f=i.length,c=f===o.length;c&&f--;)c=i[f]===o[f];if(c)return void(e.k=n.k);e.k=e.m();var l=[];return Un(n.k,e.k,l,0),void(l.length>0&&Mn(r,1,t,l));case 4:for(var s=n.j,v=e.j,d=!1,b=n.k;4===b.$;)d=!0,"object"!=typeof s?s=[s,b.j]:s.push(b.j),b=b.k;for(var p=e.k;4===p.$;)d=!0,"object"!=typeof v?v=[v,p.j]:v.push(p.j),p=p.k;return d&&s.length!==v.length?void Mn(r,0,t,e):((d?function(n,e){for(var r=0;n.length>r;r++)if(n[r]!==e[r])return!1;return!0}(s,v):s===v)||Mn(r,2,t,v),void Un(b,p,r,t+1));case 0:return void(n.a!==e.a&&Mn(r,3,t,e.a));case 1:return void qn(n,e,r,t,Wn);case 2:return void qn(n,e,r,t,Rn);case 3:if(n.h!==e.h)return void Mn(r,0,t,e);var h=In(n.d,e.d);h&&Mn(r,4,t,h);var m=e.i(n.g,e.g);return void(m&&Mn(r,5,t,m))}}}function qn(n,e,r,t,u){if(n.c===e.c&&n.f===e.f){var a=In(n.d,e.d);a&&Mn(r,4,t,a),u(n,e,r,t)}else Mn(r,0,t,e)}function In(n,e,r){var t;for(var u in n)if("a1"!==u&&"a0"!==u&&"a3"!==u&&"a4"!==u)if(u in e){var a=n[u],i=e[u];a===i&&"value"!==u&&"checked"!==u||"a0"===r&&On(a,i)||((t=t||{})[u]=i)}else(t=t||{})[u]=r?"a1"===r?"":"a0"===r||"a3"===r?void 0:{f:n[u].f,o:void 0}:"string"==typeof n[u]?"":null;else{var o=In(n[u],e[u]||{},u);o&&((t=t||{})[u]=o)}for(var f in e)f in n||((t=t||{})[f]=e[f]);return t}function Wn(n,e,r,t){var u=n.e,a=e.e,i=u.length,o=a.length;i>o?Mn(r,6,t,{v:o,i:i-o}):o>i&&Mn(r,7,t,{v:i,e:a});for(var f=o>i?i:o,c=0;f>c;c++){var l=u[c];Un(l,a[c],r,++t),t+=l.b||0}}function Rn(n,e,r,t){for(var u=[],a={},i=[],o=n.e,f=e.e,c=o.length,l=f.length,s=0,v=0,d=t;c>s&&l>v;){var b=(A=o[s]).a,p=(P=f[v]).a,h=A.b,m=P.b,g=void 0,x=void 0;if(b!==p){var $=o[s+1],w=f[v+1];if($){var y=$.a,k=$.b;x=p===y}if(w){var E=w.a,j=w.b;g=b===E}if(g&&x)Un(h,j,u,++d),Gn(a,u,b,m,v,i),d+=h.b||0,Xn(a,u,b,k,++d),d+=k.b||0,s+=2,v+=2;else if(g)d++,Gn(a,u,p,m,v,i),Un(h,j,u,d),d+=h.b||0,s+=1,v+=2;else if(x)Xn(a,u,b,h,++d),d+=h.b||0,Un(k,m,u,++d),d+=k.b||0,s+=2,v+=1;else{if(!$||y!==E)break;Xn(a,u,b,h,++d),Gn(a,u,p,m,v,i),d+=h.b||0,Un(k,j,u,++d),d+=k.b||0,s+=2,v+=2}}else Un(h,m,u,++d),d+=h.b||0,s++,v++}for(;c>s;){var A;Xn(a,u,(A=o[s]).a,h=A.b,++d),d+=h.b||0,s++}for(;l>v;){var P,L=L||[];Gn(a,u,(P=f[v]).a,P.b,void 0,L),v++}(u.length>0||i.length>0||L)&&Mn(r,8,t,{w:u,x:i,y:L})}var Jn="_elmW6BL";function Gn(n,e,r,t,u,a){var i=n[r];if(!i)return a.push({r:u,A:i={c:0,z:t,r:u,s:void 0}}),void(n[r]=i);if(1===i.c){a.push({r:u,A:i}),i.c=2;var o=[];return Un(i.z,t,o,i.r),i.r=u,void(i.s.s={w:o,A:i})}Gn(n,e,r+Jn,t,u,a)}function Xn(n,e,r,t,u){var a=n[r];if(a){if(0===a.c){a.c=2;var i=[];return Un(t,a.z,i,u),void Mn(e,9,u,{w:i,A:a})}Xn(n,e,r+Jn,t,u)}else{var o=Mn(e,9,u,void 0);n[r]={c:1,z:t,r:u,s:o}}}function Vn(n,e,r,t){return 0===r.length?n:(function n(e,r,t,u){!function e(r,t,u,a,i,o,f){for(var c=u[a],l=c.r;l===i;){var s=c.$;if(1===s)n(r,t.k,c.s,f);else if(8===s)c.t=r,c.u=f,(v=c.s.w).length>0&&e(r,t,v,0,i,o,f);else if(9===s){c.t=r,c.u=f;var v,d=c.s;d&&(d.A.s=r,(v=d.w).length>0&&e(r,t,v,0,i,o,f))}else c.t=r,c.u=f;if(!(c=u[++a])||(l=c.r)>o)return a}var b=t.$;if(4===b){for(var p=t.k;4===p.$;)p=p.k;return e(r,p,u,a,i+1,o,r.elm_event_node_ref)}for(var h=t.e,m=r.childNodes,g=0;h.length>g;g++){var x=1===b?h[g]:h[g].b,$=++i+(x.b||0);if(!(i>l||l>$||(c=u[a=e(m[g],x,u,a,i,$,f)])&&(l=c.r)<=o))return a;i=$}return a}(e,r,t,0,0,r.b,u)}(n,e,r,t),Qn(n,r))}function Qn(n,e){for(var r=0;e.length>r;r++){var t=e[r],u=t.t,a=Yn(u,t);u===n&&(n=a)}return n}function Yn(n,e){switch(e.$){case 0:return function(n){var r=n.parentNode,t=Hn(e.s,e.u);return t.elm_event_node_ref||(t.elm_event_node_ref=n.elm_event_node_ref),r&&t!==n&&r.replaceChild(t,n),t}(n);case 4:return zn(n,e.u,e.s),n;case 3:return n.replaceData(0,n.length,e.s),n;case 1:return Qn(n,e.s);case 2:return n.elm_event_node_ref?n.elm_event_node_ref.j=e.s:n.elm_event_node_ref={j:e.s,p:e.u},n;case 6:for(var r=e.s,t=0;r.i>t;t++)n.removeChild(n.childNodes[r.v]);return n;case 7:for(var u=(r=e.s).e,a=n.childNodes[t=r.v];u.length>t;t++)n.insertBefore(Hn(u[t],e.u),a);return n;case 9:if(!(r=e.s))return n.parentNode.removeChild(n),n;var i=r.A;return void 0!==i.r&&n.parentNode.removeChild(n),i.s=Qn(n,r.w),n;case 8:return function(n,e){var r=e.s,t=function(n,e){if(n){for(var r=xn.createDocumentFragment(),t=0;n.length>t;t++){var u=n[t].A;$n(r,2===u.c?u.s:Hn(u.z,e.u))}return r}}(r.y,e);n=Qn(n,r.w);for(var u=r.x,a=0;u.length>a;a++){var i=u[a],o=i.A,f=2===o.c?o.s:Hn(o.z,e.u);n.insertBefore(f,n.childNodes[i.r])}return t&&$n(n,t),n}(n,e);case 5:return e.s(n);default:v(10)}}var Kn=u(function(n,e,r,t){return function(n,e,r,t,u,a){var o=i(S,n,J(e?e.flags:void 0));ze(o)||v(2);var f={},c=r(o.a),l=c.a,s=a(b,l),d=function(n,e){var r;for(var t in un){var u=un[t];u.a&&((r=r||{})[t]=u.a(t,e)),n[t]=an(u,e)}return r}(f,b);function b(n,e){var r=i(t,n,l);s(l=r.a,e),sn(f,r.b,u(l))}return sn(f,c.b,u(l)),d?{ports:d}:{}}(e,t,n.aP,n.aW,n.aU,function(e,r){var u=n.aX,a=t.node,f=function n(e){if(3===e.nodeType)return wn(e.textContent);if(1!==e.nodeType)return wn("");for(var r=w,t=e.attributes,u=t.length;u--;){var a=t[u];r=y(i(Ln,a.name,a.value),r)}var f=e.tagName.toLowerCase(),c=w,l=e.childNodes;for(u=l.length;u--;)c=y(n(l[u]),c);return o(kn,f,r,c)}(a);return function(n,e){e(n);var r=0;function t(){r=1===r?0:(Zn(t),e(n),1)}return function(u,a){n=u,a?(e(n),2===r&&(r=1)):(0===r&&Zn(t),r=2)}}(r,function(n){var r=u(n),t=function(n,e){var r=[];return Un(n,e,r,0),r}(f,r);a=Vn(a,f,t,e),f=r})})}),Zn=("undefined"!=typeof cancelAnimationFrame&&cancelAnimationFrame,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:function(n){return setTimeout(n,1e3/60)});"undefined"!=typeof document&&document,"undefined"!=typeof window&&window;var ne=k,ee=t(function(n,e,r){for(;;){if(-2===r.$)return e;var t=r.d,u=n,a=o(n,r.b,r.c,o(ee,n,e,r.e));n=u,e=a,r=t}}),re=function(n){return o(ee,t(function(n,e,r){return i(ne,m(n,e),r)}),w,n)},te=function(n){return{$:0,a:n}},ue=E([0,1,2,3,4]),ae=function(n){return{$:1,a:n}},ie=r(function(n,e){return{$:3,a:n,b:e}}),oe=r(function(n,e){return{$:0,a:n,b:e}}),fe=r(function(n,e){return{$:1,a:n,b:e}}),ce=function(n){return{$:0,a:n}},le=function(n){return{$:2,a:n}},se={$:1},ve=x,de=N,be=r(function(n,e){return i(_,n,function(n){for(var e=[];n.b;n=n.b)e.push(n.a);return e}(e))}),pe=t(function(n,e,r){for(;;){if(!r.b)return e;var t=r.b,u=n,a=i(n,r.a,e);n=u,e=a,r=t}}),he=function(n){return o(pe,ne,w,n)},me=u(function(n,e,r,t){return{$:0,a:n,b:e,c:r,d:t}}),ge=[],xe=j,$e=r(function(n,e){return L(e)/L(n)}),we=xe(i($e,2,32)),ye=f(me,0,we,ge,ge),ke=l,Ee=A,je=function(n){return n.length},Ae=r(function(n,e){return p(n,e)>0?n:e}),Pe=s,Le=r(function(n,e){for(;;){var r=i(Pe,32,n),t=r.b,u=i(ne,{$:0,a:r.a},e);if(!t.b)return he(u);n=t,e=u}}),Te=r(function(n,e){for(;;){var r=xe(e/32);if(1===r)return i(Pe,32,n).a;n=i(Le,n,w),e=r}}),_e=r(function(n,e){if(e.a){var r=32*e.a,t=Ee(i($e,32,r-1)),u=n?he(e.d):e.d,a=i(Te,u,e.a);return f(me,je(e.c)+r,i(Ae,5,t*we),a,e.c)}return f(me,je(e.c),we,ge,e.c)}),Ne=a(function(n,e,r,t,u){for(;;){if(0>e)return i(_e,!1,{d:t,a:r/32|0,c:u});var a={$:1,a:o(ke,32,e,n)};n=n,e-=32,r=r,t=i(ne,a,t),u=u}}),He=r(function(n,e){if(n>0){var r=n%32;return c(Ne,e,n-r-32,n,w,o(ke,r,n-r,e))}return ye}),ze=function(n){return!n.$},Ce=B,Fe=u(function(n,e,r,t){return{$:0,a:n,b:e,c:r,d:t}}),Be=f(Fe,52/255,101/255,164/255,1),De=t(function(n,e,r){return e(n(r))}),Se=D,Oe=function(n){switch(n.$){case 0:return 0;case 1:return 1;case 2:return 2;default:return 3}},Me=V,Ue=Me(0),qe=u(function(n,e,r,t){if(t.b){var u=t.a,a=t.b;if(a.b){var c=a.a,l=a.b;if(l.b){var s=l.a,v=l.b;if(v.b){var d=v.b;return i(n,u,i(n,c,i(n,s,i(n,v.a,r>500?o(pe,n,e,he(d)):f(qe,n,e,r+1,d)))))}return i(n,u,i(n,c,i(n,s,e)))}return i(n,u,i(n,c,e))}return i(n,u,e)}return e}),Ie=t(function(n,e,r){return f(qe,n,e,0,r)}),We=r(function(n,e){return o(Ie,r(function(e,r){return i(ne,n(e),r)}),w,e)}),Re=Y,Je=r(function(n,e){return i(Re,function(e){return Me(n(e))},e)}),Ge=t(function(n,e,r){return i(Re,function(e){return i(Re,function(r){return Me(i(n,e,r))},r)},e)}),Xe=on,Ve=r(function(n,e){var r=e;return function(n){return Q(function(e){e(V(Z(n)))})}(i(Re,Xe(n),r))});un.Task={b:Ue,c:t(function(n,e){return i(Je,function(){return 0},(r=i(We,Ve(n),e),o(Ie,Ge(ne),Me(w),r)));var r}),d:t(function(){return Me(0)}),e:r(function(n,e){return i(Je,n,e)}),f:void 0};var Qe,Ye,Ke,Ze,nr,er=fn("Task"),rr=r(function(n,e){return er(i(Je,n,e))}),tr=Kn,ur=J,ar=r(function(n,e){return i(Pn,n,ur(e))}),ir=ar("className"),or=function(n){var e=function(n){switch(n){case 0:return"Page";case 1:return"PageHeaderContainer";case 2:return"PageHeader";case 3:return"PageHeaderLink";case 4:return"PageHeaderLinkText";case 5:return"PageDescription";default:return"Example"}};return ir(i(be," ",i(We,ve("avh4--elm-beautiful-example--"),i(We,e,n))))},fr=r(function(n,e){return e.b?o(Ie,ne,e,n):n}),cr=f(Fe,211/255,215/255,207/255,1),lr=u(function(n,e,r,t){var u={a:n,b:e,c:r},a=u.a,i=u.b,o=u.c,c=o>.5?o+i-o*i:o*(i+1),l=2*o-c,s=function(n){var e=0>n?n+1:n>1?n-1:n;return 1>6*e?l+(c-l)*e*6:1>2*e?c:2>3*e?l+(c-l)*(2/3-e)*6:l},v=s(a-1/3),d=s(a),b=s(a+1/3);return f(Fe,b,d,v,t)}),sr=t(function(n,e,r){return f(lr,n,e,r,1)}),vr=function(n){return kn(function(n){return"script"==n?"p":n}(n))},dr=wn,br=N,pr=P,hr=function(n){var e,r,t=n.b,u=n.c,a=n.d,o=function(n){return pr(1e4*n)/100};return e=E(["rgba(",br(o(n.a)),"%,",br(o(t)),"%,",br(o(u)),"%,",br((r=a,pr(1e3*r)/1e3)),")"]),i(be,"",e)},mr=T,gr=r(function(n,e){return 0>p(n,e)?n:e}),xr=function(n){var e=n.a,r=n.b,t=n.c,u=n.d,a=i(gr,e,i(gr,r,t)),o=i(Ae,e,i(Ae,r,t)),f=(a+o)/2,c=d(a,o)?0:.5>f?(o-a)/(o+a):(o-a)/(2-o-a),l=(d(o,e)?(r-t)/(o-a):d(o,r)?2+(t-e)/(o-a):4+(e-r)/(o-a))*(1/6);return{w:u,ae:mr(l)?0:0>l?l+1:l,ag:f,au:c}},$r=r(function(n,e){return e.$?n:e.a}),wr=r(function(n,e){var r=i($r,cr,e),t=xr(r),u=t.ae,a=t.au,f=t.ag,c=o(sr,u,1.2*a,.05*f+.93),l=o(sr,u,.8*a,.5*f+.28),s=o(sr,u,a,.7*f);return o(vr,"style",w,E([dr(i(be,"\n",E([".avh4--elm-beautiful-example--Page {"," max-width: "+de(n)+"px;","}",".avh4--elm-beautiful-example--PageHeader {"," color: "+hr(s)+";","}",".avh4--elm-beautiful-example--PageHeaderLink {"," color: "+hr(l)+";","}",".avh4--elm-beautiful-example--PageHeaderLink:hover {"," background-color: "+hr(c)+";","}",".avh4--elm-beautiful-example--PageDescription {"," color: "+hr(l)+";","}",".avh4--elm-beautiful-example--Example {"," background-color: "+hr(c)+";"," color: "+hr(s)+";","}",".avh4--elm-beautiful-example--Example button {"," background-color: "+hr(r)+";"," color: #fff;","}",".avh4--elm-beautiful-example--Example button:hover {"," background-color: "+hr(l)+";","}",".avh4--elm-beautiful-example--Example button:active {"," background-color: "+hr(c)+";","}",".avh4--elm-beautiful-example--Example input {"," color: "+hr(r)+";"," border-color: "+hr(r)+";","}",".avh4--elm-beautiful-example--Example textarea {"," color: "+hr(r)+";"," border-color: "+hr(r)+";","}"])))]))}),yr=kn("div"),kr=Ln("fill"),Er=Ln("height"),jr=Ln("points"),Ar=yn("http://www.w3.org/2000/svg"),Pr=Ar("polygon"),Lr=Ar("rect"),Tr=An,_r=Ar("svg"),Nr=Ln("transform"),Hr=Ln("version"),zr=Ln("viewBox"),Cr=Ln("width"),Fr=Ln("x"),Br=Ln("y"),Dr=function(n){return i(_r,E([Hr("1.1"),zr("0 0 323.141 322.95"),i(Tr,"height","0.8em")]),E([i(Pr,E([kr(hr(n)),jr("161.649,152.782 231.514,82.916 91.783,82.916")]),w),i(Pr,E([kr(hr(n)),jr("8.867,0 79.241,70.375 232.213,70.375 161.838,0")]),w),i(Lr,E([kr(hr(n)),Fr("192.99"),Br("107.392"),Cr("107.676"),Er("108.167"),Nr("matrix(0.7071 0.7071 -0.7071 0.7071 186.4727 -127.2386)")]),w),i(Pr,E([kr(hr(n)),jr("323.298,143.724 323.298,0 179.573,0")]),w),i(Pr,E([kr(hr(n)),jr("152.781,161.649 0,8.868 0,314.432")]),w),i(Pr,E([kr(hr(n)),jr("255.522,246.655 323.298,314.432 323.298,178.879")]),w),i(Pr,E([kr(hr(n)),jr("161.649,170.517 8.869,323.298 314.43,323.298")]),w)]))},Sr=r(function(n,e){return i(Ln,function(n){return/^(on|formAction$)/i.test(n)?"data-"+n:n}(n),Tn(e))}),Or=Ln("d"),Mr=Ar("path"),Ur=function(n){return i(_r,E([i(Sr,"aria-hidden","true"),Hr("1.1"),zr("0 0 16 16"),i(Tr,"height","0.8em")]),E([i(Mr,E([Or("M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"),kr(hr(n)),i(Sr,"fill-rule","evenodd")]),w)]))},qr=kn("h1"),Ir=kn("header"),Wr=kn("a"),Rr=function(n){return i(ar,"href",/^javascript:/i.test((e=n).replace(/\s/g,""))?"":e);var e},Jr=kn("span"),Gr=u(function(n,e,r,t){return i(Wr,E([Rr(t),or(E([3]))]),E([e(n),dr(" "),i(Jr,E([or(E([4]))]),E([dr(r)]))]))}),Xr=kn("main"),Vr=kn("p"),Qr=o(vr,"style",w,E([dr("\n.avh4--elm-beautiful-example--Page {\n margin: auto;\n padding: 48px 0;\n font-family: sans-serif;\n}\n.avh4--elm-beautiful-example--PageHeaderContainer {\n font-weight: 200;\n font-size: 32px;\n line-height: 37px;\n margin-top: 0;\n}\n.avh4--elm-beautiful-example--PageHeader {\n font-weight: 200;\n font-size: 32px;\n line-height: 37px;\n display: inline;\n}\n.avh4--elm-beautiful-example--PageHeaderLink {\n padding: 3px 8px 1px;\n text-decoration: none;\n vertical-align: bottom;\n border-radius: 4px;\n}\n.avh4--elm-beautiful-example--PageHeaderLink:hover .avh4--elm-beautiful-example--PageHeaderLinkText {\n text-decoration: underline;\n}\n.avh4--elm-beautiful-example--PageHeaderLinkText {\n font-size: 12px;\n font-weight: 200;\n line-height: 37px;\n margin-top: 0;\n vertical-align: bottom;\n}\n.avh4--elm-beautiful-example--PageDescription {\n font-weight: 200;\n font-style: italic;\n line-height: 1.5em;\n}\n.avh4--elm-beautiful-example--Example {\n padding: 16px;\n border-radius: 6px;\n line-height: 1.5em;\n}\n.avh4--elm-beautiful-example--Example > *:first-child {\n margin-top: 0;\n}\n.avh4--elm-beautiful-example--Example > *:last-child {\n margin-bottom: 0;\n}\n.avh4--elm-beautiful-example--Example > * > *:first-child {\n margin-top: 0;\n}\n.avh4--elm-beautiful-example--Example > * > *:last-child {\n margin-bottom: 0;\n}\n.avh4--elm-beautiful-example--Example button {\n cursor: pointer;\n border-style: none;\n border-radius: 2px;\n height: 28px;\n line-height: 28px;\n padding: 0 16px;\n text-transform: uppercase;\n font-size: 14px;\n letter-spacing: 0.5px;\n text-align: center;\n text-decoration: none;\n transition: 0.3s ease-out;\n box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2);\n margin: 4px 0;\n}\n.avh4--elm-beautiful-example--Example button:hover {\n box-shadow: 0 3px 3px 0 rgba(0,0,0,0.14), 0 1px 7px 0 rgba(0,0,0,0.12), 0 3px 1px -1px rgba(0,0,0,0.2);\n}\n.avh4--elm-beautiful-example--Example input {\n padding: 4px;\n border-radius: 4px;\n border: 2px solid;\n margin: 4px 0;\n font-size: 16px;\n box-sizing: border-box;\n}\n.avh4--elm-beautiful-example--Example textarea {\n padding: 4px;\n border-radius: 4px;\n border: 2px solid;\n margin: 4px 0;\n font-size: 16px;\n display: block;\n box-sizing: border-box;\n width: 100%;\n}\n.avh4--elm-beautiful-example--Example pre {\n line-height: 14px;\n font-size: 12px;\n}\n")])),Yr=r(function(n,e){var r,t=xr(i($r,cr,n.aF)),u=o(sr,t.ae,.8*t.au,.5*t.ag+.28);return i(yr,E([or(E([0]))]),E([Qr,i(wr,n.aQ,n.aF),i(Ir,E([or(E([1]))]),(r=E([E([i(qr,E([or(E([2]))]),E([dr(n.aV)]))]),function(){var e=n.aH;if(1===e.$)return w;var r=e.a;return E([dr(" "),f(Gr,u,Dr,"Documentation",r)])}(),function(){var e=n.aL;if(1===e.$)return w;var r=e.a;return E([dr(" "),f(Gr,u,Ur,"Source",r)])}()]),o(Ie,fr,w,r))),i(Xr,w,E([i(Vr,E([or(E([5]))]),E([dr(i($r,"",n.aG))])),i(yr,E([or(E([6]))]),E([e]))]))]))}),Kr=r(function(n,e){return tr({aP:e.aP,aU:e.aU,aW:e.aW,aX:i(De,e.aX,Yr(n))})}),Zr=F,nt=function(n){return{$:3,a:n}},et=function(n){return{$:2,a:n}},rt=function(n){return{$:2,m:n}},tt=r(function(n,e){return{$:0,a:n,b:e}}),ut=tt,at=Q(function(n){n(V(i(ut,-(new Date).getTimezoneOffset(),w)))}),it=function(n){switch(n){case"en-US":return ce(0);case"pl":return ce(1);case"cs":return ce(2);case"th-TH":return ce(3);case"eo":return ce(4);default:return ae("unsupported locale: "+n)}},ot=function(n){return n},ft=(Qe=ot,Q(function(n){n(V(Qe(Date.now())))})),ct=i(tt,0,w),lt=function(n){switch(n){case 0:return"en-US";case 1:return"pl";case 2:return"cs";case 3:return"th-TH";default:return"eo"}},st=C,vt=function(n){return{$:6,a:n}},dt=z,bt=(Ye=dt,bn("gotBundles"),un.gotBundles={f:gn,u:Ye,a:function(n,e){var r=w,u=un[n].u,a=V(null);return un[n].b=a,un[n].c=t(function(n,e){return r=e,a}),{send:function(n){var t=i(S,u,J(n));ze(t)||v(4);for(var a=t.a,o=r;o.b;o=o.b)e(o.a(a))}}}},fn("gotBundles")),pt=r(function(n,e){return J(o(pe,function(n){return r(function(e,r){return r.push(G(n(e))),r})}(n),[],e))}),ht=function(n,e){return bn(n),un[n]={e:pn,u:e,a:hn},fn(n)}("changeDesirecLocale",pt(ur)),mt=rt(w),gt=r(function(n,e){switch(n.$){case 6:return m(g(e,{r:n.a}),mt);case 0:return m(e,ht(E([n.a])));case 1:return m(g(e,{C:n.a}),mt);case 2:return m(g(e,{U:n.a}),mt);case 3:return m(g(e,{J:n.a}),mt);case 4:return m(g(e,{I:n.a}),mt);default:var r=function(n){switch(n){case"apple":return ce(0);case"orange":return ce(1);case"lemon":return ce(2);default:return ae("Unknown fruit: "+n)}}(n.a);return m(r.$?e:g(e,{H:r.a}),mt)}}),xt=function(n){return{$:0,a:n}},$t=function(n){return{$:5,a:n}},wt=function(n){return{$:1,a:n}},yt=function(n){return{$:4,a:n}},kt=E([0,1,2]),Et=kn("br"),jt=function(n){switch(n){case 0:return"apple";case 1:return"orange";default:return"lemon"}},At=kn("input"),Pt=J,Lt=kn("label"),Tt=function(n){return J(o(pe,r(function(n,e){return o(X,n.a,n.b,e)}),{},n))},_t=function(n){return m(n,!0)},Nt=jn,Ht=r(function(n,e){return i(Nt,n,{$:1,a:e})}),zt=i(r(function(n,e){return o(Ie,Zr,e,n)}),E(["target","value"]),st),Ct=function(n){return i(Ht,"input",i(Se,_t,i(Se,n,zt)))},Ft=kn("option"),Bt=r(function(n,e){return i(Pn,function(n){return"innerHTML"==n||"formAction"==n?"data-"+n:n}(n),Tn(e))}),Dt=kn("select"),St=ar("value");Ze={Example:{init:(Ke=r(function(n,e){var r=he(i(We,n,e));return r.b?r.b.b?r.b.b.b?i(be,", ",he(i(ne,"and "+r.a,r.b))):r.b.a+" and "+r.a:r.a:""}),i(Kr,{aF:te(Be),aG:te(i(be," ",E(["A demonstration of using fluent-web custom web components for",de((nr=ue,o(pe,r(function(n,e){return e+1}),0,nr))),"locales,",i(Ke,lt,ue)+".","These components are for doing l10n using https://projectfluent.org/."]))),aH:te("https://github.com/wolfadex/fluent-web/blob/master/docs/index.md"),aL:te("https://github.com/wolfadex/fluent-web"),aQ:400,aV:"Fluent-Web"},{aP:function(n){var e,r=n.r;return m({V:i($r,0,(e=it(n.M),e.$?se:te(e.a))),r:r,H:0,C:"Carl",I:"",J:ot(0),U:ct},rt(E([i(rr,nt,ft),i(rr,et,at)])))},aU:function(){return bt(vt)},aW:gt,aX:function(n){var e,r=i(Bt,"bundles",n.r);return i(yr,w,E([i(Lt,w,E([dr("Active Locale"),i(Dt,E([Ct(xt)]),i(We,function(n){return i(Ft,E([St(lt(n))]),E([dr(lt(n))]))},ue))])),i(Et,w,w),i(Et,w,w),dr("Basic key-value:"),i(Et,w,w),o(vr,"fluent-text",E([r,i(Sr,"messageid","hello-no-name")]),w),i(Et,w,w),i(Et,w,w),dr("Styled key-value:"),i(Et,w,w),o(vr,"fluent-text",E([r,i(Sr,"messageid","sign-in-or-cancel")]),w),i(Et,w,w),i(Et,w,w),dr("Today’s Date:"),i(Et,w,w),o(vr,"fluent-text",E([r,i(Sr,"messageid","today-date"),i(Bt,"args",Tt(E([m("date",Pt((e=n.J,e)))])))]),w),i(Et,w,w),i(Et,w,w),dr("Message with argument:"),i(Et,w,w),i(At,E([St(n.C),Ct(wt)]),w),i(Et,w,w),o(vr,"fluent-text",E([r,i(Sr,"messageid","hello"),i(Bt,"args",Tt(E([m("userName",ur(n.C))])))]),w),i(Et,w,w),i(Et,w,w),dr("Input localized:"),i(Et,w,w),o(vr,"fluent-element",E([r,i(Sr,"messageid","type-name"),i(Bt,"attributeWhitelist",i(pt,ur,E(["placeholder"])))]),E([i(At,E([Ct(yt),St(n.I)]),w)])),i(Et,w,w),i(Et,w,w),dr("Select with localized options:"),i(Et,w,w),i(Lt,w,E([o(vr,"fluent-text",E([r,i(Sr,"messageid","favorite-fruit")]),w)])),i(Dt,E([Ct($t),St(jt(n.H))]),i(We,function(n){return i(Ft,E([St(jt(n))]),E([o(vr,"fluent-text",E([r,i(Sr,"messageid","fruit-"+jt(n))]),w)]))},kt)),i(Et,w,w),i(Et,w,w),dr("Provider-based messages:"),i(Et,w,w),o(vr,"fluent-provider",E([r]),E([o(vr,"fluent-text",E([i(Sr,"messageid","hello-no-name")]),w),i(Et,w,w),o(vr,"fluent-text",E([i(Sr,"messageid","sign-in-or-cancel")]),w)]))]))}}))(i(Ce,function(n){return i(Ce,function(e){return{$:0,a:{r:e,M:n}}},i(Zr,"bundles",dt))},i(Zr,"initialLocale",st)))(0)}},n.Elm?function n(e,r){for(var t in r)t in e?"init"==t?v(6):n(e[t],r[t]):e[t]=r[t]}(n.Elm,Ze):n.Elm=Ze}(this);
29 | },{}],"LAvi":[function(require,module,exports) {
30 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e=require("@fluent/bundle");const n=new e.FluentResource("\nhello = Hello, { $userName }!\nhello-no-name = Hello, stranger!\ntype-name =\n .placeholder = Your name\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Today is { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = It’s {$date}.\n\nsign-in-or-cancel = Sign in or cancel.\nclicked-sign-in = You are now signed in.\nclicked-cancel = OK, nevermind.\n\nfavorite-fruit = Favorite Fruit\nfruit-apple = Apple\nfruit-orange = Orange\nfruit-lemon = Lemon\n"),a=new e.FluentResource("\nhello = Cześć { $userName }!\n# hello-no-name = Witaj nieznajomy!\ntype-name =\n .placeholder = Twoje imię\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Dziś jest {DATETIME($date)}.\n\n# Commented out to demonstrate fallback.\n# $date (Date) - Current date, formatted as weekday.\n# today-weekday = Jest {$date}.\n\nsign-in-or-cancel = Zaloguj albo anuluj.\nclicked-sign-in = Brawo!\nclicked-cancel = OK, nieważne.\n\nfavorite-fruit = Ulubiony owoc\nfruit-apple = Jabłko\nfruit-orange = Pomarańczowy\nfruit-lemon = Cytrynowy\n"),t=new e.FluentResource("\nhello = Ahoj, { $userName }!\nhello-no-name = Vítej cizinče!\ntype-name =\n .placeholder = Tvé jméno\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Dnes je { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = Je {$date}.\n\nsign-in-or-cancel = Přihlásit nebo zrušit.\nclicked-sign-in = Nyní jsi přihlášen.\nclicked-cancel = Ok, nevadí.\n\nfavorite-fruit = Oblíbené ovoce\nfruit-apple = Jablko\nfruit-orange = Pomeranč\nfruit-lemon = Citrón\n"),o=new e.FluentResource("\nhello = สวัสดีค่ะ คุณ{ $userName }\nhello-no-name = สวัสดีค่ะ\ntype-name =\n .placeholder = ชื่อของคุณ\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = วันนี้เป็น { DATETIME($date) }\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = มันคือ {$date}\n\nsign-in-or-cancel = เข้าสู่ระบบ หรือ ยกเลิก\nclicked-sign-in = เรียบร้อย\nclicked-cancel = ไม่เป็นไร\n\nfavorite-fruit = ผลไม้ที่ชอบ\nfruit-apple = แอปเปิ้ล\nfruit-orange = ส้ม\nfruit-lemon = มะนาว\n"),r=new e.FluentResource("\nhello = Saluton, { $userName }!\nhello-no-name = Saluton, fremdulo!\ntype-name =\n .placeholder = Via nomo\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Hodiaŭ estas { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = Estas {$date}.\n\nsign-in-or-cancel = Ensaluti aŭ nuligi.\nclicked-sign-in = Vi estas nun ensalutina.\nclicked-cancel = Bone, ne gravas.\n\nfavorite-fruit = Preferata Frukto\nfruit-apple = Pomo\nfruit-orange = Oranĝo\nfruit-lemon = Citrono\n");var d={"en-US":n,pl:a,cs:t,"th-TH":o,eo:r};exports.default=d;
31 | },{"@fluent/bundle":"bNFF"}],"Zdfz":[function(require,module,exports) {
32 | "use strict";var e=require("@fluent/langneg"),n=require("@fluent/bundle"),t=require("./Example.elm"),o=r(require("../common/resources.js"));function r(e){return e&&e.__esModule?e:{default:e}}const u=Object.keys(o.default);function s(n){return(0,e.negotiateLanguages)(n,u,{defaultLocale:"en-US"})}function a(e){const t=s(e),r=[];for(const u of t){const e=new n.FluentBundle(u);e.addResource(o.default[u]),r.push(e)}return r}window.addEventListener("fluent-web-error",function(e){console.error(e)});const l=t.Elm.Example.init({node:document.getElementById("root"),flags:{bundles:a(navigator.languages),initialLocale:s(navigator.languages)[0]}});l.ports.changeDesirecLocale.subscribe(function(e){l.ports.gotBundles.send(a(e))});
33 | },{"@fluent/langneg":"SVcC","@fluent/bundle":"bNFF","./Example.elm":"Y9sf","../common/resources.js":"LAvi"}]},{},["Zdfz"], null)
34 | //# sourceMappingURL=/example.986e475a.js.map
--------------------------------------------------------------------------------
/example.986e475a.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../../node_modules/@fluent/langneg/esm/subtags.js","../../node_modules/@fluent/langneg/esm/locale.js","../../node_modules/@fluent/langneg/esm/matches.js","../../node_modules/@fluent/langneg/esm/negotiate_languages.js","../../node_modules/@fluent/langneg/esm/accepted_languages.js","../../node_modules/@fluent/langneg/esm/index.js","../../node_modules/@fluent/bundle/esm/types.js","../../node_modules/@fluent/bundle/esm/resolver.js","../../node_modules/@fluent/bundle/esm/scope.js","../../node_modules/@fluent/bundle/esm/builtins.js","../../node_modules/@fluent/bundle/esm/bundle.js","../../node_modules/@fluent/bundle/esm/resource.js","../../node_modules/@fluent/bundle/esm/index.js","../common/resources.js","example.js"],"names":["likelySubtagsMin","regionMatchingLangs","getLikelySubtagsMin","loc","hasOwnProperty","Locale","locale","language","includes","region","toUpperCase","languageCodeRe","scriptCodeRe","regionCodeRe","variantCodeRe","localeRe","RegExp","constructor","result","exec","replace","isWellFormed","script","variant","toLowerCase","slice","isEqual","other","matches","thisRange","otherRange","undefined","toString","filter","part","join","clearVariants","clearRegion","addLikelySubtags","newLocale","filterMatches","requestedLocales","availableLocales","strategy","supportedLocales","Set","availableLocalesMap","Map","set","outer","reqLocStr","reqLocStrLC","requestedLocale","key","keys","add","delete","Array","from","availableLocale","entries","negotiateLanguages","defaultLocale","Object","map","String","Error","length","push","acceptedLanguages","str","TypeError","tokens","split","t","trim","FluentType","value","valueOf","FluentNone","scope","FluentNumber","opts","nf","memoizeIntlObject","Intl","NumberFormat","format","err","reportError","FluentDateTime","dtf","DateTimeFormat","Date","toISOString","MAX_PLACEABLES","FSI","PDI","match","selector","PluralRules","select","getDefault","variants","star","resolvePattern","RangeError","getArguments","args","positional","named","create","arg","type","name","resolveExpression","expr","minimumFractionDigits","precision","resolveVariableReference","resolveMessageReference","resolveTermReference","resolveFunctionReference","resolveSelectExpression","params","prototype","call","ReferenceError","getTime","attr","message","bundle","_messages","get","attribute","attributes","id","term","_terms","resolved","func","_functions","sel","resolveComplexPattern","ptn","dirty","has","useIsolating","_useIsolating","elem","placeables","_transform","Scope","errors","WeakSet","error","ctor","cache","_intls","JSON","stringify","locales","values","allowed","unwrapped","opt","NUMBER_ALLOWED","NUMBER","DATETIME_ALLOWED","DATETIME","FluentBundle","functions","transform","v","WeakMap","isArray","hasMessage","getMessage","addResource","res","allowOverrides","i","body","entry","startsWith","formatPattern","pattern","RE_MESSAGE_START","RE_ATTRIBUTE_START","RE_VARIANT_START","RE_NUMBER_LITERAL","RE_IDENTIFIER","RE_REFERENCE","RE_FUNCTION_NAME","RE_TEXT_RUN","RE_STRING_RUN","RE_STRING_ESCAPE","RE_UNICODE_ESCAPE","RE_LEADING_NEWLINES","RE_TRAILING_SPACES","RE_BLANK_LINES","RE_INDENT","TOKEN_BRACE_OPEN","TOKEN_BRACE_CLOSE","TOKEN_BRACKET_OPEN","TOKEN_BRACKET_CLOSE","TOKEN_PAREN_OPEN","TOKEN_ARROW","TOKEN_COLON","TOKEN_COMMA","TOKEN_BLANK","FluentResource","source","lastIndex","cursor","next","parseMessage","SyntaxError","test","re","consumeChar","char","errorClass","consumeToken","match1","parsePattern","parseAttributes","attrs","first","parsePatternElements","Infinity","indent","parseIndent","elements","commonIndent","parsePlaceable","Math","min","lastElement","baked","element","Indent","parseInlineExpression","parseVariants","count","parseVariantKey","sigil","parseArguments","parseArgument","parseLiteral","parseNumberLiteral","parseStringLiteral","parseEscapeSequence","fraction","parseFloat","codepoint4","codepoint6","codepoint","parseInt","fromCodePoint","start","makeIndent","text","blank","enUS","pl","cs","thTH","eo","resources","getCurrentLocales","desiredLocales","getBundles","currentLocales","bundles","window","addEventListener","event","console","app","Elm","Example","init","node","document","getElementById","flags","navigator","languages","initialLocale","ports","changeDesirecLocale","subscribe","gotBundles","send"],"mappings":"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","file":"example.986e475a.js","sourceRoot":"example/elm","sourcesContent":["import { Locale } from \"./locale\";\n/**\n * Below is a manually a list of likely subtags corresponding to Unicode\n * CLDR likelySubtags list.\n * This list is curated by the maintainers of Project Fluent and is\n * intended to be used in place of the full likelySubtags list in use cases\n * where full list cannot be (for example, due to the size).\n *\n * This version of the list is based on CLDR 30.0.3.\n */\nconst likelySubtagsMin = {\n \"ar\": \"ar-arab-eg\",\n \"az-arab\": \"az-arab-ir\",\n \"az-ir\": \"az-arab-ir\",\n \"be\": \"be-cyrl-by\",\n \"da\": \"da-latn-dk\",\n \"el\": \"el-grek-gr\",\n \"en\": \"en-latn-us\",\n \"fa\": \"fa-arab-ir\",\n \"ja\": \"ja-jpan-jp\",\n \"ko\": \"ko-kore-kr\",\n \"pt\": \"pt-latn-br\",\n \"sr\": \"sr-cyrl-rs\",\n \"sr-ru\": \"sr-latn-ru\",\n \"sv\": \"sv-latn-se\",\n \"ta\": \"ta-taml-in\",\n \"uk\": \"uk-cyrl-ua\",\n \"zh\": \"zh-hans-cn\",\n \"zh-hant\": \"zh-hant-tw\",\n \"zh-hk\": \"zh-hant-hk\",\n \"zh-gb\": \"zh-hant-gb\",\n \"zh-us\": \"zh-hant-us\",\n};\nconst regionMatchingLangs = [\n \"az\",\n \"bg\",\n \"cs\",\n \"de\",\n \"es\",\n \"fi\",\n \"fr\",\n \"hu\",\n \"it\",\n \"lt\",\n \"lv\",\n \"nl\",\n \"pl\",\n \"ro\",\n \"ru\",\n];\nexport function getLikelySubtagsMin(loc) {\n if (likelySubtagsMin.hasOwnProperty(loc)) {\n return new Locale(likelySubtagsMin[loc]);\n }\n const locale = new Locale(loc);\n if (locale.language && regionMatchingLangs.includes(locale.language)) {\n locale.region = locale.language.toUpperCase();\n return locale;\n }\n return null;\n}\n","/* eslint no-magic-numbers: 0 */\nimport { getLikelySubtagsMin } from \"./subtags\";\nconst languageCodeRe = \"([a-z]{2,3}|\\\\*)\";\nconst scriptCodeRe = \"(?:-([a-z]{4}|\\\\*))\";\nconst regionCodeRe = \"(?:-([a-z]{2}|\\\\*))\";\nconst variantCodeRe = \"(?:-(([0-9][a-z0-9]{3}|[a-z0-9]{5,8})|\\\\*))\";\n/**\n * Regular expression splitting locale id into four pieces:\n *\n * Example: `en-Latn-US-macos`\n *\n * language: en\n * script: Latn\n * region: US\n * variant: macos\n *\n * It can also accept a range `*` character on any position.\n */\nconst localeRe = new RegExp(`^${languageCodeRe}${scriptCodeRe}?${regionCodeRe}?${variantCodeRe}?$`, \"i\");\nexport class Locale {\n /**\n * Parses a locale id using the localeRe into an array with four elements.\n *\n * If the second argument `range` is set to true, it places range `*` char\n * in place of any missing piece.\n *\n * It also allows skipping the script section of the id, so `en-US` is\n * properly parsed as `en-*-US-*`.\n */\n constructor(locale) {\n const result = localeRe.exec(locale.replace(/_/g, \"-\"));\n if (!result) {\n this.isWellFormed = false;\n return;\n }\n let [, language, script, region, variant] = result;\n if (language) {\n this.language = language.toLowerCase();\n }\n if (script) {\n this.script = script[0].toUpperCase() + script.slice(1);\n }\n if (region) {\n this.region = region.toUpperCase();\n }\n this.variant = variant;\n this.isWellFormed = true;\n }\n isEqual(other) {\n return this.language === other.language\n && this.script === other.script\n && this.region === other.region\n && this.variant === other.variant;\n }\n matches(other, thisRange = false, otherRange = false) {\n return (this.language === other.language\n || thisRange && this.language === undefined\n || otherRange && other.language === undefined)\n && (this.script === other.script\n || thisRange && this.script === undefined\n || otherRange && other.script === undefined)\n && (this.region === other.region\n || thisRange && this.region === undefined\n || otherRange && other.region === undefined)\n && (this.variant === other.variant\n || thisRange && this.variant === undefined\n || otherRange && other.variant === undefined);\n }\n toString() {\n return [this.language, this.script, this.region, this.variant]\n .filter(part => part !== undefined)\n .join(\"-\");\n }\n clearVariants() {\n this.variant = undefined;\n }\n clearRegion() {\n this.region = undefined;\n }\n addLikelySubtags() {\n const newLocale = getLikelySubtagsMin(this.toString().toLowerCase());\n if (newLocale) {\n this.language = newLocale.language;\n this.script = newLocale.script;\n this.region = newLocale.region;\n this.variant = newLocale.variant;\n return true;\n }\n return false;\n }\n}\n","/* eslint no-magic-numbers: 0 */\nimport { Locale } from \"./locale\";\n/**\n * Negotiates the languages between the list of requested locales against\n * a list of available locales.\n *\n * The algorithm is based on the BCP4647 3.3.2 Extended Filtering algorithm,\n * with several modifications:\n *\n * 1) available locales are treated as ranges\n *\n * This change allows us to match a more specific request against\n * more generic available locale.\n *\n * For example, if the available locale list provides locale `en`,\n * and the requested locale is `en-US`, we treat the available locale as\n * a locale that matches all possible english requests.\n *\n * This means that we expect available locale ID to be as precize as\n * the matches they want to cover.\n *\n * For example, if there is only `sr` available, it's ok to list\n * it in available locales. But once the available locales has both,\n * Cyrl and Latn variants, the locale IDs should be `sr-Cyrl` and `sr-Latn`\n * to avoid any `sr-*` request to match against whole `sr` range.\n *\n * What it does ([requested] * [available] = [supported]):\n *\n * ['en-US'] * ['en'] = ['en']\n *\n * 2) likely subtags from LDML 4.3 Likely Subtags has been added\n *\n * The most obvious likely subtag that can be computed is a duplication\n * of the language field onto region field (`fr` => `fr-FR`).\n *\n * On top of that, likely subtags may use a list of mappings, that\n * allow the algorithm to handle non-obvious matches.\n * For example, making sure that we match `en` to `en-US` or `sr` to\n * `sr-Cyrl`, while `sr-RU` to `sr-Latn-RU`.\n *\n * This list can be taken directly from CLDR Supplemental Data.\n *\n * What it does ([requested] * [available] = [supported]):\n *\n * ['fr'] * ['fr-FR'] = ['fr-FR']\n * ['en'] * ['en-US'] = ['en-US']\n * ['sr'] * ['sr-Latn', 'sr-Cyrl'] = ['sr-Cyrl']\n *\n * 3) variant/region range check has been added\n *\n * Lastly, the last form of check is against the requested locale ID\n * but with the variant/region field replaced with a `*` range.\n *\n * The rationale here laid out in LDML 4.4 Language Matching:\n * \"(...) normally the fall-off between the user's languages is\n * substantially greated than regional variants.\"\n *\n * In other words, if we can't match for the given region, maybe\n * we can match for the same language/script but other region, and\n * it will in most cases be preferred over falling back on the next\n * language.\n *\n * What it does ([requested] * [available] = [supported]):\n *\n * ['en-AU'] * ['en-US'] = ['en-US']\n * ['sr-RU'] * ['sr-Latn-RO'] = ['sr-Latn-RO'] // sr-RU -> sr-Latn-RU\n *\n * It works similarly to getParentLocales algo, except that we stop\n * after matching against variant/region ranges and don't try to match\n * ignoring script ranges. That means that `sr-Cyrl` will never match\n * against `sr-Latn`.\n */\nexport function filterMatches(requestedLocales, availableLocales, strategy) {\n const supportedLocales = new Set();\n const availableLocalesMap = new Map();\n for (let locale of availableLocales) {\n let newLocale = new Locale(locale);\n if (newLocale.isWellFormed) {\n availableLocalesMap.set(locale, new Locale(locale));\n }\n }\n outer: for (const reqLocStr of requestedLocales) {\n const reqLocStrLC = reqLocStr.toLowerCase();\n const requestedLocale = new Locale(reqLocStrLC);\n if (requestedLocale.language === undefined) {\n continue;\n }\n // 1) Attempt to make an exact match\n // Example: `en-US` === `en-US`\n for (const key of availableLocalesMap.keys()) {\n if (reqLocStrLC === key.toLowerCase()) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n // 2) Attempt to match against the available range\n // This turns `en` into `en-*-*-*` and `en-US` into `en-*-US-*`\n // Example: ['en-US'] * ['en'] = ['en']\n for (const [key, availableLocale] of availableLocalesMap.entries()) {\n if (availableLocale.matches(requestedLocale, true, false)) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n // 3) Attempt to retrieve a maximal version of the requested locale ID\n // If data is available, it'll expand `en` into `en-Latn-US` and\n // `zh` into `zh-Hans-CN`.\n // Example: ['en'] * ['en-GB', 'en-US'] = ['en-US']\n if (requestedLocale.addLikelySubtags()) {\n for (const [key, availableLocale] of availableLocalesMap.entries()) {\n if (availableLocale.matches(requestedLocale, true, false)) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n }\n // 4) Attempt to look up for a different variant for the same locale ID\n // Example: ['en-US-mac'] * ['en-US-win'] = ['en-US-win']\n requestedLocale.clearVariants();\n for (const [key, availableLocale] of availableLocalesMap.entries()) {\n if (availableLocale.matches(requestedLocale, true, true)) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n // 5) Attempt to match against the likely subtag without region\n // In the example below, addLikelySubtags will turn\n // `zh-Hant` into `zh-Hant-TW` giving `zh-TW` priority match\n // over `zh-CN`.\n //\n // Example: ['zh-Hant-HK'] * ['zh-TW', 'zh-CN'] = ['zh-TW']\n requestedLocale.clearRegion();\n if (requestedLocale.addLikelySubtags()) {\n for (const [key, availableLocale] of availableLocalesMap.entries()) {\n if (availableLocale.matches(requestedLocale, true, false)) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n }\n // 6) Attempt to look up for a different region for the same locale ID\n // Example: ['en-US'] * ['en-AU'] = ['en-AU']\n requestedLocale.clearRegion();\n for (const [key, availableLocale] of availableLocalesMap.entries()) {\n if (availableLocale.matches(requestedLocale, true, true)) {\n supportedLocales.add(key);\n availableLocalesMap.delete(key);\n if (strategy === \"lookup\") {\n return Array.from(supportedLocales);\n }\n else if (strategy === \"filtering\") {\n continue;\n }\n else {\n continue outer;\n }\n }\n }\n }\n return Array.from(supportedLocales);\n}\n","import { filterMatches } from \"./matches\";\n/**\n * Negotiates the languages between the list of requested locales against\n * a list of available locales.\n *\n * It accepts three arguments:\n *\n * requestedLocales:\n * an Array of strings with BCP47 locale IDs sorted\n * according to user preferences.\n *\n * availableLocales:\n * an Array of strings with BCP47 locale IDs of locale for which\n * resources are available. Unsorted.\n *\n * options:\n * An object with the following, optional keys:\n *\n * strategy: 'filtering' (default) | 'matching' | 'lookup'\n *\n * defaultLocale:\n * a string with BCP47 locale ID to be used\n * as a last resort locale.\n *\n *\n * It returns an Array of strings with BCP47 locale IDs sorted according to the\n * user preferences.\n *\n * The exact list will be selected differently depending on the strategy:\n *\n * 'filtering': (default)\n * In the filtering strategy, the algorithm will attempt to match\n * as many keys in the available locales in order of the requested locales.\n *\n * 'matching':\n * In the matching strategy, the algorithm will attempt to find the\n * best possible match for each element of the requestedLocales list.\n *\n * 'lookup':\n * In the lookup strategy, the algorithm will attempt to find a single\n * best available locale based on the requested locales list.\n *\n * This strategy requires defaultLocale option to be set.\n */\nexport function negotiateLanguages(requestedLocales, availableLocales, { strategy = \"filtering\", defaultLocale, } = {}) {\n const supportedLocales = filterMatches(Array.from(Object(requestedLocales)).map(String), Array.from(Object(availableLocales)).map(String), strategy);\n if (strategy === \"lookup\") {\n if (defaultLocale === undefined) {\n throw new Error(\"defaultLocale cannot be undefined for strategy `lookup`\");\n }\n if (supportedLocales.length === 0) {\n supportedLocales.push(defaultLocale);\n }\n }\n else if (defaultLocale && !supportedLocales.includes(defaultLocale)) {\n supportedLocales.push(defaultLocale);\n }\n return supportedLocales;\n}\n","export function acceptedLanguages(str = \"\") {\n if (typeof str !== \"string\") {\n throw new TypeError(\"Argument must be a string\");\n }\n const tokens = str.split(\",\").map(t => t.trim());\n return tokens.filter(t => t !== \"\").map(t => t.split(\";\")[0]);\n}\n","/*\n * @module fluent-langneg\n * @overview\n *\n * `fluent-langneg` provides language negotiation API that fits into\n * Project Fluent localization composition and fallbacking strategy.\n *\n */\nexport { negotiateLanguages } from \"./negotiate_languages\";\nexport { acceptedLanguages } from \"./accepted_languages\";\n","/**\n * The `FluentType` class is the base of Fluent's type system.\n *\n * Fluent types wrap JavaScript values and store additional configuration for\n * them, which can then be used in the `toString` method together with a proper\n * `Intl` formatter.\n */\nexport class FluentType {\n /**\n * Create a `FluentType` instance.\n *\n * @param value The JavaScript value to wrap.\n */\n constructor(value) {\n this.value = value;\n }\n /**\n * Unwrap the raw value stored by this `FluentType`.\n */\n valueOf() {\n return this.value;\n }\n}\n/**\n * A `FluentType` representing no correct value.\n */\nexport class FluentNone extends FluentType {\n /**\n * Create an instance of `FluentNone` with an optional fallback value.\n * @param value The fallback value of this `FluentNone`.\n */\n constructor(value = \"???\") {\n super(value);\n }\n /**\n * Format this `FluentNone` to the fallback string.\n */\n toString(scope) {\n return `{${this.value}}`;\n }\n}\n/**\n * A `FluentType` representing a number.\n *\n * A `FluentNumber` instance stores the number value of the number it\n * represents. It may also store an option bag of options which will be passed\n * to `Intl.NumerFormat` when the `FluentNumber` is formatted to a string.\n */\nexport class FluentNumber extends FluentType {\n /**\n * Create an instance of `FluentNumber` with options to the\n * `Intl.NumberFormat` constructor.\n *\n * @param value The number value of this `FluentNumber`.\n * @param opts Options which will be passed to `Intl.NumberFormat`.\n */\n constructor(value, opts = {}) {\n super(value);\n this.opts = opts;\n }\n /**\n * Format this `FluentNumber` to a string.\n */\n toString(scope) {\n try {\n const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);\n return nf.format(this.value);\n }\n catch (err) {\n scope.reportError(err);\n return this.value.toString(10);\n }\n }\n}\n/**\n * A `FluentType` representing a date and time.\n *\n * A `FluentDateTime` instance stores the number value of the date it\n * represents, as a numerical timestamp in milliseconds. It may also store an\n * option bag of options which will be passed to `Intl.DateTimeFormat` when the\n * `FluentDateTime` is formatted to a string.\n */\nexport class FluentDateTime extends FluentType {\n /**\n * Create an instance of `FluentDateTime` with options to the\n * `Intl.DateTimeFormat` constructor.\n *\n * @param value The number value of this `FluentDateTime`, in milliseconds.\n * @param opts Options which will be passed to `Intl.DateTimeFormat`.\n */\n constructor(value, opts = {}) {\n super(value);\n this.opts = opts;\n }\n /**\n * Format this `FluentDateTime` to a string.\n */\n toString(scope) {\n try {\n const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);\n return dtf.format(this.value);\n }\n catch (err) {\n scope.reportError(err);\n return new Date(this.value).toISOString();\n }\n }\n}\n","/* global Intl */\n/**\n * @overview\n *\n * The role of the Fluent resolver is to format a `Pattern` to an instance of\n * `FluentValue`. For performance reasons, primitive strings are considered\n * such instances, too.\n *\n * Translations can contain references to other messages or variables,\n * conditional logic in form of select expressions, traits which describe their\n * grammatical features, and can use Fluent builtins which make use of the\n * `Intl` formatters to format numbers and dates into the bundle's languages.\n * See the documentation of the Fluent syntax for more information.\n *\n * In case of errors the resolver will try to salvage as much of the\n * translation as possible. In rare situations where the resolver didn't know\n * how to recover from an error it will return an instance of `FluentNone`.\n *\n * All expressions resolve to an instance of `FluentValue`. The caller should\n * use the `toString` method to convert the instance to a native value.\n *\n * Functions in this file pass around an instance of the `Scope` class, which\n * stores the data required for successful resolution and error recovery.\n */\nimport { FluentType, FluentNone, FluentNumber, FluentDateTime } from \"./types.js\";\n// The maximum number of placeables which can be expanded in a single call to\n// `formatPattern`. The limit protects against the Billion Laughs and Quadratic\n// Blowup attacks. See https://msdn.microsoft.com/en-us/magazine/ee335713.aspx.\nconst MAX_PLACEABLES = 100;\n// Unicode bidi isolation characters.\nconst FSI = \"\\u2068\";\nconst PDI = \"\\u2069\";\n// Helper: match a variant key to the given selector.\nfunction match(scope, selector, key) {\n if (key === selector) {\n // Both are strings.\n return true;\n }\n // XXX Consider comparing options too, e.g. minimumFractionDigits.\n if (key instanceof FluentNumber &&\n selector instanceof FluentNumber &&\n key.value === selector.value) {\n return true;\n }\n if (selector instanceof FluentNumber && typeof key === \"string\") {\n let category = scope\n .memoizeIntlObject(Intl.PluralRules, selector.opts)\n .select(selector.value);\n if (key === category) {\n return true;\n }\n }\n return false;\n}\n// Helper: resolve the default variant from a list of variants.\nfunction getDefault(scope, variants, star) {\n if (variants[star]) {\n return resolvePattern(scope, variants[star].value);\n }\n scope.reportError(new RangeError(\"No default\"));\n return new FluentNone();\n}\n// Helper: resolve arguments to a call expression.\nfunction getArguments(scope, args) {\n const positional = [];\n const named = Object.create(null);\n for (const arg of args) {\n if (arg.type === \"narg\") {\n named[arg.name] = resolveExpression(scope, arg.value);\n }\n else {\n positional.push(resolveExpression(scope, arg));\n }\n }\n return { positional, named };\n}\n// Resolve an expression to a Fluent type.\nfunction resolveExpression(scope, expr) {\n switch (expr.type) {\n case \"str\":\n return expr.value;\n case \"num\":\n return new FluentNumber(expr.value, {\n minimumFractionDigits: expr.precision\n });\n case \"var\":\n return resolveVariableReference(scope, expr);\n case \"mesg\":\n return resolveMessageReference(scope, expr);\n case \"term\":\n return resolveTermReference(scope, expr);\n case \"func\":\n return resolveFunctionReference(scope, expr);\n case \"select\":\n return resolveSelectExpression(scope, expr);\n default:\n return new FluentNone();\n }\n}\n// Resolve a reference to a variable.\nfunction resolveVariableReference(scope, { name }) {\n let arg;\n if (scope.params) {\n // We're inside a TermReference. It's OK to reference undefined parameters.\n if (Object.prototype.hasOwnProperty.call(scope.params, name)) {\n arg = scope.params[name];\n }\n else {\n return new FluentNone(`$${name}`);\n }\n }\n else if (scope.args\n && Object.prototype.hasOwnProperty.call(scope.args, name)) {\n // We're in the top-level Pattern or inside a MessageReference. Missing\n // variables references produce ReferenceErrors.\n arg = scope.args[name];\n }\n else {\n scope.reportError(new ReferenceError(`Unknown variable: $${name}`));\n return new FluentNone(`$${name}`);\n }\n // Return early if the argument already is an instance of FluentType.\n if (arg instanceof FluentType) {\n return arg;\n }\n // Convert the argument to a Fluent type.\n switch (typeof arg) {\n case \"string\":\n return arg;\n case \"number\":\n return new FluentNumber(arg);\n case \"object\":\n if (arg instanceof Date) {\n return new FluentDateTime(arg.getTime());\n }\n // eslint-disable-next-line no-fallthrough\n default:\n scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`));\n return new FluentNone(`$${name}`);\n }\n}\n// Resolve a reference to another message.\nfunction resolveMessageReference(scope, { name, attr }) {\n const message = scope.bundle._messages.get(name);\n if (!message) {\n scope.reportError(new ReferenceError(`Unknown message: ${name}`));\n return new FluentNone(name);\n }\n if (attr) {\n const attribute = message.attributes[attr];\n if (attribute) {\n return resolvePattern(scope, attribute);\n }\n scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));\n return new FluentNone(`${name}.${attr}`);\n }\n if (message.value) {\n return resolvePattern(scope, message.value);\n }\n scope.reportError(new ReferenceError(`No value: ${name}`));\n return new FluentNone(name);\n}\n// Resolve a call to a Term with key-value arguments.\nfunction resolveTermReference(scope, { name, attr, args }) {\n const id = `-${name}`;\n const term = scope.bundle._terms.get(id);\n if (!term) {\n scope.reportError(new ReferenceError(`Unknown term: ${id}`));\n return new FluentNone(id);\n }\n if (attr) {\n const attribute = term.attributes[attr];\n if (attribute) {\n // Every TermReference has its own variables.\n scope.params = getArguments(scope, args).named;\n const resolved = resolvePattern(scope, attribute);\n scope.params = null;\n return resolved;\n }\n scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));\n return new FluentNone(`${id}.${attr}`);\n }\n scope.params = getArguments(scope, args).named;\n const resolved = resolvePattern(scope, term.value);\n scope.params = null;\n return resolved;\n}\n// Resolve a call to a Function with positional and key-value arguments.\nfunction resolveFunctionReference(scope, { name, args }) {\n // Some functions are built-in. Others may be provided by the runtime via\n // the `FluentBundle` constructor.\n let func = scope.bundle._functions[name];\n if (!func) {\n scope.reportError(new ReferenceError(`Unknown function: ${name}()`));\n return new FluentNone(`${name}()`);\n }\n if (typeof func !== \"function\") {\n scope.reportError(new TypeError(`Function ${name}() is not callable`));\n return new FluentNone(`${name}()`);\n }\n try {\n let resolved = getArguments(scope, args);\n return func(resolved.positional, resolved.named);\n }\n catch (err) {\n scope.reportError(err);\n return new FluentNone(`${name}()`);\n }\n}\n// Resolve a select expression to the member object.\nfunction resolveSelectExpression(scope, { selector, variants, star }) {\n let sel = resolveExpression(scope, selector);\n if (sel instanceof FluentNone) {\n return getDefault(scope, variants, star);\n }\n // Match the selector against keys of each variant, in order.\n for (const variant of variants) {\n const key = resolveExpression(scope, variant.key);\n if (match(scope, sel, key)) {\n return resolvePattern(scope, variant.value);\n }\n }\n return getDefault(scope, variants, star);\n}\n// Resolve a pattern (a complex string with placeables).\nexport function resolveComplexPattern(scope, ptn) {\n if (scope.dirty.has(ptn)) {\n scope.reportError(new RangeError(\"Cyclic reference\"));\n return new FluentNone();\n }\n // Tag the pattern as dirty for the purpose of the current resolution.\n scope.dirty.add(ptn);\n const result = [];\n // Wrap interpolations with Directional Isolate Formatting characters\n // only when the pattern has more than one element.\n const useIsolating = scope.bundle._useIsolating && ptn.length > 1;\n for (const elem of ptn) {\n if (typeof elem === \"string\") {\n result.push(scope.bundle._transform(elem));\n continue;\n }\n scope.placeables++;\n if (scope.placeables > MAX_PLACEABLES) {\n scope.dirty.delete(ptn);\n // This is a fatal error which causes the resolver to instantly bail out\n // on this pattern. The length check protects against excessive memory\n // usage, and throwing protects against eating up the CPU when long\n // placeables are deeply nested.\n throw new RangeError(`Too many placeables expanded: ${scope.placeables}, ` +\n `max allowed is ${MAX_PLACEABLES}`);\n }\n if (useIsolating) {\n result.push(FSI);\n }\n result.push(resolveExpression(scope, elem).toString(scope));\n if (useIsolating) {\n result.push(PDI);\n }\n }\n scope.dirty.delete(ptn);\n return result.join(\"\");\n}\n// Resolve a simple or a complex Pattern to a FluentString (which is really the\n// string primitive).\nfunction resolvePattern(scope, value) {\n // Resolve a simple pattern.\n if (typeof value === \"string\") {\n return scope.bundle._transform(value);\n }\n return resolveComplexPattern(scope, value);\n}\n","export class Scope {\n constructor(bundle, errors, args) {\n /** The Set of patterns already encountered during this resolution.\n * Used to detect and prevent cyclic resolutions. */\n this.dirty = new WeakSet();\n /** A dict of parameters passed to a TermReference. */\n this.params = null;\n /** The running count of placeables resolved so far. Used to detect the\n * Billion Laughs and Quadratic Blowup attacks. */\n this.placeables = 0;\n this.bundle = bundle;\n this.errors = errors;\n this.args = args;\n }\n reportError(error) {\n if (!this.errors) {\n throw error;\n }\n this.errors.push(error);\n }\n memoizeIntlObject(ctor, opts) {\n let cache = this.bundle._intls.get(ctor);\n if (!cache) {\n cache = {};\n this.bundle._intls.set(ctor, cache);\n }\n let id = JSON.stringify(opts);\n if (!cache[id]) {\n cache[id] = new ctor(this.bundle.locales, opts);\n }\n return cache[id];\n }\n}\n","/**\n * @overview\n *\n * The FTL resolver ships with a number of functions built-in.\n *\n * Each function take two arguments:\n * - args - an array of positional args\n * - opts - an object of key-value args\n *\n * Arguments to functions are guaranteed to already be instances of\n * `FluentValue`. Functions must return `FluentValues` as well.\n */\nimport { FluentNone, FluentNumber, FluentDateTime } from \"./types.js\";\nfunction values(opts, allowed) {\n const unwrapped = Object.create(null);\n for (const [name, opt] of Object.entries(opts)) {\n if (allowed.includes(name)) {\n unwrapped[name] = opt.valueOf();\n }\n }\n return unwrapped;\n}\nconst NUMBER_ALLOWED = [\n \"unitDisplay\",\n \"currencyDisplay\",\n \"useGrouping\",\n \"minimumIntegerDigits\",\n \"minimumFractionDigits\",\n \"maximumFractionDigits\",\n \"minimumSignificantDigits\",\n \"maximumSignificantDigits\",\n];\n/**\n * The implementation of the `NUMBER()` builtin available to translations.\n *\n * Translations may call the `NUMBER()` builtin in order to specify formatting\n * options of a number. For example:\n *\n * pi = The value of π is {NUMBER($pi, maximumFractionDigits: 2)}.\n *\n * The implementation expects an array of `FluentValues` representing the\n * positional arguments, and an object of named `FluentValues` representing the\n * named parameters.\n *\n * The following options are recognized:\n *\n * unitDisplay\n * currencyDisplay\n * useGrouping\n * minimumIntegerDigits\n * minimumFractionDigits\n * maximumFractionDigits\n * minimumSignificantDigits\n * maximumSignificantDigits\n *\n * Other options are ignored.\n *\n * @param args The positional arguments passed to this `NUMBER()`.\n * @param opts The named argments passed to this `NUMBER()`.\n */\nexport function NUMBER(args, opts) {\n let arg = args[0];\n if (arg instanceof FluentNone) {\n return new FluentNone(`NUMBER(${arg.valueOf()})`);\n }\n if (arg instanceof FluentNumber || arg instanceof FluentDateTime) {\n return new FluentNumber(arg.valueOf(), {\n ...arg.opts,\n ...values(opts, NUMBER_ALLOWED)\n });\n }\n throw new TypeError(\"Invalid argument to NUMBER\");\n}\nconst DATETIME_ALLOWED = [\n \"dateStyle\",\n \"timeStyle\",\n \"fractionalSecondDigits\",\n \"dayPeriod\",\n \"hour12\",\n \"weekday\",\n \"era\",\n \"year\",\n \"month\",\n \"day\",\n \"hour\",\n \"minute\",\n \"second\",\n \"timeZoneName\",\n];\n/**\n * The implementation of the `DATETIME()` builtin available to translations.\n *\n * Translations may call the `DATETIME()` builtin in order to specify\n * formatting options of a number. For example:\n *\n * now = It's {DATETIME($today, month: \"long\")}.\n *\n * The implementation expects an array of `FluentValues` representing the\n * positional arguments, and an object of named `FluentValues` representing the\n * named parameters.\n *\n * The following options are recognized:\n *\n * dateStyle\n * timeStyle\n * fractionalSecondDigits\n * dayPeriod\n * hour12\n * weekday\n * era\n * year\n * month\n * day\n * hour\n * minute\n * second\n * timeZoneName\n *\n * Other options are ignored.\n *\n * @param args The positional arguments passed to this `DATETIME()`.\n * @param opts The named argments passed to this `DATETIME()`.\n */\nexport function DATETIME(args, opts) {\n let arg = args[0];\n if (arg instanceof FluentNone) {\n return new FluentNone(`DATETIME(${arg.valueOf()})`);\n }\n if (arg instanceof FluentNumber || arg instanceof FluentDateTime) {\n return new FluentDateTime(arg.valueOf(), {\n ...arg.opts,\n ...values(opts, DATETIME_ALLOWED)\n });\n }\n throw new TypeError(\"Invalid argument to DATETIME\");\n}\n","import { resolveComplexPattern } from \"./resolver.js\";\nimport { Scope } from \"./scope.js\";\nimport { FluentNone } from \"./types.js\";\nimport { NUMBER, DATETIME } from \"./builtins.js\";\n/**\n * Message bundles are single-language stores of translation resources. They are\n * responsible for formatting message values and attributes to strings.\n */\nexport class FluentBundle {\n /**\n * Create an instance of `FluentBundle`.\n *\n * The `locales` argument is used to instantiate `Intl` formatters used by\n * translations. The `options` object can be used to configure the bundle.\n *\n * Examples:\n *\n * let bundle = new FluentBundle([\"en-US\", \"en\"]);\n *\n * let bundle = new FluentBundle(locales, {useIsolating: false});\n *\n * let bundle = new FluentBundle(locales, {\n * useIsolating: true,\n * functions: {\n * NODE_ENV: () => process.env.NODE_ENV\n * }\n * });\n *\n * Available options:\n *\n * - `functions` - an object of additional functions available to\n * translations as builtins.\n *\n * - `useIsolating` - boolean specifying whether to use Unicode isolation\n * marks (FSI, PDI) for bidi interpolations. Default: `true`.\n *\n * - `transform` - a function used to transform string parts of patterns.\n */\n constructor(locales, { functions, useIsolating = true, transform = (v) => v } = {}) {\n this._terms = new Map();\n this._messages = new Map();\n this._intls = new WeakMap();\n this.locales = Array.isArray(locales) ? locales : [locales];\n this._functions = {\n NUMBER,\n DATETIME,\n ...functions\n };\n this._useIsolating = useIsolating;\n this._transform = transform;\n }\n /**\n * Check if a message is present in the bundle.\n *\n * @param id - The identifier of the message to check.\n */\n hasMessage(id) {\n return this._messages.has(id);\n }\n /**\n * Return a raw unformatted message object from the bundle.\n *\n * Raw messages are `{value, attributes}` shapes containing translation units\n * called `Patterns`. `Patterns` are implementation-specific; they should be\n * treated as black boxes and formatted with `FluentBundle.formatPattern`.\n *\n * @param id - The identifier of the message to check.\n */\n getMessage(id) {\n return this._messages.get(id);\n }\n /**\n * Add a translation resource to the bundle.\n *\n * The translation resource must be an instance of `FluentResource`.\n *\n * let res = new FluentResource(\"foo = Foo\");\n * bundle.addResource(res);\n * bundle.getMessage(\"foo\");\n * // → {value: .., attributes: {..}}\n *\n * Available options:\n *\n * - `allowOverrides` - boolean specifying whether it's allowed to override\n * an existing message or term with a new value. Default: `false`.\n *\n * @param res - FluentResource object.\n * @param options\n */\n addResource(res, { allowOverrides = false } = {}) {\n const errors = [];\n for (let i = 0; i < res.body.length; i++) {\n let entry = res.body[i];\n if (entry.id.startsWith(\"-\")) {\n // Identifiers starting with a dash (-) define terms. Terms are private\n // and cannot be retrieved from FluentBundle.\n if (allowOverrides === false && this._terms.has(entry.id)) {\n errors.push(new Error(`Attempt to override an existing term: \"${entry.id}\"`));\n continue;\n }\n this._terms.set(entry.id, entry);\n }\n else {\n if (allowOverrides === false && this._messages.has(entry.id)) {\n errors.push(new Error(`Attempt to override an existing message: \"${entry.id}\"`));\n continue;\n }\n this._messages.set(entry.id, entry);\n }\n }\n return errors;\n }\n /**\n * Format a `Pattern` to a string.\n *\n * Format a raw `Pattern` into a string. `args` will be used to resolve\n * references to variables passed as arguments to the translation.\n *\n * In case of errors `formatPattern` will try to salvage as much of the\n * translation as possible and will still return a string. For performance\n * reasons, the encountered errors are not returned but instead are appended\n * to the `errors` array passed as the third argument.\n *\n * let errors = [];\n * bundle.addResource(\n * new FluentResource(\"hello = Hello, {$name}!\"));\n *\n * let hello = bundle.getMessage(\"hello\");\n * if (hello.value) {\n * bundle.formatPattern(hello.value, {name: \"Jane\"}, errors);\n * // Returns \"Hello, Jane!\" and `errors` is empty.\n *\n * bundle.formatPattern(hello.value, undefined, errors);\n * // Returns \"Hello, {$name}!\" and `errors` is now:\n * // []\n * }\n *\n * If `errors` is omitted, the first encountered error will be thrown.\n */\n formatPattern(pattern, args = null, errors = null) {\n // Resolve a simple pattern without creating a scope. No error handling is\n // required; by definition simple patterns don't have placeables.\n if (typeof pattern === \"string\") {\n return this._transform(pattern);\n }\n // Resolve a complex pattern.\n let scope = new Scope(this, errors, args);\n try {\n let value = resolveComplexPattern(scope, pattern);\n return value.toString(scope);\n }\n catch (err) {\n if (scope.errors) {\n scope.errors.push(err);\n return new FluentNone().toString(scope);\n }\n throw err;\n }\n }\n}\n","// This regex is used to iterate through the beginnings of messages and terms.\n// With the /m flag, the ^ matches at the beginning of every line.\nconst RE_MESSAGE_START = /^(-?[a-zA-Z][\\w-]*) *= */gm;\n// Both Attributes and Variants are parsed in while loops. These regexes are\n// used to break out of them.\nconst RE_ATTRIBUTE_START = /\\.([a-zA-Z][\\w-]*) *= */y;\nconst RE_VARIANT_START = /\\*?\\[/y;\nconst RE_NUMBER_LITERAL = /(-?[0-9]+(?:\\.([0-9]+))?)/y;\nconst RE_IDENTIFIER = /([a-zA-Z][\\w-]*)/y;\nconst RE_REFERENCE = /([$-])?([a-zA-Z][\\w-]*)(?:\\.([a-zA-Z][\\w-]*))?/y;\nconst RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/;\n// A \"run\" is a sequence of text or string literal characters which don't\n// require any special handling. For TextElements such special characters are: {\n// (starts a placeable), and line breaks which require additional logic to check\n// if the next line is indented. For StringLiterals they are: \\ (starts an\n// escape sequence), \" (ends the literal), and line breaks which are not allowed\n// in StringLiterals. Note that string runs may be empty; text runs may not.\nconst RE_TEXT_RUN = /([^{}\\n\\r]+)/y;\nconst RE_STRING_RUN = /([^\\\\\"\\n\\r]*)/y;\n// Escape sequences.\nconst RE_STRING_ESCAPE = /\\\\([\\\\\"])/y;\nconst RE_UNICODE_ESCAPE = /\\\\u([a-fA-F0-9]{4})|\\\\U([a-fA-F0-9]{6})/y;\n// Used for trimming TextElements and indents.\nconst RE_LEADING_NEWLINES = /^\\n+/;\nconst RE_TRAILING_SPACES = / +$/;\n// Used in makeIndent to strip spaces from blank lines and normalize CRLF to LF.\nconst RE_BLANK_LINES = / *\\r?\\n/g;\n// Used in makeIndent to measure the indentation.\nconst RE_INDENT = /( *)$/;\n// Common tokens.\nconst TOKEN_BRACE_OPEN = /{\\s*/y;\nconst TOKEN_BRACE_CLOSE = /\\s*}/y;\nconst TOKEN_BRACKET_OPEN = /\\[\\s*/y;\nconst TOKEN_BRACKET_CLOSE = /\\s*] */y;\nconst TOKEN_PAREN_OPEN = /\\s*\\(\\s*/y;\nconst TOKEN_ARROW = /\\s*->\\s*/y;\nconst TOKEN_COLON = /\\s*:\\s*/y;\n// Note the optional comma. As a deviation from the Fluent EBNF, the parser\n// doesn't enforce commas between call arguments.\nconst TOKEN_COMMA = /\\s*,?\\s*/y;\nconst TOKEN_BLANK = /\\s+/y;\n/**\n * Fluent Resource is a structure storing parsed localization entries.\n */\nexport class FluentResource {\n constructor(source) {\n this.body = [];\n RE_MESSAGE_START.lastIndex = 0;\n let cursor = 0;\n // Iterate over the beginnings of messages and terms to efficiently skip\n // comments and recover from errors.\n while (true) {\n let next = RE_MESSAGE_START.exec(source);\n if (next === null) {\n break;\n }\n cursor = RE_MESSAGE_START.lastIndex;\n try {\n this.body.push(parseMessage(next[1]));\n }\n catch (err) {\n if (err instanceof SyntaxError) {\n // Don't report any Fluent syntax errors. Skip directly to the\n // beginning of the next message or term.\n continue;\n }\n throw err;\n }\n }\n // The parser implementation is inlined below for performance reasons,\n // as well as for convenience of accessing `source` and `cursor`.\n // The parser focuses on minimizing the number of false negatives at the\n // expense of increasing the risk of false positives. In other words, it\n // aims at parsing valid Fluent messages with a success rate of 100%, but it\n // may also parse a few invalid messages which the reference parser would\n // reject. The parser doesn't perform any validation and may produce entries\n // which wouldn't make sense in the real world. For best results users are\n // advised to validate translations with the fluent-syntax parser\n // pre-runtime.\n // The parser makes an extensive use of sticky regexes which can be anchored\n // to any offset of the source string without slicing it. Errors are thrown\n // to bail out of parsing of ill-formed messages.\n function test(re) {\n re.lastIndex = cursor;\n return re.test(source);\n }\n // Advance the cursor by the char if it matches. May be used as a predicate\n // (was the match found?) or, if errorClass is passed, as an assertion.\n function consumeChar(char, errorClass) {\n if (source[cursor] === char) {\n cursor++;\n return true;\n }\n if (errorClass) {\n throw new errorClass(`Expected ${char}`);\n }\n return false;\n }\n // Advance the cursor by the token if it matches. May be used as a predicate\n // (was the match found?) or, if errorClass is passed, as an assertion.\n function consumeToken(re, errorClass) {\n if (test(re)) {\n cursor = re.lastIndex;\n return true;\n }\n if (errorClass) {\n throw new errorClass(`Expected ${re.toString()}`);\n }\n return false;\n }\n // Execute a regex, advance the cursor, and return all capture groups.\n function match(re) {\n re.lastIndex = cursor;\n let result = re.exec(source);\n if (result === null) {\n throw new SyntaxError(`Expected ${re.toString()}`);\n }\n cursor = re.lastIndex;\n return result;\n }\n // Execute a regex, advance the cursor, and return the capture group.\n function match1(re) {\n return match(re)[1];\n }\n function parseMessage(id) {\n let value = parsePattern();\n let attributes = parseAttributes();\n if (value === null && Object.keys(attributes).length === 0) {\n throw new SyntaxError(\"Expected message value or attributes\");\n }\n return { id, value, attributes };\n }\n function parseAttributes() {\n let attrs = Object.create(null);\n while (test(RE_ATTRIBUTE_START)) {\n let name = match1(RE_ATTRIBUTE_START);\n let value = parsePattern();\n if (value === null) {\n throw new SyntaxError(\"Expected attribute value\");\n }\n attrs[name] = value;\n }\n return attrs;\n }\n function parsePattern() {\n let first;\n // First try to parse any simple text on the same line as the id.\n if (test(RE_TEXT_RUN)) {\n first = match1(RE_TEXT_RUN);\n }\n // If there's a placeable on the first line, parse a complex pattern.\n if (source[cursor] === \"{\" || source[cursor] === \"}\") {\n // Re-use the text parsed above, if possible.\n return parsePatternElements(first ? [first] : [], Infinity);\n }\n // RE_TEXT_VALUE stops at newlines. Only continue parsing the pattern if\n // what comes after the newline is indented.\n let indent = parseIndent();\n if (indent) {\n if (first) {\n // If there's text on the first line, the blank block is part of the\n // translation content in its entirety.\n return parsePatternElements([first, indent], indent.length);\n }\n // Otherwise, we're dealing with a block pattern, i.e. a pattern which\n // starts on a new line. Discrad the leading newlines but keep the\n // inline indent; it will be used by the dedentation logic.\n indent.value = trim(indent.value, RE_LEADING_NEWLINES);\n return parsePatternElements([indent], indent.length);\n }\n if (first) {\n // It was just a simple inline text after all.\n return trim(first, RE_TRAILING_SPACES);\n }\n return null;\n }\n // Parse a complex pattern as an array of elements.\n function parsePatternElements(elements = [], commonIndent) {\n while (true) {\n if (test(RE_TEXT_RUN)) {\n elements.push(match1(RE_TEXT_RUN));\n continue;\n }\n if (source[cursor] === \"{\") {\n elements.push(parsePlaceable());\n continue;\n }\n if (source[cursor] === \"}\") {\n throw new SyntaxError(\"Unbalanced closing brace\");\n }\n let indent = parseIndent();\n if (indent) {\n elements.push(indent);\n commonIndent = Math.min(commonIndent, indent.length);\n continue;\n }\n break;\n }\n let lastIndex = elements.length - 1;\n let lastElement = elements[lastIndex];\n // Trim the trailing spaces in the last element if it's a TextElement.\n if (typeof lastElement === \"string\") {\n elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES);\n }\n let baked = [];\n for (let element of elements) {\n if (element instanceof Indent) {\n // Dedent indented lines by the maximum common indent.\n element = element.value.slice(0, element.value.length - commonIndent);\n }\n if (element) {\n baked.push(element);\n }\n }\n return baked;\n }\n function parsePlaceable() {\n consumeToken(TOKEN_BRACE_OPEN, SyntaxError);\n let selector = parseInlineExpression();\n if (consumeToken(TOKEN_BRACE_CLOSE)) {\n return selector;\n }\n if (consumeToken(TOKEN_ARROW)) {\n let variants = parseVariants();\n consumeToken(TOKEN_BRACE_CLOSE, SyntaxError);\n return {\n type: \"select\",\n selector,\n ...variants\n };\n }\n throw new SyntaxError(\"Unclosed placeable\");\n }\n function parseInlineExpression() {\n if (source[cursor] === \"{\") {\n // It's a nested placeable.\n return parsePlaceable();\n }\n if (test(RE_REFERENCE)) {\n let [, sigil, name, attr = null] = match(RE_REFERENCE);\n if (sigil === \"$\") {\n return { type: \"var\", name };\n }\n if (consumeToken(TOKEN_PAREN_OPEN)) {\n let args = parseArguments();\n if (sigil === \"-\") {\n // A parameterized term: -term(...).\n return { type: \"term\", name, attr, args };\n }\n if (RE_FUNCTION_NAME.test(name)) {\n return { type: \"func\", name, args };\n }\n throw new SyntaxError(\"Function names must be all upper-case\");\n }\n if (sigil === \"-\") {\n // A non-parameterized term: -term.\n return {\n type: \"term\",\n name,\n attr,\n args: []\n };\n }\n return { type: \"mesg\", name, attr };\n }\n return parseLiteral();\n }\n function parseArguments() {\n let args = [];\n while (true) {\n switch (source[cursor]) {\n case \")\": // End of the argument list.\n cursor++;\n return args;\n case undefined: // EOF\n throw new SyntaxError(\"Unclosed argument list\");\n }\n args.push(parseArgument());\n // Commas between arguments are treated as whitespace.\n consumeToken(TOKEN_COMMA);\n }\n }\n function parseArgument() {\n let expr = parseInlineExpression();\n if (expr.type !== \"mesg\") {\n return expr;\n }\n if (consumeToken(TOKEN_COLON)) {\n // The reference is the beginning of a named argument.\n return {\n type: \"narg\",\n name: expr.name,\n value: parseLiteral()\n };\n }\n // It's a regular message reference.\n return expr;\n }\n function parseVariants() {\n let variants = [];\n let count = 0;\n let star;\n while (test(RE_VARIANT_START)) {\n if (consumeChar(\"*\")) {\n star = count;\n }\n let key = parseVariantKey();\n let value = parsePattern();\n if (value === null) {\n throw new SyntaxError(\"Expected variant value\");\n }\n variants[count++] = { key, value };\n }\n if (count === 0) {\n return null;\n }\n if (star === undefined) {\n throw new SyntaxError(\"Expected default variant\");\n }\n return { variants, star };\n }\n function parseVariantKey() {\n consumeToken(TOKEN_BRACKET_OPEN, SyntaxError);\n let key;\n if (test(RE_NUMBER_LITERAL)) {\n key = parseNumberLiteral();\n }\n else {\n key = {\n type: \"str\",\n value: match1(RE_IDENTIFIER)\n };\n }\n consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError);\n return key;\n }\n function parseLiteral() {\n if (test(RE_NUMBER_LITERAL)) {\n return parseNumberLiteral();\n }\n if (source[cursor] === '\"') {\n return parseStringLiteral();\n }\n throw new SyntaxError(\"Invalid expression\");\n }\n function parseNumberLiteral() {\n let [, value, fraction = \"\"] = match(RE_NUMBER_LITERAL);\n let precision = fraction.length;\n return {\n type: \"num\",\n value: parseFloat(value),\n precision\n };\n }\n function parseStringLiteral() {\n consumeChar('\"', SyntaxError);\n let value = \"\";\n while (true) {\n value += match1(RE_STRING_RUN);\n if (source[cursor] === \"\\\\\") {\n value += parseEscapeSequence();\n continue;\n }\n if (consumeChar('\"')) {\n return { type: \"str\", value };\n }\n // We've reached an EOL of EOF.\n throw new SyntaxError(\"Unclosed string literal\");\n }\n }\n // Unescape known escape sequences.\n function parseEscapeSequence() {\n if (test(RE_STRING_ESCAPE)) {\n return match1(RE_STRING_ESCAPE);\n }\n if (test(RE_UNICODE_ESCAPE)) {\n let [, codepoint4, codepoint6] = match(RE_UNICODE_ESCAPE);\n let codepoint = parseInt(codepoint4 || codepoint6, 16);\n return codepoint <= 0xd7ff || 0xe000 <= codepoint\n // It's a Unicode scalar value.\n ? String.fromCodePoint(codepoint)\n // Lonely surrogates can cause trouble when the parsing result is\n // saved using UTF-8. Use U+FFFD REPLACEMENT CHARACTER instead.\n : \"�\";\n }\n throw new SyntaxError(\"Unknown escape sequence\");\n }\n // Parse blank space. Return it if it looks like indent before a pattern\n // line. Skip it othwerwise.\n function parseIndent() {\n let start = cursor;\n consumeToken(TOKEN_BLANK);\n // Check the first non-blank character after the indent.\n switch (source[cursor]) {\n case \".\":\n case \"[\":\n case \"*\":\n case \"}\":\n case undefined: // EOF\n // A special character. End the Pattern.\n return false;\n case \"{\":\n // Placeables don't require indentation (in EBNF: block-placeable).\n // Continue the Pattern.\n return makeIndent(source.slice(start, cursor));\n }\n // If the first character on the line is not one of the special characters\n // listed above, it's a regular text character. Check if there's at least\n // one space of indent before it.\n if (source[cursor - 1] === \" \") {\n // It's an indented text character (in EBNF: indented-char). Continue\n // the Pattern.\n return makeIndent(source.slice(start, cursor));\n }\n // A not-indented text character is likely the identifier of the next\n // message. End the Pattern.\n return false;\n }\n // Trim blanks in text according to the given regex.\n function trim(text, re) {\n return text.replace(re, \"\");\n }\n // Normalize a blank block and extract the indent details.\n function makeIndent(blank) {\n let value = blank.replace(RE_BLANK_LINES, \"\\n\");\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n let length = RE_INDENT.exec(blank)[1].length;\n return new Indent(value, length);\n }\n }\n}\nclass Indent {\n constructor(value, length) {\n this.value = value;\n this.length = length;\n }\n}\n","/**\n * @module fluent\n * @overview\n *\n * `fluent` is a JavaScript implementation of Project Fluent, a localization\n * framework designed to unleash the expressive power of the natural language.\n *\n */\nexport { FluentBundle } from \"./bundle.js\";\nexport { FluentResource } from \"./resource.js\";\nexport { FluentType, FluentNumber, FluentDateTime } from \"./types.js\";\n","import { FluentResource } from \"@fluent/bundle\";\n\nconst enUS = new FluentResource(`\nhello = Hello, { $userName }!\nhello-no-name = Hello, stranger!\ntype-name =\n .placeholder = Your name\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Today is { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = It’s {$date}.\n\nsign-in-or-cancel = Sign in or cancel.\nclicked-sign-in = You are now signed in.\nclicked-cancel = OK, nevermind.\n\nfavorite-fruit = Favorite Fruit\nfruit-apple = Apple\nfruit-orange = Orange\nfruit-lemon = Lemon\n`);\n\nconst pl = new FluentResource(`\nhello = Cześć { $userName }!\n# hello-no-name = Witaj nieznajomy!\ntype-name =\n .placeholder = Twoje imię\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Dziś jest {DATETIME($date)}.\n\n# Commented out to demonstrate fallback.\n# $date (Date) - Current date, formatted as weekday.\n# today-weekday = Jest {$date}.\n\nsign-in-or-cancel = Zaloguj albo anuluj.\nclicked-sign-in = Brawo!\nclicked-cancel = OK, nieważne.\n\nfavorite-fruit = Ulubiony owoc\nfruit-apple = Jabłko\nfruit-orange = Pomarańczowy\nfruit-lemon = Cytrynowy\n`);\n\nconst cs = new FluentResource(`\nhello = Ahoj, { $userName }!\nhello-no-name = Vítej cizinče!\ntype-name =\n .placeholder = Tvé jméno\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Dnes je { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = Je {$date}.\n\nsign-in-or-cancel = Přihlásit nebo zrušit.\nclicked-sign-in = Nyní jsi přihlášen.\nclicked-cancel = Ok, nevadí.\n\nfavorite-fruit = Oblíbené ovoce\nfruit-apple = Jablko\nfruit-orange = Pomeranč\nfruit-lemon = Citrón\n`);\n\nconst thTH = new FluentResource(`\nhello = สวัสดีค่ะ คุณ{ $userName }\nhello-no-name = สวัสดีค่ะ\ntype-name =\n .placeholder = ชื่อของคุณ\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = วันนี้เป็น { DATETIME($date) }\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = มันคือ {$date}\n\nsign-in-or-cancel = เข้าสู่ระบบ หรือ ยกเลิก\nclicked-sign-in = เรียบร้อย\nclicked-cancel = ไม่เป็นไร\n\nfavorite-fruit = ผลไม้ที่ชอบ\nfruit-apple = แอปเปิ้ล\nfruit-orange = ส้ม\nfruit-lemon = มะนาว\n`);\n\nconst eo = new FluentResource(`\nhello = Saluton, { $userName }!\nhello-no-name = Saluton, fremdulo!\ntype-name =\n .placeholder = Via nomo\n\n# $date (Date) - Current date, formatted as month and day.\ntoday-date = Hodiaŭ estas { DATETIME($date) }.\n# $date (Date) - Current date, formatted as weekday.\ntoday-weekday = Estas {$date}.\n\nsign-in-or-cancel = Ensaluti aŭ nuligi.\nclicked-sign-in = Vi estas nun ensalutina.\nclicked-cancel = Bone, ne gravas.\n\nfavorite-fruit = Preferata Frukto\nfruit-apple = Pomo\nfruit-orange = Oranĝo\nfruit-lemon = Citrono\n`);\n\nexport default {\n \"en-US\": enUS,\n \"pl\": pl,\n \"cs\": cs,\n \"th-TH\": thTH,\n \"eo\": eo,\n};\n","import { negotiateLanguages } from '@fluent/langneg';\nimport { FluentBundle, FluentResource } from '@fluent/bundle';\nimport { Elm } from \"./Example.elm\";\nimport resources from \"../common/resources.js\";\n\nconst supportedLocales = Object.keys(resources);\n\nfunction getCurrentLocales(desiredLocales) {\n\treturn negotiateLanguages(\n desiredLocales,\n supportedLocales,\n { defaultLocale: 'en-US' }\n )\n}\n\nfunction getBundles(desiredLocales) {\n const currentLocales = getCurrentLocales(desiredLocales);\n const bundles = [];\n\n for (const locale of currentLocales) {\n const bundle = new FluentBundle(locale);\n bundle.addResource(resources[locale]);\n bundles.push(bundle)\n }\n\n return bundles;\n}\n\n// Log translation errors\nwindow.addEventListener(\"fluent-web-error\", function(event) {\n console.error(event);\n})\n\nconst app = Elm.Example.init({\n node: document.getElementById(\"root\"),\n flags: {\n \tbundles: getBundles(navigator.languages,),\n \tinitialLocale: getCurrentLocales(navigator.languages)[0],\n }\n});\n\n\napp.ports.changeDesirecLocale.subscribe(function(locales) {\n\tapp.ports.gotBundles.send(getBundles(locales))\n})\n"]}
--------------------------------------------------------------------------------
/example/common/resources.js:
--------------------------------------------------------------------------------
1 | import { FluentResource } from "@fluent/bundle";
2 |
3 | const enUS = new FluentResource(`
4 | hello = Hello, { $userName }!
5 | hello-no-name = Hello, stranger!
6 | type-name =
7 | .placeholder = Your name
8 |
9 | # $date (Date) - Current date, formatted as month and day.
10 | today-date = Today is { DATETIME($date) }.
11 | # $date (Date) - Current date, formatted as weekday.
12 | today-weekday = It’s {$date}.
13 |
14 | sign-in-or-cancel = Sign in or cancel.
15 | clicked-sign-in = You are now signed in.
16 | clicked-cancel = OK, nevermind.
17 |
18 | favorite-fruit = Favorite Fruit
19 | fruit-apple = Apple
20 | fruit-orange = Orange
21 | fruit-lemon = Lemon
22 | `);
23 |
24 | const pl = new FluentResource(`
25 | hello = Cześć { $userName }!
26 | # hello-no-name = Witaj nieznajomy!
27 | type-name =
28 | .placeholder = Twoje imię
29 |
30 | # $date (Date) - Current date, formatted as month and day.
31 | today-date = Dziś jest {DATETIME($date)}.
32 |
33 | # Commented out to demonstrate fallback.
34 | # $date (Date) - Current date, formatted as weekday.
35 | # today-weekday = Jest {$date}.
36 |
37 | sign-in-or-cancel = Zaloguj albo anuluj.
38 | clicked-sign-in = Brawo!
39 | clicked-cancel = OK, nieważne.
40 |
41 | favorite-fruit = Ulubiony owoc
42 | fruit-apple = Jabłko
43 | fruit-orange = Pomarańczowy
44 | fruit-lemon = Cytrynowy
45 | `);
46 |
47 | const cs = new FluentResource(`
48 | hello = Ahoj, { $userName }!
49 | hello-no-name = Vítej cizinče!
50 | type-name =
51 | .placeholder = Tvé jméno
52 |
53 | # $date (Date) - Current date, formatted as month and day.
54 | today-date = Dnes je { DATETIME($date) }.
55 | # $date (Date) - Current date, formatted as weekday.
56 | today-weekday = Je {$date}.
57 |
58 | sign-in-or-cancel = Přihlásit nebo zrušit.
59 | clicked-sign-in = Nyní jsi přihlášen.
60 | clicked-cancel = Ok, nevadí.
61 |
62 | favorite-fruit = Oblíbené ovoce
63 | fruit-apple = Jablko
64 | fruit-orange = Pomeranč
65 | fruit-lemon = Citrón
66 | `);
67 |
68 | const thTH = new FluentResource(`
69 | hello = สวัสดีค่ะ คุณ{ $userName }
70 | hello-no-name = สวัสดีค่ะ
71 | type-name =
72 | .placeholder = ชื่อของคุณ
73 |
74 | # $date (Date) - Current date, formatted as month and day.
75 | today-date = วันนี้เป็น { DATETIME($date) }
76 | # $date (Date) - Current date, formatted as weekday.
77 | today-weekday = มันคือ {$date}
78 |
79 | sign-in-or-cancel = เข้าสู่ระบบ หรือ ยกเลิก
80 | clicked-sign-in = เรียบร้อย
81 | clicked-cancel = ไม่เป็นไร
82 |
83 | favorite-fruit = ผลไม้ที่ชอบ
84 | fruit-apple = แอปเปิ้ล
85 | fruit-orange = ส้ม
86 | fruit-lemon = เลมอน
87 | `);
88 |
89 | const eo = new FluentResource(`
90 | hello = Saluton, { $userName }!
91 | hello-no-name = Saluton, fremdulo!
92 | type-name =
93 | .placeholder = Via nomo
94 |
95 | # $date (Date) - Current date, formatted as month and day.
96 | today-date = Hodiaŭ estas { DATETIME($date) }.
97 | # $date (Date) - Current date, formatted as weekday.
98 | today-weekday = Estas {$date}.
99 |
100 | sign-in-or-cancel = Ensaluti aŭ nuligi.
101 | clicked-sign-in = Vi estas nun ensalutina.
102 | clicked-cancel = Bone, ne gravas.
103 |
104 | favorite-fruit = Preferata Frukto
105 | fruit-apple = Pomo
106 | fruit-orange = Oranĝo
107 | fruit-lemon = Citrono
108 | `);
109 |
110 | export default {
111 | "en-US": enUS,
112 | "pl": pl,
113 | "cs": cs,
114 | "th-TH": thTH,
115 | "eo": eo,
116 | };
117 |
--------------------------------------------------------------------------------
/example/elm/Example.elm:
--------------------------------------------------------------------------------
1 | port module Example exposing (main)
2 |
3 | import BeautifulExample
4 | import Color
5 | import Html exposing (Html)
6 | import Html.Attributes
7 | import Html.Events
8 | import Json.Decode exposing (Decoder)
9 | import Json.Encode exposing (Value)
10 | import Task
11 | import Time exposing (Posix, Zone)
12 |
13 |
14 | main : Program Flags Model Msg
15 | main =
16 | let
17 | oxfordCommaify : (a -> String) -> List a -> String
18 | oxfordCommaify stringifier list =
19 | case List.reverse (List.map stringifier list) of
20 | [] ->
21 | ""
22 |
23 | x :: [] ->
24 | x
25 |
26 | y :: x :: [] ->
27 | x ++ " and " ++ y
28 |
29 | z :: zs ->
30 | String.join ", " (List.reverse (("and " ++ z) :: zs))
31 | in
32 | BeautifulExample.element
33 | { title = "Fluent-Web"
34 | , details =
35 | Just
36 | (String.join " "
37 | [ "A demonstration of using fluent-web custom web components for"
38 | , String.fromInt (List.length allLocales)
39 | , "locales,"
40 | , oxfordCommaify localeToString allLocales ++ "."
41 | , "These components are for doing l10n using https://projectfluent.org/."
42 | ]
43 | )
44 | , color = Just Color.blue
45 | , maxWidth = 400
46 | , githubUrl = Just "https://github.com/wolfadex/fluent-web"
47 | , documentationUrl = Just "https://github.com/wolfadex/fluent-web/blob/master/docs/index.md"
48 | }
49 | { init = init
50 | , view = view
51 | , update = update
52 | , subscriptions = subscriptions
53 | }
54 |
55 |
56 | type alias Model =
57 | { bundles : Bundles
58 | , activeLocale : Locale
59 | , personName : String
60 | , time : Posix
61 | , zone : Zone
62 | , placeholderInput : String
63 | , favoriteFruit : Fruit
64 | }
65 |
66 |
67 | type Msg
68 | = ChangeLocale String
69 | | SetPersonName String
70 | | SetZone Zone
71 | | SetTime Posix
72 | | SetPlaceholderInput String
73 | | SetFavoriteFruit String
74 | | GotBundles Bundles
75 |
76 |
77 | type alias Bundles =
78 | Value
79 |
80 |
81 | type Fruit
82 | = Apple
83 | | Orange
84 | | Lemon
85 |
86 |
87 | fruitToString : Fruit -> String
88 | fruitToString fruit =
89 | case fruit of
90 | Apple ->
91 | "apple"
92 |
93 | Orange ->
94 | "orange"
95 |
96 | Lemon ->
97 | "lemon"
98 |
99 |
100 | fruitFromString : String -> Result String Fruit
101 | fruitFromString maybeFruit =
102 | case maybeFruit of
103 | "apple" ->
104 | Ok Apple
105 |
106 | "orange" ->
107 | Ok Orange
108 |
109 | "lemon" ->
110 | Ok Lemon
111 |
112 | _ ->
113 | Err ("Unknown fruit: " ++ maybeFruit)
114 |
115 |
116 | allFruit : List Fruit
117 | allFruit =
118 | [ Apple, Orange, Lemon ]
119 |
120 |
121 | type Locale
122 | = EnUS
123 | | Pl
124 | | Cs
125 | | ThTH
126 | | Eo
127 |
128 |
129 | allLocales : List Locale
130 | allLocales =
131 | [ EnUS
132 | , Pl
133 | , Cs
134 | , ThTH
135 | , Eo
136 | ]
137 |
138 |
139 | decodeLocale : Decoder Locale
140 | decodeLocale =
141 | Json.Decode.string
142 | |> Json.Decode.andThen
143 | (\localeStr ->
144 | case localeFromString localeStr of
145 | Ok locale ->
146 | Json.Decode.succeed locale
147 |
148 | Err err ->
149 | Json.Decode.fail err
150 | )
151 |
152 |
153 | localeToString : Locale -> String
154 | localeToString locale =
155 | case locale of
156 | EnUS ->
157 | "en-US"
158 |
159 | Pl ->
160 | "pl"
161 |
162 | Cs ->
163 | "cs"
164 |
165 | ThTH ->
166 | "th-TH"
167 |
168 | Eo ->
169 | "eo"
170 |
171 |
172 | localeFromString : String -> Result String Locale
173 | localeFromString localeStr =
174 | case localeStr of
175 | "en-US" ->
176 | Ok EnUS
177 |
178 | "pl" ->
179 | Ok Pl
180 |
181 | "cs" ->
182 | Ok Cs
183 |
184 | "th-TH" ->
185 | Ok ThTH
186 |
187 | "eo" ->
188 | Ok Eo
189 |
190 | _ ->
191 | Err ("unsupported locale: " ++ localeStr)
192 |
193 |
194 | type alias Flags =
195 | { bundles : Bundles
196 | , initialLocale : String
197 | }
198 |
199 |
200 | init : Flags -> ( Model, Cmd Msg )
201 | init { bundles, initialLocale } =
202 | ( { bundles = bundles
203 | , activeLocale =
204 | localeFromString initialLocale
205 | |> Result.toMaybe
206 | |> Maybe.withDefault EnUS
207 | , personName = "Carl"
208 | , time = Time.millisToPosix 0
209 | , zone = Time.utc
210 | , placeholderInput = ""
211 | , favoriteFruit = Apple
212 | }
213 | , Cmd.batch
214 | [ Task.perform SetTime Time.now
215 | , Task.perform SetZone Time.here
216 | ]
217 | )
218 |
219 |
220 | subscriptions : Model -> Sub Msg
221 | subscriptions _ =
222 | gotBundles GotBundles
223 |
224 |
225 | port gotBundles : (Bundles -> msg) -> Sub msg
226 |
227 |
228 | port changeDesirecLocale : List String -> Cmd msg
229 |
230 |
231 | update : Msg -> Model -> ( Model, Cmd Msg )
232 | update msg model =
233 | case msg of
234 | GotBundles bundles ->
235 | ( { model | bundles = bundles }, Cmd.none )
236 |
237 | ChangeLocale newLocale ->
238 | ( model, changeDesirecLocale [newLocale] )
239 |
240 | SetPersonName name ->
241 | ( { model | personName = name }, Cmd.none )
242 |
243 | SetZone zone ->
244 | ( { model | zone = zone }, Cmd.none )
245 |
246 | SetTime time ->
247 | ( { model | time = time }, Cmd.none )
248 |
249 | SetPlaceholderInput val ->
250 | ( { model | placeholderInput = val }, Cmd.none )
251 |
252 | SetFavoriteFruit fruitStr ->
253 | case fruitFromString fruitStr of
254 | Ok fruit ->
255 | ( { model | favoriteFruit = fruit }, Cmd.none )
256 |
257 | Err _ ->
258 | ( model, Cmd.none )
259 |
260 |
261 | view : Model -> Html Msg
262 | view model =
263 | let
264 | bundless =
265 | model.bundles
266 | |> Html.Attributes.property "bundles"
267 | in
268 | Html.div
269 | []
270 | [ Html.label
271 | []
272 | [ Html.text "Active Locale"
273 | , Html.select
274 | [ Html.Events.onInput ChangeLocale ]
275 | (List.map
276 | (\locale ->
277 | Html.option
278 | [ Html.Attributes.value (localeToString locale) ]
279 | [ Html.text (localeToString locale) ]
280 | )
281 | allLocales
282 | )
283 | ]
284 | , Html.br [] []
285 | , Html.br [] []
286 | , Html.text "Basic key-value:"
287 | , Html.br [] []
288 | , Html.node "fluent-text"
289 | [ bundless
290 | , Html.Attributes.attribute "messageid" "hello-no-name"
291 | ]
292 | []
293 | , Html.br [] []
294 | , Html.br [] []
295 | , Html.text "Styled key-value:"
296 | , Html.br [] []
297 | , Html.node "fluent-text"
298 | [ bundless
299 | , Html.Attributes.attribute "messageid" "sign-in-or-cancel"
300 | ]
301 | []
302 | , Html.br [] []
303 | , Html.br [] []
304 | , Html.text "Today’s Date:"
305 | , Html.br [] []
306 | , Html.node "fluent-text"
307 | [ bundless
308 | , Html.Attributes.attribute "messageid" "today-date"
309 | , Html.Attributes.property "args" <|
310 | Json.Encode.object
311 | [ ( "date", Json.Encode.int (Time.posixToMillis model.time) ) ]
312 | ]
313 | []
314 | , Html.br [] []
315 | , Html.br [] []
316 | , Html.text "Message with argument:"
317 | , Html.br [] []
318 | , Html.input
319 | [ Html.Attributes.value model.personName
320 | , Html.Events.onInput SetPersonName
321 | ]
322 | []
323 | , Html.br [] []
324 | , Html.node "fluent-text"
325 | [ bundless
326 | , Html.Attributes.attribute "messageid" "hello"
327 | , Html.Attributes.property "args" <|
328 | Json.Encode.object
329 | [ ( "userName", Json.Encode.string model.personName ) ]
330 | ]
331 | []
332 | , Html.br [] []
333 | , Html.br [] []
334 | , Html.text "Input localized:"
335 | , Html.br [] []
336 | , Html.node "fluent-element"
337 | [ bundless
338 | , Html.Attributes.attribute "messageid" "type-name"
339 | , Html.Attributes.property "attributeWhitelist" <|
340 | Json.Encode.list Json.Encode.string ["placeholder"]
341 | ]
342 | [ Html.input
343 | [ Html.Events.onInput SetPlaceholderInput
344 | , Html.Attributes.value model.placeholderInput
345 | ]
346 | []
347 | ]
348 | , Html.br [] []
349 | , Html.br [] []
350 | , Html.text "Select with localized options:"
351 | , Html.br [] []
352 | , Html.label
353 | []
354 | [ Html.node "fluent-text"
355 | [ bundless
356 | , Html.Attributes.attribute "messageid" "favorite-fruit"
357 | ]
358 | []
359 | ]
360 | , Html.select
361 | [ Html.Events.onInput SetFavoriteFruit
362 | , Html.Attributes.value (fruitToString model.favoriteFruit)
363 | ]
364 | (List.map
365 | (\fruit ->
366 | Html.option
367 | [ Html.Attributes.value (fruitToString fruit)
368 | ]
369 | [ Html.node "fluent-text"
370 | [ bundless
371 | , Html.Attributes.attribute "messageid" ("fruit-" ++ fruitToString fruit)
372 | ]
373 | []
374 | ]
375 | )
376 | allFruit
377 | )
378 | , Html.br [] []
379 | , Html.br [] []
380 | , Html.text "Provider-based messages:"
381 | , Html.br [] []
382 | , Html.node "fluent-provider"
383 | [ bundless ]
384 | [ Html.node "fluent-text"
385 | [ Html.Attributes.attribute "messageid" "hello-no-name"
386 | ]
387 | []
388 | , Html.br [] []
389 | , Html.node "fluent-text"
390 | [ Html.Attributes.attribute "messageid" "sign-in-or-cancel"
391 | ]
392 | []
393 | ]
394 | ]
395 |
--------------------------------------------------------------------------------
/example/elm/example.js:
--------------------------------------------------------------------------------
1 | import { negotiateLanguages } from '@fluent/langneg';
2 | import { FluentBundle, FluentResource } from '@fluent/bundle';
3 | import { Elm } from "./Example.elm";
4 | import resources from "../common/resources.js";
5 |
6 | const supportedLocales = Object.keys(resources);
7 |
8 | function getCurrentLocales(desiredLocales) {
9 | return negotiateLanguages(
10 | desiredLocales,
11 | supportedLocales,
12 | { defaultLocale: 'en-US' }
13 | )
14 | }
15 |
16 | function getBundles(desiredLocales) {
17 | const currentLocales = getCurrentLocales(desiredLocales);
18 | const bundles = [];
19 |
20 | for (const locale of currentLocales) {
21 | const bundle = new FluentBundle(locale);
22 | bundle.addResource(resources[locale]);
23 | bundles.push(bundle)
24 | }
25 |
26 | return bundles;
27 | }
28 |
29 | // Log translation errors
30 | window.addEventListener("fluent-web-error", function(event) {
31 | console.error(event);
32 | })
33 |
34 | const app = Elm.Example.init({
35 | node: document.getElementById("root"),
36 | flags: {
37 | bundles: getBundles(navigator.languages,),
38 | initialLocale: getCurrentLocales(navigator.languages)[0],
39 | }
40 | });
41 |
42 |
43 | app.ports.changeDesirecLocale.subscribe(function(locales) {
44 | app.ports.gotBundles.send(getBundles(locales))
45 | })
46 |
--------------------------------------------------------------------------------
/example/elm/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/svelte/public/global.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | color: #333;
9 | margin: 0;
10 | padding: 8px;
11 | box-sizing: border-box;
12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
13 | }
14 |
15 | a {
16 | color: rgb(0,100,200);
17 | text-decoration: none;
18 | }
19 |
20 | a:hover {
21 | text-decoration: underline;
22 | }
23 |
24 | a:visited {
25 | color: rgb(0,80,160);
26 | }
27 |
28 | label {
29 | display: block;
30 | }
31 |
32 | input, button, select, textarea {
33 | font-family: inherit;
34 | font-size: inherit;
35 | padding: 0.4em;
36 | margin: 0 0 0.5em 0;
37 | box-sizing: border-box;
38 | border: 1px solid #ccc;
39 | border-radius: 2px;
40 | }
41 |
42 | input:disabled {
43 | color: #ccc;
44 | }
45 |
46 | input[type="range"] {
47 | height: 0;
48 | }
49 |
50 | button {
51 | color: #333;
52 | background-color: #f4f4f4;
53 | outline: none;
54 | }
55 |
56 | button:disabled {
57 | color: #999;
58 | }
59 |
60 | button:not(:disabled):active {
61 | background-color: #ddd;
62 | }
63 |
64 | button:focus {
65 | border-color: #666;
66 | }
67 |
--------------------------------------------------------------------------------
/example/svelte/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Svelte app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/svelte/src/App.svelte:
--------------------------------------------------------------------------------
1 |
41 |
42 |
63 |
64 |
65 |
78 |
79 |
80 | Basic key-value:
81 |
82 |
83 |
84 |
85 | Styled key-value:
86 |
87 |
88 |
89 |
90 | Today’s Date:
91 |
92 |
93 |
94 |
95 | Message with argument:
96 |
97 |
98 |
99 |
100 |
101 |
102 | Input localized:
103 |
104 |
105 |
106 |
107 |
108 |
109 | Select with localized options:
110 |
111 |
123 |
124 |
125 | Provider-based messages:
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/example/svelte/src/main.js:
--------------------------------------------------------------------------------
1 | import "../../../src/index.js";
2 | import App from "./App.svelte";
3 | import resources from "../../common/resources.js";
4 |
5 | const app = new App({
6 | target: document.body,
7 | props: {
8 | resources,
9 | },
10 | });
11 |
12 | export default app;
13 |
--------------------------------------------------------------------------------
/example/vanillajs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 | Basic key-value:
15 |
16 |
17 |
18 |
19 | Styled key-value:
20 |
21 |
25 |
26 |
27 | Today’s Date:
28 |
29 |
30 |
31 |
32 | Message with argument:
33 |
34 |
35 |
36 |
37 |
38 |
39 | Input localized:
40 |
41 |
42 |
43 |
44 |
45 |
46 | Select with localized options:
47 |
48 |
55 |
56 |
57 | Provider-based messages:
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/example/vanillajs/index.js:
--------------------------------------------------------------------------------
1 | import { negotiateLanguages } from '@fluent/langneg';
2 | import { FluentBundle, FluentResource } from '@fluent/bundle';
3 | import resources from "../common/resources.js";
4 |
5 | const supportedLocales = Object.keys(resources);
6 |
7 | function getCurrentLocales(desiredLocales) {
8 | return negotiateLanguages(
9 | desiredLocales,
10 | supportedLocales,
11 | { defaultLocale: 'en-US' }
12 | )
13 | }
14 |
15 | function getBundles(desiredLocales) {
16 | const currentLocales = getCurrentLocales(desiredLocales);
17 | const bundles = [];
18 |
19 | for (const locale of currentLocales) {
20 | const bundle = new FluentBundle(locale);
21 | bundle.addResource(resources[locale]);
22 | bundles.push(bundle)
23 | }
24 |
25 | return bundles;
26 | }
27 |
28 | const elLocaleSelector = document.getElementById("locale-selector");
29 | let currentLocale = getCurrentLocales(navigator.languages)[0];
30 |
31 | supportedLocales.map((locale) => {
32 | const option = document.createElement("option");
33 | option.value = locale;
34 | option.innerText = locale;
35 | elLocaleSelector.appendChild(option);
36 | });
37 | elLocaleSelector.value = currentLocale;
38 | elLocaleSelector.addEventListener("change", (event) => {
39 | currentLocale = event.target.value;
40 | updateLocalization();
41 | });
42 |
43 | const elHelloNoName = document.getElementById("helloNoName");
44 |
45 | const elSignInOrCancel = document.getElementById("signInOrCancel");
46 | const elTodayDate = document.getElementById("todayDate");
47 | const elPersonNameInput = document.getElementById("personNameInput");
48 | const elProvider = document.getElementsByTagName("fluent-provider")[0];
49 | let personName = "Carl";
50 |
51 | elPersonNameInput.value = "Carl";
52 | elPersonNameInput.addEventListener("input", (event) => {
53 | const bundles = getBundles([currentLocale]);
54 |
55 | personName = event.target.value;
56 | elHelloName.bundles = bundles;
57 | elHelloName.args = {
58 | userName: personName,
59 | };
60 | });
61 |
62 | const elHelloName = document.getElementById("helloName");
63 | const elTypeName = document.getElementById("typeName");
64 |
65 | elTypeName.attributeWhitelist = ["placeholder"];
66 |
67 | const elFavoriteFruitLabel = document.getElementById("favoriteFruitLabel");
68 | const fruits = ["apple", "orange", "lemon"];
69 | let favoriteFruit = fruits[0];
70 | const elFavoriteFruitSelect = document.getElementById("favoriteFruitSelect");
71 | const elFruitList = [];
72 |
73 | fruits.map((fruit) => {
74 | const optionText = document.createElement("fluent-text");
75 | const option = document.createElement("option");
76 |
77 | optionText.setAttribute("messageid", `fruit-${fruit}`);
78 | elFruitList.push(optionText);
79 | option.value = fruit;
80 | option.appendChild(optionText);
81 | elFavoriteFruitSelect.appendChild(option);
82 | });
83 | elFavoriteFruitSelect.value = favoriteFruit;
84 | elFavoriteFruitSelect.addEventListener("change", (event) => {
85 | const bundles = getBundles([currentLocale]);
86 |
87 | favoriteFruit = event.target.value;
88 | elFruitList.map((el) => (el.bundles = bundles));
89 | });
90 |
91 | function updateLocalization() {
92 | const bundles = getBundles([currentLocale]);
93 |
94 | elHelloNoName.bundles = bundles;
95 |
96 | elSignInOrCancel.bundles = bundles;
97 |
98 | elTodayDate.bundles = bundles;
99 | elTodayDate.args = { date: new Date() };
100 |
101 | elHelloName.bundles = bundles;
102 | elHelloName.args = {
103 | userName: personName,
104 | };
105 |
106 | elTypeName.bundles = bundles;
107 |
108 | elFavoriteFruitLabel.bundles = bundles;
109 | elFruitList.map((el) => (el.bundles = bundles));
110 |
111 | elProvider.bundles = bundles;
112 | }
113 |
114 | updateLocalization();
115 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@wolfadex/fluent-web",
3 | "version": "3.1.0",
4 | "main": "./commonjs/index.js",
5 | "module": "./src/index.js",
6 | "license": "MIT",
7 | "keywords": [
8 | "localization",
9 | "l10n",
10 | "internationalization",
11 | "i18n",
12 | "locale",
13 | "language",
14 | "formatting",
15 | "translate",
16 | "translation",
17 | "format"
18 | ],
19 | "scripts": {
20 | "dev-demo": "parcel example/elm/index.html",
21 | "build-demo": "parcel build example/elm/index.html -d .",
22 | "build": "rollup -c",
23 | "dev-svelte": "rollup -c rollup.svelte.js -w",
24 | "start-svelte": "sirv example/svelte/public",
25 | "dev-vanilla": "parcel example/vanillajs/index.html"
26 | },
27 | "devDependencies": {
28 | "@fluent/dedent": "^0.2.0",
29 | "@rollup/plugin-commonjs": "^11.0.0",
30 | "@rollup/plugin-node-resolve": "^7.0.0",
31 | "elm-hot": "^1.1.4",
32 | "node-elm-compiler": "^5.0.4",
33 | "parcel-bundler": "^1.12.4",
34 | "prettier": "^2.0.4",
35 | "rollup": "^1.20.0",
36 | "rollup-plugin-livereload": "^1.0.0",
37 | "rollup-plugin-svelte": "^5.0.3",
38 | "rollup-plugin-terser": "^5.1.2",
39 | "sirv-cli": "^0.4.4",
40 | "svelte": "^3.0.0",
41 | "typescript": "^3.8.3"
42 | },
43 | "dependencies": {
44 | "@fluent/bundle": "^0.15.1",
45 | "@fluent/langneg": "^0.4.0",
46 | "@fluent/sequence": "^0.5.0",
47 | "cached-iterable": "^0.3.0"
48 | },
49 | "browserslist": [
50 | "last 1 Chrome versions"
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from "@rollup/plugin-node-resolve";
2 | import commonjs from "@rollup/plugin-commonjs";
3 | import { terser } from "rollup-plugin-terser";
4 |
5 | export default {
6 | input: "src/index.js",
7 | output: {
8 | sourcemap: true,
9 | format: "iife",
10 | file: "commonjs/index.js",
11 | },
12 | plugins: [
13 | // If you have external dependencies installed from
14 | // npm, you'll most likely need these plugins. In
15 | // some cases you'll need additional configuration -
16 | // consult the documentation for details:
17 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
18 | resolve({
19 | browser: true,
20 | }),
21 | commonjs(),
22 | terser(),
23 | ],
24 | };
25 |
--------------------------------------------------------------------------------
/rollup.svelte.js:
--------------------------------------------------------------------------------
1 | import svelte from "rollup-plugin-svelte";
2 | import resolve from "@rollup/plugin-node-resolve";
3 | import commonjs from "@rollup/plugin-commonjs";
4 | import livereload from "rollup-plugin-livereload";
5 | import { terser } from "rollup-plugin-terser";
6 |
7 | const production = !process.env.ROLLUP_WATCH;
8 |
9 | export default {
10 | input: "example/svelte/src/main.js",
11 | output: {
12 | sourcemap: true,
13 | format: "iife",
14 | name: "app",
15 | file: "example/svelte/public/build/bundle.js",
16 | },
17 | plugins: [
18 | svelte({
19 | // enable run-time checks when not in production
20 | dev: !production,
21 | // we'll extract any component CSS out into
22 | // a separate file - better for performance
23 | css: (css) => {
24 | css.write("example/svelte/public/build/bundle.css");
25 | },
26 | }),
27 |
28 | // If you have external dependencies installed from
29 | // npm, you'll most likely need these plugins. In
30 | // some cases you'll need additional configuration -
31 | // consult the documentation for details:
32 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
33 | resolve({
34 | browser: true,
35 | dedupe: ["svelte"],
36 | }),
37 | commonjs(),
38 |
39 | // In dev mode, call `npm run start` once
40 | // the bundle has been generated
41 | !production && serve(),
42 |
43 | // Watch the `public` directory and refresh the
44 | // browser on changes when not in production
45 | !production && livereload("example/svelte/public"),
46 |
47 | // If we're building for production (npm run build
48 | // instead of npm run dev), minify
49 | production && terser(),
50 | ],
51 | watch: {
52 | clearScreen: false,
53 | },
54 | };
55 |
56 | function serve() {
57 | let started = false;
58 |
59 | return {
60 | writeBundle() {
61 | if (!started) {
62 | started = true;
63 |
64 | require("child_process").spawn(
65 | "npm",
66 | ["run", "start-svelte", "--", "--dev"],
67 | {
68 | stdio: ["ignore", "inherit", "inherit"],
69 | shell: true,
70 | }
71 | );
72 | }
73 | },
74 | };
75 | }
76 |
--------------------------------------------------------------------------------
/screen_shot_en-us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wolfadex/fluent-web/18bd925344eefbc2fcc8714b6db7cc65eeb14a08/screen_shot_en-us.png
--------------------------------------------------------------------------------
/screen_shot_pl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wolfadex/fluent-web/18bd925344eefbc2fcc8714b6db7cc65eeb14a08/screen_shot_pl.png
--------------------------------------------------------------------------------
/src.19911aa5.js:
--------------------------------------------------------------------------------
1 | parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;cr(e,n)):r(e,n)}function r(e,r){for(const n of e)if(n.hasMessage(r))return n;return null}Object.defineProperty(exports,"__esModule",{value:!0}),exports.mapBundleSync=e;
3 | },{}],"JDfh":[function(require,module,exports) {
4 | "use strict";async function e(e,r){if(!Array.isArray(r)){for await(const t of e)if(t.hasMessage(r))return t;return null}const t=new Array(r.length).fill(null);let n=r.length;for await(const s of e)for(const[e,o]of r.entries())if(!t[e]&&s.hasMessage(o)&&(t[e]=s,n--),0===n)return t;return t}Object.defineProperty(exports,"__esModule",{value:!0}),exports.mapBundleAsync=e;
5 | },{}],"QccG":[function(require,module,exports) {
6 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"mapBundleSync",{enumerable:!0,get:function(){return e.mapBundleSync}}),Object.defineProperty(exports,"mapBundleAsync",{enumerable:!0,get:function(){return n.mapBundleAsync}});var e=require("./map_sync.js"),n=require("./map_async.js");
7 | },{"./map_sync.js":"mDcL","./map_async.js":"JDfh"}],"Upfk":[function(require,module,exports) {
8 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;class e extends Array{static from(e){return e instanceof this?e:new this(e)}}exports.default=e;
9 | },{}],"OKyI":[function(require,module,exports) {
10 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var t=e(require("./cached_iterable.mjs"));function e(t){return t&&t.__esModule?t:{default:t}}class r extends t.default{constructor(t){if(super(),!(Symbol.iterator in Object(t)))throw new TypeError("Argument must implement the iteration protocol.");this.iterator=t[Symbol.iterator]()}[Symbol.iterator](){const t=this;let e=0;return{next:()=>(t.length<=e&&t.push(t.iterator.next()),t[e++])}}touchNext(t=1){let e=0;for(;e++(t.length<=e&&t.push(t.iterator.next()),t[e++])}}async touchNext(t=1){let e=0;for(;e++{r.includes(e)&&(i.attributes[e]=l.formatPattern(t,a,u))}),u.length>0){const s=new CustomEvent("fluent-web-error",{bubbles:!0,detail:{messageId:t,args:a,message:e,errors:u}});this.dispatchEvent(s)}return i}{const e=new CustomEvent("fluent-web-error",{bubbles:!0,detail:{messageId:t,args:s,errors:[new Error("Message object not found")]}});this.dispatchEvent(e)}}}return null}connectedCallback(){this.dispatchEvent(new CustomEvent("fluent-bundles-subscribe",{bubbles:!0,target:this})),this.render()}disconnectedCallback(){this.dispatchEvent(new CustomEvent("fluent-bundles-unsubscribe",{bubbles:!0,target:this}))}set providerBundles(e){this._providerBundles=a(this,e),this.render()}set bundles(e){this._bundles=a(this,e),this.render()}set attributeWhitelist(e){this.whitelist=e,this.render()}set args(e){this.messageArgs=e,this.render()}set unsafeArgs(e){this.messageUnsafeArgs=e,this.render()}static get observedAttributes(){return[s,n]}attributeChangedCallback(e,t,n){e.toLowerCase()===s&&t!==n&&this.render()}}class i extends HTMLElement{constructor(){super(),this._listeners=[]}connectedCallback(){this._listeners=[],this.addEventListener("fluent-bundles-subscribe",l),this.addEventListener("fluent-bundles-unsubscribe",u)}disconnectedCallback(){this._listeners=[],this.removeEventListener("fluent-bundles-subscribe",l),this.removeEventListener("fluent-bundles-unsubscribe",u)}get bundles(){return this._bundles}set bundles(e){this._bundles=a(this,e),this._listeners.forEach(e=>{e.providerBundles=this._bundles})}}function l(e){const t=e.currentTarget;t._listeners.push(e.target),e.target.providerBundles=t._bundles}function u(e){const t=e.currentTarget,s=t._listeners.findIndex(e.target);s>=0&&t._listeners.splice(s,1)}function a(e,s){if(s){if(s.constructor===t.CachedSyncIterable)return s;if("function"==typeof s[Symbol.iterator])return t.CachedSyncIterable.from(s)}return null!==s&&e.dispatchEvent(new CustomEvent("fluent-web-error",{bubbles:!0,detail:{bundles:s,errors:[new Error("bundles property must be iterable or null")]}})),null}function d(e,t){if(t.value&&"{???}"!==t.value){const s=document.createElement("template");s.innerHTML=t.value,e.innerHTML="",Array.from(s.content.childNodes).forEach(t=>{e.appendChild(t)})}}customElements.define("fluent-text",class extends r{render(){const e=this.getMessage({messageId:this.getAttribute(s)||this.getAttribute(n),args:this.messageArgs,unsafeArgs:this.messageUnsafeArgs});e&&d(this,e)}}),customElements.define("fluent-element",class extends r{render(){if(this.firstElementChild){const e=this.getMessage({messageId:this.getAttribute(s)||this.getAttribute(n),args:this.messageArgs,unsafeArgs:this.messageUnsafeArgs,whitelist:this.whitelist});e&&(Object.entries(e.attributes).forEach(([e,t])=>{this.firstElementChild.setAttribute(e,t)}),d(this.firstElementChild,e))}}}),customElements.define("fluent-provider",i);
17 | },{"@fluent/sequence":"QccG","cached-iterable":"PQe0"}]},{},["uOLC"], null)
18 | //# sourceMappingURL=/src.19911aa5.js.map
--------------------------------------------------------------------------------
/src.19911aa5.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../../node_modules/@fluent/sequence/esm/map_sync.js","../../node_modules/@fluent/sequence/esm/map_async.js","../../node_modules/@fluent/sequence/esm/index.js","../../node_modules/cached-iterable/src/cached_iterable.mjs","../../node_modules/cached-iterable/src/cached_sync_iterable.mjs","../../node_modules/cached-iterable/src/cached_async_iterable.mjs","../../node_modules/cached-iterable/src/index.mjs","../../src/index.js"],"names":["mapBundleSync","bundles","ids","Array","isArray","map","id","getBundleForId","bundle","hasMessage","mapBundleAsync","foundBundles","length","fill","remainingCount","index","entries","CachedIterable","from","iterable","CachedSyncIterable","constructor","Symbol","iterator","Object","TypeError","cached","cur","next","push","touchNext","count","idx","last","done","CachedAsyncIterable","asyncIterator","MESSAGE_ID_ATTRIBUTE","DEPRECATED_MESSAGE_ID_ATTRIBUTE","FluentElement","HTMLElement","getMessage","messageId","args","unsafeArgs","whitelist","_bundles","_providerBundles","message","formatted","value","attributes","errors","preparedArgs","assign","escaper","document","createElement","name","arg","innerText","innerHTML","formatPattern","forEach","includes","errorEvent","CustomEvent","bubbles","detail","dispatchEvent","Error","connectedCallback","target","render","disconnectedCallback","providerBundles","newBundles","cacheBundles","attributeWhitelist","newValue","messageArgs","messageUnsafeArgs","observedAttributes","attributeChangedCallback","oldValue","toLowerCase","FluentProvider","_listeners","addEventListener","bundlesSubscribe","bundlesUnsubscribe","removeEventListener","event","provider","currentTarget","i","findIndex","splice","el","semiSafeInnerHTML","template","content","childNodes","node","appendChild","customElements","define","getAttribute","firstElementChild","setAttribute"],"mappings":"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","file":"src.19911aa5.js","sourceRoot":"example/elm","sourcesContent":["/*\n * Synchronously map an identifier or an array of identifiers to the best\n * `FluentBundle` instance(s).\n *\n * @param bundles - An iterable of bundles to sift through.\n * @param ids - An id or ids to map.\n */\nexport function mapBundleSync(bundles, ids) {\n if (!Array.isArray(ids)) {\n return getBundleForId(bundles, ids);\n }\n return ids.map(id => getBundleForId(bundles, id));\n}\n/*\n * Find the best `FluentBundle` with the translation for `id`.\n */\nfunction getBundleForId(bundles, id) {\n for (const bundle of bundles) {\n if (bundle.hasMessage(id)) {\n return bundle;\n }\n }\n return null;\n}\n","/*\n * Asynchronously map an identifier or an array of identifiers to the best\n * `FluentBundle` instance(s).\n *\n * @param bundles - An iterable of bundles to sift through.\n * @param ids - An id or ids to map.\n */\nexport async function mapBundleAsync(bundles, ids) {\n if (!Array.isArray(ids)) {\n for await (const bundle of bundles) {\n if (bundle.hasMessage(ids)) {\n return bundle;\n }\n }\n return null;\n }\n const foundBundles = new Array(ids.length).fill(null);\n let remainingCount = ids.length;\n for await (const bundle of bundles) {\n for (const [index, id] of ids.entries()) {\n if (!foundBundles[index] && bundle.hasMessage(id)) {\n foundBundles[index] = bundle;\n remainingCount--;\n }\n // Return early when all ids have been mapped to bundles.\n if (remainingCount === 0) {\n return foundBundles;\n }\n }\n }\n return foundBundles;\n}\n","/*\n * @module fluent-sequence\n * @overview Manage ordered sequences of FluentBundles.\n */\nexport { mapBundleSync } from \"./map_sync.js\";\nexport { mapBundleAsync } from \"./map_async.js\";\n","/*\n * Base CachedIterable class.\n */\nexport default class CachedIterable extends Array {\n /**\n * Create a `CachedIterable` instance from an iterable or, if another\n * instance of `CachedIterable` is passed, return it without any\n * modifications.\n *\n * @param {Iterable} iterable\n * @returns {CachedIterable}\n */\n static from(iterable) {\n if (iterable instanceof this) {\n return iterable;\n }\n\n return new this(iterable);\n }\n}\n","import CachedIterable from \"./cached_iterable.mjs\";\n\n/*\n * CachedSyncIterable caches the elements yielded by an iterable.\n *\n * It can be used to iterate over an iterable many times without depleting the\n * iterable.\n */\nexport default class CachedSyncIterable extends CachedIterable {\n /**\n * Create an `CachedSyncIterable` instance.\n *\n * @param {Iterable} iterable\n * @returns {CachedSyncIterable}\n */\n constructor(iterable) {\n super();\n\n if (Symbol.iterator in Object(iterable)) {\n this.iterator = iterable[Symbol.iterator]();\n } else {\n throw new TypeError(\"Argument must implement the iteration protocol.\");\n }\n }\n\n [Symbol.iterator]() {\n const cached = this;\n let cur = 0;\n\n return {\n next() {\n if (cached.length <= cur) {\n cached.push(cached.iterator.next());\n }\n return cached[cur++];\n }\n };\n }\n\n /**\n * This method allows user to consume the next element from the iterator\n * into the cache.\n *\n * @param {number} count - number of elements to consume\n */\n touchNext(count = 1) {\n let idx = 0;\n while (idx++ < count) {\n const last = this[this.length - 1];\n if (last && last.done) {\n break;\n }\n this.push(this.iterator.next());\n }\n // Return the last cached {value, done} object to allow the calling\n // code to decide if it needs to call touchNext again.\n return this[this.length - 1];\n }\n}\n","import CachedIterable from \"./cached_iterable.mjs\";\n\n/*\n * CachedAsyncIterable caches the elements yielded by an async iterable.\n *\n * It can be used to iterate over an iterable many times without depleting the\n * iterable.\n */\nexport default class CachedAsyncIterable extends CachedIterable {\n /**\n * Create an `CachedAsyncIterable` instance.\n *\n * @param {Iterable} iterable\n * @returns {CachedAsyncIterable}\n */\n constructor(iterable) {\n super();\n\n if (Symbol.asyncIterator in Object(iterable)) {\n this.iterator = iterable[Symbol.asyncIterator]();\n } else if (Symbol.iterator in Object(iterable)) {\n this.iterator = iterable[Symbol.iterator]();\n } else {\n throw new TypeError(\"Argument must implement the iteration protocol.\");\n }\n }\n\n /**\n * Asynchronous iterator caching the yielded elements.\n *\n * Elements yielded by the original iterable will be cached and available\n * synchronously. Returns an async generator object implementing the\n * iterator protocol over the elements of the original (async or sync)\n * iterable.\n */\n [Symbol.asyncIterator]() {\n const cached = this;\n let cur = 0;\n\n return {\n async next() {\n if (cached.length <= cur) {\n cached.push(cached.iterator.next());\n }\n return cached[cur++];\n }\n };\n }\n\n /**\n * This method allows user to consume the next element from the iterator\n * into the cache.\n *\n * @param {number} count - number of elements to consume\n */\n async touchNext(count = 1) {\n let idx = 0;\n while (idx++ < count) {\n const last = this[this.length - 1];\n if (last && (await last).done) {\n break;\n }\n this.push(this.iterator.next());\n }\n // Return the last cached {value, done} object to allow the calling\n // code to decide if it needs to call touchNext again.\n return this[this.length - 1];\n }\n}\n","export {default as CachedSyncIterable} from \"./cached_sync_iterable.mjs\";\nexport {default as CachedAsyncIterable} from \"./cached_async_iterable.mjs\";\n","import { mapBundleSync } from \"@fluent/sequence\";\nimport { CachedSyncIterable } from \"cached-iterable\";\n\nconst MESSAGE_ID_ATTRIBUTE = \"messageid\";\nconst DEPRECATED_MESSAGE_ID_ATTRIBUTE = \"messageId\";\n\nclass FluentElement extends HTMLElement {\n getMessage({ messageId, args, unsafeArgs, whitelist = [] }) {\n const bundles = this._bundles || this._providerBundles;\n if (bundles) {\n const bundle = mapBundleSync(bundles, messageId);\n\n if (bundle) {\n const message = bundle.getMessage(messageId);\n\n if (message) {\n const formatted = { value: null, attributes: {} };\n let errors = [];\n\n const preparedArgs = Object.assign({}, unsafeArgs || {});\n const escaper = document.createElement(\"div\");\n for (let [name, arg] of Object.entries(args || {})) {\n if (typeof arg === \"string\") {\n escaper.innerText = arg;\n preparedArgs[name] = escaper.innerHTML;\n }\n else {\n preparedArgs[name] = arg;\n }\n }\n if (message.value) {\n formatted.value = bundle.formatPattern(message.value, preparedArgs, errors);\n }\n\n Object.entries(message.attributes).forEach(([name, value]) => {\n if (whitelist.includes(name)) {\n formatted.attributes[name] = bundle.formatPattern(value, preparedArgs, errors);\n }\n });\n\n if (errors.length > 0) {\n const errorEvent = new CustomEvent(\"fluent-web-error\", {\n bubbles: true,\n detail: {\n messageId,\n args: preparedArgs,\n message,\n errors,\n },\n });\n this.dispatchEvent(errorEvent);\n }\n\n return formatted;\n } else {\n const errorEvent = new CustomEvent(\"fluent-web-error\", {\n bubbles: true,\n detail: {\n messageId,\n args,\n errors: [new Error(\"Message object not found\")],\n },\n });\n this.dispatchEvent(errorEvent);\n }\n }\n }\n\n return null;\n }\n\n connectedCallback() {\n this.dispatchEvent(\n new CustomEvent(\"fluent-bundles-subscribe\", {\n bubbles: true,\n target: this,\n })\n );\n this.render();\n }\n disconnectedCallback() {\n this.dispatchEvent(\n new CustomEvent(\"fluent-bundles-unsubscribe\", {\n bubbles: true,\n target: this,\n })\n );\n }\n\n set providerBundles(newBundles) {\n this._providerBundles = cacheBundles(this, newBundles);\n this.render();\n }\n\n set bundles(newBundles) {\n this._bundles = cacheBundles(this, newBundles);\n this.render();\n }\n\n set attributeWhitelist(whitelist) {\n this.whitelist = whitelist;\n this.render();\n }\n\n set args(newValue) {\n this.messageArgs = newValue;\n this.render();\n }\n\n set unsafeArgs(newValue) {\n this.messageUnsafeArgs = newValue;\n this.render();\n }\n\n static get observedAttributes() {\n return [MESSAGE_ID_ATTRIBUTE, DEPRECATED_MESSAGE_ID_ATTRIBUTE];\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n if (name.toLowerCase() === MESSAGE_ID_ATTRIBUTE && oldValue !== newValue) {\n this.render();\n }\n }\n}\n\nclass FluentProvider extends HTMLElement {\n constructor() {\n super();\n this._listeners = [];\n }\n connectedCallback() {\n this._listeners = [];\n this.addEventListener(\"fluent-bundles-subscribe\", bundlesSubscribe);\n this.addEventListener(\"fluent-bundles-unsubscribe\", bundlesUnsubscribe);\n }\n disconnectedCallback() {\n this._listeners = [];\n this.removeEventListener(\"fluent-bundles-subscribe\", bundlesSubscribe);\n this.removeEventListener(\"fluent-bundles-unsubscribe\", bundlesUnsubscribe);\n }\n get bundles() {\n return this._bundles;\n }\n set bundles(newBundles) {\n this._bundles = cacheBundles(this, newBundles);\n this._listeners.forEach((target) => {\n target.providerBundles = this._bundles;\n });\n }\n}\nfunction bundlesSubscribe(event) {\n const provider = event.currentTarget;\n provider._listeners.push(event.target);\n event.target.providerBundles = provider._bundles;\n}\nfunction bundlesUnsubscribe(event) {\n const provider = event.currentTarget;\n const i = provider._listeners.findIndex(event.target);\n if (i >= 0) {\n provider._listeners.splice(i, 1);\n }\n}\n\nfunction cacheBundles(el, bundles) {\n // Allow iterables (usually an array) or null\n if (bundles) {\n // Already cached, don't cache it twice\n if (bundles.constructor === CachedSyncIterable) {\n return bundles;\n }\n // Iterable check: https://stackoverflow.com/a/32538867/2782048\n if (typeof bundles[Symbol.iterator] === \"function\") {\n return CachedSyncIterable.from(bundles);\n }\n }\n if (bundles !== null) {\n el.dispatchEvent(\n new CustomEvent(\"fluent-web-error\", {\n bubbles: true,\n detail: {\n bundles,\n errors: [new Error(\"bundles property must be iterable or null\")],\n },\n }),\n );\n }\n return null;\n}\n\nfunction semiSafeInnerHTML(el, message) {\n if (message.value && message.value !== \"{???}\") {\n const template = document.createElement(\"template\");\n template.innerHTML = message.value;\n el.innerHTML = \"\";\n Array.from(template.content.childNodes).forEach((node) => {\n el.appendChild(node);\n });\n }\n}\n\ncustomElements.define(\n \"fluent-text\",\n class extends FluentElement {\n render() {\n const message = this.getMessage({\n messageId: this.getAttribute(MESSAGE_ID_ATTRIBUTE) || this.getAttribute(DEPRECATED_MESSAGE_ID_ATTRIBUTE),\n args: this.messageArgs,\n unsafeArgs: this.messageUnsafeArgs,\n });\n\n if (message) {\n semiSafeInnerHTML(this, message);\n }\n }\n }\n);\n\ncustomElements.define(\n \"fluent-element\",\n class extends FluentElement {\n render() {\n if (this.firstElementChild) {\n const message = this.getMessage({\n messageId: this.getAttribute(MESSAGE_ID_ATTRIBUTE) || this.getAttribute(DEPRECATED_MESSAGE_ID_ATTRIBUTE),\n args: this.messageArgs,\n unsafeArgs: this.messageUnsafeArgs,\n whitelist: this.whitelist\n });\n\n if (message) {\n Object.entries(message.attributes).forEach(([name, value]) => {\n this.firstElementChild.setAttribute(name, value);\n });\n\n semiSafeInnerHTML(this.firstElementChild, message);\n }\n }\n }\n }\n);\n\ncustomElements.define(\"fluent-provider\", FluentProvider);\n"]}
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { mapBundleSync } from "@fluent/sequence";
2 | import { CachedSyncIterable } from "cached-iterable";
3 |
4 | const MESSAGE_ID_ATTRIBUTE = "messageid";
5 | const DEPRECATED_MESSAGE_ID_ATTRIBUTE = "messageId";
6 |
7 | class FluentElement extends HTMLElement {
8 | getMessage({ messageId, args, unsafeArgs, whitelist = [] }) {
9 | const bundles = this._bundles || this._providerBundles;
10 | if (bundles) {
11 | const bundle = mapBundleSync(bundles, messageId);
12 |
13 | if (bundle) {
14 | const message = bundle.getMessage(messageId);
15 |
16 | if (message) {
17 | const formatted = { value: null, attributes: {} };
18 | let errors = [];
19 |
20 | const preparedArgs = Object.assign({}, unsafeArgs || {});
21 | const escaper = document.createElement("div");
22 | for (let [name, arg] of Object.entries(args || {})) {
23 | if (typeof arg === "string") {
24 | escaper.innerText = arg;
25 | preparedArgs[name] = escaper.innerHTML;
26 | }
27 | else {
28 | preparedArgs[name] = arg;
29 | }
30 | }
31 | if (message.value) {
32 | formatted.value = bundle.formatPattern(message.value, preparedArgs, errors);
33 | }
34 |
35 | Object.entries(message.attributes).forEach(([name, value]) => {
36 | if (whitelist.includes(name)) {
37 | formatted.attributes[name] = bundle.formatPattern(value, preparedArgs, errors);
38 | }
39 | });
40 |
41 | if (errors.length > 0) {
42 | const errorEvent = new CustomEvent("fluent-web-error", {
43 | bubbles: true,
44 | detail: {
45 | messageId,
46 | args: preparedArgs,
47 | message,
48 | errors,
49 | },
50 | });
51 | this.dispatchEvent(errorEvent);
52 | }
53 |
54 | return formatted;
55 | } else {
56 | const errorEvent = new CustomEvent("fluent-web-error", {
57 | bubbles: true,
58 | detail: {
59 | messageId,
60 | args,
61 | errors: [new Error("Message object not found")],
62 | },
63 | });
64 | this.dispatchEvent(errorEvent);
65 | }
66 | }
67 | }
68 |
69 | return null;
70 | }
71 |
72 | connectedCallback() {
73 | this.dispatchEvent(
74 | new CustomEvent("fluent-bundles-subscribe", {
75 | bubbles: true,
76 | target: this,
77 | })
78 | );
79 | this.render();
80 | }
81 | disconnectedCallback() {
82 | this.dispatchEvent(
83 | new CustomEvent("fluent-bundles-unsubscribe", {
84 | bubbles: true,
85 | target: this,
86 | })
87 | );
88 | }
89 |
90 | set providerBundles(newBundles) {
91 | this._providerBundles = cacheBundles(this, newBundles);
92 | this.render();
93 | }
94 |
95 | set bundles(newBundles) {
96 | this._bundles = cacheBundles(this, newBundles);
97 | this.render();
98 | }
99 |
100 | set attributeWhitelist(whitelist) {
101 | this.whitelist = whitelist;
102 | this.render();
103 | }
104 |
105 | set args(newValue) {
106 | this.messageArgs = newValue;
107 | this.render();
108 | }
109 |
110 | set unsafeArgs(newValue) {
111 | this.messageUnsafeArgs = newValue;
112 | this.render();
113 | }
114 |
115 | static get observedAttributes() {
116 | return [MESSAGE_ID_ATTRIBUTE, DEPRECATED_MESSAGE_ID_ATTRIBUTE];
117 | }
118 |
119 | attributeChangedCallback(name, oldValue, newValue) {
120 | if (name.toLowerCase() === MESSAGE_ID_ATTRIBUTE && oldValue !== newValue) {
121 | this.render();
122 | }
123 | }
124 | }
125 |
126 | class FluentProvider extends HTMLElement {
127 | constructor() {
128 | super();
129 | this._listeners = [];
130 | }
131 | connectedCallback() {
132 | this._listeners = [];
133 | this.addEventListener("fluent-bundles-subscribe", bundlesSubscribe);
134 | this.addEventListener("fluent-bundles-unsubscribe", bundlesUnsubscribe);
135 | }
136 | disconnectedCallback() {
137 | this._listeners = [];
138 | this.removeEventListener("fluent-bundles-subscribe", bundlesSubscribe);
139 | this.removeEventListener("fluent-bundles-unsubscribe", bundlesUnsubscribe);
140 | }
141 | get bundles() {
142 | return this._bundles;
143 | }
144 | set bundles(newBundles) {
145 | this._bundles = cacheBundles(this, newBundles);
146 | this._listeners.forEach((target) => {
147 | target.providerBundles = this._bundles;
148 | });
149 | }
150 | }
151 | function bundlesSubscribe(event) {
152 | const provider = event.currentTarget;
153 | provider._listeners.push(event.target);
154 | event.target.providerBundles = provider._bundles;
155 | }
156 | function bundlesUnsubscribe(event) {
157 | const provider = event.currentTarget;
158 | const i = provider._listeners.findIndex(event.target);
159 | if (i >= 0) {
160 | provider._listeners.splice(i, 1);
161 | }
162 | }
163 |
164 | function cacheBundles(el, bundles) {
165 | // Allow iterables (usually an array) or null
166 | if (bundles) {
167 | // Already cached, don't cache it twice
168 | if (bundles.constructor === CachedSyncIterable) {
169 | return bundles;
170 | }
171 | // Iterable check: https://stackoverflow.com/a/32538867/2782048
172 | if (typeof bundles[Symbol.iterator] === "function") {
173 | return CachedSyncIterable.from(bundles);
174 | }
175 | }
176 | if (bundles !== null) {
177 | el.dispatchEvent(
178 | new CustomEvent("fluent-web-error", {
179 | bubbles: true,
180 | detail: {
181 | bundles,
182 | errors: [new Error("bundles property must be iterable or null")],
183 | },
184 | }),
185 | );
186 | }
187 | return null;
188 | }
189 |
190 | function semiSafeInnerHTML(el, message) {
191 | if (message.value && message.value !== "{???}") {
192 | const template = document.createElement("template");
193 | template.innerHTML = message.value;
194 | el.innerHTML = "";
195 | Array.from(template.content.childNodes).forEach((node) => {
196 | el.appendChild(node);
197 | });
198 | }
199 | }
200 |
201 | customElements.define(
202 | "fluent-text",
203 | class extends FluentElement {
204 | render() {
205 | const message = this.getMessage({
206 | messageId: this.getAttribute(MESSAGE_ID_ATTRIBUTE) || this.getAttribute(DEPRECATED_MESSAGE_ID_ATTRIBUTE),
207 | args: this.messageArgs,
208 | unsafeArgs: this.messageUnsafeArgs,
209 | });
210 |
211 | if (message) {
212 | semiSafeInnerHTML(this, message);
213 | }
214 | }
215 | }
216 | );
217 |
218 | customElements.define(
219 | "fluent-element",
220 | class extends FluentElement {
221 | render() {
222 | if (this.firstElementChild) {
223 | const message = this.getMessage({
224 | messageId: this.getAttribute(MESSAGE_ID_ATTRIBUTE) || this.getAttribute(DEPRECATED_MESSAGE_ID_ATTRIBUTE),
225 | args: this.messageArgs,
226 | unsafeArgs: this.messageUnsafeArgs,
227 | whitelist: this.whitelist
228 | });
229 |
230 | if (message) {
231 | Object.entries(message.attributes).forEach(([name, value]) => {
232 | this.firstElementChild.setAttribute(name, value);
233 | });
234 |
235 | semiSafeInnerHTML(this.firstElementChild, message);
236 | }
237 | }
238 | }
239 | }
240 | );
241 |
242 | customElements.define("fluent-provider", FluentProvider);
243 |
--------------------------------------------------------------------------------