This commit is contained in:
18
node_modules/node-polyglot/.eslintrc
generated
vendored
Normal file
18
node_modules/node-polyglot/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"root": true,
|
||||
|
||||
"extends": "airbnb-base/legacy",
|
||||
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"func-names": 0,
|
||||
"one-var": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"no-use-before-define": 1,
|
||||
"vars-on-top": 0,
|
||||
"yoda": 0,
|
||||
}
|
||||
}
|
||||
8
node_modules/node-polyglot/.github/workflows/node-pretest.yml
generated
vendored
Normal file
8
node_modules/node-polyglot/.github/workflows/node-pretest.yml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
name: 'Tests: pretest/posttest'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
uses: ljharb/actions/.github/workflows/pretest.yml@main
|
||||
|
||||
18
node_modules/node-polyglot/.github/workflows/node.yml
generated
vendored
Normal file
18
node_modules/node-polyglot/.github/workflows/node.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: 'Tests: node.js'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
uses: ljharb/actions/.github/workflows/node.yml@main
|
||||
with:
|
||||
range: '>= 0.8'
|
||||
type: majors
|
||||
command: npm run tests-only
|
||||
|
||||
node:
|
||||
name: 'node.js tests'
|
||||
needs: [tests]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: 'echo tests completed'
|
||||
15
node_modules/node-polyglot/.github/workflows/rebase.yml
generated
vendored
Normal file
15
node_modules/node-polyglot/.github/workflows/rebase.yml
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Automatic Rebase
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
jobs:
|
||||
_:
|
||||
name: "Automatic Rebase"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ljharb/rebase@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
12
node_modules/node-polyglot/.github/workflows/require-allow-edits.yml
generated
vendored
Normal file
12
node_modules/node-polyglot/.github/workflows/require-allow-edits.yml
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: Require “Allow Edits”
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
jobs:
|
||||
_:
|
||||
name: "Require “Allow Edits”"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: ljharb/require-allow-edits@main
|
||||
141
node_modules/node-polyglot/CHANGELOG.md
generated
vendored
Normal file
141
node_modules/node-polyglot/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
### v2.6.0: July 11, 2024
|
||||
* [New] add Ukrainian (#184)
|
||||
* [Refactor] remove `array.prototype.foreach`
|
||||
* [Refactor] remove `string.prototype.trim`
|
||||
* [Refactor] use `hasown` instead of `has`
|
||||
* [meta] add missing `engines.node`
|
||||
* [Deps] update `array.prototype.foreach`, `object.entries`, `string.prototype.trim`
|
||||
* [Deps] update `aud`, `chai`, `docco`, `eslint-plugin-import`, `string.prototype.matchall`
|
||||
* [eslint] disable yoda rule entirely
|
||||
* [readme] Fixed typos (buliding, Polylglot) (#181)
|
||||
|
||||
### v2.5.0: January 23, 2023
|
||||
* [New] Add `replace` option for custom replace implementation (#171)
|
||||
* [New] Add Romanian and Macedonian (#176)
|
||||
* [Deps] update array.prototype.foreach, object.entries, `string.prototype.trim` (#172)
|
||||
* [Tests] Migrate tests to GitHub Actions (#169)
|
||||
* [Tests] Add passing tests (#168)
|
||||
|
||||
### v2.4.2: August 16, 2021
|
||||
* [Fix] Handle null and undefined gracefully in extend and unset (#161)
|
||||
|
||||
### v2.4.1: August 16, 2021
|
||||
* [Fix] French starts plural at 2 (#154)
|
||||
* [Refactor] Replace `for-each` with `object.entries` and `array.prototype.foreach` (#127)
|
||||
* [Performance] Add plural type name memoization (#158)
|
||||
* [Deps] Update `string.prototype.trim` (#127)
|
||||
* [Dev Deps] update `chai`, `safe-publish-latest`, `eslint`, `eslint-plugin-import` (#127)
|
||||
|
||||
### v2.4.0: September 10, 2019
|
||||
* [New] add ability to configure pluralization rules (#138)
|
||||
|
||||
### v2.3.1: June 20, 2019
|
||||
* [Fix] fix plurals for Russian with n > 100 (#119)
|
||||
* [Performance] Remove unnecessary dollar signs replacement (#132)
|
||||
* [Docs] fix typo in the Czech example (#123)
|
||||
* [Deps] update `warning`
|
||||
* [Dev Deps] update `chai`, `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-import`, `safe-publish-latest`, `uglify-js`
|
||||
* [Tests] on `node` `v12`, `v11`, `v10`
|
||||
|
||||
### v2.3.0: July 2, 2018
|
||||
* [New] add ability to change interpolation regex by specifying prefix and suffix (#106, #64)
|
||||
* [New] support for Serbian (Latin & Cyrillic), Bosnian (Latin & Cyrillic), Czech (#113)
|
||||
* [Fix] Moved lt to it's own group (#101)
|
||||
* [Fix] Moved tr from chinese to german group (#100)
|
||||
* [Fix] Move persian(fa) language to german group of pluralization (#86)
|
||||
* [Fix] Remove long-since-updated build files
|
||||
* [Fix] fix russian pluralization; add tests (#115)
|
||||
* [Fix] croatian is not russian (#114)
|
||||
* [Clarity] add more specific locales, even though language codes will match them (#115)
|
||||
* [Docs] document constructor options (#84)
|
||||
* [Docs] document all instance and static methods (#83)
|
||||
* [Docs] fix spelling of "delimiter" (#91)
|
||||
* [Docs] `onMissingKey` can (rather, should) return a value (#95)
|
||||
* [Docs] fix instructions to only recommend use with npm (#96)
|
||||
* [Docs] Added documentation for method has (#104)
|
||||
* [Docs] add example for languages with multiple plurals (#108)
|
||||
* [Docs] remove outdated sentence (#112, #110)
|
||||
* [Deps] update `for-each`, `has`, `warning`
|
||||
* [Dev Deps] update `chai`, `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-import`, `mocha`; remove `should`
|
||||
* [Tests] up to `node` `v10`; use `nvm install-latest-npm` to ensure new npm doesn’t break old node; improve matrix
|
||||
|
||||
### v2.2.2: January 5, 2017
|
||||
* [Fix] revert unintentional breaking change of missing substitutions being untouched
|
||||
* [Dev Deps] update `eslint`, `eslint-config-airbnb-base`, `mocha`, `should`; add `safe-publish-latest`
|
||||
|
||||
### v2.2.1: November 18, 2016
|
||||
* [Fix] restore behavior of explicit null/undefined not touching the substitution
|
||||
|
||||
### v2.2.0: November 14, 2016
|
||||
* [New] add `onMissingKey` constructor option - this can call `.transformPhrase`, or return `false`, or `undefined`, or throw - whatever you like (#34, #77)
|
||||
* [Dev Deps] update `eslint`
|
||||
|
||||
### v2.1.3: January 5, 2017
|
||||
* [Fix] revert unintentional breaking change of missing substitutions being untouched
|
||||
|
||||
### v2.1.2: November 18, 2016
|
||||
* [Fix] restore behavior of explicit null/undefined not touching the substitution
|
||||
|
||||
### v2.1.1: November 13, 2016
|
||||
* [Fix] ensure that missing or null substitutions don’t crash (#79)
|
||||
|
||||
### v2.1.0: November 11, 2016
|
||||
* [New] Merge choosePluralForm & interpolate into one exported function: `transformPhrase` (#75)
|
||||
* [New] Allow locales to have regions (#70)
|
||||
* [New] Support Arabic pluralization (#71)
|
||||
* [New] Added Lithuanian locale to russian group of pluralization (#68)
|
||||
* [Deps] update `object.assign`, `warning`
|
||||
* [Dev Deps] pin `uglify-js` because it does not follow semver
|
||||
* [Dev Deps] update `eslint-config-airbnb-base`, `eslint`, `eslint-plugin-import`, `mocha`, `should`, `uglify-js`
|
||||
* [Performance] instead of creating a new regex for each token, use the function form of `replace` (#19)
|
||||
* [Refactor] use `warning` package for warnings
|
||||
* [Robustness] Use `has` package to properly check “has own property”
|
||||
* [Robustness] use `string.prototype.trim` rather than a homegrown trim polyfill
|
||||
* [Tests] only test on latest `node` `v7`, `v6`, `v5`, `v4`, and `iojs`; improve test matrix
|
||||
* [Tests] add linting
|
||||
|
||||
### v2.0.0: April 6, 2016
|
||||
* [Breaking] Remove non-node support + use object.assign/for-each.
|
||||
* [New] Add Slovak language to the Czech pluralization group
|
||||
* [Fix] fix`warn` messages in `node`, where `this` is not the global object
|
||||
* [Tests] up to `node` `v5.10`, `v4.4`
|
||||
* [Tests] decaffeinate tests
|
||||
|
||||
### v1.0.0: November 29, 2015
|
||||
* [Tests] up to `node` `v5.1`
|
||||
* [Tests] fix npm upgrades on older nodes
|
||||
* [Dev Deps] update `uglify-js`, `docco`, `should`, `mocha`, and fix test pollution
|
||||
|
||||
### v0.4.5: November 29, 2015
|
||||
* [Fix] Ensure that dollar signs are properly escaped in substitutions (#43)
|
||||
* [Docs] use SPDX-compliant license string (#44)
|
||||
|
||||
### v0.4.4: October 26, 2015
|
||||
* [New] Add `unset` method (#43)
|
||||
* [Tests] test on travis-ci
|
||||
|
||||
### v0.4.3: June 26, 2015
|
||||
* Add `.has(key)` method (thanks @scarfacedeb).
|
||||
* Add UMD wrapper for AMD support (thanks @TomOne).
|
||||
|
||||
### v0.4.2: March 13, 2015
|
||||
* Allow blank translations.
|
||||
|
||||
### v0.4.1: July 14, 2014
|
||||
* Added support for `warn` option for custom error handler (thanks @terinjokes).
|
||||
* Added some more plural forms (thanks @jgill333).
|
||||
|
||||
### v0.4.0: May 22, 2014
|
||||
* Added support for nested phrase objects to `extend()` and in the `phrases` option in the constructor.
|
||||
|
||||
### v0.3.0: August 6, 2013
|
||||
* _Breaking change_: Removed `pluralize()` method; instead, just use the `t()` method, passing in a `smart_count` option.
|
||||
* _Breaking change_: Removed the ability to use `Array`, `Backbone.Collection`, etc. instances for the `smart_count` option; instead, must pass a `Number`.
|
||||
* Allow passing `Number` as second argument to `t()`, which gets converted to the options object `{smart_count: <my number>}`.
|
||||
|
||||
### v0.2.1: May 2, 2013
|
||||
* Added `allowMissing` option to let the phrase key be the default translation (thanks @ziad-saab).
|
||||
|
||||
### v0.2.0: Dec 20, 2012
|
||||
* _Breaking change_: Moved from Singleton pattern to class-based. Now you create an instance of the `Polyglot` class rather than using class methods directly on it. The reason is to allow maintaining multiple sets of phrases, which is something we ran into at Airbnb with a highly-concurrent Express app.
|
||||
* _Breaking change_: Removed the built-in Handlebars helpers, because Handlebars is a singleton, and it's messy to create a single helper function that can be bound to different Polyglot instances. Instead, it's super easy to create your own, based on your requirements.
|
||||
25
node_modules/node-polyglot/LICENSE
generated
vendored
Normal file
25
node_modules/node-polyglot/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2012, Airbnb
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
THIS 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.
|
||||
16
node_modules/node-polyglot/Makefile
generated
vendored
Normal file
16
node_modules/node-polyglot/Makefile
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
clean:
|
||||
@rm -rf build
|
||||
|
||||
build-js:
|
||||
@mkdir -p build
|
||||
@cp ./index.js ./build/polyglot.js
|
||||
@./node_modules/.bin/uglifyjs -o ./build/polyglot.min.js ./index.js
|
||||
@gzip -c ./build/polyglot.min.js > ./build/polyglot.min.js.gz
|
||||
|
||||
annotate:
|
||||
@./node_modules/.bin/docco ./index.js
|
||||
|
||||
build: clean build-js
|
||||
|
||||
|
||||
.PHONY: clean build build-js annotate
|
||||
348
node_modules/node-polyglot/README.md
generated
vendored
Normal file
348
node_modules/node-polyglot/README.md
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
Polyglot.js
|
||||
===========
|
||||
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
|
||||
[](https://gitter.im/airbnb/polyglot.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Polyglot.js is a tiny I18n helper library written in JavaScript, made to work both in the browser and in CommonJS environments (Node). It provides a simple solution for interpolation and pluralization, based off of Airbnb’s experience adding I18n functionality to its Backbone.js and Node apps.
|
||||
|
||||
I18n is incredibly important for us at [Airbnb](https://www.airbnb.com/), as we have listings in 192 countries, and we translate our site into 30-odd different languages.
|
||||
We’re also [hiring talented engineers](https://www.airbnb.com/jobs/departments/engineering) to help us scale up to meet the challenges of building a global marketplace.
|
||||
|
||||
View the [documentation on Github](https://github.com/airbnb/polyglot.js).
|
||||
|
||||
View the [annotated source](https://airbnb.io/polyglot.js/polyglot.html).
|
||||
|
||||
Polyglot is agnostic to your translation backend. It doesn’t perform any translation; it simply gives you a way to manage translated phrases from your client- or server-side JavaScript application.
|
||||
|
||||
## Installation
|
||||
|
||||
install with [npm](https://npmjs.org):
|
||||
|
||||
$ npm install node-polyglot
|
||||
|
||||
### Running the tests
|
||||
|
||||
Clone the repo, run `npm install`, and `npm test`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Instantiation
|
||||
|
||||
First, create an instance of the `Polyglot` class, which you will use for translation.
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot();
|
||||
```
|
||||
|
||||
Polyglot is class-based so you can maintain different sets of phrases at the same time, possibly in different locales. This is very useful for example when serving requests with [Express](http://expressjs.com), because each request may have a different locale, and you don’t want concurrent requests to clobber each other’s phrases.
|
||||
|
||||
See [Options Overview](#options-overview) for information about the options object you can choose to pass to `new Polyglot`.
|
||||
|
||||
### Translation
|
||||
|
||||
Tell Polyglot what to say by simply giving it a phrases object,
|
||||
where the key is the canonical name of the phrase and the value is
|
||||
the already-translated string.
|
||||
|
||||
```js
|
||||
polyglot.extend({
|
||||
"hello": "Hello"
|
||||
});
|
||||
|
||||
polyglot.t("hello");
|
||||
=> "Hello"
|
||||
```
|
||||
|
||||
You can also pass a mapping at instantiation, using the key `phrases`:
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot({phrases: {"hello": "Hello"}});
|
||||
```
|
||||
|
||||
Polyglot doesn’t do the translation for you. It’s up to you to give it
|
||||
the proper phrases for the user’s locale.
|
||||
|
||||
A common pattern is to gather a hash of phrases in your backend, and output
|
||||
them in a `<script>` tag at the bottom of the document. For example, in Rails:
|
||||
|
||||
`app/controllers/home_controller.rb`
|
||||
|
||||
```ruby
|
||||
def index
|
||||
@phrases = {
|
||||
"home.login" => I18n.t("home.login"),
|
||||
"home.signup" => I18n.t("home.signup"),
|
||||
...
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
`app/views/home/index.html.erb`
|
||||
|
||||
```html
|
||||
<script>
|
||||
var polyglot = new Polyglot({phrases: <%= raw @phrases.to_json %>});
|
||||
</script>
|
||||
```
|
||||
|
||||
And now you can utilize i.e. `polyglot.t("home.login")` in your JavaScript application
|
||||
or Handlebars templates.
|
||||
|
||||
### Interpolation
|
||||
|
||||
`Polyglot.t()` also provides interpolation. Pass an object with key-value pairs of
|
||||
interpolation arguments as the second parameter.
|
||||
|
||||
```js
|
||||
polyglot.extend({
|
||||
"hello_name": "Hola, %{name}."
|
||||
});
|
||||
|
||||
polyglot.t("hello_name", {name: "DeNiro"});
|
||||
=> "Hola, DeNiro."
|
||||
```
|
||||
|
||||
Polyglot also supports nested phrase objects.
|
||||
|
||||
```js
|
||||
polyglot.extend({
|
||||
"nav": {
|
||||
"hello": "Hello",
|
||||
"hello_name": "Hello, %{name}",
|
||||
"sidebar": {
|
||||
"welcome": "Welcome"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
polyglot.t("nav.sidebar.welcome");
|
||||
=> "Welcome"
|
||||
```
|
||||
|
||||
The substitution variable syntax is customizable.
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot({
|
||||
phrases: {
|
||||
"hello_name": "Hola {{name}}"
|
||||
},
|
||||
interpolation: {prefix: '{{', suffix: '}}'}
|
||||
});
|
||||
|
||||
polyglot.t("hello_name", {name: "DeNiro"});
|
||||
=> "Hola, DeNiro."
|
||||
```
|
||||
|
||||
### Pluralization
|
||||
|
||||
For pluralization to work properly, you need to tell Polyglot what the current locale is. You can use `polyglot.locale("fr")` to set the locale to, for example, French. This method is also a getter:
|
||||
|
||||
```js
|
||||
polyglot.locale()
|
||||
=> "fr"
|
||||
```
|
||||
|
||||
You can also pass this in during instantiation.
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot({locale: "fr"});
|
||||
```
|
||||
|
||||
Currently, the _only_ thing that Polyglot uses this locale setting for is pluralization.
|
||||
|
||||
Polyglot provides a very basic pattern for providing pluralization based on a single string that contains all plural forms for a given phrase. Because various languages have different nominal forms for zero, one, and multiple, and because the noun can be before or after the count, we have to be overly explicit about the possible phrases.
|
||||
|
||||
To get a pluralized phrase, still use `polyglot.t()` but use a specially-formatted phrase string that separates the plural forms by the delimiter `||||`, or four vertical pipe characters.
|
||||
|
||||
For pluralizing "car" in English, Polyglot assumes you have a phrase of the form:
|
||||
|
||||
```js
|
||||
polyglot.extend({
|
||||
"num_cars": "%{smart_count} car |||| %{smart_count} cars",
|
||||
});
|
||||
```
|
||||
Please keep in mind that `smart_count` is required. No other option name is taken into account to transform pluralization strings.
|
||||
|
||||
In English (and German, Spanish, Italian, and a few others) there are only two plural forms: singular and not-singular.
|
||||
|
||||
Some languages get a bit more complicated. In Czech, there are three separate forms: 1, 2 through 4, and 5 and up. Russian is even more involved.
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot({locale: "cs"}); // Czech
|
||||
polyglot.extend({
|
||||
"num_foxes": "Mám %{smart_count} lišku |||| Mám %{smart_count} lišky |||| Mám %{smart_count} lišek"
|
||||
})
|
||||
```
|
||||
|
||||
`polyglot.t()` will choose the appropriate phrase based on the provided `smart_count` option, whose value is a number.
|
||||
|
||||
```js
|
||||
polyglot.t("num_cars", {smart_count: 0});
|
||||
=> "0 cars"
|
||||
|
||||
polyglot.t("num_cars", {smart_count: 1});
|
||||
=> "1 car"
|
||||
|
||||
polyglot.t("num_cars", {smart_count: 2});
|
||||
=> "2 cars"
|
||||
```
|
||||
|
||||
As a shortcut, you can also pass a number to the second parameter:
|
||||
|
||||
```js
|
||||
polyglot.t("num_cars", 2);
|
||||
=> "2 cars"
|
||||
```
|
||||
|
||||
#### Custom Pluralization Rules
|
||||
|
||||
Polyglot provides some default pluralization rules for some locales. You can specify a different set of rules through the `pluralRules` constructor param.
|
||||
|
||||
```js
|
||||
var polyglot = new Polyglot({
|
||||
pluralRules: {
|
||||
pluralTypes: {
|
||||
germanLike: function (n) {
|
||||
// is 1
|
||||
if (n === 1) {
|
||||
return 0;
|
||||
}
|
||||
// everything else
|
||||
return 1;
|
||||
},
|
||||
frenchLike: function (n) {
|
||||
// is 0 or 1
|
||||
if (n <= 1) {
|
||||
return 0;
|
||||
}
|
||||
// everything else
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
pluralTypeToLanguages: {
|
||||
germanLike: ['de', 'en', 'xh', 'zu'],
|
||||
frenchLike: ['fr', 'hy']
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This can be useful to support locales that polyglot does not support by default or to change the rule definitions.
|
||||
|
||||
## Public Instance Methods
|
||||
|
||||
### Polyglot.prototype.t(key, interpolationOptions)
|
||||
|
||||
The most-used method. Provide a key, and `t()` will return the phrase.
|
||||
|
||||
```
|
||||
polyglot.t("hello");
|
||||
=> "Hello"
|
||||
```
|
||||
|
||||
The phrase value is provided first by a call to `polyglot.extend()` or `polyglot.replace()`.
|
||||
|
||||
Pass in an object as the second argument to perform interpolation.
|
||||
|
||||
```
|
||||
polyglot.t("hello_name", {name: "Spike"});
|
||||
=> "Hello, Spike"
|
||||
```
|
||||
|
||||
Pass a number as the second argument as a shortcut to `smart_count`:
|
||||
|
||||
```js
|
||||
// same as: polyglot.t("car", {smart_count: 2});
|
||||
polyglot.t("car", 2);
|
||||
=> "2 cars"
|
||||
```
|
||||
|
||||
If you like, you can provide a default value in case the phrase is missing.
|
||||
Use the special option key "_" to specify a default.
|
||||
|
||||
```js
|
||||
polyglot.t("i_like_to_write_in_language", {
|
||||
_: "I like to write in %{language}.",
|
||||
language: "JavaScript"
|
||||
});
|
||||
=> "I like to write in JavaScript."
|
||||
```
|
||||
|
||||
### Polyglot.prototype.extend(phrases)
|
||||
|
||||
Use `extend` to tell Polyglot how to translate a given key.
|
||||
|
||||
```js
|
||||
polyglot.extend({
|
||||
"hello": "Hello",
|
||||
"hello_name": "Hello, %{name}"
|
||||
});
|
||||
```
|
||||
|
||||
The key can be any string. Feel free to call `extend` multiple times; it will override any phrases with the same key, but leave existing phrases untouched.
|
||||
|
||||
### Polyglot.prototype.unset(keyOrObject)
|
||||
Use `unset` to selectively remove keys from a polyglot instance.
|
||||
`unset` accepts one argument: either a single string key, or an object whose keys are string keys, and whose values are ignored unless they are nested objects (in the same format).
|
||||
|
||||
Example:
|
||||
```js
|
||||
polyglot.unset('some_key');
|
||||
polyglot.unset({
|
||||
hello: 'Hello',
|
||||
hello_name: 'Hello, %{name}',
|
||||
foo: {
|
||||
bar: 'This phrase’s key is "foo.bar"'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Polyglot.prototype.locale([localeToSet])
|
||||
|
||||
Get or set the locale (also can be set using the [constructor option](#options-overview), which is used only for pluralization.
|
||||
If a truthy value is provided, it will set the locale. Afterwards, it will return it.
|
||||
|
||||
### Polyglot.prototype.clear()
|
||||
|
||||
Clears all phrases. Useful for special cases, such as freeing up memory if you have lots of phrases but no longer need to perform any translation. Also used internally by `replace`.
|
||||
|
||||
|
||||
### Polyglot.prototype.replace(phrases)
|
||||
|
||||
Completely replace the existing phrases with a new set of phrases.
|
||||
Normally, just use `extend` to add more phrases, but under certain circumstances, you may want to make sure no old phrases are lying around.
|
||||
|
||||
### Polyglot.prototype.has(key)
|
||||
|
||||
Returns `true` if the key does exist in the provided phrases, otherwise it will return `false`.
|
||||
|
||||
## Public Static Methods
|
||||
|
||||
### transformPhrase(phrase[, substitutions[, locale]])
|
||||
|
||||
Takes a phrase string and transforms it by choosing the correct plural form and interpolating it. This method is used internally by [t](#polyglotprototypetkey-interpolationoptions).
|
||||
The correct plural form is selected if substitutions.smart_count is set.
|
||||
You can pass in a number instead of an Object as `substitutions` as a shortcut for `smart_count`.
|
||||
You should pass in a third argument, the locale, to specify the correct plural type. It defaults to `'en'` which has 2 plural forms.
|
||||
|
||||
## Options Overview
|
||||
`new Polyglot` accepts a number of options:
|
||||
|
||||
- `phrases`: a key/value map of translated phrases. See [Translation](https://github.com/airbnb/polyglot.js#translation).
|
||||
- `locale`: a string describing the locale (language and region) of the translation, to apply pluralization rules. see [Pluralization](#pluralization)
|
||||
- `allowMissing`: a boolean to control whether missing keys in a `t` call are allowed. If `false`, by default, a missing key is returned and a warning is issued.
|
||||
- `onMissingKey`: if `allowMissing` is `true`, and this option is a function, then it will be called instead of the default functionality. Arguments passed to it are `key`, `options`, and `locale`. The return of this function will be used as a translation fallback when `polyglot.t('missing.key')` is called (hint: return the key).
|
||||
- `interpolation`: an object to change the substitution syntax for interpolation by setting the `prefix` and `suffix` fields.
|
||||
- `pluralRules`: an object of `pluralTypes` and `pluralTypeToLanguages` to control pluralization logic.
|
||||
|
||||
|
||||
## [History](CHANGELOG.md)
|
||||
|
||||
[travis-image]: https://travis-ci.org/airbnb/polyglot.js.svg
|
||||
[travis-url]: https://travis-ci.org/airbnb/polyglot.js
|
||||
|
||||
## Related projects
|
||||
|
||||
- [i18n-extract](https://github.com/oliviertassinari/i18n-extract): Manage localization with static analysis. (E.g. key usage extraction)
|
||||
518
node_modules/node-polyglot/docs/docco.css
generated
vendored
Normal file
518
node_modules/node-polyglot/docs/docco.css
generated
vendored
Normal file
@@ -0,0 +1,518 @@
|
||||
/*--------------------- Typography ----------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-light';
|
||||
src: url('public/fonts/aller-light.eot');
|
||||
src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-light.woff') format('woff'),
|
||||
url('public/fonts/aller-light.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-bold';
|
||||
src: url('public/fonts/aller-bold.eot');
|
||||
src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-bold.woff') format('woff'),
|
||||
url('public/fonts/aller-bold.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'roboto-black';
|
||||
src: url('public/fonts/roboto-black.eot');
|
||||
src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/roboto-black.woff') format('woff'),
|
||||
url('public/fonts/roboto-black.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*--------------------- Layout ----------------------------*/
|
||||
html { height: 100%; }
|
||||
body {
|
||||
font-family: "aller-light";
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: #30404f;
|
||||
margin: 0; padding: 0;
|
||||
height:100%;
|
||||
}
|
||||
#container { min-height: 100%; }
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: normal;
|
||||
font-family: "aller-bold";
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 15px 0 0px;
|
||||
}
|
||||
.annotation ul, .annotation ol {
|
||||
margin: 25px 0;
|
||||
}
|
||||
.annotation ul li, .annotation ol li {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #112233;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
font-family: "roboto-black";
|
||||
text-transform: uppercase;
|
||||
margin: 30px 0 15px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.26em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
background: 1px #ddd;
|
||||
height: 1px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
pre, tt, code {
|
||||
font-size: 12px; line-height: 16px;
|
||||
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
.annotation pre {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 7px 10px;
|
||||
background: #fcfcfc;
|
||||
-moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
overflow-x: auto;
|
||||
}
|
||||
.annotation pre code {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
blockquote {
|
||||
border-left: 5px solid #ccc;
|
||||
margin: 0;
|
||||
padding: 1px 0 1px 1em;
|
||||
}
|
||||
.sections blockquote p {
|
||||
font-family: Menlo, Consolas, Monaco, monospace;
|
||||
font-size: 12px; line-height: 16px;
|
||||
color: #999;
|
||||
margin: 10px 0 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
ul.sections {
|
||||
list-style: none;
|
||||
padding:0 0 5px 0;;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/*
|
||||
Force border-box so that % widths fit the parent
|
||||
container without overlap because of margin/padding.
|
||||
|
||||
More Info : http://www.quirksmode.org/css/box.html
|
||||
*/
|
||||
ul.sections > li > div {
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
-ms-box-sizing: border-box; /* ie */
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-khtml-box-sizing: border-box; /* konqueror */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
|
||||
|
||||
/*---------------------- Jump Page -----------------------------*/
|
||||
#jump_to, #jump_page {
|
||||
margin: 0;
|
||||
background: white;
|
||||
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
|
||||
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
|
||||
font: 16px Arial;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#jump_to a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#jump_to a.large {
|
||||
display: none;
|
||||
}
|
||||
#jump_to a.small {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #676767;
|
||||
}
|
||||
|
||||
#jump_to, #jump_wrapper {
|
||||
position: fixed;
|
||||
right: 0; top: 0;
|
||||
padding: 10px 15px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#jump_wrapper {
|
||||
display: none;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#jump_to:hover #jump_wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#jump_page_wrapper{
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#jump_page {
|
||||
padding: 5px 0 3px;
|
||||
margin: 0 0 25px 25px;
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#jump_page .source {
|
||||
display: block;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
#jump_page .source:hover {
|
||||
background: #f5f5ff;
|
||||
}
|
||||
|
||||
#jump_page .source:first-child {
|
||||
}
|
||||
|
||||
/*---------------------- Low resolutions (> 320px) ---------------------*/
|
||||
@media only screen and (min-width: 320px) {
|
||||
.pilwrap { display: none; }
|
||||
|
||||
ul.sections > li > div {
|
||||
display: block;
|
||||
padding:5px 10px 0 10px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
overflow-x:auto;
|
||||
-webkit-box-shadow: inset 0 0 5px #e5e5ee;
|
||||
box-shadow: inset 0 0 5px #e5e5ee;
|
||||
border: 1px solid #dedede;
|
||||
margin:5px 10px 5px 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 7px 0 7px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation p tt, .annotation code {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 12px;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 481px) ---------------------*/
|
||||
@media only screen and (min-width: 481px) {
|
||||
#container {
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
background-color: #F5F5FF;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
}
|
||||
pre, tt, code {
|
||||
line-height: 18px;
|
||||
}
|
||||
p, ul, ol {
|
||||
margin: 0 0 15px;
|
||||
}
|
||||
|
||||
|
||||
#jump_to {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
#jump_to, #jump_page {
|
||||
font: 10px Arial;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#jump_page .source {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_to a.large {
|
||||
display: inline-block;
|
||||
}
|
||||
#jump_to a.small {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
width: 350px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #e5e5ee;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ul.sections > li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
ul.sections > li > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 350px;
|
||||
min-width: 350px;
|
||||
min-height: 5px;
|
||||
padding: 13px;
|
||||
overflow-x: hidden;
|
||||
white-space: normal;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
padding: 13px;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.pilwrap {
|
||||
position: relative;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pilcrow {
|
||||
font: 12px Arial;
|
||||
text-decoration: none;
|
||||
color: #454545;
|
||||
position: absolute;
|
||||
top: 3px; left: -20px;
|
||||
padding: 1px 2px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
}
|
||||
.for-h1 .pilcrow {
|
||||
top: 47px;
|
||||
}
|
||||
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
|
||||
top: 35px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation:hover .pilcrow {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 1025px) ---------------------*/
|
||||
@media only screen and (min-width: 1025px) {
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
#background {
|
||||
width: 525px;
|
||||
}
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 525px;
|
||||
min-width: 525px;
|
||||
padding: 10px 25px 1px 50px;
|
||||
}
|
||||
ul.sections > li > div.content {
|
||||
padding: 9px 15px 16px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
|
||||
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
|
||||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
pre code {
|
||||
display: block; padding: 0.5em;
|
||||
color: #000;
|
||||
background: #f8f8ff
|
||||
}
|
||||
|
||||
pre .hljs-comment,
|
||||
pre .hljs-template_comment,
|
||||
pre .hljs-diff .hljs-header,
|
||||
pre .hljs-javadoc {
|
||||
color: #408080;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
pre .hljs-keyword,
|
||||
pre .hljs-assignment,
|
||||
pre .hljs-literal,
|
||||
pre .hljs-css .hljs-rule .hljs-keyword,
|
||||
pre .hljs-winutils,
|
||||
pre .hljs-javascript .hljs-title,
|
||||
pre .hljs-lisp .hljs-title,
|
||||
pre .hljs-subst {
|
||||
color: #954121;
|
||||
/*font-weight: bold*/
|
||||
}
|
||||
|
||||
pre .hljs-number,
|
||||
pre .hljs-hexcolor {
|
||||
color: #40a070
|
||||
}
|
||||
|
||||
pre .hljs-string,
|
||||
pre .hljs-tag .hljs-value,
|
||||
pre .hljs-phpdoc,
|
||||
pre .hljs-tex .hljs-formula {
|
||||
color: #219161;
|
||||
}
|
||||
|
||||
pre .hljs-title,
|
||||
pre .hljs-id {
|
||||
color: #19469D;
|
||||
}
|
||||
pre .hljs-params {
|
||||
color: #00F;
|
||||
}
|
||||
|
||||
pre .hljs-javascript .hljs-title,
|
||||
pre .hljs-lisp .hljs-title,
|
||||
pre .hljs-subst {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .hljs-class .hljs-title,
|
||||
pre .hljs-haskell .hljs-label,
|
||||
pre .hljs-tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-tag,
|
||||
pre .hljs-tag .hljs-title,
|
||||
pre .hljs-rules .hljs-property,
|
||||
pre .hljs-django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .hljs-attribute,
|
||||
pre .hljs-variable,
|
||||
pre .hljs-instancevar,
|
||||
pre .hljs-lisp .hljs-body {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
pre .hljs-regexp {
|
||||
color: #B68
|
||||
}
|
||||
|
||||
pre .hljs-class {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-symbol,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-string,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-keyword,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-keymethods,
|
||||
pre .hljs-lisp .hljs-keyword,
|
||||
pre .hljs-tex .hljs-special,
|
||||
pre .hljs-input_number {
|
||||
color: #990073
|
||||
}
|
||||
|
||||
pre .hljs-builtin,
|
||||
pre .hljs-constructor,
|
||||
pre .hljs-built_in,
|
||||
pre .hljs-lisp .hljs-title {
|
||||
color: #0086b3
|
||||
}
|
||||
|
||||
pre .hljs-preprocessor,
|
||||
pre .hljs-pi,
|
||||
pre .hljs-doctype,
|
||||
pre .hljs-shebang,
|
||||
pre .hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-deletion {
|
||||
background: #fdd
|
||||
}
|
||||
|
||||
pre .hljs-addition {
|
||||
background: #dfd
|
||||
}
|
||||
|
||||
pre .hljs-diff .hljs-change {
|
||||
background: #0086b3
|
||||
}
|
||||
|
||||
pre .hljs-chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
pre .hljs-tex .hljs-formula {
|
||||
opacity: 0.5;
|
||||
}
|
||||
613
node_modules/node-polyglot/docs/polyglot.html
generated
vendored
Normal file
613
node_modules/node-polyglot/docs/polyglot.html
generated
vendored
Normal file
@@ -0,0 +1,613 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>polyglot.js</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
|
||||
<link rel="stylesheet" media="all" href="docco.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="background"></div>
|
||||
|
||||
<ul class="sections">
|
||||
|
||||
<li id="title">
|
||||
<div class="annotation">
|
||||
<h1>polyglot.js</h1>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<li id="section-1">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<pre><code>(c) <span class="hljs-number">2012</span><span class="hljs-number">-2018</span> Airbnb, Inc.
|
||||
|
||||
polyglot.js may be freely distributed under the terms <span class="hljs-keyword">of</span> the BSD
|
||||
license. For all licensing information, details, and documention:
|
||||
http:<span class="hljs-comment">//airbnb.github.com/polyglot.js</span>
|
||||
</code></pre><p>Polyglot.js is an I18n helper library written in JavaScript, made to
|
||||
work both in the browser and in Node. It provides a simple solution for
|
||||
interpolation and pluralization, based off of Airbnb’s
|
||||
experience adding I18n functionality to its Backbone.js and Node apps.</p>
|
||||
<p>Polylglot is agnostic to your translation backend. It doesn’t perform any
|
||||
translation; it simply gives you a way to manage translated phrases from
|
||||
your client- or server-side JavaScript application.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-meta">
|
||||
'use strict'</span>;
|
||||
|
||||
<span class="hljs-keyword">var</span> forEach = <span class="hljs-built_in">require</span>(<span class="hljs-string">'for-each'</span>);
|
||||
<span class="hljs-keyword">var</span> warning = <span class="hljs-built_in">require</span>(<span class="hljs-string">'warning'</span>);
|
||||
<span class="hljs-keyword">var</span> has = <span class="hljs-built_in">require</span>(<span class="hljs-string">'has'</span>);
|
||||
<span class="hljs-keyword">var</span> trim = <span class="hljs-built_in">require</span>(<span class="hljs-string">'string.prototype.trim'</span>);
|
||||
|
||||
<span class="hljs-keyword">var</span> warn = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">warn</span>(<span class="hljs-params">message</span>) </span>{
|
||||
warning(<span class="hljs-literal">false</span>, message);
|
||||
};
|
||||
|
||||
<span class="hljs-keyword">var</span> replace = <span class="hljs-built_in">String</span>.prototype.replace;
|
||||
<span class="hljs-keyword">var</span> split = <span class="hljs-built_in">String</span>.prototype.split;</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-2">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
<h4 id="pluralization-methods">Pluralization methods</h4>
|
||||
<p>The string that separates the different phrase possibilities.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> delimiter = <span class="hljs-string">'||||'</span>;
|
||||
|
||||
<span class="hljs-keyword">var</span> russianPluralGroups = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> end = n % <span class="hljs-number">10</span>;
|
||||
<span class="hljs-keyword">if</span> (n !== <span class="hljs-number">11</span> && end === <span class="hljs-number">1</span>) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-number">2</span> <= end && end <= <span class="hljs-number">4</span> && !(n >= <span class="hljs-number">12</span> && n <= <span class="hljs-number">14</span>)) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-3">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
<p>Mapping from pluralization group plural logic.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> pluralTypes = {
|
||||
<span class="hljs-attr">arabic</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-4">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
<p><a href="http://www.arabeyes.org/Plural_Forms">http://www.arabeyes.org/Plural_Forms</a></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (n < <span class="hljs-number">3</span>) { <span class="hljs-keyword">return</span> n; }
|
||||
<span class="hljs-keyword">var</span> lastTwo = n % <span class="hljs-number">100</span>;
|
||||
<span class="hljs-keyword">if</span> (lastTwo >= <span class="hljs-number">3</span> && lastTwo <= <span class="hljs-number">10</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
|
||||
<span class="hljs-keyword">return</span> lastTwo >= <span class="hljs-number">11</span> ? <span class="hljs-number">4</span> : <span class="hljs-number">5</span>;
|
||||
},
|
||||
<span class="hljs-attr">bosnian_serbian</span>: russianPluralGroups,
|
||||
<span class="hljs-attr">chinese</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; },
|
||||
<span class="hljs-attr">croatian</span>: russianPluralGroups,
|
||||
<span class="hljs-attr">french</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{ <span class="hljs-keyword">return</span> n > <span class="hljs-number">1</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>; },
|
||||
<span class="hljs-attr">german</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{ <span class="hljs-keyword">return</span> n !== <span class="hljs-number">1</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>; },
|
||||
<span class="hljs-attr">russian</span>: russianPluralGroups,
|
||||
<span class="hljs-attr">lithuanian</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (n % <span class="hljs-number">10</span> === <span class="hljs-number">1</span> && n % <span class="hljs-number">100</span> !== <span class="hljs-number">11</span>) { <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; }
|
||||
<span class="hljs-keyword">return</span> n % <span class="hljs-number">10</span> >= <span class="hljs-number">2</span> && n % <span class="hljs-number">10</span> <= <span class="hljs-number">9</span> && (n % <span class="hljs-number">100</span> < <span class="hljs-number">11</span> || n % <span class="hljs-number">100</span> > <span class="hljs-number">19</span>) ? <span class="hljs-number">1</span> : <span class="hljs-number">2</span>;
|
||||
},
|
||||
<span class="hljs-attr">czech</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (n === <span class="hljs-number">1</span>) { <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; }
|
||||
<span class="hljs-keyword">return</span> (n >= <span class="hljs-number">2</span> && n <= <span class="hljs-number">4</span>) ? <span class="hljs-number">1</span> : <span class="hljs-number">2</span>;
|
||||
},
|
||||
<span class="hljs-attr">polish</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (n === <span class="hljs-number">1</span>) { <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; }
|
||||
<span class="hljs-keyword">var</span> end = n % <span class="hljs-number">10</span>;
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">2</span> <= end && end <= <span class="hljs-number">4</span> && (n % <span class="hljs-number">100</span> < <span class="hljs-number">10</span> || n % <span class="hljs-number">100</span> >= <span class="hljs-number">20</span>) ? <span class="hljs-number">1</span> : <span class="hljs-number">2</span>;
|
||||
},
|
||||
<span class="hljs-attr">icelandic</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{ <span class="hljs-keyword">return</span> (n % <span class="hljs-number">10</span> !== <span class="hljs-number">1</span> || n % <span class="hljs-number">100</span> === <span class="hljs-number">11</span>) ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>; },
|
||||
<span class="hljs-attr">slovenian</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> lastTwo = n % <span class="hljs-number">100</span>;
|
||||
<span class="hljs-keyword">if</span> (lastTwo === <span class="hljs-number">1</span>) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (lastTwo === <span class="hljs-number">2</span>) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (lastTwo === <span class="hljs-number">3</span> || lastTwo === <span class="hljs-number">4</span>) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
|
||||
}
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-5">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
<p>Mapping from pluralization group to individual language codes/locales.
|
||||
Will look up based on exact match, if not found and it’s a locale will parse the locale
|
||||
for language code, and if that does not exist will default to ‘en’</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>var pluralTypeToLanguages = {
|
||||
arabic: ['ar'],
|
||||
bosnian_serbian: ['bs-Latn-BA', 'bs-Cyrl-BA', 'srl-RS', 'sr-RS'],
|
||||
chinese: ['id', 'id-ID', 'ja', 'ko', 'ko-KR', 'lo', 'ms', 'th', 'th-TH', 'zh'],
|
||||
croatian: ['hr', 'hr-HR'],
|
||||
german: ['fa', 'da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hi-IN', 'hu', 'hu-HU', 'it', 'nl', 'no', 'pt', 'sv', 'tr'],
|
||||
french: ['fr', 'tl', 'pt-br'],
|
||||
russian: ['ru', 'ru-RU'],
|
||||
lithuanian: ['lt'],
|
||||
czech: ['cs', 'cs-CZ', 'sk'],
|
||||
polish: ['pl'],
|
||||
icelandic: ['is'],
|
||||
slovenian: ['sl-SL']
|
||||
};
|
||||
|
||||
function langToTypeMap(mapping) {
|
||||
var ret = {};
|
||||
forEach(mapping, function (langs, type) {
|
||||
forEach(langs, function (lang) {
|
||||
ret[lang] = type;
|
||||
});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
function pluralTypeName(locale) {
|
||||
var langToPluralType = langToTypeMap(pluralTypeToLanguages);
|
||||
return langToPluralType[locale]
|
||||
|| langToPluralType[split.call(locale, /-/, 1)[0]]
|
||||
|| langToPluralType.en;
|
||||
}
|
||||
|
||||
function pluralTypeIndex(locale, count) {
|
||||
return pluralTypes[pluralTypeName(locale)](count);
|
||||
}
|
||||
|
||||
function escape(token) {
|
||||
return token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function constructTokenRegex(opts) {
|
||||
var prefix = (opts && opts.prefix) || '%{';
|
||||
var suffix = (opts && opts.suffix) || '}';
|
||||
|
||||
if (prefix === delimiter || suffix === delimiter) {
|
||||
throw new RangeError('"' + delimiter + '" token is reserved for pluralization');
|
||||
}
|
||||
|
||||
return new RegExp(escape(prefix) + '(.*?)' + escape(suffix), 'g');
|
||||
}
|
||||
|
||||
var dollarRegex = /\$/g;
|
||||
var dollarBillsYall = '$$';
|
||||
var defaultTokenRegex = /%\{(.*?)\}/g;</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-6">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
<h3 id="transformphrase-phrase-substitutions-locale-">transformPhrase(phrase, substitutions, locale)</h3>
|
||||
<p>Takes a phrase string and transforms it by choosing the correct
|
||||
plural form and interpolating it.</p>
|
||||
<pre><code>transformPhrase(<span class="hljs-string">'Hello, %{name}!'</span>, {<span class="hljs-attr">name</span>: <span class="hljs-string">'Spike'</span>});
|
||||
<span class="hljs-comment">// "Hello, Spike!"</span>
|
||||
</code></pre><p>The correct plural form is selected if substitutions.smart_count
|
||||
is set. You can pass in a number instead of an Object as <code>substitutions</code>
|
||||
as a shortcut for <code>smart_count</code>.</p>
|
||||
<pre><code>transformPhrase(<span class="hljs-string">'%{smart_count} new messages |||| 1 new message'</span>, {<span class="hljs-attr">smart_count</span>: <span class="hljs-number">1</span>}, <span class="hljs-string">'en'</span>);
|
||||
<span class="hljs-comment">// "1 new message"</span>
|
||||
|
||||
transformPhrase(<span class="hljs-string">'%{smart_count} new messages |||| 1 new message'</span>, {<span class="hljs-attr">smart_count</span>: <span class="hljs-number">2</span>}, <span class="hljs-string">'en'</span>);
|
||||
<span class="hljs-comment">// "2 new messages"</span>
|
||||
|
||||
transformPhrase(<span class="hljs-string">'%{smart_count} new messages |||| 1 new message'</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'en'</span>);
|
||||
<span class="hljs-comment">// "5 new messages"</span>
|
||||
</code></pre><p>You should pass in a third argument, the locale, to specify the correct plural type.
|
||||
It defaults to <code>'en'</code> with 2 plural forms.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transformPhrase</span>(<span class="hljs-params">phrase, substitutions, locale, tokenRegex</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> phrase !== <span class="hljs-string">'string'</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'Polyglot.transformPhrase expects argument #1 to be string'</span>);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">if</span> (substitutions == <span class="hljs-literal">null</span>) {
|
||||
<span class="hljs-keyword">return</span> phrase;
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">var</span> result = phrase;
|
||||
<span class="hljs-keyword">var</span> interpolationRegex = tokenRegex || defaultTokenRegex;</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-7">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
<p>allow number as a pluralization shortcut</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">typeof</span> substitutions === <span class="hljs-string">'number'</span> ? { <span class="hljs-attr">smart_count</span>: substitutions } : substitutions;</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-8">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p>Select plural form: based on a phrase text that contains <code>n</code>
|
||||
plural forms separated by <code>delimiter</code>, a <code>locale</code>, and a <code>substitutions.smart_count</code>,
|
||||
choose the correct plural form. This is only done if <code>count</code> is set.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (options.smart_count != <span class="hljs-literal">null</span> && result) {
|
||||
<span class="hljs-keyword">var</span> texts = split.call(result, delimiter);
|
||||
result = trim(texts[pluralTypeIndex(locale || <span class="hljs-string">'en'</span>, options.smart_count)] || texts[<span class="hljs-number">0</span>]);
|
||||
}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-9">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>Interpolate: Creates a <code>RegExp</code> object for each interpolation placeholder.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> result = replace.call(result, interpolationRegex, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">expression, argument</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (!has(options, argument) || options[argument] == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> expression; }</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-10">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Ensure replacement value is escaped to prevent special $-prefixed regex replace tokens.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> replace.call(options[argument], dollarRegex, dollarBillsYall);
|
||||
});
|
||||
|
||||
<span class="hljs-keyword">return</span> result;
|
||||
}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-class-constructor">Polyglot class constructor</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Polyglot</span>(<span class="hljs-params">options</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> opts = options || {};
|
||||
<span class="hljs-keyword">this</span>.phrases = {};
|
||||
<span class="hljs-keyword">this</span>.extend(opts.phrases || {});
|
||||
<span class="hljs-keyword">this</span>.currentLocale = opts.locale || <span class="hljs-string">'en'</span>;
|
||||
<span class="hljs-keyword">var</span> allowMissing = opts.allowMissing ? transformPhrase : <span class="hljs-literal">null</span>;
|
||||
<span class="hljs-keyword">this</span>.onMissingKey = <span class="hljs-keyword">typeof</span> opts.onMissingKey === <span class="hljs-string">'function'</span> ? opts.onMissingKey : allowMissing;
|
||||
<span class="hljs-keyword">this</span>.warn = opts.warn || warn;
|
||||
<span class="hljs-keyword">this</span>.tokenRegex = constructTokenRegex(opts.interpolation);
|
||||
}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-locale-locale-">polyglot.locale([locale])</h3>
|
||||
<p>Get or set locale. Internally, Polyglot only uses locale for pluralization.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.locale = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">newLocale</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (newLocale) <span class="hljs-keyword">this</span>.currentLocale = newLocale;
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.currentLocale;
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-extend-phrases-">polyglot.extend(phrases)</h3>
|
||||
<p>Use <code>extend</code> to tell Polyglot how to translate a given key.</p>
|
||||
<pre><code>polyglot.extend({
|
||||
<span class="hljs-string">"hello"</span>: <span class="hljs-string">"Hello"</span>,
|
||||
<span class="hljs-string">"hello_name"</span>: <span class="hljs-string">"Hello, %{name}"</span>
|
||||
});
|
||||
</code></pre><p>The key can be any string. Feel free to call <code>extend</code> multiple times;
|
||||
it will override any phrases with the same key, but leave existing phrases
|
||||
untouched.</p>
|
||||
<p>It is also possible to pass nested phrase objects, which get flattened
|
||||
into an object with the nested keys concatenated using dot notation.</p>
|
||||
<pre><code>polyglot.extend({
|
||||
<span class="hljs-string">"nav"</span>: {
|
||||
<span class="hljs-string">"hello"</span>: <span class="hljs-string">"Hello"</span>,
|
||||
<span class="hljs-string">"hello_name"</span>: <span class="hljs-string">"Hello, %{name}"</span>,
|
||||
<span class="hljs-string">"sidebar"</span>: {
|
||||
<span class="hljs-string">"welcome"</span>: <span class="hljs-string">"Welcome"</span>
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
<span class="hljs-built_in">console</span>.log(polyglot.phrases);
|
||||
<span class="hljs-comment">// {</span>
|
||||
<span class="hljs-comment">// 'nav.hello': 'Hello',</span>
|
||||
<span class="hljs-comment">// 'nav.hello_name': 'Hello, %{name}',</span>
|
||||
<span class="hljs-comment">// 'nav.sidebar.welcome': 'Welcome'</span>
|
||||
<span class="hljs-comment">// }</span>
|
||||
</code></pre><p><code>extend</code> accepts an optional second argument, <code>prefix</code>, which can be used
|
||||
to prefix every key in the phrases object with some string, using dot
|
||||
notation.</p>
|
||||
<pre><code>polyglot.extend({
|
||||
<span class="hljs-string">"hello"</span>: <span class="hljs-string">"Hello"</span>,
|
||||
<span class="hljs-string">"hello_name"</span>: <span class="hljs-string">"Hello, %{name}"</span>
|
||||
}, <span class="hljs-string">"nav"</span>);
|
||||
|
||||
<span class="hljs-built_in">console</span>.log(polyglot.phrases);
|
||||
<span class="hljs-comment">// {</span>
|
||||
<span class="hljs-comment">// 'nav.hello': 'Hello',</span>
|
||||
<span class="hljs-comment">// 'nav.hello_name': 'Hello, %{name}'</span>
|
||||
<span class="hljs-comment">// }</span>
|
||||
</code></pre><p>This feature is used internally to support nested phrase objects.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.extend = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">morePhrases, prefix</span>) </span>{
|
||||
forEach(morePhrases, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">phrase, key</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> prefixedKey = prefix ? prefix + <span class="hljs-string">'.'</span> + key : key;
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> phrase === <span class="hljs-string">'object'</span>) {
|
||||
<span class="hljs-keyword">this</span>.extend(phrase, prefixedKey);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">this</span>.phrases[prefixedKey] = phrase;
|
||||
}
|
||||
}, <span class="hljs-keyword">this</span>);
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-unset-phrases-">polyglot.unset(phrases)</h3>
|
||||
<p>Use <code>unset</code> to selectively remove keys from a polyglot instance.</p>
|
||||
<pre><code>polyglot.unset(<span class="hljs-string">"some_key"</span>);
|
||||
polyglot.unset({
|
||||
<span class="hljs-string">"hello"</span>: <span class="hljs-string">"Hello"</span>,
|
||||
<span class="hljs-string">"hello_name"</span>: <span class="hljs-string">"Hello, %{name}"</span>
|
||||
});
|
||||
</code></pre><p>The unset method can take either a string (for the key), or an object hash with
|
||||
the keys that you would like to unset.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.unset = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">morePhrases, prefix</span>) </span>{
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> morePhrases === <span class="hljs-string">'string'</span>) {
|
||||
<span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.phrases[morePhrases];
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
forEach(morePhrases, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">phrase, key</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> prefixedKey = prefix ? prefix + <span class="hljs-string">'.'</span> + key : key;
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> phrase === <span class="hljs-string">'object'</span>) {
|
||||
<span class="hljs-keyword">this</span>.unset(phrase, prefixedKey);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.phrases[prefixedKey];
|
||||
}
|
||||
}, <span class="hljs-keyword">this</span>);
|
||||
}
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-clear-">polyglot.clear()</h3>
|
||||
<p>Clears all phrases. Useful for special cases, such as freeing
|
||||
up memory if you have lots of phrases but no longer need to
|
||||
perform any translation. Also used internally by <code>replace</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.clear = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
|
||||
<span class="hljs-keyword">this</span>.phrases = {};
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-replace-phrases-">polyglot.replace(phrases)</h3>
|
||||
<p>Completely replace the existing phrases with a new set of phrases.
|
||||
Normally, just use <code>extend</code> to add more phrases, but under certain
|
||||
circumstances, you may want to make sure no old phrases are lying around.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.replace = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">newPhrases</span>) </span>{
|
||||
<span class="hljs-keyword">this</span>.clear();
|
||||
<span class="hljs-keyword">this</span>.extend(newPhrases);
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-t-key-options-">polyglot.t(key, options)</h3>
|
||||
<p>The most-used method. Provide a key, and <code>t</code> will return the
|
||||
phrase.</p>
|
||||
<pre><code>polyglot.t(<span class="hljs-string">"hello"</span>);
|
||||
=> <span class="hljs-string">"Hello"</span>
|
||||
</code></pre><p>The phrase value is provided first by a call to <code>polyglot.extend()</code> or
|
||||
<code>polyglot.replace()</code>.</p>
|
||||
<p>Pass in an object as the second argument to perform interpolation.</p>
|
||||
<pre><code>polyglot.t(<span class="hljs-string">"hello_name"</span>, {<span class="hljs-attr">name</span>: <span class="hljs-string">"Spike"</span>});
|
||||
=> <span class="hljs-string">"Hello, Spike"</span>
|
||||
</code></pre><p>If you like, you can provide a default value in case the phrase is missing.
|
||||
Use the special option key “_” to specify a default.</p>
|
||||
<pre><code>polyglot.t(<span class="hljs-string">"i_like_to_write_in_language"</span>, {
|
||||
<span class="hljs-attr">_</span>: <span class="hljs-string">"I like to write in %{language}."</span>,
|
||||
<span class="hljs-attr">language</span>: <span class="hljs-string">"JavaScript"</span>
|
||||
});
|
||||
=> <span class="hljs-string">"I like to write in JavaScript."</span>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.t = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key, options</span>) </span>{
|
||||
<span class="hljs-keyword">var</span> phrase, result;
|
||||
<span class="hljs-keyword">var</span> opts = options == <span class="hljs-literal">null</span> ? {} : options;
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-keyword">this</span>.phrases[key] === <span class="hljs-string">'string'</span>) {
|
||||
phrase = <span class="hljs-keyword">this</span>.phrases[key];
|
||||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> opts._ === <span class="hljs-string">'string'</span>) {
|
||||
phrase = opts._;
|
||||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.onMissingKey) {
|
||||
<span class="hljs-keyword">var</span> onMissingKey = <span class="hljs-keyword">this</span>.onMissingKey;
|
||||
result = onMissingKey(key, opts, <span class="hljs-keyword">this</span>.currentLocale, <span class="hljs-keyword">this</span>.tokenRegex);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">this</span>.warn(<span class="hljs-string">'Missing translation for key: "'</span> + key + <span class="hljs-string">'"'</span>);
|
||||
result = key;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> phrase === <span class="hljs-string">'string'</span>) {
|
||||
result = transformPhrase(phrase, opts, <span class="hljs-keyword">this</span>.currentLocale, <span class="hljs-keyword">this</span>.tokenRegex);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> result;
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<h3 id="polyglot-has-key-">polyglot.has(key)</h3>
|
||||
<p>Check if polyglot has a translation for given key</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.prototype.has = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key</span>) </span>{
|
||||
<span class="hljs-keyword">return</span> has(<span class="hljs-keyword">this</span>.phrases, key);
|
||||
};</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>export transformPhrase</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Polyglot.transformPhrase = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transform</span>(<span class="hljs-params">phrase, substitutions, locale</span>) </span>{
|
||||
<span class="hljs-keyword">return</span> transformPhrase(phrase, substitutions, locale);
|
||||
};
|
||||
|
||||
<span class="hljs-built_in">module</span>.exports = Polyglot;</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
462
node_modules/node-polyglot/index.js
generated
vendored
Normal file
462
node_modules/node-polyglot/index.js
generated
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
// (c) 2012-2018 Airbnb, Inc.
|
||||
//
|
||||
// polyglot.js may be freely distributed under the terms of the BSD
|
||||
// license. For all licensing information, details, and documentation:
|
||||
// http://airbnb.github.com/polyglot.js
|
||||
//
|
||||
//
|
||||
// Polyglot.js is an I18n helper library written in JavaScript, made to
|
||||
// work both in the browser and in Node. It provides a simple solution for
|
||||
// interpolation and pluralization, based off of Airbnb's
|
||||
// experience adding I18n functionality to its Backbone.js and Node apps.
|
||||
//
|
||||
// Polylglot is agnostic to your translation backend. It doesn't perform any
|
||||
// translation; it simply gives you a way to manage translated phrases from
|
||||
// your client- or server-side JavaScript application.
|
||||
//
|
||||
|
||||
'use strict';
|
||||
|
||||
var entries = require('object.entries');
|
||||
var warning = require('warning');
|
||||
var has = require('hasown');
|
||||
|
||||
var warn = function warn(message) {
|
||||
warning(false, message);
|
||||
};
|
||||
|
||||
var defaultReplace = String.prototype.replace;
|
||||
var split = String.prototype.split;
|
||||
|
||||
// #### Pluralization methods
|
||||
// The string that separates the different phrase possibilities.
|
||||
var delimiter = '||||';
|
||||
|
||||
var russianPluralGroups = function (n) {
|
||||
var lastTwo = n % 100;
|
||||
var end = lastTwo % 10;
|
||||
if (lastTwo !== 11 && end === 1) {
|
||||
return 0;
|
||||
}
|
||||
if (2 <= end && end <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
};
|
||||
|
||||
var defaultPluralRules = {
|
||||
// Mapping from pluralization group plural logic.
|
||||
pluralTypes: {
|
||||
arabic: function (n) {
|
||||
// http://www.arabeyes.org/Plural_Forms
|
||||
if (n < 3) { return n; }
|
||||
var lastTwo = n % 100;
|
||||
if (lastTwo >= 3 && lastTwo <= 10) return 3;
|
||||
return lastTwo >= 11 ? 4 : 5;
|
||||
},
|
||||
bosnian_serbian: russianPluralGroups,
|
||||
chinese: function () { return 0; },
|
||||
croatian: russianPluralGroups,
|
||||
french: function (n) { return n >= 2 ? 1 : 0; },
|
||||
german: function (n) { return n !== 1 ? 1 : 0; },
|
||||
russian: russianPluralGroups,
|
||||
lithuanian: function (n) {
|
||||
if (n % 10 === 1 && n % 100 !== 11) { return 0; }
|
||||
return n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19) ? 1 : 2;
|
||||
},
|
||||
czech: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
return (n >= 2 && n <= 4) ? 1 : 2;
|
||||
},
|
||||
polish: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
var end = n % 10;
|
||||
return 2 <= end && end <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
|
||||
},
|
||||
icelandic: function (n) { return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; },
|
||||
slovenian: function (n) {
|
||||
var lastTwo = n % 100;
|
||||
if (lastTwo === 1) {
|
||||
return 0;
|
||||
}
|
||||
if (lastTwo === 2) {
|
||||
return 1;
|
||||
}
|
||||
if (lastTwo === 3 || lastTwo === 4) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
},
|
||||
romanian: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
var lastTwo = n % 100;
|
||||
if (n === 0 || (lastTwo >= 2 && lastTwo <= 19)) { return 1; }
|
||||
return 2;
|
||||
},
|
||||
ukrainian: russianPluralGroups
|
||||
},
|
||||
|
||||
// Mapping from pluralization group to individual language codes/locales.
|
||||
// Will look up based on exact match, if not found and it's a locale will parse the locale
|
||||
// for language code, and if that does not exist will default to 'en'
|
||||
pluralTypeToLanguages: {
|
||||
arabic: ['ar'],
|
||||
bosnian_serbian: ['bs-Latn-BA', 'bs-Cyrl-BA', 'srl-RS', 'sr-RS'],
|
||||
chinese: ['id', 'id-ID', 'ja', 'ko', 'ko-KR', 'lo', 'ms', 'th', 'th-TH', 'zh'],
|
||||
croatian: ['hr', 'hr-HR'],
|
||||
german: ['fa', 'da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hi-IN', 'hu', 'hu-HU', 'it', 'nl', 'no', 'pt', 'sv', 'tr'],
|
||||
french: ['fr', 'tl', 'pt-br'],
|
||||
russian: ['ru', 'ru-RU'],
|
||||
lithuanian: ['lt'],
|
||||
czech: ['cs', 'cs-CZ', 'sk'],
|
||||
polish: ['pl'],
|
||||
icelandic: ['is', 'mk'],
|
||||
slovenian: ['sl-SL'],
|
||||
romanian: ['ro'],
|
||||
ukrainian: ['uk', 'ua']
|
||||
}
|
||||
};
|
||||
|
||||
function langToTypeMap(mapping) {
|
||||
var ret = {};
|
||||
var mappingEntries = entries(mapping);
|
||||
for (var i = 0; i < mappingEntries.length; i += 1) {
|
||||
var type = mappingEntries[i][0];
|
||||
var langs = mappingEntries[i][1];
|
||||
for (var j = 0; j < langs.length; j += 1) {
|
||||
ret[langs[j]] = type;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function pluralTypeName(pluralRules, locale) {
|
||||
var langToPluralType = langToTypeMap(pluralRules.pluralTypeToLanguages);
|
||||
return langToPluralType[locale]
|
||||
|| langToPluralType[split.call(locale, /-/, 1)[0]]
|
||||
|| langToPluralType.en;
|
||||
}
|
||||
|
||||
function pluralTypeIndex(pluralRules, pluralType, count) {
|
||||
return pluralRules.pluralTypes[pluralType](count);
|
||||
}
|
||||
|
||||
function createMemoizedPluralTypeNameSelector() {
|
||||
var localePluralTypeStorage = {};
|
||||
|
||||
return function (pluralRules, locale) {
|
||||
var pluralType = localePluralTypeStorage[locale];
|
||||
|
||||
if (pluralType && !pluralRules.pluralTypes[pluralType]) {
|
||||
pluralType = null;
|
||||
localePluralTypeStorage[locale] = pluralType;
|
||||
}
|
||||
|
||||
if (!pluralType) {
|
||||
pluralType = pluralTypeName(pluralRules, locale);
|
||||
|
||||
if (pluralType) {
|
||||
localePluralTypeStorage[locale] = pluralType;
|
||||
}
|
||||
}
|
||||
|
||||
return pluralType;
|
||||
};
|
||||
}
|
||||
|
||||
function escape(token) {
|
||||
return token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function constructTokenRegex(opts) {
|
||||
var prefix = (opts && opts.prefix) || '%{';
|
||||
var suffix = (opts && opts.suffix) || '}';
|
||||
|
||||
if (prefix === delimiter || suffix === delimiter) {
|
||||
throw new RangeError('"' + delimiter + '" token is reserved for pluralization');
|
||||
}
|
||||
|
||||
return new RegExp(escape(prefix) + '(.*?)' + escape(suffix), 'g');
|
||||
}
|
||||
|
||||
var memoizedPluralTypeName = createMemoizedPluralTypeNameSelector();
|
||||
|
||||
var defaultTokenRegex = /%\{(.*?)\}/g;
|
||||
|
||||
// ### transformPhrase(phrase, substitutions, locale)
|
||||
//
|
||||
// Takes a phrase string and transforms it by choosing the correct
|
||||
// plural form and interpolating it.
|
||||
//
|
||||
// transformPhrase('Hello, %{name}!', {name: 'Spike'});
|
||||
// // "Hello, Spike!"
|
||||
//
|
||||
// The correct plural form is selected if substitutions.smart_count
|
||||
// is set. You can pass in a number instead of an Object as `substitutions`
|
||||
// as a shortcut for `smart_count`.
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 1}, 'en');
|
||||
// // "1 new message"
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 2}, 'en');
|
||||
// // "2 new messages"
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', 5, 'en');
|
||||
// // "5 new messages"
|
||||
//
|
||||
// You should pass in a third argument, the locale, to specify the correct plural type.
|
||||
// It defaults to `'en'` with 2 plural forms.
|
||||
function transformPhrase(
|
||||
phrase,
|
||||
substitutions,
|
||||
locale,
|
||||
tokenRegex,
|
||||
pluralRules,
|
||||
replaceImplementation
|
||||
) {
|
||||
if (typeof phrase !== 'string') {
|
||||
throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string');
|
||||
}
|
||||
|
||||
if (substitutions == null) {
|
||||
return phrase;
|
||||
}
|
||||
|
||||
var result = phrase;
|
||||
var interpolationRegex = tokenRegex || defaultTokenRegex;
|
||||
var replace = replaceImplementation || defaultReplace;
|
||||
|
||||
// allow number as a pluralization shortcut
|
||||
var options = typeof substitutions === 'number' ? { smart_count: substitutions } : substitutions;
|
||||
|
||||
// Select plural form: based on a phrase text that contains `n`
|
||||
// plural forms separated by `delimiter`, a `locale`, and a `substitutions.smart_count`,
|
||||
// choose the correct plural form. This is only done if `count` is set.
|
||||
if (options.smart_count != null && phrase) {
|
||||
var pluralRulesOrDefault = pluralRules || defaultPluralRules;
|
||||
var texts = split.call(phrase, delimiter);
|
||||
var bestLocale = locale || 'en';
|
||||
var pluralType = memoizedPluralTypeName(pluralRulesOrDefault, bestLocale);
|
||||
var pluralTypeWithCount = pluralTypeIndex(
|
||||
pluralRulesOrDefault,
|
||||
pluralType,
|
||||
options.smart_count
|
||||
);
|
||||
|
||||
result = defaultReplace.call(texts[pluralTypeWithCount] || texts[0], /^[^\S]*|[^\S]*$/g, '');
|
||||
}
|
||||
|
||||
// Interpolate: Creates a `RegExp` object for each interpolation placeholder.
|
||||
result = replace.call(result, interpolationRegex, function (expression, argument) {
|
||||
if (!has(options, argument) || options[argument] == null) { return expression; }
|
||||
return options[argument];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ### Polyglot class constructor
|
||||
function Polyglot(options) {
|
||||
var opts = options || {};
|
||||
this.phrases = {};
|
||||
this.extend(opts.phrases || {});
|
||||
this.currentLocale = opts.locale || 'en';
|
||||
var allowMissing = opts.allowMissing ? transformPhrase : null;
|
||||
this.onMissingKey = typeof opts.onMissingKey === 'function' ? opts.onMissingKey : allowMissing;
|
||||
this.warn = opts.warn || warn;
|
||||
this.replaceImplementation = opts.replace || defaultReplace;
|
||||
this.tokenRegex = constructTokenRegex(opts.interpolation);
|
||||
this.pluralRules = opts.pluralRules || defaultPluralRules;
|
||||
}
|
||||
|
||||
// ### polyglot.locale([locale])
|
||||
//
|
||||
// Get or set locale. Internally, Polyglot only uses locale for pluralization.
|
||||
Polyglot.prototype.locale = function (newLocale) {
|
||||
if (newLocale) this.currentLocale = newLocale;
|
||||
return this.currentLocale;
|
||||
};
|
||||
|
||||
// ### polyglot.extend(phrases)
|
||||
//
|
||||
// Use `extend` to tell Polyglot how to translate a given key.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// });
|
||||
//
|
||||
// The key can be any string. Feel free to call `extend` multiple times;
|
||||
// it will override any phrases with the same key, but leave existing phrases
|
||||
// untouched.
|
||||
//
|
||||
// It is also possible to pass nested phrase objects, which get flattened
|
||||
// into an object with the nested keys concatenated using dot notation.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "nav": {
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}",
|
||||
// "sidebar": {
|
||||
// "welcome": "Welcome"
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// console.log(polyglot.phrases);
|
||||
// // {
|
||||
// // 'nav.hello': 'Hello',
|
||||
// // 'nav.hello_name': 'Hello, %{name}',
|
||||
// // 'nav.sidebar.welcome': 'Welcome'
|
||||
// // }
|
||||
//
|
||||
// `extend` accepts an optional second argument, `prefix`, which can be used
|
||||
// to prefix every key in the phrases object with some string, using dot
|
||||
// notation.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// }, "nav");
|
||||
//
|
||||
// console.log(polyglot.phrases);
|
||||
// // {
|
||||
// // 'nav.hello': 'Hello',
|
||||
// // 'nav.hello_name': 'Hello, %{name}'
|
||||
// // }
|
||||
//
|
||||
// This feature is used internally to support nested phrase objects.
|
||||
Polyglot.prototype.extend = function (morePhrases, prefix) {
|
||||
var phraseEntries = entries(morePhrases || {});
|
||||
for (var i = 0; i < phraseEntries.length; i += 1) {
|
||||
var key = phraseEntries[i][0];
|
||||
var phrase = phraseEntries[i][1];
|
||||
var prefixedKey = prefix ? prefix + '.' + key : key;
|
||||
if (typeof phrase === 'object') {
|
||||
this.extend(phrase, prefixedKey);
|
||||
} else {
|
||||
this.phrases[prefixedKey] = phrase;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ### polyglot.unset(phrases)
|
||||
// Use `unset` to selectively remove keys from a polyglot instance.
|
||||
//
|
||||
// polyglot.unset("some_key");
|
||||
// polyglot.unset({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// });
|
||||
//
|
||||
// The unset method can take either a string (for the key), or an object hash with
|
||||
// the keys that you would like to unset.
|
||||
Polyglot.prototype.unset = function (morePhrases, prefix) {
|
||||
if (typeof morePhrases === 'string') {
|
||||
delete this.phrases[morePhrases];
|
||||
} else {
|
||||
var phraseEntries = entries(morePhrases || {});
|
||||
for (var i = 0; i < phraseEntries.length; i += 1) {
|
||||
var key = phraseEntries[i][0];
|
||||
var phrase = phraseEntries[i][1];
|
||||
var prefixedKey = prefix ? prefix + '.' + key : key;
|
||||
if (typeof phrase === 'object') {
|
||||
this.unset(phrase, prefixedKey);
|
||||
} else {
|
||||
delete this.phrases[prefixedKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ### polyglot.clear()
|
||||
//
|
||||
// Clears all phrases. Useful for special cases, such as freeing
|
||||
// up memory if you have lots of phrases but no longer need to
|
||||
// perform any translation. Also used internally by `replace`.
|
||||
Polyglot.prototype.clear = function () {
|
||||
this.phrases = {};
|
||||
};
|
||||
|
||||
// ### polyglot.replace(phrases)
|
||||
//
|
||||
// Completely replace the existing phrases with a new set of phrases.
|
||||
// Normally, just use `extend` to add more phrases, but under certain
|
||||
// circumstances, you may want to make sure no old phrases are lying around.
|
||||
Polyglot.prototype.replace = function (newPhrases) {
|
||||
this.clear();
|
||||
this.extend(newPhrases);
|
||||
};
|
||||
|
||||
// ### polyglot.t(key, options)
|
||||
//
|
||||
// The most-used method. Provide a key, and `t` will return the
|
||||
// phrase.
|
||||
//
|
||||
// polyglot.t("hello");
|
||||
// => "Hello"
|
||||
//
|
||||
// The phrase value is provided first by a call to `polyglot.extend()` or
|
||||
// `polyglot.replace()`.
|
||||
//
|
||||
// Pass in an object as the second argument to perform interpolation.
|
||||
//
|
||||
// polyglot.t("hello_name", {name: "Spike"});
|
||||
// => "Hello, Spike"
|
||||
//
|
||||
// If you like, you can provide a default value in case the phrase is missing.
|
||||
// Use the special option key "_" to specify a default.
|
||||
//
|
||||
// polyglot.t("i_like_to_write_in_language", {
|
||||
// _: "I like to write in %{language}.",
|
||||
// language: "JavaScript"
|
||||
// });
|
||||
// => "I like to write in JavaScript."
|
||||
//
|
||||
Polyglot.prototype.t = function (key, options) {
|
||||
var phrase, result;
|
||||
var opts = options == null ? {} : options;
|
||||
if (typeof this.phrases[key] === 'string') {
|
||||
phrase = this.phrases[key];
|
||||
} else if (typeof opts._ === 'string') {
|
||||
phrase = opts._;
|
||||
} else if (this.onMissingKey) {
|
||||
var onMissingKey = this.onMissingKey;
|
||||
result = onMissingKey(
|
||||
key,
|
||||
opts,
|
||||
this.currentLocale,
|
||||
this.tokenRegex,
|
||||
this.pluralRules,
|
||||
this.replaceImplementation
|
||||
);
|
||||
} else {
|
||||
this.warn('Missing translation for key: "' + key + '"');
|
||||
result = key;
|
||||
}
|
||||
if (typeof phrase === 'string') {
|
||||
result = transformPhrase(
|
||||
phrase,
|
||||
opts,
|
||||
this.currentLocale,
|
||||
this.tokenRegex,
|
||||
this.pluralRules,
|
||||
this.replaceImplementation
|
||||
);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// ### polyglot.has(key)
|
||||
//
|
||||
// Check if polyglot has a translation for given key
|
||||
Polyglot.prototype.has = function (key) {
|
||||
return has(this.phrases, key);
|
||||
};
|
||||
|
||||
// export transformPhrase
|
||||
Polyglot.transformPhrase = function transform(phrase, substitutions, locale) {
|
||||
return transformPhrase(phrase, substitutions, locale);
|
||||
};
|
||||
|
||||
module.exports = Polyglot;
|
||||
55
node_modules/node-polyglot/package.json
generated
vendored
Normal file
55
node_modules/node-polyglot/package.json
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "node-polyglot",
|
||||
"version": "2.6.0",
|
||||
"description": "Give your JavaScript the ability to speak many languages.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prepublishOnly": "safe-publish-latest",
|
||||
"prepublish": "not-in-publish || npm run prepublishOnly",
|
||||
"pretest": "npm run lint",
|
||||
"test": "npm run tests-only",
|
||||
"tests-only": "nyc mocha test/*.js --reporter spec",
|
||||
"posttest": "aud --production",
|
||||
"lint": "eslint .",
|
||||
"docs": "docco -o docs/ index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/airbnb/polyglot.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"i18n",
|
||||
"internationalization",
|
||||
"internationalisation",
|
||||
"translation",
|
||||
"interpolation",
|
||||
"translate",
|
||||
"polyglot"
|
||||
],
|
||||
"author": "Spike Brehm <spike@airbnb.com>",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2",
|
||||
"object.entries": "^1.1.8",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"array.prototype.foreach": "^1.0.7",
|
||||
"aud": "^2.0.4",
|
||||
"chai": "^3.5.0",
|
||||
"docco": "^0.7.0",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"in-publish": "^2.0.1",
|
||||
"iterate-iterator": "^1.0.2",
|
||||
"mocha": "^3.5.3",
|
||||
"nyc": "^10.3.2",
|
||||
"safe-publish-latest": "^2.0.0",
|
||||
"string.prototype.matchall": "^4.0.11",
|
||||
"uglify-js": "^2.7.3"
|
||||
},
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
}
|
||||
9
node_modules/node-polyglot/test/.eslintrc
generated
vendored
Normal file
9
node_modules/node-polyglot/test/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"rules": {
|
||||
"max-len": 0,
|
||||
},
|
||||
|
||||
"env": {
|
||||
"mocha": true,
|
||||
},
|
||||
}
|
||||
942
node_modules/node-polyglot/test/index.js
generated
vendored
Normal file
942
node_modules/node-polyglot/test/index.js
generated
vendored
Normal file
@@ -0,0 +1,942 @@
|
||||
'use strict';
|
||||
|
||||
var Polyglot = require('../');
|
||||
var expect = require('chai').expect;
|
||||
var forEach = require('array.prototype.foreach');
|
||||
var iterate = require('iterate-iterator');
|
||||
var matchAll = require('string.prototype.matchall');
|
||||
|
||||
describe('t', function () {
|
||||
var phrases = {
|
||||
hello: 'Hello',
|
||||
hi_name_welcome_to_place: 'Hi, %{name}, welcome to %{place}!',
|
||||
name_your_name_is_name: '%{name}, your name is %{name}!',
|
||||
empty_string: ''
|
||||
};
|
||||
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot({ phrases: phrases });
|
||||
});
|
||||
|
||||
it('translates a simple string', function () {
|
||||
expect(polyglot.t('hello')).to.equal('Hello');
|
||||
});
|
||||
|
||||
it('returns the key if translation not found', function () {
|
||||
expect(polyglot.t('bogus_key')).to.equal('bogus_key');
|
||||
});
|
||||
|
||||
it('interpolates', function () {
|
||||
expect(polyglot.t('hi_name_welcome_to_place', {
|
||||
name: 'Spike',
|
||||
place: 'the webz'
|
||||
})).to.equal('Hi, Spike, welcome to the webz!');
|
||||
});
|
||||
|
||||
it('interpolates with missing substitutions', function () {
|
||||
expect(polyglot.t('hi_name_welcome_to_place', {
|
||||
place: undefined
|
||||
})).to.equal('Hi, %{name}, welcome to %{place}!');
|
||||
});
|
||||
|
||||
it('interpolates the same placeholder multiple times', function () {
|
||||
expect(polyglot.t('name_your_name_is_name', {
|
||||
name: 'Spike'
|
||||
})).to.equal('Spike, your name is Spike!');
|
||||
});
|
||||
|
||||
it('allows you to supply default values', function () {
|
||||
expect(polyglot.t('can_i_call_you_name', {
|
||||
_: 'Can I call you %{name}?',
|
||||
name: 'Robert'
|
||||
})).to.equal('Can I call you Robert?');
|
||||
});
|
||||
|
||||
it('returns the non-interpolated key if not initialized with allowMissing and translation not found', function () {
|
||||
expect(polyglot.t('Welcome %{name}', {
|
||||
name: 'Robert'
|
||||
})).to.equal('Welcome %{name}');
|
||||
});
|
||||
|
||||
it('returns an interpolated key if initialized with allowMissing and translation not found', function () {
|
||||
var instance = new Polyglot({ phrases: phrases, allowMissing: true });
|
||||
expect(instance.t('Welcome %{name}', {
|
||||
name: 'Robert'
|
||||
})).to.equal('Welcome Robert');
|
||||
});
|
||||
|
||||
describe('custom interpolation syntax', function () {
|
||||
var createWithInterpolation = function (interpolation) {
|
||||
return new Polyglot({ phrases: {}, allowMissing: true, interpolation: interpolation });
|
||||
};
|
||||
|
||||
it('interpolates with the specified custom token syntax', function () {
|
||||
var instance = createWithInterpolation({ prefix: '{{', suffix: '}}' });
|
||||
expect(instance.t('Welcome {{name}}', {
|
||||
name: 'Robert'
|
||||
})).to.equal('Welcome Robert');
|
||||
});
|
||||
|
||||
it('interpolates if the prefix and suffix are the same', function () {
|
||||
var instance = createWithInterpolation({ prefix: '|', suffix: '|' });
|
||||
expect(instance.t('Welcome |name|, how are you, |name|?', {
|
||||
name: 'Robert'
|
||||
})).to.equal('Welcome Robert, how are you, Robert?');
|
||||
});
|
||||
|
||||
it('interpolates when using regular expression tokens', function () {
|
||||
var instance = createWithInterpolation({ prefix: '\\s.*', suffix: '\\d.+' });
|
||||
expect(instance.t('Welcome \\s.*name\\d.+', {
|
||||
name: 'Robert'
|
||||
})).to.equal('Welcome Robert');
|
||||
});
|
||||
|
||||
it('throws an error when either prefix or suffix equals to pluralization delimiter', function () {
|
||||
expect(function () { createWithInterpolation({ prefix: '||||', suffix: '}}' }); }).to.throw(RangeError);
|
||||
expect(function () { createWithInterpolation({ prefix: '{{', suffix: '||||' }); }).to.throw(RangeError);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the translation even if it is an empty string', function () {
|
||||
expect(polyglot.t('empty_string')).to.equal('');
|
||||
});
|
||||
|
||||
it('returns the default value even if it is an empty string', function () {
|
||||
expect(polyglot.t('bogus_key', { _: '' })).to.equal('');
|
||||
});
|
||||
|
||||
it('handles dollar signs in the substitution value', function () {
|
||||
expect(polyglot.t('hi_name_welcome_to_place', {
|
||||
name: '$abc $0',
|
||||
place: '$1 $&'
|
||||
})).to.equal('Hi, $abc $0, welcome to $1 $&!');
|
||||
});
|
||||
|
||||
it('supports nested phrase objects', function () {
|
||||
var nestedPhrases = {
|
||||
nav: {
|
||||
presentations: 'Presentations',
|
||||
hi_user: 'Hi, %{user}.',
|
||||
cta: {
|
||||
join_now: 'Join now!'
|
||||
}
|
||||
},
|
||||
'header.sign_in': 'Sign In'
|
||||
};
|
||||
var instance = new Polyglot({ phrases: nestedPhrases });
|
||||
expect(instance.t('nav.presentations')).to.equal('Presentations');
|
||||
expect(instance.t('nav.hi_user', { user: 'Raph' })).to.equal('Hi, Raph.');
|
||||
expect(instance.t('nav.cta.join_now')).to.equal('Join now!');
|
||||
expect(instance.t('header.sign_in')).to.equal('Sign In');
|
||||
});
|
||||
|
||||
it('supports custom replace implementation', function () {
|
||||
var instance = new Polyglot({
|
||||
phrases: phrases,
|
||||
replace: function (interpolationRegex, callback) {
|
||||
var phrase = this;
|
||||
var i = 0;
|
||||
|
||||
var children = [];
|
||||
iterate(matchAll(phrase, interpolationRegex), function (match) {
|
||||
if (match.index > i) {
|
||||
children.push(phrase.slice(i, match.index));
|
||||
}
|
||||
children.push(callback(match[0], match[1]));
|
||||
i = match.index + match[0].length;
|
||||
});
|
||||
|
||||
if (i < phrase.length) {
|
||||
children.push(phrase.slice(i));
|
||||
}
|
||||
|
||||
return { type: 'might_be_react_fragment', children: children };
|
||||
}
|
||||
});
|
||||
|
||||
expect(instance.t(
|
||||
'hi_name_welcome_to_place',
|
||||
{
|
||||
name: { type: 'might_be_react_node', children: ['Rudolf'] },
|
||||
place: { type: 'might_be_react_node', children: ['Earth'] }
|
||||
}
|
||||
)).to.deep.equal({
|
||||
children: [
|
||||
'Hi, ',
|
||||
{
|
||||
children: [
|
||||
'Rudolf'
|
||||
],
|
||||
type: 'might_be_react_node'
|
||||
},
|
||||
', welcome to ',
|
||||
{
|
||||
children: [
|
||||
'Earth'
|
||||
],
|
||||
type: 'might_be_react_node'
|
||||
},
|
||||
'!'
|
||||
],
|
||||
type: 'might_be_react_fragment'
|
||||
});
|
||||
});
|
||||
|
||||
describe('onMissingKey', function () {
|
||||
it('calls the function when a key is missing', function () {
|
||||
var expectedKey = 'some key';
|
||||
var expectedOptions = {};
|
||||
var expectedLocale = 'oz';
|
||||
var returnValue = {};
|
||||
var onMissingKey = function (key, options, locale) {
|
||||
expect(key).to.equal(expectedKey);
|
||||
expect(options).to.equal(expectedOptions);
|
||||
expect(locale).to.equal(expectedLocale);
|
||||
return returnValue;
|
||||
};
|
||||
var instance = new Polyglot({ onMissingKey: onMissingKey, locale: expectedLocale });
|
||||
var result = instance.t(expectedKey, expectedOptions);
|
||||
expect(result).to.equal(returnValue);
|
||||
});
|
||||
|
||||
it('overrides allowMissing', function (done) {
|
||||
var missingKey = 'missing key';
|
||||
var onMissingKey = function (key) {
|
||||
expect(key).to.equal(missingKey);
|
||||
done();
|
||||
};
|
||||
var instance = new Polyglot({ onMissingKey: onMissingKey, allowMissing: true });
|
||||
instance.t(missingKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('pluralize', function () {
|
||||
var phrases = {
|
||||
count_name: '%{smart_count} Name |||| %{smart_count} Names'
|
||||
};
|
||||
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot({ phrases: phrases, locale: 'en' });
|
||||
});
|
||||
|
||||
it('supports pluralization with an integer', function () {
|
||||
expect(polyglot.t('count_name', { smart_count: 0 })).to.equal('0 Names');
|
||||
expect(polyglot.t('count_name', { smart_count: 1 })).to.equal('1 Name');
|
||||
expect(polyglot.t('count_name', { smart_count: 2 })).to.equal('2 Names');
|
||||
expect(polyglot.t('count_name', { smart_count: 3 })).to.equal('3 Names');
|
||||
});
|
||||
|
||||
it('accepts a number as a shortcut to pluralize a word', function () {
|
||||
expect(polyglot.t('count_name', 0)).to.equal('0 Names');
|
||||
expect(polyglot.t('count_name', 1)).to.equal('1 Name');
|
||||
expect(polyglot.t('count_name', 2)).to.equal('2 Names');
|
||||
expect(polyglot.t('count_name', 3)).to.equal('3 Names');
|
||||
});
|
||||
|
||||
it('ignores a region subtag when choosing a pluralization rule', function () {
|
||||
var instance = new Polyglot({ phrases: phrases, locale: 'fr-FR' });
|
||||
// French rule: "0" is singular
|
||||
expect(instance.t('count_name', 0)).to.equal('0 Name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('locale-specific pluralization rules', function () {
|
||||
it('pluralizes in Arabic', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'ولا صوت',
|
||||
'صوت واحد',
|
||||
'صوتان',
|
||||
'%{smart_count} أصوات',
|
||||
'%{smart_count} صوت',
|
||||
'%{smart_count} صوت'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'ar' });
|
||||
|
||||
expect(polyglot.t('n_votes', 0)).to.equal('ولا صوت');
|
||||
expect(polyglot.t('n_votes', 1)).to.equal('صوت واحد');
|
||||
expect(polyglot.t('n_votes', 2)).to.equal('صوتان');
|
||||
expect(polyglot.t('n_votes', 3)).to.equal('3 أصوات');
|
||||
expect(polyglot.t('n_votes', 11)).to.equal('11 صوت');
|
||||
expect(polyglot.t('n_votes', 102)).to.equal('102 صوت');
|
||||
});
|
||||
|
||||
it('interpolates properly in Arabic', function () {
|
||||
var phrases = {
|
||||
hello: 'الرمز ${code} غير صحيح' // eslint-disable-line no-template-curly-in-string
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({
|
||||
phrases: phrases,
|
||||
locale: 'ar',
|
||||
interpolation: { prefix: '${', suffix: '}' }
|
||||
});
|
||||
|
||||
expect(polyglot.t('hello', { code: 'De30Niro' })).to.equal('الرمز De30Niro غير صحيح');
|
||||
|
||||
// note how the "30" in the next line shows up in the wrong place:
|
||||
expect(polyglot.t('hello', { code: '30DeNiro' })).to.equal('الرمز 30DeNiro غير صحيح');
|
||||
// but with a directional marker character, it shows up in the right place:
|
||||
expect(polyglot.t('hello', { code: '\u200E30DeNiroMarker' })).to.equal('الرمز \u200E30DeNiroMarker غير صحيح');
|
||||
// see https://github.com/airbnb/polyglot.js/issues/167 / https://stackoverflow.com/a/34903965 for why it's impractical to handle in polyglot
|
||||
});
|
||||
|
||||
it('pluralizes in Russian', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} машина',
|
||||
'%{smart_count} машины',
|
||||
'%{smart_count} машин'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglotLanguageCode = new Polyglot({ phrases: phrases, locale: 'ru' });
|
||||
|
||||
expect(polyglotLanguageCode.t('n_votes', 1)).to.equal('1 машина');
|
||||
expect(polyglotLanguageCode.t('n_votes', 11)).to.equal('11 машин');
|
||||
expect(polyglotLanguageCode.t('n_votes', 101)).to.equal('101 машина');
|
||||
expect(polyglotLanguageCode.t('n_votes', 112)).to.equal('112 машин');
|
||||
expect(polyglotLanguageCode.t('n_votes', 932)).to.equal('932 машины');
|
||||
expect(polyglotLanguageCode.t('n_votes', 324)).to.equal('324 машины');
|
||||
expect(polyglotLanguageCode.t('n_votes', 12)).to.equal('12 машин');
|
||||
expect(polyglotLanguageCode.t('n_votes', 13)).to.equal('13 машин');
|
||||
expect(polyglotLanguageCode.t('n_votes', 14)).to.equal('14 машин');
|
||||
expect(polyglotLanguageCode.t('n_votes', 15)).to.equal('15 машин');
|
||||
|
||||
var polyglotLocaleId = new Polyglot({ phrases: phrases, locale: 'ru-RU' });
|
||||
|
||||
expect(polyglotLocaleId.t('n_votes', 1)).to.equal('1 машина');
|
||||
expect(polyglotLocaleId.t('n_votes', 11)).to.equal('11 машин');
|
||||
expect(polyglotLocaleId.t('n_votes', 101)).to.equal('101 машина');
|
||||
expect(polyglotLocaleId.t('n_votes', 112)).to.equal('112 машин');
|
||||
expect(polyglotLocaleId.t('n_votes', 932)).to.equal('932 машины');
|
||||
expect(polyglotLocaleId.t('n_votes', 324)).to.equal('324 машины');
|
||||
expect(polyglotLocaleId.t('n_votes', 12)).to.equal('12 машин');
|
||||
expect(polyglotLocaleId.t('n_votes', 13)).to.equal('13 машин');
|
||||
expect(polyglotLocaleId.t('n_votes', 14)).to.equal('14 машин');
|
||||
expect(polyglotLocaleId.t('n_votes', 15)).to.equal('15 машин');
|
||||
});
|
||||
|
||||
it('pluralizes in Croatian (guest) Test', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} gost',
|
||||
'%{smart_count} gosta',
|
||||
'%{smart_count} gostiju'
|
||||
];
|
||||
var phrases = {
|
||||
n_guests: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglotLocale = new Polyglot({ phrases: phrases, locale: 'hr-HR' });
|
||||
|
||||
expect(polyglotLocale.t('n_guests', 1)).to.equal('1 gost');
|
||||
expect(polyglotLocale.t('n_guests', 11)).to.equal('11 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 21)).to.equal('21 gost');
|
||||
|
||||
expect(polyglotLocale.t('n_guests', 2)).to.equal('2 gosta');
|
||||
expect(polyglotLocale.t('n_guests', 3)).to.equal('3 gosta');
|
||||
expect(polyglotLocale.t('n_guests', 4)).to.equal('4 gosta');
|
||||
|
||||
expect(polyglotLocale.t('n_guests', 12)).to.equal('12 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 13)).to.equal('13 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 14)).to.equal('14 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 112)).to.equal('112 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 113)).to.equal('113 gostiju');
|
||||
expect(polyglotLocale.t('n_guests', 114)).to.equal('114 gostiju');
|
||||
});
|
||||
|
||||
it('pluralizes in Croatian (vote) Test', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} glas',
|
||||
'%{smart_count} glasa',
|
||||
'%{smart_count} glasova'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglotLocale = new Polyglot({ phrases: phrases, locale: 'hr-HR' });
|
||||
|
||||
forEach([1, 21, 31, 101], function (c) {
|
||||
expect(polyglotLocale.t('n_votes', c)).to.equal(c + ' glas');
|
||||
});
|
||||
forEach([2, 3, 4, 22, 23, 24, 32, 33, 34], function (c) {
|
||||
expect(polyglotLocale.t('n_votes', c)).to.equal(c + ' glasa');
|
||||
});
|
||||
forEach([0, 5, 6, 11, 12, 13, 14, 15, 16, 17, 25, 26, 35, 36, 112, 113, 114], function (c) {
|
||||
expect(polyglotLocale.t('n_votes', c)).to.equal(c + ' glasova');
|
||||
});
|
||||
|
||||
var polyglotLanguageCode = new Polyglot({ phrases: phrases, locale: 'hr' });
|
||||
|
||||
forEach([1, 21, 31, 101], function (c) {
|
||||
expect(polyglotLanguageCode.t('n_votes', c)).to.equal(c + ' glas');
|
||||
});
|
||||
forEach([2, 3, 4, 22, 23, 24, 32, 33, 34], function (c) {
|
||||
expect(polyglotLanguageCode.t('n_votes', c)).to.equal(c + ' glasa');
|
||||
});
|
||||
forEach([0, 5, 6, 11, 12, 13, 14, 15, 16, 17, 25, 26, 35, 36, 112, 113, 114], function (c) {
|
||||
expect(polyglotLanguageCode.t('n_votes', c)).to.equal(c + ' glasova');
|
||||
});
|
||||
});
|
||||
|
||||
it('pluralizes in Serbian (Latin & Cyrillic)', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} miš',
|
||||
'%{smart_count} miša',
|
||||
'%{smart_count} miševa'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglotLatin = new Polyglot({ phrases: phrases, locale: 'srl-RS' });
|
||||
|
||||
expect(polyglotLatin.t('n_votes', 1)).to.equal('1 miš');
|
||||
expect(polyglotLatin.t('n_votes', 11)).to.equal('11 miševa');
|
||||
expect(polyglotLatin.t('n_votes', 101)).to.equal('101 miš');
|
||||
expect(polyglotLatin.t('n_votes', 932)).to.equal('932 miša');
|
||||
expect(polyglotLatin.t('n_votes', 324)).to.equal('324 miša');
|
||||
expect(polyglotLatin.t('n_votes', 12)).to.equal('12 miševa');
|
||||
expect(polyglotLatin.t('n_votes', 13)).to.equal('13 miševa');
|
||||
expect(polyglotLatin.t('n_votes', 14)).to.equal('14 miševa');
|
||||
expect(polyglotLatin.t('n_votes', 15)).to.equal('15 miševa');
|
||||
expect(polyglotLatin.t('n_votes', 0)).to.equal('0 miševa');
|
||||
|
||||
var polyglotCyrillic = new Polyglot({ phrases: phrases, locale: 'sr-RS' });
|
||||
|
||||
expect(polyglotCyrillic.t('n_votes', 1)).to.equal('1 miš');
|
||||
expect(polyglotCyrillic.t('n_votes', 11)).to.equal('11 miševa');
|
||||
expect(polyglotCyrillic.t('n_votes', 101)).to.equal('101 miš');
|
||||
expect(polyglotCyrillic.t('n_votes', 932)).to.equal('932 miša');
|
||||
expect(polyglotCyrillic.t('n_votes', 324)).to.equal('324 miša');
|
||||
expect(polyglotCyrillic.t('n_votes', 12)).to.equal('12 miševa');
|
||||
expect(polyglotCyrillic.t('n_votes', 13)).to.equal('13 miševa');
|
||||
expect(polyglotCyrillic.t('n_votes', 14)).to.equal('14 miševa');
|
||||
expect(polyglotCyrillic.t('n_votes', 15)).to.equal('15 miševa');
|
||||
expect(polyglotCyrillic.t('n_votes', 0)).to.equal('0 miševa');
|
||||
});
|
||||
|
||||
it('pluralizes in Bosnian (Latin & Cyrillic)', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} članak',
|
||||
'%{smart_count} članka',
|
||||
'%{smart_count} članaka'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglotLatin = new Polyglot({ phrases: phrases, locale: 'bs-Latn-BA' });
|
||||
|
||||
expect(polyglotLatin.t('n_votes', 1)).to.equal('1 članak');
|
||||
expect(polyglotLatin.t('n_votes', 11)).to.equal('11 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 101)).to.equal('101 članak');
|
||||
expect(polyglotLatin.t('n_votes', 932)).to.equal('932 članka');
|
||||
expect(polyglotLatin.t('n_votes', 324)).to.equal('324 članka');
|
||||
expect(polyglotLatin.t('n_votes', 12)).to.equal('12 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 13)).to.equal('13 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 14)).to.equal('14 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 15)).to.equal('15 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 112)).to.equal('112 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 113)).to.equal('113 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 114)).to.equal('114 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 115)).to.equal('115 članaka');
|
||||
expect(polyglotLatin.t('n_votes', 0)).to.equal('0 članaka');
|
||||
|
||||
var polyglotCyrillic = new Polyglot({ phrases: phrases, locale: 'bs-Cyrl-BA' });
|
||||
|
||||
expect(polyglotCyrillic.t('n_votes', 1)).to.equal('1 članak');
|
||||
expect(polyglotCyrillic.t('n_votes', 11)).to.equal('11 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 101)).to.equal('101 članak');
|
||||
expect(polyglotCyrillic.t('n_votes', 932)).to.equal('932 članka');
|
||||
expect(polyglotCyrillic.t('n_votes', 324)).to.equal('324 članka');
|
||||
expect(polyglotCyrillic.t('n_votes', 12)).to.equal('12 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 13)).to.equal('13 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 14)).to.equal('14 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 15)).to.equal('15 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 112)).to.equal('112 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 113)).to.equal('113 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 114)).to.equal('114 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 115)).to.equal('115 članaka');
|
||||
expect(polyglotCyrillic.t('n_votes', 0)).to.equal('0 članaka');
|
||||
});
|
||||
|
||||
it('pluralizes in Czech', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} komentář',
|
||||
'%{smart_count} komentáře',
|
||||
'%{smart_count} komentářů'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'cs-CZ' });
|
||||
|
||||
expect(polyglot.t('n_votes', 1)).to.equal('1 komentář');
|
||||
expect(polyglot.t('n_votes', 2)).to.equal('2 komentáře');
|
||||
expect(polyglot.t('n_votes', 3)).to.equal('3 komentáře');
|
||||
expect(polyglot.t('n_votes', 4)).to.equal('4 komentáře');
|
||||
expect(polyglot.t('n_votes', 0)).to.equal('0 komentářů');
|
||||
expect(polyglot.t('n_votes', 11)).to.equal('11 komentářů');
|
||||
expect(polyglot.t('n_votes', 12)).to.equal('12 komentářů');
|
||||
expect(polyglot.t('n_votes', 16)).to.equal('16 komentářů');
|
||||
});
|
||||
|
||||
it('pluralizes in Slovenian', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} komentar',
|
||||
'%{smart_count} komentarja',
|
||||
'%{smart_count} komentarji',
|
||||
'%{smart_count} komentarjev'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'sl-SL' });
|
||||
|
||||
forEach([1, 12301, 101, 1001, 201, 301], function (c) {
|
||||
expect(polyglot.t('n_votes', c)).to.equal(c + ' komentar');
|
||||
});
|
||||
|
||||
forEach([2, 102, 202, 302], function (c) {
|
||||
expect(polyglot.t('n_votes', c)).to.equal(c + ' komentarja');
|
||||
});
|
||||
|
||||
forEach([0, 11, 12, 13, 14, 52, 53], function (c) {
|
||||
expect(polyglot.t('n_votes', c)).to.equal(c + ' komentarjev');
|
||||
});
|
||||
});
|
||||
|
||||
it('pluralizes in Turkish', function () {
|
||||
var whatSomeoneTranslated = [
|
||||
'Sepetinizde %{smart_count} X var. Bunu almak istiyor musunuz?',
|
||||
'Sepetinizde %{smart_count} X var. Bunları almak istiyor musunuz?'
|
||||
];
|
||||
var phrases = {
|
||||
n_x_cart: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'tr' });
|
||||
|
||||
expect(polyglot.t('n_x_cart', 1)).to.equal('Sepetinizde 1 X var. Bunu almak istiyor musunuz?');
|
||||
expect(polyglot.t('n_x_cart', 2)).to.equal('Sepetinizde 2 X var. Bunları almak istiyor musunuz?');
|
||||
});
|
||||
|
||||
it('pluralizes in Lithuanian', function () {
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} balsas',
|
||||
'%{smart_count} balsai',
|
||||
'%{smart_count} balsų'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'lt' });
|
||||
|
||||
expect(polyglot.t('n_votes', 0)).to.equal('0 balsų');
|
||||
expect(polyglot.t('n_votes', 1)).to.equal('1 balsas');
|
||||
expect(polyglot.t('n_votes', 2)).to.equal('2 balsai');
|
||||
expect(polyglot.t('n_votes', 9)).to.equal('9 balsai');
|
||||
expect(polyglot.t('n_votes', 10)).to.equal('10 balsų');
|
||||
expect(polyglot.t('n_votes', 11)).to.equal('11 balsų');
|
||||
expect(polyglot.t('n_votes', 12)).to.equal('12 balsų');
|
||||
expect(polyglot.t('n_votes', 90)).to.equal('90 balsų');
|
||||
expect(polyglot.t('n_votes', 91)).to.equal('91 balsas');
|
||||
expect(polyglot.t('n_votes', 92)).to.equal('92 balsai');
|
||||
expect(polyglot.t('n_votes', 102)).to.equal('102 balsai');
|
||||
});
|
||||
|
||||
it('pluralizes in Romanian', function () {
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} zi',
|
||||
'%{smart_count} zile',
|
||||
'%{smart_count} de zile'
|
||||
];
|
||||
var phrases = {
|
||||
n_days: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'ro' });
|
||||
|
||||
expect(polyglot.t('n_days', 0)).to.equal('0 zile');
|
||||
expect(polyglot.t('n_days', 1)).to.equal('1 zi');
|
||||
expect(polyglot.t('n_days', 2)).to.equal('2 zile');
|
||||
expect(polyglot.t('n_days', 10)).to.equal('10 zile');
|
||||
expect(polyglot.t('n_days', 19)).to.equal('19 zile');
|
||||
expect(polyglot.t('n_days', 20)).to.equal('20 de zile');
|
||||
expect(polyglot.t('n_days', 21)).to.equal('21 de zile');
|
||||
expect(polyglot.t('n_days', 100)).to.equal('100 de zile');
|
||||
expect(polyglot.t('n_days', 101)).to.equal('101 de zile');
|
||||
expect(polyglot.t('n_days', 102)).to.equal('102 zile');
|
||||
expect(polyglot.t('n_days', 119)).to.equal('119 zile');
|
||||
expect(polyglot.t('n_days', 120)).to.equal('120 de zile');
|
||||
});
|
||||
|
||||
it('pluralizes in Macedonian', function () {
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} ден',
|
||||
'%{smart_count} дена'
|
||||
];
|
||||
var phrases = {
|
||||
n_days: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'mk' });
|
||||
|
||||
expect(polyglot.t('n_days', 0)).to.equal('0 дена');
|
||||
expect(polyglot.t('n_days', 1)).to.equal('1 ден');
|
||||
expect(polyglot.t('n_days', 2)).to.equal('2 дена');
|
||||
expect(polyglot.t('n_days', 10)).to.equal('10 дена');
|
||||
expect(polyglot.t('n_days', 11)).to.equal('11 дена');
|
||||
expect(polyglot.t('n_days', 21)).to.equal('21 ден');
|
||||
expect(polyglot.t('n_days', 100)).to.equal('100 дена');
|
||||
expect(polyglot.t('n_days', 101)).to.equal('101 ден');
|
||||
expect(polyglot.t('n_days', 111)).to.equal('111 дена');
|
||||
});
|
||||
|
||||
it('pluralizes in Ukrainian', function () {
|
||||
// English would be: "1 vote" / "%{smart_count} votes"
|
||||
var whatSomeoneTranslated = [
|
||||
'%{smart_count} голос',
|
||||
'%{smart_count} голоси',
|
||||
'%{smart_count} голосів'
|
||||
];
|
||||
var phrases = {
|
||||
n_votes: whatSomeoneTranslated.join(' |||| ')
|
||||
};
|
||||
|
||||
var polyglot = new Polyglot({ phrases: phrases, locale: 'uk' });
|
||||
|
||||
// Singular form
|
||||
expect(polyglot.t('n_votes', 1)).to.equal('1 голос');
|
||||
expect(polyglot.t('n_votes', 21)).to.equal('21 голос');
|
||||
|
||||
// Few form
|
||||
expect(polyglot.t('n_votes', 2)).to.equal('2 голоси');
|
||||
expect(polyglot.t('n_votes', 3)).to.equal('3 голоси');
|
||||
expect(polyglot.t('n_votes', 4)).to.equal('4 голоси');
|
||||
|
||||
// Many form
|
||||
expect(polyglot.t('n_votes', 0)).to.equal('0 голосів');
|
||||
expect(polyglot.t('n_votes', 5)).to.equal('5 голосів');
|
||||
expect(polyglot.t('n_votes', 6)).to.equal('6 голосів');
|
||||
expect(polyglot.t('n_votes', 7)).to.equal('7 голосів');
|
||||
expect(polyglot.t('n_votes', 8)).to.equal('8 голосів');
|
||||
expect(polyglot.t('n_votes', 9)).to.equal('9 голосів');
|
||||
expect(polyglot.t('n_votes', 11)).to.equal('11 голосів');
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom pluralRules', function () {
|
||||
var customPluralRules = {
|
||||
pluralTypes: {
|
||||
germanLike: function (n) {
|
||||
// is 1
|
||||
if (n === 1) {
|
||||
return 0;
|
||||
}
|
||||
// everything else
|
||||
return 1;
|
||||
},
|
||||
frenchLike: function (n) {
|
||||
// is 0 or 1
|
||||
if (n <= 1) {
|
||||
return 0;
|
||||
}
|
||||
// everything else
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
pluralTypeToLanguages: {
|
||||
germanLike: ['x1'],
|
||||
frenchLike: ['x2']
|
||||
}
|
||||
};
|
||||
|
||||
var testPhrases = {
|
||||
test_phrase: '%{smart_count} form zero |||| %{smart_count} form one'
|
||||
};
|
||||
|
||||
it('pluralizes in x1', function () {
|
||||
var polyglot = new Polyglot({
|
||||
phrases: testPhrases,
|
||||
locale: 'x1',
|
||||
pluralRules: customPluralRules
|
||||
});
|
||||
|
||||
expect(polyglot.t('test_phrase', 0)).to.equal('0 form one');
|
||||
expect(polyglot.t('test_phrase', 1)).to.equal('1 form zero');
|
||||
expect(polyglot.t('test_phrase', 2)).to.equal('2 form one');
|
||||
});
|
||||
|
||||
it('pluralizes in x2', function () {
|
||||
var polyglot = new Polyglot({
|
||||
phrases: testPhrases,
|
||||
locale: 'x2',
|
||||
pluralRules: customPluralRules
|
||||
});
|
||||
|
||||
expect(polyglot.t('test_phrase', 0)).to.equal('0 form zero');
|
||||
expect(polyglot.t('test_phrase', 1)).to.equal('1 form zero');
|
||||
expect(polyglot.t('test_phrase', 2)).to.equal('2 form one');
|
||||
});
|
||||
|
||||
it('memoizes plural type language correctly and selects the correct locale after several calls', function () {
|
||||
var polyglot = new Polyglot({
|
||||
phrases: {
|
||||
test_phrase: '%{smart_count} Name |||| %{smart_count} Names'
|
||||
},
|
||||
locale: 'x1',
|
||||
pluralRules: customPluralRules
|
||||
});
|
||||
|
||||
expect(polyglot.t('test_phrase', 0)).to.equal('0 Names');
|
||||
expect(polyglot.t('test_phrase', 0)).to.equal('0 Names');
|
||||
expect(polyglot.t('test_phrase', 1)).to.equal('1 Name');
|
||||
expect(polyglot.t('test_phrase', 1)).to.equal('1 Name');
|
||||
expect(polyglot.t('test_phrase', 2)).to.equal('2 Names');
|
||||
expect(polyglot.t('test_phrase', 2)).to.equal('2 Names');
|
||||
});
|
||||
});
|
||||
|
||||
describe('locale', function () {
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot();
|
||||
});
|
||||
|
||||
it('defaults to "en"', function () {
|
||||
expect(polyglot.locale()).to.equal('en');
|
||||
});
|
||||
|
||||
it('gets and sets locale', function () {
|
||||
polyglot.locale('es');
|
||||
expect(polyglot.locale()).to.equal('es');
|
||||
|
||||
polyglot.locale('fr');
|
||||
expect(polyglot.locale()).to.equal('fr');
|
||||
});
|
||||
});
|
||||
|
||||
describe('extend', function () {
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot();
|
||||
});
|
||||
|
||||
it('handles null gracefully', function () {
|
||||
expect(function () { polyglot.extend(null); }).to.not.throw();
|
||||
});
|
||||
|
||||
it('handles undefined gracefully', function () {
|
||||
expect(function () { polyglot.extend(undefined); }).to.not.throw();
|
||||
});
|
||||
|
||||
it('supports multiple extends, overriding old keys', function () {
|
||||
polyglot.extend({ aKey: 'First time' });
|
||||
polyglot.extend({ aKey: 'Second time' });
|
||||
expect(polyglot.t('aKey')).to.equal('Second time');
|
||||
});
|
||||
|
||||
it('does not forget old keys', function () {
|
||||
polyglot.extend({ firstKey: 'Numba one', secondKey: 'Numba two' });
|
||||
polyglot.extend({ secondKey: 'Numero dos' });
|
||||
expect(polyglot.t('firstKey')).to.equal('Numba one');
|
||||
});
|
||||
|
||||
it('supports optional `prefix` argument', function () {
|
||||
polyglot.extend({ click: 'Click', hover: 'Hover' }, 'sidebar');
|
||||
expect(polyglot.phrases['sidebar.click']).to.equal('Click');
|
||||
expect(polyglot.phrases['sidebar.hover']).to.equal('Hover');
|
||||
expect(polyglot.phrases).not.to.have.property('click');
|
||||
});
|
||||
|
||||
it('supports nested object', function () {
|
||||
polyglot.extend({
|
||||
sidebar: {
|
||||
click: 'Click',
|
||||
hover: 'Hover'
|
||||
},
|
||||
nav: {
|
||||
header: {
|
||||
log_in: 'Log In'
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(polyglot.phrases['sidebar.click']).to.equal('Click');
|
||||
expect(polyglot.phrases['sidebar.hover']).to.equal('Hover');
|
||||
expect(polyglot.phrases['nav.header.log_in']).to.equal('Log In');
|
||||
expect(polyglot.phrases).not.to.have.property('click');
|
||||
expect(polyglot.phrases).not.to.have.property('header.log_in');
|
||||
expect(polyglot.phrases).not.to.have.property('log_in');
|
||||
});
|
||||
});
|
||||
|
||||
describe('clear', function () {
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot();
|
||||
});
|
||||
|
||||
it('wipes out old phrases', function () {
|
||||
polyglot.extend({ hiFriend: 'Hi, Friend.' });
|
||||
polyglot.clear();
|
||||
expect(polyglot.t('hiFriend')).to.equal('hiFriend');
|
||||
});
|
||||
});
|
||||
|
||||
describe('replace', function () {
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot();
|
||||
});
|
||||
|
||||
it('wipes out old phrases and replace with new phrases', function () {
|
||||
polyglot.extend({ hiFriend: 'Hi, Friend.', byeFriend: 'Bye, Friend.' });
|
||||
polyglot.replace({ hiFriend: 'Hi, Friend.' });
|
||||
expect(polyglot.t('hiFriend')).to.equal('Hi, Friend.');
|
||||
expect(polyglot.t('byeFriend')).to.equal('byeFriend');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unset', function () {
|
||||
var polyglot;
|
||||
beforeEach(function () {
|
||||
polyglot = new Polyglot();
|
||||
});
|
||||
|
||||
it('handles null gracefully', function () {
|
||||
expect(function () { polyglot.unset(null); }).to.not.throw();
|
||||
});
|
||||
|
||||
it('handles undefined gracefully', function () {
|
||||
expect(function () { polyglot.unset(undefined); }).to.not.throw();
|
||||
});
|
||||
|
||||
it('unsets a key based on a string', function () {
|
||||
polyglot.extend({ test_key: 'test_value' });
|
||||
expect(polyglot.has('test_key')).to.equal(true);
|
||||
|
||||
polyglot.unset('test_key');
|
||||
expect(polyglot.has('test_key')).to.equal(false);
|
||||
});
|
||||
|
||||
it('unsets a key based on an object hash', function () {
|
||||
polyglot.extend({ test_key: 'test_value', foo: 'bar' });
|
||||
expect(polyglot.has('test_key')).to.equal(true);
|
||||
expect(polyglot.has('foo')).to.equal(true);
|
||||
|
||||
polyglot.unset({ test_key: 'test_value', foo: 'bar' });
|
||||
expect(polyglot.has('test_key')).to.equal(false);
|
||||
expect(polyglot.has('foo')).to.equal(false);
|
||||
});
|
||||
|
||||
it('unsets nested objects using recursive prefix call', function () {
|
||||
polyglot.extend({ foo: { bar: 'foobar' } });
|
||||
expect(polyglot.has('foo.bar')).to.equal(true);
|
||||
|
||||
polyglot.unset({ foo: { bar: 'foobar' } });
|
||||
expect(polyglot.has('foo.bar')).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformPhrase', function () {
|
||||
var simple = '%{name} is %{attribute}';
|
||||
var english = '%{smart_count} Name |||| %{smart_count} Names';
|
||||
var arabic = [
|
||||
'ولا صوت',
|
||||
'صوت واحد',
|
||||
'صوتان',
|
||||
'%{smart_count} أصوات',
|
||||
'%{smart_count} صوت',
|
||||
'%{smart_count} صوت'
|
||||
].join(' |||| ');
|
||||
|
||||
it('does simple interpolation', function () {
|
||||
expect(Polyglot.transformPhrase(simple, { name: 'Polyglot', attribute: 'awesome' })).to.equal('Polyglot is awesome');
|
||||
});
|
||||
|
||||
it('removes missing keys', function () {
|
||||
expect(Polyglot.transformPhrase(simple, { name: 'Polyglot' })).to.equal('Polyglot is %{attribute}');
|
||||
});
|
||||
|
||||
it('selects the correct plural form based on smart_count', function () {
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'en')).to.equal('0 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 1 }, 'en')).to.equal('1 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 2 }, 'en')).to.equal('2 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 3 }, 'en')).to.equal('3 Names');
|
||||
});
|
||||
|
||||
it('selects the correct locale', function () {
|
||||
// French rule: "0" is singular
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'fr')).to.equal('0 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 1 }, 'fr')).to.equal('1 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 1.5 }, 'fr')).to.equal('1.5 Name');
|
||||
// French rule: plural starts at 2 included
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 2 }, 'fr')).to.equal('2 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 3 }, 'fr')).to.equal('3 Names');
|
||||
|
||||
// Arabic has 6 rules
|
||||
expect(Polyglot.transformPhrase(arabic, 0, 'ar')).to.equal('ولا صوت');
|
||||
expect(Polyglot.transformPhrase(arabic, 1, 'ar')).to.equal('صوت واحد');
|
||||
expect(Polyglot.transformPhrase(arabic, 2, 'ar')).to.equal('صوتان');
|
||||
expect(Polyglot.transformPhrase(arabic, 3, 'ar')).to.equal('3 أصوات');
|
||||
expect(Polyglot.transformPhrase(arabic, 11, 'ar')).to.equal('11 صوت');
|
||||
expect(Polyglot.transformPhrase(arabic, 102, 'ar')).to.equal('102 صوت');
|
||||
});
|
||||
|
||||
it('defaults to `en`', function () {
|
||||
// French rule: "0" is singular
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 })).to.equal('0 Names');
|
||||
});
|
||||
|
||||
it('ignores a region subtag when choosing a pluralization rule', function () {
|
||||
// French rule: "0" is singular
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'fr-FR')).to.equal('0 Name');
|
||||
});
|
||||
|
||||
it('works without arguments', function () {
|
||||
expect(Polyglot.transformPhrase(english)).to.equal(english);
|
||||
});
|
||||
|
||||
it('respects a number as shortcut for smart_count', function () {
|
||||
expect(Polyglot.transformPhrase(english, 0, 'en')).to.equal('0 Names');
|
||||
expect(Polyglot.transformPhrase(english, 1, 'en')).to.equal('1 Name');
|
||||
expect(Polyglot.transformPhrase(english, 5, 'en')).to.equal('5 Names');
|
||||
});
|
||||
|
||||
it('throws without sane phrase string', function () {
|
||||
expect(function () { Polyglot.transformPhrase(); }).to.throw(TypeError);
|
||||
expect(function () { Polyglot.transformPhrase(null); }).to.throw(TypeError);
|
||||
expect(function () { Polyglot.transformPhrase(32); }).to.throw(TypeError);
|
||||
expect(function () { Polyglot.transformPhrase({}); }).to.throw(TypeError);
|
||||
});
|
||||
|
||||
it('memoizes plural type language correctly and selects the correct locale after several calls', function () {
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'en')).to.equal('0 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'en')).to.equal('0 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 1 }, 'en')).to.equal('1 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 1 }, 'en')).to.equal('1 Name');
|
||||
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'fr')).to.equal('0 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 0 }, 'fr')).to.equal('0 Name');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 2 }, 'fr')).to.equal('2 Names');
|
||||
expect(Polyglot.transformPhrase(english, { smart_count: 2 }, 'fr')).to.equal('2 Names');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user