[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[{package.json,.*rc,*.yml}]\nindent_style = space\nindent_size = 2\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".gitignore",
    "content": "/docs\n/dist\n/test-reports\n/node_modules\n/npm-debug.log\n.DS_Store\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - stable\n\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2017, Synacor, Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# preact-i18n 🌎 [![npm](https://img.shields.io/npm/v/preact-i18n.svg?style=flat)](https://npm.im/preact-i18n) [![travis](https://travis-ci.org/synacor/preact-i18n.svg?branch=master)](https://travis-ci.org/synacor/preact-i18n) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n?ref=badge_shield)\n\n<img src=\"resources/example.png\" width=\"600\" alt=\"Usage example\" />\n\n**Simple localization for Preact.**\n\n-   Tiny: about 1.3kb gzipped\n-   Supports dictionary and key scopes/namespaces while maintaining a global dictionary\n-   Supports nested dictionaries:\n    -   Wrap your component in a default dictionary and scope key\n    -   Wrap it again later on (in an app!) to override the defaults\n-   Supports pluralization of strings using nested objects.\n-   Supports template `{{fields}}` in definition values\n-   Has a companion [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-preact-i18n) to help catch bugs early\n\n* * *\n\n-   [Installation](#installation)\n-   [Getting Started](#getting-started)\n    -   [Fallback Text](#fallback-text)\n    -   [Pluralization and Templating](#pluralization-and-templating)\n-   [ESLint Plugin](#eslint-plugin)\n-   [API](#api)\n\n<!-- /MDTOC -->\n\n## Preact Version Support\n\nBy default, the `master` branch of this repo supports preact 9 and below, and is published in normal patch/minor/major releases to the `latest` tag in npm.  Support for preact X (versions 10+ of preact) is handled in the `preactX` branch and are always published to the `preactx` tag in npm.  When preact X obtains widespread adoption, the `master` branch of this project will support preact X and a new major version under `latest` tag will be published to in npm.\n\n## Installation\n\n```sh\nnpm install --save preact-i18n\n\n# For TypeScript Definitions\nnpm install --save-dev @types/preact-i18n\n```\n\n## Getting Started\n\n1.  Create a definition. Typically JSON files, we'll call ours `fr.json`:\n\n```json\n{\n\t\"news\": {\n\t\t\"title\": \"Nouvelles du Monde\",\n\t\t\"totalStories\": {\n\t\t\t\"none\": \"Aucun article\",\n\t\t\t\"one\": \"Un article\",\n\t\t\t\"many\": \"{{count}} articles\"\n\t\t}\n\t}\n}\n```\n\n2.  Expose the definition to your whole app via `<IntlProvider>`:\n\n```js\nimport { IntlProvider } from 'preact-i18n';\nimport definition from './fr.json';\n\nrender(\n\t<IntlProvider definition={definition}>\n\t\t<App />\n\t</IntlProvider>\n);\n```\n\n3.  Use `<Text />` to translate string literals:\n\n```js\nimport { Text } from 'preact-i18n';\n\n// Assume the \"stories\" prop is a list of news stories.\nconst App = ({ stories=[] }) => (\n\t<div class=\"app\">\n\t\t<h1>\n\t\t\t{/* Default fallback text example: */}\n\t\t\t<Text id=\"news.title\">World News</Text>\n\t\t</h1>\n\t\t<footer>\n\t\t\t{/* Pluralization example: */}\n\t\t\t<Text\n\t\t\t\tid=\"news.totalStories\"\n\t\t\t\tplural={stories.length}\n\t\t\t\tfields={{\n\t\t\t\t\tcount: stories.length\n\t\t\t\t}}\n\t\t\t/>\n\t\t</footer>\n\t</div>\n);\n```\n\nThat's it!\n\n### Fallback Text\n\nRendering our example app with an empty definition _(or without the Provider)_ will attempt to use any text contained within `<Text>..</Text>` as fallback text.\n\nIn our example, this would mean rendering without a definition for `news.title` would produce `<h1>World News</h1>`.\n\nIf we provide a definition that has a `title` key inside a `news` object, that value will be rendered instead.\n\n### Pluralization and Templating\n\nIn our example, `<footer>` is using `<Text>` as a convenient way to do pluralization and templating. In our definition, `news.totalStories` is an Object with pluralization keys. The values in that object will be selected based on an integer `plural` prop passed to `<Text>`.\n\nAny definition value _(including pluralization values)_ can contain `{{field}}` placeholders. These placeholders get replaced with matched keys in an object passed as the `fields` prop.  In our example, the \"many\" plural form is such a template - it will render `\"5 articles\"` when `fields={{ count: 5 }}`.\n\nThe available forms for specifying pluralization values are as follows:\n\n-   `\"key\": { \"singular\":\"apple\", \"plural\":\"apples\" }`\n-   `\"key\": { \"none\":\"no apples\", \"one\":\"apple\", \"many\":\"apples\" }`\n-   `\"key\": { \"zero\":\"no apples\", \"one\":\"apple\", \"other\":\"apples\" }`\n-   `\"key\": [\"apples\", \"apple\"]`\n\nTaking `<Text id=\"news.totalStories\" ..>` from our example:\n\n-   `<.. plural={0}>` renders `Aucun article` _(no articles)_\n-   `<.. plural={1}>` renders `Un article` _(one article)_\n-   `<.. plural={2} fields={{ count: 2 }}>` renders `2 articles`\n-   `<.. plural={3} fields={{ count: 3 }}>` renders `3 articles`\n\nIn addition to [`<Text>`](#Text), [`withText()`](#withText) and [`<Localizer>`](#Localizer) provide ways to translate more than just display text - HTML attributes, component props, arbitrary Strings, etc.\n\n## ESLint Plugin\n\nA companion ESLint plugin exists, [eslint-plugin-preact-i18n](https://www.npmjs.com/package/eslint-plugin-preact-i18n), which has several rules that help spot common issues like un-i18n'd text, misconfigured tags, and missing keys, that are beneficial in spotting defects early and ensuring that your application is properly i18n'd.\n\n* * *\n\n## API\n\n<!-- Generated by documentation.js. Update this documentation by updating the source code. -->\n\n#### Table of Contents\n\n-   [IntlProvider](#intlprovider)\n    -   [Parameters](#parameters)\n    -   [Examples](#examples)\n-   [Localizer](#localizer)\n    -   [Parameters](#parameters-1)\n    -   [Examples](#examples-1)\n-   [MarkupText](#markuptext)\n    -   [Parameters](#parameters-2)\n    -   [Examples](#examples-2)\n-   [Text](#text)\n    -   [Parameters](#parameters-3)\n    -   [Examples](#examples-3)\n-   [withText](#withtext)\n    -   [Parameters](#parameters-4)\n    -   [Examples](#examples-4)\n-   [intl](#intl)\n    -   [Parameters](#parameters-5)\n\n### IntlProvider\n\n`<IntlProvider>` is a nestable internationalization definition provider.\nIt exposes an Intl scope & definition into the tree,\nmaking them available to descendant components.\n\n> **Note:** When nested, gives precedence to keys higher up the tree!\n> This means lower-level components can set their defaults by wrapping themselves\n> in an `<IntlProvider>`, but still remain localizable by their parent components.\n\n#### Parameters\n\n-   `props`  \n    -   `props.scope` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Nest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `<Text />` keys).\n    -   `props.mark` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** If `true`, all `<Text>` elements will be shown with a red/green background indicating whether they have valid Intl keys. (optional, default `false`)\n    -   `props.definition` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Merge the given definition into the current intl definition, giving the _current_ definition precedence (i.e., only adding keys, acting as defaults) (optional, default `{}`)\n\n#### Examples\n\n```javascript\n// generally imported from a JSON file:\nlet definition = {\n\tfoo: 'Le Feux'\n};\n\n<IntlProvider scope=\"weather\" definition={definition}>\n\t<Text key=\"foo\">The Foo</Text>\n</IntlProvider>\n\n// This will render the text:\n\"Le Feux\"\n```\n\n### Localizer\n\n`<Localizer />` is a Compositional Component.\nIt \"renders\" out any `<Text />` values in its child's props.\n\n#### Parameters\n\n-   `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `props.children` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Child components with props to localize.\n-   `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info\n\n#### Examples\n\n```javascript\n<Localizer>\n\t<input placeholder={<Text id=\"username.placeholder\" />} />\n</Localizer>\n// produces:\n<input placeholder=\"foo\" />\n```\n\n```javascript\n<Localizer>\n\t<abbr title={<Text id=\"oss-title\">Open Source Software</Text>}>\n\t\t<Text id=\"oss\">OSS</Text>\n\t</abbr>\n</Localizer>\n// produces:\n<abbr title=\"Open Source Software\">OSS</abbr>\n```\n\n### MarkupText\n\n`<MarkupText>` is just like [Text](#text) but it can also contain html markup in rendered strings.  It wraps its contents in a `<span>` tag.\n\n#### Parameters\n\n-   `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** props\n    -   `props.id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Key to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)\n    -   `props.fields` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Values to inject into template `{{fields}}`.  Values in the `fields` object will be coerced to strings, with the exception of `<Text/>` nodes which will be resolved to their translated value (optional, default `{}`)\n    -   `props.plural` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Integer \"count\", used to select plural forms\n-   `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info\n\n#### Examples\n\n```javascript\n// If there is no dictionary in context..\n<MarkupText id=\"foo\"><b>The Foo</b></MarkupText>\n// ..produces the vnode:\n<span><b>The Foo</b></span>\n```\n\n```javascript\n// Given a dictionary and some fields..\n<IntlProvider definition={{ foo:'Le Feux <b>{{bar}}</b>' }}>\n\t<MarkupText id=\"foo\" fields={{ bar: 'BEAR' }}>The Foo</MarkupText>\n</IntlProvider>\n// ..produces the vnode:\n<span>Le Feux <b>BEAR</b></span>\n```\n\n```javascript\n// Within a scope, both `id` and the definition are namespaced..\n<IntlProvider scope=\"weather\" definition={{ foo:'Le <a href=\"http://foo.com\">Feux</a>' }}>\n\t<MarkupText id=\"foo\">The Foo</MarkupText>\n</IntlProvider>\n// ..produces the vnode:\n<span>Le <a href=\"http://foo.com\">Feux</a></span>\n```\n\n```javascript\n// renders nothing if there is no key match and no fallback\n<div><MarkupText /></div>\n// ..produces the vnode:\n<div/>\n```\n\n### Text\n\n`<Text>` renders internationalized text.\nIt attempts to look up translated values from a dictionary in context.\n\nTemplate strings can contain `{{field}}` placeholders,\nwhich injects values from the `fields` prop.\n\nWhen string lookup fails, renders its children as fallback text.\n\n#### Parameters\n\n-   `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** props\n    -   `props.id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Key to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)\n    -   `props.plural` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Integer \"count\", used to select plural forms\n    -   `props.fields` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Values to inject into template `{{fields}}`.  Values in the `fields` object will be coerced to strings, with the exception of `<Text/>` nodes which will be resolved to their translated value (optional, default `{}`)\n    -   `props.children`  \n-   `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info\n\n#### Examples\n\n```javascript\n// If there is no dictionary in context..\n<Text id=\"foo\">The Foo</Text>\n// ..produces the text:\n\"The Foo\"\n```\n\n```javascript\n// Given a dictionary and some fields..\n<IntlProvider definition={{ foo:'Le Feux {{bar}}' }}>\n\t<Text id=\"foo\" fields={{ bar: 'BEAR' }}>The Foo</Text>\n</IntlProvider>\n// ..produces the text:\n\"Le Feux BEAR\"\n```\n\n```javascript\n// Within a scope, both `id` and the definition are namespaced..\n<IntlProvider scope=\"weather\" definition={{ foo:'Le Feux' }}>\n\t<Text id=\"foo\">The Foo</Text>\n</IntlProvider>\n// ..produces the text:\n\"Le Feux\"\n```\n\n### withText\n\n`@withText()` is a Higher Order Component, often used as a decorator.\n\nIt wraps a child component and passes it translations\nbased on a mapping to the dictionary & scope in context.\n\n#### Parameters\n\n-   `mapping` **([Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) \\| [Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function) \\| [String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))** Maps prop names to intl keys (or `<Text>` nodes).\n\n#### Examples\n\n```javascript\n@withText({\n\tplaceholder: 'user.placeholder'\n})\nclass Foo {\n\t// now the `placeholder` prop is our localized String:\n\trender({ placeholder }) {\n\t\treturn <input placeholder={placeholder} />\n\t}\n}\n```\n\n```javascript\n@withText({\n\tplaceholder: <Text id=\"user.placeholder\">fallback text</Text>\n})\nclass Foo {\n\trender({ placeholder }) {\n\t\treturn <input placeholder={placeholder} />\n\t}\n}\n```\n\n```javascript\n@withText('user.placeholder')\nclass Foo {\n\t// for Strings/Arrays, the last path segment becomes the prop name:\n\trender({ placeholder }) {\n\t\treturn <input placeholder={placeholder} />\n\t}\n}\n```\n\nWorks with functional components, too\n\n\n```javascript\nconst Foo = withText('user.placeholder')( props =>\n\t<input placeholder={props.placeholder} />\n)\n```\n\ngetWrappedComponent() returns wrapped child Component\n\n\n```javascript\nconst Foo = () => <div/>;\nconst WrappedFoo = withText('user.placeholer')(Foo);\nWrappedFoo.getWrappedComponent() === Foo; // true\n```\n\n### intl\n\nHigher-order function that creates an `<IntlProvider />` wrapper component for the given component.  It\ntakes two forms depending on how many arguments it's given:\nIt can take a functional form like:\nintl(ComponentToWrap, options)\n\nor it can take an annotation form like:\n\n#### Parameters\n\n-   `Child`  \n-   `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** If there are two arguments, the second argument is Passed as `props` to `<IntlProvider />`\n    -   `options.scope`  Nest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `<Text />` keys).\n    -   `options.definition`  Merge the given definition into the current intl definition, giving the _current_ definition precedence (i.e., only adding keys, acting as defaults) (optional, default `{}`)\n\n## License\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n?ref=badge_large)\n"
  },
  {
    "path": "karma.conf.js",
    "content": "/* eslint-disable */\n\nvar path = require('path');\n\nvar pkg = require('./package.json');\n\nvar REPORTER = process.env.REPORTER || (process.env.ENVIRONMENT==='ci' && 'junit') || '';\n\nmodule.exports = function(config) {\n\tconfig.set({\n\t\tbrowsers: ['ChromeHeadless'],\n\t\tframeworks: ['mocha', 'chai-sinon'],\n\t\treporters: ['mocha'].concat(REPORTER.split(/[, ]/)).filter(dedupe),\n\t\tjunitReporter: {\n\t\t\toutputDir: 'test-reports', // results will be saved as $outputDir/$browserName.xml\n\t\t\tsuite: require('./package.json').name\n\t\t},\n\t\tmochaReporter: { showDiff: true },\n\t\tfiles: [\n\t\t\t'test/**/*.js'\n\t\t],\n\t\tpreprocessors: {\n\t\t\t'{src,test}/**/*': ['webpack', 'sourcemap']\n\t\t},\n\t\twebpack: {\n\t\t\tmode: 'development',\n\t\t\tdevtool: 'inline-source-map',\n\t\t\tresolve: {\n\t\t\t\talias: {\n\t\t\t\t\t'preact-i18n': path.resolve(__dirname, process.env.TEST_PRODUCTION ? pkg.main : 'src')\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodule: {\n\t\t\t\trules: [{\n\t\t\t\t\ttest: /\\.jsx?$/,\n\t\t\t\t\texclude: /node_modules/,\n\t\t\t\t\tloader: 'babel-loader',\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tpresets: [ '@babel/env' ],\n\t\t\t\t\t\tplugins: [\n\t\t\t\t\t\t\t['@babel/plugin-transform-react-jsx', { pragma: 'h' }]\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}]\n\t\t\t},\n\t\t},\n\t\twebpackServer: { stats: 'errors-only' }\n\t});\n};\n\n// filters out empties && dupes\nfunction dedupe(v, i, arr) { return v && arr.indexOf(v)===i; }\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"preact-i18n\",\n  \"amdName\": \"preactLocalize\",\n  \"version\": \"1.5.0\",\n  \"description\": \"Preact internationalization, done simply.\",\n  \"source\": \"src/index.js\",\n  \"module\": \"dist/preact-i18n.esm.js\",\n  \"main\": \"dist/preact-i18n.js\",\n  \"umd:main\": \"dist/preact-i18n.umd.js\",\n  \"scripts\": {\n    \"test\": \"npm-run-all --silent -p lint build test:unit -s test:prod\",\n    \"lint\": \"eslint src test\",\n    \"test:watch\": \"npm run test:unit -- --no-single-run\",\n    \"test:unit\": \"karma start karma.conf.js --single-run\",\n    \"test:prod\": \"cross-env TEST_PRODUCTION=true karma start karma.conf.js --single-run\",\n    \"build\": \"npm-run-all --silent clean -p rollup:* -p minify:* -s docs size\",\n    \"clean\": \"rimraf dist && mkdirp dist\",\n    \"rollup:cjs\": \"cross-var rollup -c rollup.config.js -m -f cjs -n $npm_package_amdName -i $npm_package_source -o $npm_package_main\",\n    \"rollup:umd\": \"cross-var rollup -c rollup.config.js -m -f umd -n $npm_package_amdName -i $npm_package_source -o $npm_package_umd_main\",\n    \"rollup:esm\": \"cross-var rollup -c rollup.config.js -m -f es --environment FORMAT:es -n $npm_package_amdName -i $npm_package_source -o $npm_package_module\",\n    \"minify:cjs\": \"cross-var uglifyjs $npm_package_main -c -m toplevel -o $npm_package_main --source-map content=$npm_package_main.map\",\n    \"minify:umd\": \"cross-var uglifyjs $npm_package_umd_main -c -m -o $npm_package_umd_main --source-map content=$npm_package_umd_main.map\",\n    \"docs\": \"documentation readme -q --section API src\",\n    \"size\": \"cross-var echo \\\"Gzipped Size: $(strip-json-comments --no-whitespace $npm_package_main | gzip-size --raw)\\\"\",\n    \"prepublishOnly\": \"cross-var npm run build -s && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags\"\n  },\n  \"repository\": \"synacor/preact-i18n\",\n  \"keywords\": [\n    \"intl\",\n    \"internationalization\",\n    \"localization\"\n  ],\n  \"homepage\": \"https://github.com/synacor/preact-i18n\",\n  \"authors\": [\n    \"Jason Miller <jasonmiller@synacor.com>\",\n    \"Bill Neff <billneff79@gmail.com>\"\n  ],\n  \"license\": \"BSD-3-Clause\",\n  \"files\": [\n    \"src\",\n    \"dist\"\n  ],\n  \"eslintConfig\": {\n    \"extends\": \"eslint-config-synacor\",\n    \"rules\": {\n      \"guard-for-in\": 0\n    }\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.4.0\",\n    \"@babel/plugin-transform-react-jsx\": \"^7.3.0\",\n    \"@babel/preset-env\": \"^7.4.2\",\n    \"babel-eslint\": \"^10.0.1\",\n    \"babel-loader\": \"^8.0.5\",\n    \"buble\": \"^0.19.7\",\n    \"chai\": \"^4.2.0\",\n    \"chai-as-promised\": \"^7.1.1\",\n    \"cross-env\": \"^5.2.0\",\n    \"cross-var\": \"^1.1.0\",\n    \"documentation\": \"^9.3.1\",\n    \"documentation-theme-default\": \"^3.0.0\",\n    \"eslint\": \"^5.15.3\",\n    \"eslint-config-synacor\": \"^3.0.3\",\n    \"gzip-size-cli\": \"^3.0.0\",\n    \"karma\": \"^4.0.1\",\n    \"karma-chai\": \"^0.1.0\",\n    \"karma-chai-as-promised\": \"^0.1.2\",\n    \"karma-chai-sinon\": \"^0.1.5\",\n    \"karma-chrome-launcher\": \"^2.2.0\",\n    \"karma-cli\": \"^2.0.0\",\n    \"karma-junit-reporter\": \"^1.2.0\",\n    \"karma-mocha\": \"^1.3.0\",\n    \"karma-mocha-reporter\": \"^2.2.5\",\n    \"karma-sourcemap-loader\": \"^0.3.7\",\n    \"karma-webpack\": \"^3.0.5\",\n    \"mkdirp\": \"^0.5.1\",\n    \"mocha\": \"^6.0.2\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"preact\": \"^8.2.5\",\n    \"preact-jsx-chai\": \"^2.2.1\",\n    \"rimraf\": \"^2.6.3\",\n    \"rollup\": \"^1.7.0\",\n    \"rollup-plugin-buble\": \"^0.19.6\",\n    \"rollup-plugin-memory\": \"^3.0.0\",\n    \"sinon\": \"^7.3.0\",\n    \"sinon-chai\": \"^3.3.0\",\n    \"strip-json-comments-cli\": \"^1.0.1\",\n    \"uglify-js\": \"^3.5.1\",\n    \"webpack\": \"^4.29.6\"\n  },\n  \"dependencies\": {\n    \"dlv\": \"^1.1.3\"\n  },\n  \"peerDependencies\": {\n    \"preact\": \"<10\"\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "/*eslint-disable*/\nimport memory from 'rollup-plugin-memory';\nimport buble from 'rollup-plugin-buble';\n\nexport default function(config) {\n\tlet format = config.format;\n\treturn {\n\t\texternal: [\n\t\t\t'preact',\n\t\t\t'dlv'\n\t\t],\n\t\toutput: {\n\t\t\tstrict: false,\n\t\t\texports: format==='es' ? null : 'named',\n\t\t\tglobals: {\n\t\t\t\tpreact: 'preact',\n\t\t\t\tdlv: 'dlv'\n\t\t\t}\n\t\t},\n\t\tplugins: [\n\t\t\tformat!=='es' && memory({\n\t\t\t\tpath: 'src/entry.js',\n\t\t\t\tcontents: \"export { default } from './index';\"\n\t\t\t}),\n\t\t\tbuble({\n\t\t\t\tjsx: 'h'\n\t\t\t})\n\t\t].filter(Boolean)\n\t};\n}\n"
  },
  {
    "path": "src/components/highlight-i18n.js",
    "content": "import { h } from 'preact';\nimport delve from 'dlv';\n\n\n/** Highlight/colorize the i18n'd node if `mark` is set on `intl` in context.  If not, just returns `value`\n *\n *\t@private\n *\t@param {String|VNode} value\tThe l10n'd text/vnode to highlight or pass through\n *\t@param {string} id\tThe key used to lookup the value in the intl dictionary\n */\nexport function HighlightI18N({ value, id }, { intl }) {\n\n\tif (intl && intl.mark) {\n\t\tconst dictionaryKey = `dictionary${intl && intl.scope ? `.${intl.scope}` : ''}.${id}`;\n\t\treturn h('mark', {\n\t\t\tstyle: 'background: ' + (\n\t\t\t\tvalue\n\t\t\t\t\t? delve(intl, dictionaryKey)\n\t\t\t\t\t\t? 'rgba(119,231,117,.5)'      // Green = this string is fully internationalized\n\t\t\t\t\t\t: 'rgba(229,226,41,.5)'       // Yellow = this string does not have a value in the dictionary, but it has a fallback value\n\t\t\t\t\t: 'rgba(228,147,51,.5)'         // Red = this string has no value and no fallback\n\t\t\t),\n\t\t\ttitle: id\n\t\t}, value);\n\t}\n\n\treturn \tvalue ;\n}\n"
  },
  {
    "path": "src/components/intl-provider.js",
    "content": "import { h, Component } from 'preact';\nimport { assign, deepAssign } from '../lib/util';\n\n\nconst URL_FLAG = /[?&#]intl=show/;\n\n\n/** `<IntlProvider>` is a nestable internationalization definition provider.\n *\tIt exposes an Intl scope & definition into the tree,\n *\tmaking them available to descendant components.\n *\n *\t> **Note:** When nested, gives precedence to keys higher up the tree!\n *\t> This means lower-level components can set their defaults by wrapping themselves\n *\t> in an `<IntlProvider>`, but still remain localizable by their parent components.\n *\n *\t@name IntlProvider\n *\t@param props\n *\t@param {String} [props.scope]\t\t\tNest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `<Text />` keys).\n *\t@param {Boolean} [props.mark=false]\t\tIf `true`, all `<Text>` elements will be shown with a red/green background indicating whether they have valid Intl keys.\n *\t@param {Object} [props.definition={}]\tMerge the given definition into the current intl definition, giving the *current* definition precedence (i.e., only adding keys, acting as defaults)\n *\n *\t@example\n *\t// generally imported from a JSON file:\n *\tlet definition = {\n *\t\tfoo: 'Le Feux'\n *\t};\n *\n *\t<IntlProvider scope=\"weather\" definition={definition}>\n *\t\t<Text key=\"foo\">The Foo</Text>\n *\t</IntlProvider>\n *\n *\t// This will render the text:\n *\t\"Le Feux\"\n */\nexport class IntlProvider extends Component {\n\tgetChildContext() {\n\t\tlet { scope, definition, mark } = this.props,\n\t\t\tintl = assign({}, this.context.intl || {});\n\n\t\t// set active scope for the tree if given\n\t\tif (scope) intl.scope = scope;\n\n\t\t// merge definition into current with lower precedence\n\t\tif (definition) {\n\t\t\tintl.dictionary = deepAssign(intl.dictionary || {}, definition);\n\t\t}\n\n\t\tif (mark || (typeof location!=='undefined' && String(location).match(URL_FLAG))) {\n\t\t\tintl.mark = true;\n\t\t}\n\n\t\treturn { intl };\n\t}\n\n\trender({ children }) {\n\t\treturn children && children[0] || null;\n\t}\n}\n"
  },
  {
    "path": "src/components/localizer.js",
    "content": "import { cloneElement } from 'preact';\nimport translateMapping from '../lib/translate-mapping';\n\n/** `<Localizer />` is a Compositional Component.\n *\tIt \"renders\" out any `<Text />` values in its child's props.\n *\n *\t@name Localizer\n *\t@param {Object} props\n *\t@param {Object} props.children\tChild components with props to localize.\n *\t@param {Object} context\n *\t@param {Object} context.intl\t\t[internal] dictionary and scope info\n *\t@example\n *\t<Localizer>\n *\t\t<input placeholder={<Text id=\"username.placeholder\" />} />\n *\t</Localizer>\n *\t// produces:\n *\t<input placeholder=\"foo\" />\n *\n *\t@example\n *\t<Localizer>\n *\t\t<abbr title={<Text id=\"oss-title\">Open Source Software</Text>}>\n *\t\t\t<Text id=\"oss\">OSS</Text>\n *\t\t</abbr>\n *\t</Localizer>\n *\t// produces:\n *\t<abbr title=\"Open Source Software\">OSS</abbr>\n */\nexport function Localizer({ children }, { intl }) {\n\tlet child = children && children[0];\n\treturn child && cloneElement(child, translateMapping(child.attributes, intl, true));\n}\n"
  },
  {
    "path": "src/components/markup-text.js",
    "content": "import { h } from 'preact';\nimport { Text } from './text';\nimport { Localizer } from './localizer';\nimport { HighlightI18N } from './highlight-i18n';\n\n/* eslint-disable react/no-danger */\n\n/** `<MarkupText>` is just like {@link Text} but it can also contain html markup in rendered strings.  It wraps its contents in a `<span>` tag.\n *\n *\t@param {Object} props\t\t\t\tprops\n *\t@param {String} props.id\t\t\tKey to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)\n *\t@param {Object} [props.fields={}]\tValues to inject into template `{{fields}}`.  Values in the `fields` object will be coerced to strings, with the exception of `<Text/>` nodes which will be resolved to their translated value\n *\t@param {Number} [props.plural]\t\tInteger \"count\", used to select plural forms\n *\t@param {Object} context\n *\t@param {Object} context.intl\t\t[internal] dictionary and scope info\n *\n *\t@example\n *\t// If there is no dictionary in context..\n *\t<MarkupText id=\"foo\"><b>The Foo</b></MarkupText>\n *\t// ..produces the vnode:\n *\t<span><b>The Foo</b></span>\n *\n *\t@example\n *\t// Given a dictionary and some fields..\n *\t<IntlProvider definition={{ foo:'Le Feux <b>{{bar}}</b>' }}>\n *\t\t<MarkupText id=\"foo\" fields={{ bar: 'BEAR' }}>The Foo</MarkupText>\n *\t</IntlProvider>\n *\t// ..produces the vnode:\n *\t<span>Le Feux <b>BEAR</b></span>\n *\n *\t@example\n *\t// Within a scope, both `id` and the definition are namespaced..\n *\t<IntlProvider scope=\"weather\" definition={{ foo:'Le <a href=\"http://foo.com\">Feux</a>' }}>\n *\t\t<MarkupText id=\"foo\">The Foo</MarkupText>\n *\t</IntlProvider>\n *\t// ..produces the vnode:\n *\t<span>Le <a href=\"http://foo.com\">Feux</a></span>\n *\n *\t@example\n *\t// renders nothing if there is no key match and no fallback\n *\t<div><MarkupText /></div>\n *\t// ..produces the vnode:\n *\t<div/>\n */\nexport function MarkupText(props) {\n\treturn (\n\t\t<Localizer>\n\t\t\t<Html html={<Text {...props} />} id={props.id} />\n\t\t</Localizer>\n\t);\n}\n\nfunction Html({ html, id }) {\n\tlet value = !html ? html : typeof html === 'string' ? <span dangerouslySetInnerHTML={{ __html: html }} /> : <span>{html}</span> ;\n\treturn <HighlightI18N id={id} value={value} />;\n}\n"
  },
  {
    "path": "src/components/text.js",
    "content": "import { h } from 'preact';\nimport translate from '../lib/translate';\nimport { HighlightI18N } from './highlight-i18n';\n\n/** `<Text>` renders internationalized text.\n *\tIt attempts to look up translated values from a dictionary in context.\n *\n *\tTemplate strings can contain `{{field}}` placeholders,\n *\twhich injects values from the `fields` prop.\n *\n *\tWhen string lookup fails, renders its children as fallback text.\n *\n *\t@param {Object} props\t\t\t\tprops\n *\t@param {String} props.id\t\t\tKey to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)\n *\t@param {Object} [props.fields={}]\tValues to inject into template `{{fields}}`.  Values in the `fields` object will be coerced to strings, with the exception of `<Text/>` nodes which will be resolved to their translated value\n *\t@param {Number} [props.plural]\t\tInteger \"count\", used to select plural forms\n *\t@param {Object} context\n *\t@param {Object} context.intl\t\t[internal] dictionary and scope info\n *\n *\t@example\n *\t// If there is no dictionary in context..\n *\t<Text id=\"foo\">The Foo</Text>\n *\t// ..produces the text:\n *\t\"The Foo\"\n *\n *\t@example\n *\t// Given a dictionary and some fields..\n *\t<IntlProvider definition={{ foo:'Le Feux {{bar}}' }}>\n *\t\t<Text id=\"foo\" fields={{ bar: 'BEAR' }}>The Foo</Text>\n *\t</IntlProvider>\n *\t// ..produces the text:\n *\t\"Le Feux BEAR\"\n *\n *\t@example\n *\t// Within a scope, both `id` and the definition are namespaced..\n *\t<IntlProvider scope=\"weather\" definition={{ foo:'Le Feux' }}>\n *\t\t<Text id=\"foo\">The Foo</Text>\n *\t</IntlProvider>\n *\t// ..produces the text:\n *\t\"Le Feux\"\n */\nexport function Text({ id, children, plural, fields }, { intl }) {\n\n\tlet fallback = children && children[0];\n\n\tlet value = translate(\n\t\tid,\n\t\tintl && intl.scope,\n\t\tintl && intl.dictionary,\n\t\tfields,\n\t\tplural,\n\t\tfallback\n\t);\n\n\treturn <HighlightI18N id={id} value={value} />;\n}\n"
  },
  {
    "path": "src/components/with-text.js",
    "content": "import { h } from 'preact';\nimport translateMapping from '../lib/translate-mapping';\nimport { assign } from '../lib/util';\n\n/** `@withText()` is a Higher Order Component, often used as a decorator.\n *\n *\tIt wraps a child component and passes it translations\n *\tbased on a mapping to the dictionary & scope in context.\n *\n *\t@param {Object|Function|String} mapping\t\tMaps prop names to intl keys (or `<Text>` nodes).\n *\n *\t@example @withText({\n *\t\tplaceholder: 'user.placeholder'\n *\t})\n *\tclass Foo {\n *\t\t// now the `placeholder` prop is our localized String:\n *\t\trender({ placeholder }) {\n *\t\t\treturn <input placeholder={placeholder} />\n *\t\t}\n *\t}\n *\n *\t@example @withText({\n *\t\tplaceholder: <Text id=\"user.placeholder\">fallback text</Text>\n *\t})\n *\tclass Foo {\n *\t\trender({ placeholder }) {\n *\t\t\treturn <input placeholder={placeholder} />\n *\t\t}\n *\t}\n *\n *\t@example @withText('user.placeholder')\n *\tclass Foo {\n *\t\t// for Strings/Arrays, the last path segment becomes the prop name:\n *\t\trender({ placeholder }) {\n *\t\t\treturn <input placeholder={placeholder} />\n *\t\t}\n *\t}\n *\n *\t@example <caption>Works with functional components, too</caption>\n *\tconst Foo = withText('user.placeholder')( props =>\n *\t\t<input placeholder={props.placeholder} />\n *\t)\n *\n * \t@example <caption>getWrappedComponent() returns wrapped child Component</caption>\n *\tconst Foo = () => <div/>;\n *\tconst WrappedFoo = withText('user.placeholer')(Foo);\n *\tWrappedFoo.getWrappedComponent() === Foo; // true\n */\nexport function withText(mapping) {\n\treturn function withTextWrapper(Child) {\n\t\tfunction WithTextWrapper(props, context) {\n\t\t\tlet map = typeof mapping==='function' ? mapping(props, context) : mapping;\n\t\t\tlet translations = translateMapping(map, context.intl);\n\t\t\treturn h(Child, assign(assign({}, props), translations));\n\t\t}\n\n\t\tWithTextWrapper.getWrappedComponent = Child && Child.getWrappedComponent || (() => Child);\n\t\treturn WithTextWrapper;\n\t};\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import { intl } from './intl';\nimport { IntlProvider } from './components/intl-provider';\nimport { Text } from './components/text';\nimport { MarkupText } from './components/markup-text';\nimport { Localizer } from './components/localizer';\nimport { withText } from './components/with-text';\n\nexport { intl, IntlProvider, Text, MarkupText, Localizer, withText };\n\nintl.intl = intl;\nintl.IntlProvider = IntlProvider;\nintl.Text = Text;\nintl.MarkupText = MarkupText;\nintl.Localizer = Localizer;\nintl.withText = withText;\nexport default intl;\n"
  },
  {
    "path": "src/intl.js",
    "content": "import { h } from 'preact';\nimport { IntlProvider } from './components/intl-provider';\n\n\n/**\n * Higher-order function that creates an `<IntlProvider />` wrapper component for the given component.  It\n * takes two forms depending on how many arguments it's given:\n * It can take a functional form like:\n * intl(ComponentToWrap, options)\n *\n * or it can take an annotation form like:\n * @intl(options)\n * class ComponentToWrap extends Component {}\n *\n *\t@param {Component or Object} args[0] If there are two arguments, the first argument is the Component to wrap in `<IntlProvider/>`. If there is just one argument, this is the options object to pass as `props` to `<IntlProvider/>`. See the definition of the options param below for details.\n *\t@param {Object} options If there are two arguments, the second argument is Passed as `props` to `<IntlProvider />`\n *\t@param [options.scope]\t\t\tNest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `<Text />` keys).\n *\t@param [options.definition={}]\tMerge the given definition into the current intl definition, giving the *current* definition precedence (i.e., only adding keys, acting as defaults)\n */\nexport function intl(Child, options) {\n\tif (arguments.length<2) {\n\t\toptions = Child;\n\t\treturn Child => intl(Child, options);\n\t}\n\tfunction IntlProviderWrapper(props) {\n\t\treturn h(\n\t\t\tIntlProvider,\n\t\t\toptions || {},\n\t\t\th(Child, props)\n\t\t);\n\t}\n\n\tIntlProviderWrapper.getWrappedComponent = Child && Child.getWrappedComponent || (() => Child);\n\treturn IntlProviderWrapper;\n}\n"
  },
  {
    "path": "src/lib/template.js",
    "content": "import { Text } from '../components/text';\nimport translate from './translate';\n\nconst EMPTY = {};\n\n/** Populate {{template.fields}} within a given string.\n *\n *\t@private\n *\t@param {String} template\tThe string containing fields to be resolved\n *\t@param {Object} [fields={}]\tOptionally nested object of fields, referencable from `template`.\n *\t@example\n *\t\ttemplate('foo{{bar}}', { bar:'baz' }) === 'foobaz'\n */\nexport default function template(template, fields, scope, dictionary) {\n\treturn template && template.replace(/\\{\\{([\\w.-]+)\\}\\}/g, replacer.bind(null, fields || EMPTY, scope, dictionary));\n}\n\n/** Replacement callback for injecting fields into a String\n *\t@private\n */\nfunction replacer(currentFields, scope, dictionary, s, field) {\n\tlet parts = field.split('.'),\n\t\tv = currentFields;\n\tfor (let i=0; i<parts.length; i++) {\n\t\tv = v[parts[i]];\n\t\tif (v == null) return ''; // eslint-disable-line eqeqeq\n\n\t\t//allow field values to be <Text /> nodes\n\t\tif (v && v.nodeName === Text) {\n\t\t\treturn translate(v.attributes.id, scope, dictionary, v.attributes.fields, v.attributes.plural, v.attributes.fallback);\n\t\t}\n\t}\n\t// allow for recursive {{config.xx}} references:\n\tif (typeof v==='string' && v.match(/\\{\\{/)) {\n\t\tv = template(v, currentFields);\n\t}\n\treturn v;\n}\n"
  },
  {
    "path": "src/lib/translate-mapping.js",
    "content": "import { assign, select } from './util';\nimport translate from './translate';\nimport { Text } from '../components/text';\n\n/** Translates the property values in an Object, returning a copy.\n *\t**Note:** By default, `String` keys will be treated as Intl ID's.\n *\tPass `true` to return an Object containing *only* translated\n *\tvalues where the prop is a <Text /> node.\n *\n *\t@private\n *\t@param {Object} props\tAn object with values to translate\n *\t@param {Object} intl\tAn intl context object (eg: `context.intl`)\n *\t@param {Boolean} [onlyTextNodes=false]\tOnly process `<Text />` values\n *\t@returns {Object} translatedProps\n */\nexport default function translateMapping(props, intl, onlyTextNodes) {\n\tlet out = {};\n\tintl = intl || {};\n\tprops = select(props);\n\tfor (let name in props) {\n\t\tif (props.hasOwnProperty(name) && props[name]) {\n\t\t\tlet def = props[name];\n\n\t\t\t// if onlyTextNodes=true, skip any props that aren't <Text /> vnodes\n\t\t\tif (!onlyTextNodes && typeof def==='string') {\n\t\t\t\tout[name] = translate(def, intl.scope, intl.dictionary);\n\t\t\t}\n\t\t\telse if (def.nodeName===Text) {\n\t\t\t\t// it's a <Text />, just grab its props:\n\t\t\t\tlet c = def.children;\n\t\t\t\tdef = assign({\n\t\t\t\t\t//no fallback if there are no children.  Return first child if there is only 1, or array of children if there are more than one\n\t\t\t\t\tfallback: c.length && (c.length === 1 ? c[0] : c)\n\t\t\t\t}, def.attributes);\n\t\t\t\tout[name] = translate(def.id, intl.scope, intl.dictionary, def.fields, def.plural, def.fallback);\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n}\n"
  },
  {
    "path": "src/lib/translate.js",
    "content": "import delve from 'dlv';\nimport { defined } from './util';\nimport template from './template';\n\n/** Attempts to look up a translated value from a given dictionary.\n *  Also supports json templating using the format: {{variable}}\n *\tFalls back to default text.\n *\n *\t@private\n *\t@param {String} id\t\t\t\tIntl field name/id (subject to scope)\n *\t@param {String} [scope='']\t\tScope, which prefixes `id` with `${scope}.`\n *\t@param {Object} dictionary\t\tA nested object containing translations\n *\t@param {Object} [fields={}]\t\tTemplate fields for use by translated strings\n *\t@param {Number} [plural]\t\tIndicates a quantity, used to trigger pluralization\n *\t@param {String|Array} [fallback]\tText to return if no translation is found\n *\t@returns {String} translated\n */\nexport default function translate(id, scope, dictionary, fields, plural, fallback) {\n\tif (scope) id = scope + '.' + id;\n\n\tlet value = dictionary && delve(dictionary, id);\n\n\t// plural forms:\n\t// key: ['plural', 'singular']\n\t// key: { none, one, many }\n\t// key: { zero, one, other }\n\t// key: { singular, plural }\n\tif ((plural || plural===0) && value && typeof value==='object') {\n\t\tif (value.splice) {\n\t\t\tvalue = value[plural] || value[0];\n\t\t}\n\t\telse if (plural===0 && defined(value.none || value.zero)) {\n\t\t\tvalue = value.none || value.zero;\n\t\t}\n\t\telse if (plural===1 && defined(value.one || value.singular)) {\n\t\t\tvalue = value.one || value.singular;\n\t\t}\n\t\telse {\n\t\t\tvalue = value.some || value.many || value.plural || value.other || value;\n\t\t}\n\t}\n\n\treturn value && template(value, fields, scope, dictionary) || fallback || null;\n}\n"
  },
  {
    "path": "src/lib/util.js",
    "content": "/** Check if an object is not null or undefined\n *\t@private\n */\nexport function defined(obj) {\n\treturn obj!==null && obj!==undefined;\n}\n\n\n/** A simpler Object.assign\n *  @private\n */\nexport function assign(obj, props) {\n\tfor (let i in props) {\n\t\tobj[i] = props[i];\n\t}\n\treturn obj;\n}\n\n\n/** Recursively copy keys from `source` to `target`, skipping truthy values already in `target`.\n *\t@private\n */\nexport function deepAssign(target, source) {\n\tlet out = assign({}, target);\n\tfor (let i in source) {\n\t\tif (source.hasOwnProperty(i)) {\n\t\t\tif (target[i] && source[i] && typeof target[i]==='object' && typeof source[i]==='object') {\n\t\t\t\tout[i] = deepAssign(target[i], source[i]);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tout[i] = target[i] || source[i];\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n}\n\n/** select('foo,bar') creates a mapping: `{ foo, bar }`\n *\t@private\n */\nexport function select(properties) {\n\tproperties = properties || {};\n\tif (typeof properties==='string') {\n\t\tproperties = properties.split(',');\n\t}\n\tif ('join' in properties) {\n\t\tlet selected = {};\n\t\tfor (let i=0; i<properties.length; i++) {\n\t\t\tlet val = properties[i].trim();\n\t\t\tif (val) selected[val.split('.').pop()] = val;\n\t\t}\n\t\treturn selected;\n\t}\n\treturn properties;\n}\n"
  },
  {
    "path": "test/.eslintrc",
    "content": "{\n  \"extends\": \"eslint-config-synacor/test-rules\"\n}\n"
  },
  {
    "path": "test/index.js",
    "content": "import { h, render } from 'preact';\nimport 'preact-jsx-chai';\nimport wrap, { intl, IntlProvider, Text, MarkupText, Localizer, withText } from 'preact-i18n';\n/* eslint-disable react/no-danger */\n\nfunction Empty() {}\n\ndescribe('intl', () => {\n\tlet scope = 'test-scope',\n\t\tdictionary = { foo: 'bar', baz: 'bat' },\n\t\toptions = { scope, definition: dictionary };\n\n\tbefore( () => rndr() );\n\n\tlet scratch = document.createElement('div'),\n\t\troot;\n\tfunction rndr(jsx) {\n\t\troot = render(<Empty />, scratch, root);\n\t\tif (jsx) root = render(jsx, scratch, root);\n\t\treturn root;\n\t}\n\n\tit('should export things', () => {\n\t\texpect(intl).to.be.a('function');\n\t\texpect(wrap).to.be.a('function');\n\t\texpect(IntlProvider).to.be.a('function');\n\t\texpect(Text).to.be.a('function');\n\t});\n\n\tit('should work as a decorator @intl when given one argumnt', () => {\n\t\tlet TestClass = () => <div />;\n\t\tlet IntlTestClass = intl(options)(TestClass);\n\t\texpect(<IntlTestClass />).to.equal(\n\t\t\t<IntlProvider scope={scope} definition={dictionary}>\n\t\t\t\t<TestClass />\n\t\t\t</IntlProvider>\n\t\t);\n\t});\n\n\tit('should work as a function when given two arguments', () => {\n\t\tlet TestClass = () => <div />;\n\t\tlet IntlTestClass = intl(TestClass, options);\n\t\texpect(<IntlTestClass />).to.equal(\n\t\t\t<IntlProvider scope={scope} definition={dictionary}>\n\t\t\t\t<TestClass />\n\t\t\t</IntlProvider>\n\t\t);\n\t});\n\n\tdescribe('getWrappedComponent()', () => {\n\n\t\tit('should be a function', () => {\n\t\t\tlet Wrapped = intl(options)(sinon.spy());\n\t\t\texpect(Wrapped.getWrappedComponent).to.be.a('function');\n\t\t});\n\n\t\tit('should return the Child component that it is wrapping', () => {\n\t\t\tlet Foo = sinon.spy();\n\t\t\tlet Wrapped = intl(options)(Foo);\n\t\t\texpect(Wrapped.getWrappedComponent()).to.equal(Foo);\n\t\t});\n\n\t\tit('should recursively call getWrappedComponent() on Child components to return the first non-decorator Child', () => {\n\t\t\tlet Foo = sinon.spy();\n\t\t\t//Wrap Foo in two layers of configuration to make sure Foo is returned by the top level call to getWrappedComponent\n\t\t\tlet Wrapped = intl(options)(intl(options)(Foo));\n\t\t\texpect(Wrapped.getWrappedComponent()).to.equal(Foo);\n\t\t});\n\n\t});\n\n\n\tdescribe('<IntlProvider>', () => {\n\t\tit('should provide context', () => {\n\t\t\tlet Spy = sinon.stub().returns(null);\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={dictionary}>\n\t\t\t\t\t<Spy />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Spy).to.have.been.calledOnce.and.calledWithMatch({}, { intl: { dictionary } });\n\n\t\t\tSpy.reset();\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider scope=\"foo\" definition={{ foo: dictionary }}>\n\t\t\t\t\t<Spy />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Spy).to.have.been.calledOnce.and.calledWithMatch({}, {\n\t\t\t\tintl: {\n\t\t\t\t\tscope: 'foo',\n\t\t\t\t\tdictionary: { foo: dictionary }\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tdescribe('mark', () => {\n\t\t\tit('should be off by default', () => {\n\t\t\t\tconst Child = sinon.spy( () => <div /> );\n\n\t\t\t\trndr(\n\t\t\t\t\t<IntlProvider>\n\t\t\t\t\t\t<Child />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t);\n\n\t\t\t\texpect(Child).to.have.been.calledWithMatch({ }, { intl: { } });\n\t\t\t});\n\n\t\t\tit('should be triggered by <IntlProvider mark>', () => {\n\t\t\t\tconst Child = sinon.spy( () => <div /> );\n\n\t\t\t\trndr(\n\t\t\t\t\t<IntlProvider mark>\n\t\t\t\t\t\t<Child />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t);\n\n\t\t\t\texpect(Child).to.have.been.calledWithMatch({ }, { intl: { mark: true } });\n\t\t\t});\n\n\t\t\tit('should be triggered by URL flag', () => {\n\t\t\t\tlet url = location.pathname;\n\n\t\t\t\tfunction test(urlSuffix) {\n\t\t\t\t\thistory.replaceState(null, null, url+urlSuffix);\n\t\t\t\t\tconst Child = sinon.spy( () => <div /> );\n\t\t\t\t\trndr(\n\t\t\t\t\t\t<IntlProvider>\n\t\t\t\t\t\t\t<Child />\n\t\t\t\t\t\t</IntlProvider>\n\t\t\t\t\t);\n\t\t\t\t\texpect(Child).to.have.been.calledWithMatch({ }, { intl: { mark: true } });\n\t\t\t\t}\n\n\t\t\t\ttest('?intl=show');\n\t\t\t\ttest('#intl=show');\n\t\t\t\ttest('?foo&intl=show');\n\t\t\t\ttest('?foo=bar=&intl=show&baz=bat');\n\n\t\t\t\thistory.replaceState(null, null, url);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('<Text>', () => {\n\t\tit('should fall back if not wrapped in a Provider', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<Text>FOO</Text>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('FOO');\n\t\t});\n\n\t\tit('should render text without scope', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider definition={{ foo: 'FOO!' }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<Text id=\"foo\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('<div>FOO!</div>');\n\t\t});\n\n\t\tit('should render text with scope', () => {\n\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider scope=\"foo\" definition={{ foo: { bar: 'BAR!' } }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<Text id=\"bar\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div>BAR!</div>');\n\t\t});\n\n\t\tit('should render html markup as string data, not markup', () => {\n\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider definition={{ foo: '<b>FOO</b>' }} >\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<Text id=\"foo\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div>&lt;b&gt;FOO&lt;/b&gt;</div>');\n\t\t});\n\n\n\t\tit('should render default when requested id is not present', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider scope=\"foo\" definition={{ foo: { bar: 'BAR!' } }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<Text id=\"asdf\">DEFAULT</Text>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div>DEFAULT</div>');\n\t\t});\n\n\t\tdescribe('mark', () => {\n\t\t\tit('should render translations with a green wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: 'BAR!' }}>\n\t\t\t\t\t\t<Text id=\"bar\" />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(119,231,117,.5)\" title=\"bar\">BAR!</mark>\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('should render translations relying on a fallback with a yellow wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: 'BAR!' }}>\n\t\t\t\t\t\t<Text id=\"foo\">Fooey</Text>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(229,226,41,.5)\" title=\"foo\">Fooey</mark>\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('should render missing translations with an orange wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: 'BAR!' }}>\n\t\t\t\t\t\t<Text id=\"foo\" />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(228,147,51,.5)\" title=\"foo\" />\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('<MarkupText>', () => {\n\n\t\tit('should render nothing if no key or fallback is found', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<MarkupText />\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('');\n\t\t});\n\n\n\t\tit('should fall back if not wrapped in a Provider', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<MarkupText><b>FOO</b></MarkupText>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('<span><b>FOO</b></span>');\n\t\t});\n\n\t\tit('should render multi-child fallback', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<MarkupText>This <b>is the fallback</b> with multiple children</MarkupText>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('<span>This <b>is the fallback</b> with multiple children</span>');\n\t\t});\n\n\t\tit('should render text without scope', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider definition={{ foo: 'FOO!' }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<MarkupText id=\"foo\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML).to.equal('<div><span>FOO!</span></div>');\n\t\t});\n\n\t\tit('should render text with scope', () => {\n\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider scope=\"foo\" definition={{ foo: { bar: 'BAR!' } }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<MarkupText id=\"bar\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div><span>BAR!</span></div>');\n\t\t});\n\n\n\t\tit('should render default when requested id is not present', () => {\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider scope=\"foo\" definition={{ foo: { bar: 'BAR!' } }}>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<MarkupText id=\"asdf\"><b>DEFAULT</b></MarkupText>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div><span><b>DEFAULT</b></span></div>');\n\t\t});\n\n\t\tit('should render html markup as markup', () => {\n\n\t\t\trndr(\n\t\t\t\t<div>\n\t\t\t\t\t<IntlProvider definition={{ foo: '<b>FOO</b>' }} >\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<MarkupText id=\"foo\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t</div>\n\t\t\t);\n\n\t\t\texpect(root.innerHTML, '').to.equal('<div><span><b>FOO</b></span></div>');\n\t\t});\n\n\t\tdescribe('mark', () => {\n\t\t\tit('should render translations with a green wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: '<b>BAR!</b>' }}>\n\t\t\t\t\t\t<MarkupText id=\"bar\" />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(119,231,117,.5)\" title=\"bar\">\n\t\t\t\t\t\t<span dangerouslySetInnerHTML={{ __html: '<b>BAR!</b>' }} />\n\t\t\t\t\t</mark>);\n\t\t\t});\n\n\t\t\tit('should render translations relying on a fallback with a yellow wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: 'BAR!' }}>\n\t\t\t\t\t\t<MarkupText id=\"foo\"><b>Fooey</b></MarkupText>\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(229,226,41,.5)\" title=\"foo\">\n\t\t\t\t\t\t<span><b>Fooey</b></span>\n\t\t\t\t\t</mark>\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('should render missing translations with an orange wrapping <mark>', () => {\n\t\t\t\texpect(\n\t\t\t\t\t<IntlProvider mark definition={{ bar: 'BAR!' }}>\n\t\t\t\t\t\t<MarkupText id=\"foo\" />\n\t\t\t\t\t</IntlProvider>\n\t\t\t\t).to.eql(\n\t\t\t\t\t<mark style=\"background: rgba(228,147,51,.5)\" title=\"foo\" />\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\n\t});\n\n\tdescribe('withText()', () => {\n\t\tit('should provide strings to child as props', () => {\n\t\t\tconst Child = sinon.stub().returns(<div />);\n\t\t\tconst Wrapped = withText({\n\t\t\t\tpropName: 'foo'\n\t\t\t})(Child);\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={{ foo: 'FOO!' }}>\n\t\t\t\t\t<Wrapped />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Child).to.have.been.calledOnce.and.calledWithMatch({ propName: 'FOO!' });\n\t\t});\n\n\t\tit('should accept a CSV of keys', () => {\n\t\t\tconst Child = sinon.stub().returns(<div />);\n\t\t\tconst Wrapped = withText('foo,bar,baz')(Child);\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={{ foo: '1', bar: '2', baz: '3' }}>\n\t\t\t\t\t<Wrapped />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Child).to.have.been.calledOnce.and.calledWithMatch({ foo: '1', bar: '2', baz: '3' });\n\t\t});\n\n\t\tit('should accept an Array of keys', () => {\n\t\t\tconst Child = sinon.stub().returns(<div />);\n\t\t\tconst Wrapped = withText(['foo','bar','baz'])(Child);\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={{ foo: '1', bar: '2', baz: '3' }}>\n\t\t\t\t\t<Wrapped />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Child).to.have.been.calledOnce.and.calledWithMatch({ foo: '1', bar: '2', baz: '3' });\n\t\t});\n\n\t\tit('should support <Text> as a value', () => {\n\t\t\tconst Child = sinon.stub().returns(<div />);\n\t\t\tconst Wrapped = withText({\n\t\t\t\tnormal: <Text id=\"foo\" />,\n\t\t\t\tmissing: <Text id=\"bar\" />,\n\t\t\t\twithchild: <Text id=\"baz\">child</Text>,\n\t\t\t\twithfallback: <Text id=\"bat\" fallback=\"fallback\" />\n\t\t\t})(Child);\n\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={{ foo: 'FOO!' }}>\n\t\t\t\t\t<Wrapped />\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(Child).to.have.been.calledOnce.and.calledWithMatch({\n\t\t\t\tnormal: 'FOO!',\n\t\t\t\tmissing: null,\n\t\t\t\twithchild: 'child',\n\t\t\t\twithfallback: 'fallback'\n\t\t\t});\n\t\t});\n\n\t\tdescribe('getWrappedComponent()', () => {\n\n\t\t\tit('should be a function', () => {\n\t\t\t\tconst Wrapped = withText(['foo','bar','baz'])(sinon.spy());\n\t\t\t\texpect(Wrapped.getWrappedComponent).to.be.a('function');\n\t\t\t});\n\n\t\t\tit('should return the Child component that it is wrapping', () => {\n\t\t\t\tlet Foo = sinon.spy();\n\t\t\t\tlet Wrapped = withText(['foo','bar','baz'])(Foo);\n\t\t\t\texpect(Wrapped.getWrappedComponent()).to.equal(Foo);\n\t\t\t});\n\n\t\t\tit('should recursively call getWrappedComponent() on Child components to return the first non-decorator Child', () => {\n\t\t\t\tlet Foo = sinon.spy();\n\t\t\t\t//Wrap Foo in two layers of configuration to make sure Foo is returned by the top level call to getWrappedComponent\n\t\t\t\tlet Wrapped = withText(['foo','bar','baz'])(withText(['buzz'])(Foo));\n\t\t\t\texpect(Wrapped.getWrappedComponent()).to.equal(Foo);\n\t\t\t});\n\n\t\t});\n\n\t});\n\n\tdescribe('<Localizer>', () => {\n\t\tit('should translate any <Text> props on its child', () => {\n\t\t\trndr(\n\t\t\t\t<IntlProvider definition={{ input: { pl: 'type a name' } }}>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<Localizer>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\tplaceholder={<Text id=\"input.pl\" />}\n\t\t\t\t\t\t\t\ttitle={<Text id=\"input.title\">blah</Text>}\n\t\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\t\tminlength={0}\n\t\t\t\t\t\t\t\tmaxlength={1}\n\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Localizer>\n\t\t\t\t\t</div>\n\t\t\t\t</IntlProvider>\n\t\t\t);\n\n\t\t\texpect(root).to.have.property('innerHTML', `<input placeholder=\"type a name\" title=\"blah\" type=\"email\" minlength=\"0\" maxlength=\"1\" required=\"\">`);\n\t\t});\n\n\t});\n});\n"
  },
  {
    "path": "test/lib/template.js",
    "content": "import template from '../../src/lib/template';\n\ndescribe('template()', () => {\n\tit('should leave fieldless unmodified', () => {\n\t\texpect(template('foo')).to.equal('foo');\n\t\texpect(template('{foo}')).to.equal('{foo}');\n\t\texpect(template('{{foo\\\\}}')).to.equal('{{foo\\\\}}');\n\t\texpect(template('a{{$$}}')).to.equal('a{{$$}}');\n\t});\n\n\tit('should inject top-level fields', () => {\n\t\tconst FIELDS = {\n\t\t\tfoo: 'FOO',\n\t\t\tbar: 'baz'\n\t\t};\n\n\t\texpect(template('{{foo}}', FIELDS)).to.equal('FOO');\n\t\texpect(template('{{foo}}{{bar}}', FIELDS)).to.equal('FOObaz');\n\t\texpect(template('a {{foo}} b {{bar}} c', FIELDS)).to.equal('a FOO b baz c');\n\t});\n\n\tit('should inject nested fields', () => {\n\t\tconst FIELDS = {\n\t\t\tfoo: {\n\t\t\t\tbar: {\n\t\t\t\t\tbaz: 'bat'\n\t\t\t\t}\n\t\t\t},\n\t\t\tarr: [\n\t\t\t\t'a',\n\t\t\t\t{ b: 1 }\n\t\t\t]\n\t\t};\n\n\t\texpect(template('{{foo.bar.baz}}', FIELDS)).to.equal('bat');\n\t\texpect(template('{{foo.bar}}', FIELDS)).to.equal('[object Object]');\n\t\texpect(template('{{arr.0}}', FIELDS)).to.equal('a');\n\t\texpect(template('{{arr.1.b}}', FIELDS)).to.equal('1');\n\t});\n\n\tit('should support recursive field injection', () => {\n\t\tconst FIELDS = {\n\t\t\tfirst: '1{{second}}2',\n\t\t\tsecond: '3{{third}}4',\n\t\t\tthird: 'THIRD'\n\t\t};\n\n\t\texpect(template('{{first}}', FIELDS)).to.equal('13THIRD42');\n\t});\n\n\tit('should replace empty fields with the empty string', () => {\n\t\tconst FIELDS = {\n\t\t\tbaz: 'baz'\n\t\t};\n\n\t\texpect(template('{{foo}}', FIELDS)).to.equal('');\n\t\texpect(template('{{foo.bar}}', FIELDS)).to.equal('');\n\t\texpect(template('Fooey {{foo.bar}}', FIELDS)).to.equal('Fooey ');\n\t\texpect(template('Fooey {{foo.bar}} {{baz}}', FIELDS)).to.equal('Fooey  baz');\n\t});\n\n\tit('should replace fields with falsey values', () => {\n\t\tconst FIELDS = {\n\t\t\tfoo: 0,\n\t\t\tbar: false\n\t\t};\n\n\t\texpect(template('{{foo}}', FIELDS)).to.equal('0');\n\t\texpect(template('{{bar}}', FIELDS)).to.equal('false');\n\t});\n\n});\n"
  },
  {
    "path": "test/lib/translate.js",
    "content": "import { h } from 'preact';\nimport translate from '../../src/lib/translate';\nimport { Text } from '../../src/components/text';\n\ndescribe('translate', () => {\n\n\tit('should return the value from the dictionary if a dot-notated match on id is found', () => {\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: 'hello' } })).to.equal('hello');\n\t});\n\n\tit('should prefix scope to id to resolve dot-notated id in dictionary', () => {\n\t\texpect(translate('foo.bar', 'myScope', { myScope: { foo: { bar: 'hello' } } })).to.equal('hello');\n\t\texpect(translate('foo.bar', 'myScope', { foo: { bar: 'hello' } })).to.be.null;\n\t});\n\n\tit('should return null if no id match is found in the dictionary and not fallback is provided', () => {\n\t\texpect(translate('foo.bar', undefined, {})).to.be.null;\n\t});\n\n\tit('should return the fallback when a value from the dictionary by a dot-notated id match is not found', () => {\n\t\texpect(translate('foo.bar', undefined, {}, undefined, undefined, 'testFallback')).to.equal('testFallback');\n\t});\n\n\tit('should replace dot-notated templated strings when given a fields attribute', () => {\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: 'hello{{c.d}}' } }, { c: { d: 'World' } })).to.equal('helloWorld');\n\t});\n\n\tit('should translate <Text /> components that exist in field values when working on templated strings', () => {\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: 'hello{{c.d}}' }, e: 'World' }, { c: { d: <Text id=\"e\" /> } })).to.equal('helloWorld');\n\t});\n\t\n\tit('should pluralise for none/one/many pluralisation keys', () => {\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { none: 'none', one: 'one', many: 'many' } } }, undefined, 0)).to.equal('none');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { none: 'none', one: 'one', many: 'many' } } }, undefined, 1)).to.equal('one');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { none: 'none', one: 'one', many: 'many' } } }, undefined, 2)).to.equal('many');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { none: 'none', one: 'one', many: 'many' } } }, undefined, 100)).to.equal('many');\n\t});\n\t\n\tit('should pluralise for zero/one/other pluralisation keys', () => {\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { zero: 'zero', one: 'one', other: 'other' } } }, undefined, 0)).to.equal('zero');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { zero: 'zero', one: 'one', other: 'other' } } }, undefined, 1)).to.equal('one');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { zero: 'zero', one: 'one', other: 'other' } } }, undefined, 2)).to.equal('other');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { zero: 'zero', one: 'one', other: 'other' } } }, undefined, 100)).to.equal('other');\n\t});\n\t\n\tit('should pluralise for singular/plural pluralisation keys', () => {\n\t\t// assume 0 is a plural form if using the singular/plural pluralisation convention\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { singular: 'singular', plural: 'plural' } } }, undefined, 0)).to.equal('plural');\n\t\t\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { singular: 'singular', plural: 'plural' } } }, undefined, 1)).to.equal('singular');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { singular: 'singular', plural: 'plural' } } }, undefined, 2)).to.equal('plural');\n\t\texpect(translate('foo.bar', undefined, { foo: { bar: { singular: 'singular', plural: 'plural' } } }, undefined, 100)).to.equal('plural');\n\t});\n\n\n});\n"
  },
  {
    "path": "test/lib/util.js",
    "content": "import { select } from '../../src/lib/util';\n\ndescribe('util', () => {\n\tdescribe('select()', () => {\n\t\tit('should return objects unmodified', () => {\n\t\t\tlet obj = { foo: 'foo', bar: 'bar' };\n\t\t\texpect(select(obj)).to.equal(obj);\n\t\t});\n\n\t\tit('should create an object mapping from an Array', () => {\n\t\t\texpect(select(['foo'])).to.eql({ foo: 'foo' });\n\t\t\texpect(select(['foo', 'bar'])).to.eql({ foo: 'foo', bar: 'bar' });\n\t\t\texpect(select(['foo.a', 'bar.b'])).to.eql({ a: 'foo.a', b: 'bar.b' });\n\t\t});\n\n\t\tit('should return create an object mapping from a CSV String', () => {\n\t\t\texpect(select('a')).to.eql({ a: 'a' });\n\t\t\texpect(select('foo,bar')).to.eql({ foo: 'foo', bar: 'bar' });\n\t\t\texpect(select('foo , bar')).to.eql({ foo: 'foo', bar: 'bar' });\n\t\t});\n\t});\n});\n"
  }
]