let i18nextBrowserLanguageDetector detect the lang

This commit is contained in:
s2
2019-04-15 17:55:56 +02:00
parent 84ba6c30f3
commit 0be7831276
147 changed files with 927 additions and 139 deletions

View File

@@ -0,0 +1,40 @@
### v3.0.1
- typescript: fix types [165](https://github.com/i18next/i18next-browser-languageDetector/pull/165)
### v3.0.0
- typescript: add types [164](https://github.com/i18next/i18next-browser-languageDetector/pull/164)
### v2.2.4
- fix [157](https://github.com/i18next/i18next-browser-languageDetector/issues/157)
### v2.2.3
- fix [159](https://github.com/i18next/i18next-browser-languageDetector/pull/159)
### v2.2.2
- Lang by path: skip if language not found [159](https://github.com/i18next/i18next-browser-languageDetector/pull/159)
### v2.2.1
- fixes option validation in path lookup [158](https://github.com/i18next/i18next-browser-languageDetector/issues/158)
- fixes lookup from href for subdomain [157](https://github.com/i18next/i18next-browser-languageDetector/issues/157)
### v2.2.0
- add detector for path and subdomain [PR153](https://github.com/i18next/i18next-browser-languageDetector/pull/153) and [PR152](https://github.com/i18next/i18next-browser-languageDetector/pull/152)
### v2.1.1
- support for fallback language in form of object [151](https://github.com/i18next/i18next-browser-languageDetector/issues/151)
### v2.1.0
- add .js for browser import implementation [PR147](https://github.com/i18next/i18next-browser-languageDetector/pull/147)
### v2.0.0
- [BREAKING] options.excludeCacheFor (array of language codes; default ['cimode']): if a language maps a value in that list the language will not be written to cache (eg. localStorage, cookie). If you use lng cimode in your tests and require it to be cached set the option to false or empty array

22
node_modules/i18next-browser-languagedetector/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 i18next
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

148
node_modules/i18next-browser-languagedetector/README.md generated vendored Normal file
View File

@@ -0,0 +1,148 @@
# Introduction
[![npm version](https://img.shields.io/npm/v/i18next-browser-languagedetector.svg?style=flat-square)](https://www.npmjs.com/package/i18next-browser-languagedetector)
[![Bower](https://img.shields.io/bower/v/i18next-browser-languagedetector.svg)]()
[![David](https://img.shields.io/david/i18next/i18next-browser-languagedetector.svg?style=flat-square)](https://david-dm.org/i18next/i18next-browser-languagedetector)
This is a i18next language detection plugin use to detect user language in the browser with support for:
- cookie
- localStorage
- navigator
- querystring (append `?lng=LANGUAGE` to URL)
- htmlTag
- path
- subdomain
# Getting started
Source can be loaded via [npm](https://www.npmjs.com/package/i18next-browser-languagedetector), bower or [downloaded](https://github.com/i18next/i18next-browser-languagedetector/blob/master/i18nextBrowserLanguageDetector.min.js) from this repo.
```
# npm package
$ npm install i18next-browser-languagedetector
# bower
$ bower install i18next-browser-languagedetector
```
- If you don't use a module loader it will be added to `window.i18nextBrowserLanguageDetector`
Wiring up:
```js
import i18next from 'i18next';
import LngDetector from 'i18next-browser-languagedetector';
i18next
.use(LngDetector)
.init(i18nextOptions);
```
As with all modules you can either pass the constructor function (class) to the i18next.use or a concrete instance.
## Detector Options
```js
{
// order and from where user language should be detected
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],
// keys or params to lookup language from
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
lookupFromPathIndex: 0,
lookupFromSubdomainIndex: 0,
// cache user language on
caches: ['localStorage', 'cookie'],
excludeCacheFor: ['cimode'], // languages to not persist (cookie, localStorage)
// optional expire and domain for set cookie
cookieMinutes: 10,
cookieDomain: 'myDomain',
// optional htmlTag with lang attribute, the default is:
htmlTag: document.documentElement
}
```
Options can be passed in:
**preferred** - by setting options.detection in i18next.init:
```js
import i18next from 'i18next';
import LngDetector from 'i18next-browser-languagedetector';
i18next
.use(LngDetector)
.init({
detection: options
});
```
on construction:
```js
import LngDetector from 'i18next-browser-languagedetector';
const lngDetector = new LngDetector(null, options);
```
via calling init:
```js
import LngDetector from 'i18next-browser-languagedetector';
const lngDetector = new LngDetector();
lngDetector.init(options);
```
## Adding own detection functionality
### interface
```js
export default {
name: 'myDetectorsName',
lookup(options) {
// options -> are passed in options
return 'en';
},
cacheUserLanguage(lng, options) {
// options -> are passed in options
// lng -> current language, will be called after init and on changeLanguage
// store it
}
};
```
### adding it
```js
import LngDetector from 'i18next-browser-languagedetector';
const lngDetector = new LngDetector();
lngDetector.addDetector(myDetector);
i18next
.use(lngDetector)
.init({
detection: options
});
```
Don't forget: You have to add the name of your detector (`myDetectorsName` in this case) to the `order` array in your `options` object. Without that, your detector won't be used. See the [Detector Options section for more](#detector-options).
--------------
<h3 align="center">Gold Sponsors</h3>
<p align="center">
<a href="https://locize.com/" target="_blank">
<img src="https://raw.githubusercontent.com/i18next/i18next/master/assets/locize_sponsor_240.gif" width="240px">
</a>
</p>

View File

@@ -0,0 +1,322 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.i18nextBrowserLanguageDetector = factory());
}(this, function () { 'use strict';
var arr = [];
var each = arr.forEach;
var slice = arr.slice;
function defaults(obj) {
each.call(slice.call(arguments, 1), function (source) {
if (source) {
for (var prop in source) {
if (obj[prop] === undefined) obj[prop] = source[prop];
}
}
});
return obj;
}
var cookie = {
create: function create(name, value, minutes, domain) {
var expires = void 0;
if (minutes) {
var date = new Date();
date.setTime(date.getTime() + minutes * 60 * 1000);
expires = '; expires=' + date.toGMTString();
} else expires = '';
domain = domain ? 'domain=' + domain + ';' : '';
document.cookie = name + '=' + value + expires + ';' + domain + 'path=/';
},
read: function read(name) {
var nameEQ = name + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
},
remove: function remove(name) {
this.create(name, '', -1);
}
};
var cookie$1 = {
name: 'cookie',
lookup: function lookup(options) {
var found = void 0;
if (options.lookupCookie && typeof document !== 'undefined') {
var c = cookie.read(options.lookupCookie);
if (c) found = c;
}
return found;
},
cacheUserLanguage: function cacheUserLanguage(lng, options) {
if (options.lookupCookie && typeof document !== 'undefined') {
cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain);
}
}
};
var querystring = {
name: 'querystring',
lookup: function lookup(options) {
var found = void 0;
if (typeof window !== 'undefined') {
var query = window.location.search.substring(1);
var params = query.split('&');
for (var i = 0; i < params.length; i++) {
var pos = params[i].indexOf('=');
if (pos > 0) {
var key = params[i].substring(0, pos);
if (key === options.lookupQuerystring) {
found = params[i].substring(pos + 1);
}
}
}
}
return found;
}
};
var hasLocalStorageSupport = void 0;
try {
hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null;
var testKey = 'i18next.translate.boo';
window.localStorage.setItem(testKey, 'foo');
window.localStorage.removeItem(testKey);
} catch (e) {
hasLocalStorageSupport = false;
}
var localStorage = {
name: 'localStorage',
lookup: function lookup(options) {
var found = void 0;
if (options.lookupLocalStorage && hasLocalStorageSupport) {
var lng = window.localStorage.getItem(options.lookupLocalStorage);
if (lng) found = lng;
}
return found;
},
cacheUserLanguage: function cacheUserLanguage(lng, options) {
if (options.lookupLocalStorage && hasLocalStorageSupport) {
window.localStorage.setItem(options.lookupLocalStorage, lng);
}
}
};
var navigator$1 = {
name: 'navigator',
lookup: function lookup(options) {
var found = [];
if (typeof navigator !== 'undefined') {
if (navigator.languages) {
// chrome only; not an array, so can't use .push.apply instead of iterating
for (var i = 0; i < navigator.languages.length; i++) {
found.push(navigator.languages[i]);
}
}
if (navigator.userLanguage) {
found.push(navigator.userLanguage);
}
if (navigator.language) {
found.push(navigator.language);
}
}
return found.length > 0 ? found : undefined;
}
};
var htmlTag = {
name: 'htmlTag',
lookup: function lookup(options) {
var found = void 0;
var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null);
if (htmlTag && typeof htmlTag.getAttribute === 'function') {
found = htmlTag.getAttribute('lang');
}
return found;
}
};
var path = {
name: 'path',
lookup: function lookup(options) {
var found = void 0;
if (typeof window !== 'undefined') {
var language = window.location.pathname.match(/\/([a-zA-Z-]*)/g);
if (language instanceof Array) {
if (typeof options.lookupFromPathIndex === 'number') {
if (typeof language[options.lookupFromPathIndex] !== 'string') {
return undefined;
}
found = language[options.lookupFromPathIndex].replace('/', '');
} else {
found = language[0].replace('/', '');
}
}
}
return found;
}
};
var subdomain = {
name: 'subdomain',
lookup: function lookup(options) {
var found = void 0;
if (typeof window !== 'undefined') {
var language = window.location.href.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi);
if (language instanceof Array) {
if (typeof options.lookupFromSubdomainIndex === 'number') {
found = language[options.lookupFromSubdomainIndex].replace('http://', '').replace('https://', '').replace('.', '');
} else {
found = language[0].replace('http://', '').replace('https://', '').replace('.', '');
}
}
}
return found;
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function getDefaults() {
return {
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag'],
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
// cache user language
caches: ['localStorage'],
excludeCacheFor: ['cimode']
//cookieMinutes: 10,
//cookieDomain: 'myDomain'
};
}
var Browser = function () {
function Browser(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Browser);
this.type = 'languageDetector';
this.detectors = {};
this.init(services, options);
}
_createClass(Browser, [{
key: 'init',
value: function init(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
this.services = services;
this.options = defaults(options, this.options || {}, getDefaults());
// backwards compatibility
if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex;
this.i18nOptions = i18nOptions;
this.addDetector(cookie$1);
this.addDetector(querystring);
this.addDetector(localStorage);
this.addDetector(navigator$1);
this.addDetector(htmlTag);
this.addDetector(path);
this.addDetector(subdomain);
}
}, {
key: 'addDetector',
value: function addDetector(detector) {
this.detectors[detector.name] = detector;
}
}, {
key: 'detect',
value: function detect(detectionOrder) {
var _this = this;
if (!detectionOrder) detectionOrder = this.options.order;
var detected = [];
detectionOrder.forEach(function (detectorName) {
if (_this.detectors[detectorName]) {
var lookup = _this.detectors[detectorName].lookup(_this.options);
if (lookup && typeof lookup === 'string') lookup = [lookup];
if (lookup) detected = detected.concat(lookup);
}
});
var found = void 0;
detected.forEach(function (lng) {
if (found) return;
var cleanedLng = _this.services.languageUtils.formatLanguageCode(lng);
if (_this.services.languageUtils.isWhitelisted(cleanedLng)) found = cleanedLng;
});
if (!found) {
var fallbacks = this.i18nOptions.fallbackLng;
if (typeof fallbacks === 'string') fallbacks = [fallbacks];
if (!fallbacks) fallbacks = [];
if (Object.prototype.toString.apply(fallbacks) === '[object Array]') {
found = fallbacks[0];
} else {
found = fallbacks[0] || fallbacks.default && fallbacks.default[0];
}
};
return found;
}
}, {
key: 'cacheUserLanguage',
value: function cacheUserLanguage(lng, caches) {
var _this2 = this;
if (!caches) caches = this.options.caches;
if (!caches) return;
if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return;
caches.forEach(function (cacheName) {
if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options);
});
}
}]);
return Browser;
}();
Browser.type = 'languageDetector';
return Browser;
}));

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,66 @@
declare namespace I18nextBrowserLanguageDetector {
interface DetectorOptions {
/**
* order and from where user language should be detected
*/
order?: Array<"querystring" | "cookie" | "localStorage" | "navigator" | "htmlTag" | string>;
/**
* keys or params to lookup language from
*/
lookupQuerystring?: string;
lookupCookie?: string;
lookupLocalStorage?: string;
/**
* cache user language on
*/
caches?: string[];
/**
* languages to not persist (cookie, localStorage)
*/
excludeCacheFor?: string[];
/**
* optional expire and domain for set cookie
* @default 10
*/
cookieMinutes?: number;
cookieDomain?: string;
/**
* optional htmlTag with lang attribute
* @default document.documentElement
*/
htmlTag?: HTMLElement | null;
}
interface CustomDetector {
name: string;
cacheUserLanguage?(lng: string, options: DetectorOptions): void;
lookup(options: DetectorOptions): string | undefined;
}
}
export default class I18nextBrowserLanguageDetector {
constructor(services?: any, options?: I18nextBrowserLanguageDetector.DetectorOptions);
/**
* Adds detector.
*/
addDetector(detector: I18nextBrowserLanguageDetector.CustomDetector): I18nextBrowserLanguageDetector;
/**
* Initializes detector.
*/
init(services?: any, options?: I18nextBrowserLanguageDetector.DetectorOptions): void;
detect(detectionOrder?: I18nextBrowserLanguageDetector.DetectorOptions): string | undefined;
cacheUserLanguage(lng: string, caches?: string[]): void;
type: "languageDetector";
detectors: { [key: string]: any };
services: any;
i18nOptions: any;
}

View File

@@ -0,0 +1,5 @@
/* eslint no-var: 0 */
var main = require('./dist/commonjs/index.js').default;
module.exports = main;
module.exports.default = main;

View File

@@ -0,0 +1,89 @@
{
"_from": "i18next-browser-languagedetector",
"_id": "i18next-browser-languagedetector@3.0.1",
"_inBundle": false,
"_integrity": "sha512-WFjPLNPWl62uu07AHY2g+KsC9qz0tyMq+OZEB/H7N58YKL/JLiCz9U709gaR20Mule/Ppn+uyfVx5REJJjn1HA==",
"_location": "/i18next-browser-languagedetector",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "i18next-browser-languagedetector",
"name": "i18next-browser-languagedetector",
"escapedName": "i18next-browser-languagedetector",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-3.0.1.tgz",
"_shasum": "a47c43176e8412c91e808afb7c6eb5367649aa8e",
"_spec": "i18next-browser-languagedetector",
"_where": "F:\\projects\\vanillajs-seed",
"author": {
"name": "Jan Mühlemann",
"email": "jan.muehlemann@gmail.com",
"url": "https://github.com/jamuhl"
},
"bugs": {
"url": "https://github.com/i18next/i18next-browser-languageDetector/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "language detector used in browser environment for i18next",
"devDependencies": {
"babel-cli": "6.22.2",
"babel-core": "6.22.1",
"babel-eslint": "7.1.1",
"babel-plugin-external-helpers": "6.22.0",
"babel-plugin-transform-es2015-classes": "6.22.0",
"babel-preset-es2015": "6.22.0",
"babel-preset-stage-0": "6.22.0",
"dtslint": "^0.4.2",
"eslint": "2.8.0",
"eslint-config-airbnb": "7.0.0",
"mkdirp": "0.5.1",
"rimraf": "2.5.2",
"rollup": "0.25.8",
"rollup-plugin-babel": "2.4.0",
"rollup-plugin-node-resolve": "1.7.1",
"rollup-plugin-uglify": "0.2.0",
"tslint": "^5.12.1",
"typescript": "^3.3.1",
"yargs": "4.6.0"
},
"homepage": "https://github.com/i18next/i18next-browser-languageDetector",
"jsnext:main": "dist/es/index.js",
"keywords": [
"i18next",
"i18next-languageDetector"
],
"license": "MIT",
"main": "./index.js",
"name": "i18next-browser-languagedetector",
"repository": {
"type": "git",
"url": "git+https://github.com/i18next/i18next-browser-languageDetector.git"
},
"scripts": {
"build": "npm run clean && npm run build:cjs && npm run build:es && npm run build:umd && npm run copy",
"build:amd": "rollup -c rollup.config.js --format amd && rollup -c rollup.config.js --format umd --uglify",
"build:cjs": "babel src --out-dir dist/commonjs",
"build:es": "BABEL_ENV=jsnext babel src --out-dir dist/es",
"build:iife": "rollup -c rollup.config.js --format iife && rollup -c rollup.config.js --format iife --uglify",
"build:umd": "rollup -c rollup.config.js --format umd && rollup -c rollup.config.js --format umd --uglify",
"clean": "rimraf dist && mkdirp dist",
"copy": "cp ./dist/umd/i18nextBrowserLanguageDetector.min.js ./i18nextBrowserLanguageDetector.min.js && cp ./dist/umd/i18nextBrowserLanguageDetector.js ./i18nextBrowserLanguageDetector.js",
"postversion": "git push && git push --tags",
"pretest": "npm run test:typescript",
"preversion": "npm run build && git push",
"test": "echo 'TODO'",
"test:typescript": "tslint --project tsconfig.json"
},
"types": "./index.d.ts",
"version": "3.0.1"
}

View File

@@ -0,0 +1,31 @@
import babel from 'rollup-plugin-babel';
import uglify from 'rollup-plugin-uglify';
import nodeResolve from 'rollup-plugin-node-resolve';
import { argv } from 'yargs';
const format = argv.format || argv.f || 'iife';
const compress = argv.uglify;
const babelOptions = {
exclude: 'node_modules/**',
presets: [['es2015', { modules: false }], 'stage-0'],
babelrc: false
};
const dest = {
amd: `dist/amd/i18nextBrowserLanguageDetector${compress ? '.min' : ''}.js`,
umd: `dist/umd/i18nextBrowserLanguageDetector${compress ? '.min' : ''}.js`,
iife: `dist/iife/i18nextBrowserLanguageDetector${compress ? '.min' : ''}.js`
}[format];
export default {
entry: 'src/index.js',
format,
plugins: [
babel(babelOptions),
nodeResolve({ jsnext: true })
].concat(compress ? uglify() : []),
moduleName: 'i18nextBrowserLanguageDetector',
// moduleId: 'i18nextBrowserLanguageDetector',
dest
};

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"jsx": "react",
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noEmit": true,
"baseUrl": ".",
"paths": { "i18next-browser-languagedetector": ["./index.d.ts"] }
},
"include": ["./indext.d.ts", "./test/**/*.ts*"]
}

View File

@@ -0,0 +1,7 @@
{
"defaultSeverity": "error",
"extends": "dtslint/dtslint.json",
"rules": {
"semicolon": false
}
}