From 13182a3a8e17f84c11f5fa8f20e2c3e004a26eb6 Mon Sep 17 00:00:00 2001 From: florrain Date: Sun, 2 Apr 2017 23:41:43 +0200 Subject: [PATCH 01/17] Move from CoffeeScript to ES6 - Addition of a gulpfile to manage the build pipeline + TDD task (mocha, eslint) - ESLint integration - Babel integration - Upgrade of all dev dependencies - Translate main source file and tests to ES6 - Breaking off main file into separate ES6 class files --- .babelrc | 3 + .eslintignore | 2 + .eslintrc | 8 +++ examples/express.js | 30 +++++---- examples/http.js | 26 +++---- gulpfile.js | 52 ++++++++++++++ lib/index.js | 161 -------------------------------------------- lib/test.js | 146 --------------------------------------- package.json | 33 ++++++--- src/index.coffee | 108 ----------------------------- src/index.js | 25 +++++++ src/locale.js | 31 +++++++++ src/locales.js | 114 +++++++++++++++++++++++++++++++ src/test.coffee | 114 ------------------------------- test/.eslintrc | 5 ++ test/mocha.opts | 2 - test/tests.js | 122 +++++++++++++++++++++++++++++++++ 17 files changed, 417 insertions(+), 565 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 gulpfile.js delete mode 100644 lib/index.js delete mode 100644 lib/test.js delete mode 100644 src/index.coffee create mode 100644 src/index.js create mode 100644 src/locale.js create mode 100644 src/locales.js delete mode 100644 src/test.coffee create mode 100644 test/.eslintrc delete mode 100644 test/mocha.opts create mode 100644 test/tests.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..c13c5f6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..afbaad8 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +dist/* +gulpfile.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..76a177f --- /dev/null +++ b/.eslintrc @@ -0,0 +1,8 @@ +{ + "extends": "airbnb", + "rules": { + "func-names": ["error", "never"], + "no-underscore-dangle": ["error", { "allowAfterThis": true }], + "prefer-arrow-callback": 0 + } +} diff --git a/examples/express.js b/examples/express.js index b007bb9..0c653ad 100644 --- a/examples/express.js +++ b/examples/express.js @@ -1,17 +1,19 @@ -var http = require("http") - , express = require("express") - , locale = require("../lib") - , supported = ["en", "en_US", "ja"] - , app = express.createServer(locale(supported)) +// const http = require('http'); +const express = require('express'); // eslint-disable-line import/no-extraneous-dependencies -app.get("/", function(req, res) { - res.header("Content-Type", "text/plain") +const locale = require('../src'); + +const supported = ['en', 'en_US', 'ja']; +const app = express.createServer(locale(supported)); + +app.get('/', function (req, res) { + res.header('Content-Type', 'text/plain'); res.send( - "You asked for: " + req.headers["accept-language"] + "\n" + - "We support: " + supported + "\n" + - "Our default is: " + locale.Locale["default"] + "\n" + - "The best match is: " + req.locale + "\n" - ) -}) + `You asked for: ${req.headers['accept-language']} + We support: ${supported} + Our default is: ${locale.Locale.default} + The best match is: ${req.locale}` // eslint-disable-line comma-dangle + ); +}); -app.listen(8000) \ No newline at end of file +app.listen(8000); diff --git a/examples/http.js b/examples/http.js index 2dbe2e4..b66f011 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,14 +1,16 @@ -var http = require("http") - , locale = require("../lib") - , supported = new locale.Locales(["en", "en_US", "ja"]) +const http = require('http'); -http.createServer(function(req, res) { - var locales = new locale.Locales(req.headers["accept-language"]) - res.writeHeader(200, {"Content-Type": "text/plain"}) +const locale = require('../src'); + +const supported = new locale.Locales(['en', 'en_US', 'ja']); + +http.createServer(function (req, res) { + const locales = new locale.Locales(req.headers['accept-language']); + res.writeHeader(200, { 'Content-Type': 'text/plain' }); res.end( - "You asked for: " + req.headers["accept-language"] + "\n" + - "We support: " + supported + "\n" + - "Our default is: " + locale.Locale["default"] + "\n" + - "The best match is: " + locales.best(supported) + "\n" - ) -}).listen(8000) \ No newline at end of file + `You asked for: ${req.headers['accept-language']} + We support: ${supported} + Our default is: ${locale.Locale.default} + The best match is: ' + ${locales.best(supported)}` // eslint-disable-line comma-dangle + ); +}).listen(8000); diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..f150755 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,52 @@ +var gulp = require('gulp'); +var concat = require('gulp-concat'); +var uglify = require('gulp-uglify'); +var sourcemaps = require('gulp-sourcemaps'); +var babel = require('gulp-babel'); +var mocha = require('gulp-mocha'); +var gutil = require('gulp-util'); +var eslint = require('gulp-eslint'); +var del = require('del'); + +var paths = { + scripts: ['src/**.js'], + tests: ['test/tests.js'], +}; + +gulp.task('clean', function () { + return del(['build']); +}); + +gulp.task('build', ['clean'], function () { + return gulp.src(paths.scripts) + .pipe(sourcemaps.init()) + .pipe(babel({ + presets: ['es2015'], + })) + .pipe(uglify()) + .pipe(concat('min.js')) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('dist')); +}); + +gulp.task('lint', function () { + return gulp.src(['**/*.js', '!node_modules/**', '!dist/**']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + +gulp.task('mocha', function () { + return gulp.src(paths.tests, { read: false }) + .pipe(mocha({ + reporter: 'spec', + compilers: 'js:babel-core/register', + })) + .on('error', gutil.log); +}); + +gulp.task('watch', function () { + gulp.watch([paths.scripts, paths.tests], ['lint', 'mocha']); +}); + +gulp.task('default', ['watch']); diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index e8b194b..0000000 --- a/lib/index.js +++ /dev/null @@ -1,161 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var Locale, Locales, app, _ref, - __slice = [].slice; - - app = function(supported, def) { - if (!(supported instanceof Locales)) { - supported = new Locales(supported, def); - supported.index(); - } - return function(req, res, next) { - var bestLocale, locales; - locales = new Locales(req.headers["accept-language"]); - bestLocale = locales.best(supported); - req.locale = String(bestLocale); - req.rawLocale = bestLocale; - return next(); - }; - }; - - app.Locale = (function() { - var serialize; - - Locale["default"] = new Locale(process.env.LANG || "en_US"); - - function Locale(str) { - var country, language, match, normalized; - if (!(match = str != null ? str.match(/[a-z]+/gi) : void 0)) { - return; - } - language = match[0], country = match[1]; - this.code = str; - this.language = language.toLowerCase(); - if (country) { - this.country = country.toUpperCase(); - } - normalized = [this.language]; - if (this.country) { - normalized.push(this.country); - } - this.normalized = normalized.join("_"); - } - - serialize = function() { - if (this.language) { - return this.code; - } else { - return null; - } - }; - - Locale.prototype.toString = serialize; - - Locale.prototype.toJSON = serialize; - - return Locale; - - })(); - - app.Locales = (function() { - var serialize; - - Locales.prototype.length = 0; - - Locales.prototype._index = null; - - Locales.prototype.sort = Array.prototype.sort; - - Locales.prototype.push = Array.prototype.push; - - function Locales(str, def) { - var item, locale, q, _i, _len, _ref, _ref1; - if (def) { - this["default"] = new Locale(def); - } - if (!str) { - return; - } - _ref = (String(str)).split(","); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - item = _ref[_i]; - _ref1 = item.split(";"), locale = _ref1[0], q = _ref1[1]; - locale = new Locale(locale.trim()); - locale.score = q ? +q.slice(2) || 0 : 1; - this.push(locale); - } - this.sort(function(a, b) { - return b.score - a.score; - }); - } - - Locales.prototype.index = function() { - var idx, locale, _i, _len; - if (!this._index) { - this._index = {}; - for (idx = _i = 0, _len = this.length; _i < _len; idx = ++_i) { - locale = this[idx]; - this._index[locale.normalized] = idx; - } - } - return this._index; - }; - - Locales.prototype.best = function(locales) { - var index, item, l, languageIndex, locale, normalizedIndex, setLocale, _i, _j, _len, _len1; - setLocale = function(l) { - var r; - r = l; - r.defaulted = false; - return r; - }; - locale = Locale["default"]; - if (locales && locales["default"]) { - locale = locales["default"]; - } - locale.defaulted = true; - if (!locales) { - if (this[0]) { - locale = this[0]; - locale.defaulted = true; - } - return locale; - } - index = locales.index(); - for (_i = 0, _len = this.length; _i < _len; _i++) { - item = this[_i]; - normalizedIndex = index[item.normalized]; - languageIndex = index[item.language]; - if (normalizedIndex != null) { - return setLocale(locales[normalizedIndex]); - } else if (languageIndex != null) { - return setLocale(locales[languageIndex]); - } else { - for (_j = 0, _len1 = locales.length; _j < _len1; _j++) { - l = locales[_j]; - if (l.language === item.language) { - return setLocale(l); - } - } - } - } - return locale; - }; - - serialize = function() { - return __slice.call(this); - }; - - Locales.prototype.toJSON = serialize; - - Locales.prototype.toString = function() { - return String(this.toJSON()); - }; - - return Locales; - - })(); - - _ref = module.exports = app, Locale = _ref.Locale, Locales = _ref.Locales; - -}).call(this); diff --git a/lib/test.js b/lib/test.js deleted file mode 100644 index 981416a..0000000 --- a/lib/test.js +++ /dev/null @@ -1,146 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var assert, defaultLocale, express, http, locale, server; - - http = require("http"); - - assert = require("assert"); - - express = require("express"); - - locale = require("./"); - - server = null; - - defaultLocale = locale.Locale["default"]; - - before(function(callback) { - var app; - app = express(); - app.use(locale(["en-US", "fr", "fr-CA", "en", "ja", "de", "da-DK"])); - app.get("/", function(req, res) { - res.set("content-language", req.locale); - res.set("defaulted", req.rawLocale.defaulted); - res.set("Connection", "close"); - return res.send(200); - }); - return server = app.listen(8001, callback); - }); - - describe("Defaults", function() { - it("should use the environment language as default.", function(callback) { - return http.get({ - port: 8001 - }, function(res) { - assert.equal(res.headers["content-language"], defaultLocale); - assert.equal(true, !!res.headers["defaulted"]); - return callback(); - }); - }); - it("should fallback to the default for unsupported languages.", function(callback) { - return http.get({ - port: 8001, - headers: { - "Accept-Language": "es-ES" - } - }, function(res) { - assert.equal(res.headers["content-language"], defaultLocale); - assert.equal(true, !!res.headers["defaulted"]); - return callback(); - }); - }); - return it("should fallback to the instance default for unsupported languages if instance default is defined.", function(callback) { - var instanceDefault, supportedLocales; - instanceDefault = 'en_GB'; - supportedLocales = new locale.Locales(["da-DK"], instanceDefault); - assert.equal(((new locale.Locales("cs,en-US;q=0.8,en;q=0.6")).best(supportedLocales)).toString(), instanceDefault); - return callback(); - }); - }); - - describe("Priority", function() { - it("should fallback to a more general language if a country specific language isn't available.", function(callback) { - return http.get({ - port: 8001, - headers: { - "Accept-Language": "en-GB" - } - }, function(res) { - assert.equal(res.headers["content-language"], "en", "Unsupported country should fallback to countryless language"); - assert.equal(false, !res.headers["defaulted"]); - return callback(); - }); - }); - it("should use the highest quality language supported, regardless of order.", function(callback) { - http.get({ - port: 8001, - headers: { - "Accept-Language": "en;q=.8, ja" - } - }, function(res) { - assert.equal(res.headers["content-language"], "ja", "Highest quality language supported should be used, regardless of order."); - return assert.equal(false, !res.headers["defaulted"]); - }); - http.get({ - port: 8001, - headers: { - "Accept-Language": "fr-FR, ja-JA;q=0.5" - } - }, function(res) { - assert.equal(res.headers["content-language"], "fr", "Highest quality language supported should be used, regardless of order."); - return assert.equal(false, !res.headers["defaulted"]); - }); - return http.get({ - port: 8001, - headers: { - "Accept-Language": "en-US,en;q=0.93,es-ES;q=0.87,es;q=0.80,it-IT;q=0.73,it;q=0.67,de-DE;q=0.60,de;q=0.53,fr-FR;q=0.47,fr;q=0.40,ja;q=0.33,zh-Hans-CN;q=0.27,zh-Hans;q=0.20,ar-SA;q=0.13,ar;q=0.067" - } - }, function(res) { - assert.equal(res.headers["content-language"], "en-US", "Highest quality language supported should be used, regardless of order."); - assert.equal(false, !res.headers["defaulted"]); - return callback(); - }); - }); - it("should use a country specific language when an unsupported general language is requested", function(callback) { - return http.get({ - port: 8001, - headers: { - "Accept-Language": "da" - } - }, function(res) { - assert.equal(res.headers["content-language"], "da-DK"); - return callback(); - }); - }); - it("should fallback to a country specific language even when there's a lower quality exact match", function(callback) { - return http.get({ - port: 8001, - headers: { - "Accept-Language": "ja;q=.8, da" - } - }, function(res) { - assert.equal(res.headers["content-language"], "da-DK"); - assert.equal(false, !res.headers["defaulted"]); - return callback(); - }); - }); - return it("should match country-specific language codes even when the separator is different", function(callback) { - return http.get({ - port: 8001, - headers: { - "Accept-Language": "fr_CA" - } - }, function(res) { - assert.equal(res.headers["content-language"], "fr-CA"); - assert.equal(false, !res.headers["defaulted"]); - return callback(); - }); - }); - }); - - after(function() { - server.close(); - return process.exit(0)(); - }); - -}).call(this); diff --git a/package.json b/package.json index 23bd589..2008591 100644 --- a/package.json +++ b/package.json @@ -8,22 +8,39 @@ "type": "git", "url": "git://github.com/florrain/locale.git" }, - "main": "./lib", + "main": "./src", "scripts": { - "test": "./node_modules/.bin/mocha ./src/test.coffee", - "prepublish": "coffee -o lib/ -c src/" + "test": "./node_modules/.bin/mocha ./test/tests.js", + "prepublish": "gulp build" }, "engines": { "node": ">0.8.x" }, "dependencies": {}, "devDependencies": { - "coffee-script": "~1.6.0", - "express": "~3.0.0", - "mocha": "~1.13.0" + "babel-core": "^6.24.0", + "babel-preset-es2015": "^6.24.0", + "del": "^2.2.2", + "eslint": "^3.18.0", + "eslint-config-airbnb": "^14.1.0", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jsx-a11y": "^4.0.0", + "eslint-plugin-react": "^6.10.3", + "express": "^3.0.6", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-concat": "^2.6.1", + "gulp-eslint": "^3.0.1", + "gulp-mocha": "^4.1.0", + "gulp-sourcemaps": "^2.4.1", + "gulp-uglify": "^2.1.2", + "gulp-util": "^3.0.8", + "mocha": "^3.2.0" }, "contributors": [ "Jed Smith (https://github.com/jed)", - "D. Stuart Freeman (https://github.com/stuartf)" - ] + "D. Stuart Freeman (https://github.com/stuartf)", + "Florian Lorrain (https://github.com/florrain)" + ], + "license": "MIT" } diff --git a/src/index.coffee b/src/index.coffee deleted file mode 100644 index 7595d8e..0000000 --- a/src/index.coffee +++ /dev/null @@ -1,108 +0,0 @@ -app = (supported, def) -> - unless supported instanceof Locales - supported = new Locales supported, def - do supported.index - - (req, res, next) -> - locales = new Locales req.headers["accept-language"] - - bestLocale = locales.best supported - req.locale = String bestLocale - req.rawLocale = bestLocale - do next - -class app.Locale - @default: new Locale process.env.LANG or "en_US" - - constructor: (str) -> - return unless match = str?.match /[a-z]+/gi - - [language, country] = match - - @code = str - @language = do language.toLowerCase - @country = do country.toUpperCase if country - - normalized = [@language] - normalized.push @country if @country - @normalized = normalized.join "_" - - serialize = -> - if @language - return @code - else - return null - - toString: serialize - toJSON: serialize - -class app.Locales - length: 0 - _index: null - - sort: Array::sort - push: Array::push - - constructor: (str, def) -> - if def - @default = new Locale def - - return unless str - - for item in (String str).split "," - [locale, q] = item.split ";" - - locale = new Locale do locale.trim - locale.score = if q then +q[2..] or 0 else 1 - - @push locale - - @sort (a, b) -> b.score - a.score - - index: -> - unless @_index - @_index = {} - @_index[locale.normalized] = idx for locale, idx in @ - - @_index - - best: (locales) -> - setLocale = (l) -> # When don't return the default - r = l - r.defaulted = false - return r - - locale = Locale.default - if locales and locales.default - locale = locales.default - locale.defaulted = true - - unless locales - if @[0] - locale = @[0] - locale.defaulted = true - return locale - - index = do locales.index - - for item in @ - normalizedIndex = index[item.normalized] - languageIndex = index[item.language] - - if normalizedIndex? then return setLocale(locales[normalizedIndex]) - else if languageIndex? then return setLocale(locales[languageIndex]) - else - for l in locales - if l.language == item.language then return setLocale(l) - - locale - - serialize = -> - [@...] - - toJSON: serialize - - toString: -> - String do @toJSON - -{Locale, Locales} = module.exports = app diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..419c807 --- /dev/null +++ b/src/index.js @@ -0,0 +1,25 @@ +const Locale = require('./locale'); +const Locales = require('./locales'); + +const app = function (supported, def) { + let supportedLocales = supported; + + if (!(supportedLocales instanceof Locales)) { + supportedLocales = new Locales(supportedLocales, def); + supportedLocales.index(); + } + + return (req, res, next) => { + const locales = new Locales(req.headers['accept-language']); + + const bestLocale = locales.best(supportedLocales); + req.locale = String(bestLocale); + req.rawLocale = bestLocale; + next(); + }; +}; + +app.Locales = Locales; +app.Locale = Locale; + +module.exports = app; diff --git a/src/locale.js b/src/locale.js new file mode 100644 index 0000000..ee36bf5 --- /dev/null +++ b/src/locale.js @@ -0,0 +1,31 @@ +const defaultLocaleString = () => process.env.LANG || 'en_US'; + +class Locale { + constructor(str) { + if (!str) return null; + + const match = str.match(/[a-z]+/gi); + const [language, country] = match; + + this.code = str; + this.language = language.toLowerCase(); + const normalized = [this.language]; + + if (country) { + this.country = country.toUpperCase(); + normalized.push(this.country); + } + + this.normalized = normalized.join('_'); + } + + serialize() { + if (!this.language) return null; + return this.code; + } +} +Locale.prototype.toString = Locale.prototype.serialize; +Locale.prototype.toJSON = Locale.prototype.serialize; +Locale.default = new Locale(defaultLocaleString()); + +module.exports = Locale; diff --git a/src/locales.js b/src/locales.js new file mode 100644 index 0000000..7b847ca --- /dev/null +++ b/src/locales.js @@ -0,0 +1,114 @@ +const Locale = require('./locale'); + +class Locales { + constructor(input, def) { + let elements = []; + + if (input) { + if (typeof input === 'string' || input instanceof String) { + elements = input.split(','); + } else if (input instanceof Array) { + elements = input.slice(); + } + + elements = elements + .map(function (item) { + if (!item) return null; + + const [locale, q] = item.split(';'); + const locale2 = new Locale(locale.trim()); + let score = 1; + + if (q) { + score = q.slice(2) || 0; + } + + locale2.score = score; + + return locale2; + }) + .filter(e => e instanceof Locale) + .sort((a, b) => b.score - a.score); + } + + this.elements = elements; + this._index = null; + if (def) { + this.default = new Locale(def); + } + } + + index() { + if (!this._index) { + this._index = {}; + + this.elements.forEach(function (locale, idx) { + this._index[locale.normalized] = idx; + }, this); + } + return this._index; + } + + best(locales) { + const setLocale = function (l) { + const r = l; + r.defaulted = false; + return r; + }; + + let locale = Locale.default; + if (locales && locales.default) { + locale = locales.default; + } + locale.defaulted = true; + + if (!locales) { + if (this.elements[0]) { + locale = this.elements[0]; + locale.defaulted = true; + } + return locale; + } + + for (const item of this.elements) { // eslint-disable-line no-restricted-syntax + const appropriateLocaleIndex = Locales.appropriateIndex(locales, item); + + if (appropriateLocaleIndex !== null) { + return setLocale(locales.elements[appropriateLocaleIndex]); + } + } + + return locale; + } + + static appropriateIndex(locales, locale) { + const index = locales.index(); + + const normalizedIndex = index[locale.normalized]; + const languageIndex = index[locale.language]; + + if (normalizedIndex !== undefined) { + return normalizedIndex; + } else if (languageIndex !== undefined) { + return languageIndex; + } + + const sameLanguageLocaleIndex = locales.elements.findIndex(l => l.language === locale.language); + if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex; + + return null; + } + + serialize() { + return [...this.elements]; + } + + toString() { + return String(this.toJSON()); + } +} +Locales.prototype.toJSON = Locales.prototype.serialize; +Locales.prototype.sort = Array.prototype.sort; +Locales.prototype.push = Array.prototype.push; + +module.exports = Locales; diff --git a/src/test.coffee b/src/test.coffee deleted file mode 100644 index 76dde21..0000000 --- a/src/test.coffee +++ /dev/null @@ -1,114 +0,0 @@ -http = require "http" -assert = require "assert" -express = require "express" -locale = require "./" - -server = null -defaultLocale = locale.Locale.default - -before (callback) -> - app = do express - - app.use locale ["en-US", "fr", "fr-CA", "en", "ja", "de", "da-DK"] - app.get "/", (req, res) -> - res.set "content-language", req.locale - res.set "defaulted", req.rawLocale.defaulted - res.set "Connection", "close" - res.send(200) - server = app.listen 8001, callback - -describe "Defaults", -> - it "should use the environment language as default.", (callback) -> - http.get port: 8001, (res) -> - assert.equal( - res.headers["content-language"] - defaultLocale - ) - assert.equal(true, !!res.headers["defaulted"]) - callback() - - it "should fallback to the default for unsupported languages.", (callback) -> - http.get port: 8001, headers: "Accept-Language": "es-ES", (res) -> - assert.equal( - res.headers["content-language"] - defaultLocale - ) - assert.equal(true, !!res.headers["defaulted"]) - callback() - - it "should fallback to the instance default for unsupported languages if instance default is defined.", (callback) -> - instanceDefault = 'SomeFakeLanguage-NotReal' - supportedLocales = new locale.Locales ["en-US", "fr", "fr-CA", "en", "ja", "de", "da-DK"], instanceDefault - assert.equal( - ((new locale.Locales "es-ES").best supportedLocales).toString() - instanceDefault - ) - callback() - -describe "Priority", -> - it "should fallback to a more general language if a country specific language isn't available.", (callback) -> - http.get port: 8001, headers: "Accept-Language": "en-GB", (res) -> - assert.equal( - res.headers["content-language"] - "en" - "Unsupported country should fallback to countryless language" - ) - assert.equal(false, !res.headers["defaulted"]) - callback() - - it "should use the highest quality language supported, regardless of order.", (callback) -> - http.get port: 8001, headers: "Accept-Language": "en;q=.8, ja", (res) -> - assert.equal( - res.headers["content-language"] - "ja" - "Highest quality language supported should be used, regardless of order." - ) - assert.equal(false, !res.headers["defaulted"]) - - http.get port: 8001, headers: "Accept-Language": "fr-FR, ja-JA;q=0.5", (res) -> - assert.equal( - res.headers["content-language"] - "fr" - "Highest quality language supported should be used, regardless of order." - ) - assert.equal(false, !res.headers["defaulted"]) - - http.get port: 8001, headers: "Accept-Language": "en-US,en;q=0.93,es-ES;q=0.87,es;q=0.80,it-IT;q=0.73,it;q=0.67,de-DE;q=0.60,de;q=0.53,fr-FR;q=0.47,fr;q=0.40,ja;q=0.33,zh-Hans-CN;q=0.27,zh-Hans;q=0.20,ar-SA;q=0.13,ar;q=0.067", (res) -> - assert.equal( - res.headers["content-language"] - "en-US" - "Highest quality language supported should be used, regardless of order." - ) - assert.equal(false, !res.headers["defaulted"]) - - callback() - - it "should use a country specific language when an unsupported general language is requested", (callback) -> - http.get port: 8001, headers: "Accept-Language": "da", (res) -> - assert.equal( - res.headers["content-language"] - "da-DK" - ) - callback() - - it "should fallback to a country specific language even when there's a lower quality exact match", (callback) -> - http.get port: 8001, headers: "Accept-Language": "ja;q=.8, da", (res) -> - assert.equal( - res.headers["content-language"] - "da-DK" - ) - assert.equal(false, !res.headers["defaulted"]) - callback() - - it "should match country-specific language codes even when the separator is different", (callback) -> - http.get port: 8001, headers: "Accept-Language": "fr_CA", (res) -> - assert.equal( - res.headers["content-language"] - "fr-CA" - ) - assert.equal(false, !res.headers["defaulted"]) - callback() - -after -> - do server.close - do process.exit 0 diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000..7eeefc3 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "mocha": true + } +} diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 6300284..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1,2 +0,0 @@ ---reporter spec ---compilers coffee:coffee-script diff --git a/test/tests.js b/test/tests.js new file mode 100644 index 0000000..ad43f40 --- /dev/null +++ b/test/tests.js @@ -0,0 +1,122 @@ +const http = require('http'); +const assert = require('assert'); +const express = require('express'); +const locale = require('../src/'); + +let server = null; +const defaultLocale = locale.Locale.default; + +before(function (callback) { + const app = express(); + + app.use(locale(['en-US', 'fr', 'fr-CA', 'en', 'ja', 'de', 'da-DK'])); + app.get('/', function (req, res) { + res.set('content-language', req.locale); + res.set('defaulted', req.rawLocale.defaulted); + res.set('Connection', 'close'); + res.send(200); + }); + server = app.listen(8001, callback); +}); + +after(function () { + server.close(); +}); + +describe('Defaults', function () { + it('should use the environment language as default.', function (callback) { + http.get({ port: 8001 }, function (res) { + assert.equal( + res.headers['content-language'], + defaultLocale, + ); + assert.equal(true, !!res.headers.defaulted); + callback(); + }); + }); + + it('should fallback to the default for unsupported languages.', function (callback) { + http.get({ port: 8001, headers: { 'Accept-Language': 'es-ES' } }, function (res) { + assert.equal( + res.headers['content-language'], + defaultLocale, + ); + assert.equal(true, !!res.headers.defaulted); + callback(); + }); + }); + + it('should fallback to the instance default for unsupported languages if instance default is defined.', function (callback) { + const instanceDefault = 'SomeFakeLanguage-NotReal'; + const supportedLocales = new locale.Locales(['en-US', 'fr', 'fr-CA', 'en', 'ja', 'de', 'da-DK'], instanceDefault); + assert.equal( + ((new locale.Locales('es-ES')).best(supportedLocales)).toString(), + instanceDefault, + ); + callback(); + }); +}); + +describe('Priority', function () { + it('should fallback to a more general language if a country specific language isn\'t available.', function (callback) { + return http.get({ port: 8001, headers: { 'Accept-Language': 'en-GB' } }, function (res) { + assert.equal(res.headers['content-language'], 'en', 'Unsupported country should fallback to countryless language'); + assert.equal(false, !res.headers.defaulted); + callback(); + }); + }); + + it('should use the highest quality language supported, regardless of order.', function (callback) { + http.get({ port: 8001, headers: { 'Accept-Language': 'en;q=.8, ja' } }, function (res) { + assert.equal(res.headers['content-language'], 'ja', 'Highest quality language supported should be used, regardless of order.'); + assert.equal(false, !res.headers.defaulted); + }); + http.get({ port: 8001, headers: { 'Accept-Language': 'fr-FR, ja-JA;q=0.5' } }, function (res) { + assert.equal(res.headers['content-language'], 'fr', 'Highest quality language supported should be used, regardless of order.'); + assert.equal(false, !res.headers.defaulted); + }); + http.get({ + port: 8001, + headers: { + 'Accept-Language': 'en-US,en;q=0.93,es-ES;q=0.87,es;q=0.80,it-IT;q=0.73,it;q=0.67,de-DE;q=0.60,de;q=0.53,fr-FR;q=0.47,fr;q=0.40,ja;q=0.33,zh-Hans-CN;q=0.27,zh-Hans;q=0.20,ar-SA;q=0.13,ar;q=0.067', + }, + }, function (res) { + assert.equal(res.headers['content-language'], 'en-US', 'Highest quality language supported should be used, regardless of order.'); + assert.equal(false, !res.headers.defaulted); + callback(); + }); + }); + + it('should use a country specific language when an unsupported general language is requested', function (callback) { + return http.get({ + port: 8001, + headers: { + 'Accept-Language': 'da', + }, + }, function (res) { + assert.equal(res.headers['content-language'], 'da-DK'); + callback(); + }); + }); + + it('should fallback to a country specific language even when there\'s a lower quality exact match', function (callback) { + return http.get({ + port: 8001, + headers: { + 'Accept-Language': 'ja;q=.8, da', + }, + }, function (res) { + assert.equal(res.headers['content-language'], 'da-DK'); + assert.equal(false, !res.headers.defaulted); + callback(); + }); + }); + + it('should match country-specific language codes even when the separator is different', function (callback) { + return http.get({ port: 8001, headers: { 'Accept-Language': 'fr_CA' } }, function (res) { + assert.equal(res.headers['content-language'], 'fr-CA'); + assert.equal(false, !res.headers.defaulted); + callback(); + }); + }); +}); From f357c3c89903c81f1ef7ac065dcc2aa5a3dbef07 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:05:09 +0200 Subject: [PATCH 02/17] Remove license file, keep it simple with an MIT regular license as defined in package.json --- LICENSE.txt | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 258283a..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 Jed Schmidt, http://jed.is/ - -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. \ No newline at end of file From d428382c30995633713c605b5fd6fc2803b9268e Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:05:21 +0200 Subject: [PATCH 03/17] Ignore log files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3c3629e..eb03e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +*.log From d133ae18720ea19b552f0ebb474b0d8a16013ea7 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:05:40 +0200 Subject: [PATCH 04/17] Tell Travis to build for Node 0.8 and latest stable version --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index baa0031..2f4a973 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ language: node_js node_js: - - 0.8 + - "0.8" + - "node" From 52b745989e29d66bbf7fac715ef633cae60062f5 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:06:03 +0200 Subject: [PATCH 05/17] Add minified files --- dist/min.js | 4 ++++ dist/min.js.map | 1 + 2 files changed, 5 insertions(+) create mode 100644 dist/min.js create mode 100644 dist/min.js.map diff --git a/dist/min.js b/dist/min.js new file mode 100644 index 0000000..3ddcbbd --- /dev/null +++ b/dist/min.js @@ -0,0 +1,4 @@ +"use strict";var Locale=require("./locale"),Locales=require("./locales"),app=function(e,a){var c=e;return c instanceof Locales||(c=new Locales(c,a),c.index()),function(e,a,l){var o=new Locales(e.headers["accept-language"]),r=o.best(c);e.locale=String(r),e.rawLocale=r,l()}};app.Locales=Locales,app.Locale=Locale,module.exports=app; +"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _slicedToArray=function(){function e(e,t){var r=[],n=!0,a=!1,o=void 0;try{for(var i,l=e[Symbol.iterator]();!(n=(i=l.next()).done)&&(r.push(i.value),!t||r.length!==t);n=!0);}catch(e){a=!0,o=e}finally{try{!n&&l.return&&l.return()}finally{if(a)throw o}}return r}return function(t,r){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass=function(){function e(e,t){for(var r=0;r-1?o:null}}]),e}();Locales.prototype.toJSON=Locales.prototype.serialize,Locales.prototype.sort=Array.prototype.sort,Locales.prototype.push=Array.prototype.push,module.exports=Locales; +//# sourceMappingURL=min.js.map diff --git a/dist/min.js.map b/dist/min.js.map new file mode 100644 index 0000000..e4ba581 --- /dev/null +++ b/dist/min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.js","locale.js","locales.js"],"names":["Locale","require","Locales","supported","def","supportedLocales","req","res","next","locales","headers","locale","String","bestLocale","app","defaultLocaleString","process","env","LANG","str","_classCallCheck","this","match","_match","_slicedToArray","language","country","toLowerCase","normalized","toUpperCase","push","join","code","prototype","serialize","toJSON","default","input","elements","split","Array","slice","map","item","_item$split","_item$split2","q","locale2","trim","score","filter","e","sort","b","a","_index","idx","defaulted","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","done","setLocale","r","appropriateIndex","appropriateLocaleIndex","l","err","return","concat","_toConsumableArray","index","normalizedIndex","languageIndex","sameLanguageLocaleIndex","findIndex","module","exports"],"mappings":"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","file":"min.js","sourcesContent":["const Locale = require('./locale');\nconst Locales = require('./locales');\n\nconst app = function (supported, def) {\n let supportedLocales = supported;\n\n if (!(supportedLocales instanceof Locales)) {\n supportedLocales = new Locales(supportedLocales, def);\n supportedLocales.index();\n }\n\n return (req, res, next) => {\n const locales = new Locales(req.headers['accept-language']);\n\n const bestLocale = locales.best(supportedLocales);\n req.locale = String(bestLocale);\n req.rawLocale = bestLocale;\n next();\n };\n};\n\napp.Locales = Locales;\napp.Locale = Locale;\n\nmodule.exports = app;\n","const defaultLocaleString = () => process.env.LANG || 'en_US';\n\nclass Locale {\n constructor(str) {\n if (!str) return null;\n\n const match = str.match(/[a-z]+/gi);\n const [language, country] = match;\n\n this.code = str;\n this.language = language.toLowerCase();\n const normalized = [this.language];\n\n if (country) {\n this.country = country.toUpperCase();\n normalized.push(this.country);\n }\n\n this.normalized = normalized.join('_');\n }\n\n serialize() {\n if (!this.language) return null;\n return this.code;\n }\n}\nLocale.prototype.toString = Locale.prototype.serialize;\nLocale.prototype.toJSON = Locale.prototype.serialize;\nLocale.default = new Locale(defaultLocaleString());\n\nmodule.exports = Locale;\n","const Locale = require('./locale');\n\nclass Locales {\n constructor(input, def) {\n let elements = [];\n\n if (input) {\n if (typeof input === 'string' || input instanceof String) {\n elements = input.split(',');\n } else if (input instanceof Array) {\n elements = input.slice();\n }\n\n elements = elements\n .map(function (item) {\n if (!item) return null;\n\n const [locale, q] = item.split(';');\n const locale2 = new Locale(locale.trim());\n let score = 1;\n\n if (q) {\n score = q.slice(2) || 0;\n }\n\n locale2.score = score;\n\n return locale2;\n })\n .filter(e => e instanceof Locale)\n .sort((a, b) => b.score - a.score);\n }\n\n this.elements = elements;\n this._index = null;\n if (def) {\n this.default = new Locale(def);\n }\n }\n\n index() {\n if (!this._index) {\n this._index = {};\n\n this.elements.forEach(function (locale, idx) {\n this._index[locale.normalized] = idx;\n }, this);\n }\n return this._index;\n }\n\n best(locales) {\n const setLocale = function (l) {\n const r = l;\n r.defaulted = false;\n return r;\n };\n\n let locale = Locale.default;\n if (locales && locales.default) {\n locale = locales.default;\n }\n locale.defaulted = true;\n\n if (!locales) {\n if (this.elements[0]) {\n locale = this.elements[0];\n locale.defaulted = true;\n }\n return locale;\n }\n\n for (const item of this.elements) { // eslint-disable-line no-restricted-syntax\n const appropriateLocaleIndex = Locales.appropriateIndex(locales, item);\n\n if (appropriateLocaleIndex !== null) {\n return setLocale(locales.elements[appropriateLocaleIndex]);\n }\n }\n\n return locale;\n }\n\n static appropriateIndex(locales, locale) {\n const index = locales.index();\n\n const normalizedIndex = index[locale.normalized];\n const languageIndex = index[locale.language];\n\n if (normalizedIndex !== undefined) {\n return normalizedIndex;\n } else if (languageIndex !== undefined) {\n return languageIndex;\n }\n\n const sameLanguageLocaleIndex = locales.elements.findIndex(l => l.language === locale.language);\n if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex;\n\n return null;\n }\n\n serialize() {\n return [...this.elements];\n }\n\n toString() {\n return String(this.toJSON());\n }\n}\nLocales.prototype.toJSON = Locales.prototype.serialize;\nLocales.prototype.sort = Array.prototype.sort;\nLocales.prototype.push = Array.prototype.push;\n\nmodule.exports = Locales;\n"]} \ No newline at end of file From d358b66c7eb53d02969909b13183b1f949011af4 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:39:21 +0200 Subject: [PATCH 06/17] Fix build filenames --- dist/{min.js => locale.min.js} | 2 +- dist/locale.min.js.map | 1 + dist/min.js.map | 1 - gulpfile.js | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename dist/{min.js => locale.min.js} (99%) create mode 100644 dist/locale.min.js.map delete mode 100644 dist/min.js.map diff --git a/dist/min.js b/dist/locale.min.js similarity index 99% rename from dist/min.js rename to dist/locale.min.js index 3ddcbbd..9300998 100644 --- a/dist/min.js +++ b/dist/locale.min.js @@ -1,4 +1,4 @@ "use strict";var Locale=require("./locale"),Locales=require("./locales"),app=function(e,a){var c=e;return c instanceof Locales||(c=new Locales(c,a),c.index()),function(e,a,l){var o=new Locales(e.headers["accept-language"]),r=o.best(c);e.locale=String(r),e.rawLocale=r,l()}};app.Locales=Locales,app.Locale=Locale,module.exports=app; "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _slicedToArray=function(){function e(e,t){var r=[],n=!0,a=!1,o=void 0;try{for(var i,l=e[Symbol.iterator]();!(n=(i=l.next()).done)&&(r.push(i.value),!t||r.length!==t);n=!0);}catch(e){a=!0,o=e}finally{try{!n&&l.return&&l.return()}finally{if(a)throw o}}return r}return function(t,r){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass=function(){function e(e,t){for(var r=0;r-1?o:null}}]),e}();Locales.prototype.toJSON=Locales.prototype.serialize,Locales.prototype.sort=Array.prototype.sort,Locales.prototype.push=Array.prototype.push,module.exports=Locales; -//# sourceMappingURL=min.js.map +//# sourceMappingURL=locale.min.js.map diff --git a/dist/locale.min.js.map b/dist/locale.min.js.map new file mode 100644 index 0000000..2d5bb81 --- /dev/null +++ b/dist/locale.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.js","locale.js","locales.js"],"names":["Locale","require","Locales","supported","def","supportedLocales","req","res","next","locales","headers","locale","String","bestLocale","app","defaultLocaleString","process","env","LANG","str","_classCallCheck","this","match","_match","_slicedToArray","language","country","toLowerCase","normalized","toUpperCase","push","join","code","prototype","serialize","toJSON","default","input","elements","split","Array","slice","map","item","_item$split","_item$split2","q","locale2","trim","score","filter","e","sort","b","a","_index","idx","defaulted","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","done","setLocale","r","appropriateIndex","appropriateLocaleIndex","l","err","return","concat","_toConsumableArray","index","normalizedIndex","languageIndex","sameLanguageLocaleIndex","findIndex","module","exports"],"mappings":"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","file":"locale.min.js","sourcesContent":["const Locale = require('./locale');\nconst Locales = require('./locales');\n\nconst app = function (supported, def) {\n let supportedLocales = supported;\n\n if (!(supportedLocales instanceof Locales)) {\n supportedLocales = new Locales(supportedLocales, def);\n supportedLocales.index();\n }\n\n return (req, res, next) => {\n const locales = new Locales(req.headers['accept-language']);\n\n const bestLocale = locales.best(supportedLocales);\n req.locale = String(bestLocale);\n req.rawLocale = bestLocale;\n next();\n };\n};\n\napp.Locales = Locales;\napp.Locale = Locale;\n\nmodule.exports = app;\n","const defaultLocaleString = () => process.env.LANG || 'en_US';\n\nclass Locale {\n constructor(str) {\n if (!str) return null;\n\n const match = str.match(/[a-z]+/gi);\n const [language, country] = match;\n\n this.code = str;\n this.language = language.toLowerCase();\n const normalized = [this.language];\n\n if (country) {\n this.country = country.toUpperCase();\n normalized.push(this.country);\n }\n\n this.normalized = normalized.join('_');\n }\n\n serialize() {\n if (!this.language) return null;\n return this.code;\n }\n}\nLocale.prototype.toString = Locale.prototype.serialize;\nLocale.prototype.toJSON = Locale.prototype.serialize;\nLocale.default = new Locale(defaultLocaleString());\n\nmodule.exports = Locale;\n","const Locale = require('./locale');\n\nclass Locales {\n constructor(input, def) {\n let elements = [];\n\n if (input) {\n if (typeof input === 'string' || input instanceof String) {\n elements = input.split(',');\n } else if (input instanceof Array) {\n elements = input.slice();\n }\n\n elements = elements\n .map(function (item) {\n if (!item) return null;\n\n const [locale, q] = item.split(';');\n const locale2 = new Locale(locale.trim());\n let score = 1;\n\n if (q) {\n score = q.slice(2) || 0;\n }\n\n locale2.score = score;\n\n return locale2;\n })\n .filter(e => e instanceof Locale)\n .sort((a, b) => b.score - a.score);\n }\n\n this.elements = elements;\n this._index = null;\n if (def) {\n this.default = new Locale(def);\n }\n }\n\n index() {\n if (!this._index) {\n this._index = {};\n\n this.elements.forEach(function (locale, idx) {\n this._index[locale.normalized] = idx;\n }, this);\n }\n return this._index;\n }\n\n best(locales) {\n const setLocale = function (l) {\n const r = l;\n r.defaulted = false;\n return r;\n };\n\n let locale = Locale.default;\n if (locales && locales.default) {\n locale = locales.default;\n }\n locale.defaulted = true;\n\n if (!locales) {\n if (this.elements[0]) {\n locale = this.elements[0];\n locale.defaulted = true;\n }\n return locale;\n }\n\n for (const item of this.elements) { // eslint-disable-line no-restricted-syntax\n const appropriateLocaleIndex = Locales.appropriateIndex(locales, item);\n\n if (appropriateLocaleIndex !== null) {\n return setLocale(locales.elements[appropriateLocaleIndex]);\n }\n }\n\n return locale;\n }\n\n static appropriateIndex(locales, locale) {\n const index = locales.index();\n\n const normalizedIndex = index[locale.normalized];\n const languageIndex = index[locale.language];\n\n if (normalizedIndex !== undefined) {\n return normalizedIndex;\n } else if (languageIndex !== undefined) {\n return languageIndex;\n }\n\n const sameLanguageLocaleIndex = locales.elements.findIndex(l => l.language === locale.language);\n if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex;\n\n return null;\n }\n\n serialize() {\n return [...this.elements];\n }\n\n toString() {\n return String(this.toJSON());\n }\n}\nLocales.prototype.toJSON = Locales.prototype.serialize;\nLocales.prototype.sort = Array.prototype.sort;\nLocales.prototype.push = Array.prototype.push;\n\nmodule.exports = Locales;\n"]} \ No newline at end of file diff --git a/dist/min.js.map b/dist/min.js.map deleted file mode 100644 index e4ba581..0000000 --- a/dist/min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["index.js","locale.js","locales.js"],"names":["Locale","require","Locales","supported","def","supportedLocales","req","res","next","locales","headers","locale","String","bestLocale","app","defaultLocaleString","process","env","LANG","str","_classCallCheck","this","match","_match","_slicedToArray","language","country","toLowerCase","normalized","toUpperCase","push","join","code","prototype","serialize","toJSON","default","input","elements","split","Array","slice","map","item","_item$split","_item$split2","q","locale2","trim","score","filter","e","sort","b","a","_index","idx","defaulted","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","done","setLocale","r","appropriateIndex","appropriateLocaleIndex","l","err","return","concat","_toConsumableArray","index","normalizedIndex","languageIndex","sameLanguageLocaleIndex","findIndex","module","exports"],"mappings":"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","file":"min.js","sourcesContent":["const Locale = require('./locale');\nconst Locales = require('./locales');\n\nconst app = function (supported, def) {\n let supportedLocales = supported;\n\n if (!(supportedLocales instanceof Locales)) {\n supportedLocales = new Locales(supportedLocales, def);\n supportedLocales.index();\n }\n\n return (req, res, next) => {\n const locales = new Locales(req.headers['accept-language']);\n\n const bestLocale = locales.best(supportedLocales);\n req.locale = String(bestLocale);\n req.rawLocale = bestLocale;\n next();\n };\n};\n\napp.Locales = Locales;\napp.Locale = Locale;\n\nmodule.exports = app;\n","const defaultLocaleString = () => process.env.LANG || 'en_US';\n\nclass Locale {\n constructor(str) {\n if (!str) return null;\n\n const match = str.match(/[a-z]+/gi);\n const [language, country] = match;\n\n this.code = str;\n this.language = language.toLowerCase();\n const normalized = [this.language];\n\n if (country) {\n this.country = country.toUpperCase();\n normalized.push(this.country);\n }\n\n this.normalized = normalized.join('_');\n }\n\n serialize() {\n if (!this.language) return null;\n return this.code;\n }\n}\nLocale.prototype.toString = Locale.prototype.serialize;\nLocale.prototype.toJSON = Locale.prototype.serialize;\nLocale.default = new Locale(defaultLocaleString());\n\nmodule.exports = Locale;\n","const Locale = require('./locale');\n\nclass Locales {\n constructor(input, def) {\n let elements = [];\n\n if (input) {\n if (typeof input === 'string' || input instanceof String) {\n elements = input.split(',');\n } else if (input instanceof Array) {\n elements = input.slice();\n }\n\n elements = elements\n .map(function (item) {\n if (!item) return null;\n\n const [locale, q] = item.split(';');\n const locale2 = new Locale(locale.trim());\n let score = 1;\n\n if (q) {\n score = q.slice(2) || 0;\n }\n\n locale2.score = score;\n\n return locale2;\n })\n .filter(e => e instanceof Locale)\n .sort((a, b) => b.score - a.score);\n }\n\n this.elements = elements;\n this._index = null;\n if (def) {\n this.default = new Locale(def);\n }\n }\n\n index() {\n if (!this._index) {\n this._index = {};\n\n this.elements.forEach(function (locale, idx) {\n this._index[locale.normalized] = idx;\n }, this);\n }\n return this._index;\n }\n\n best(locales) {\n const setLocale = function (l) {\n const r = l;\n r.defaulted = false;\n return r;\n };\n\n let locale = Locale.default;\n if (locales && locales.default) {\n locale = locales.default;\n }\n locale.defaulted = true;\n\n if (!locales) {\n if (this.elements[0]) {\n locale = this.elements[0];\n locale.defaulted = true;\n }\n return locale;\n }\n\n for (const item of this.elements) { // eslint-disable-line no-restricted-syntax\n const appropriateLocaleIndex = Locales.appropriateIndex(locales, item);\n\n if (appropriateLocaleIndex !== null) {\n return setLocale(locales.elements[appropriateLocaleIndex]);\n }\n }\n\n return locale;\n }\n\n static appropriateIndex(locales, locale) {\n const index = locales.index();\n\n const normalizedIndex = index[locale.normalized];\n const languageIndex = index[locale.language];\n\n if (normalizedIndex !== undefined) {\n return normalizedIndex;\n } else if (languageIndex !== undefined) {\n return languageIndex;\n }\n\n const sameLanguageLocaleIndex = locales.elements.findIndex(l => l.language === locale.language);\n if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex;\n\n return null;\n }\n\n serialize() {\n return [...this.elements];\n }\n\n toString() {\n return String(this.toJSON());\n }\n}\nLocales.prototype.toJSON = Locales.prototype.serialize;\nLocales.prototype.sort = Array.prototype.sort;\nLocales.prototype.push = Array.prototype.push;\n\nmodule.exports = Locales;\n"]} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index f150755..ca892ea 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -24,7 +24,7 @@ gulp.task('build', ['clean'], function () { presets: ['es2015'], })) .pipe(uglify()) - .pipe(concat('min.js')) + .pipe(concat('locale.min.js')) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('dist')); }); From 97100f91a47c8d78583857f5dad68b2edd6b8cd4 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 01:39:34 +0200 Subject: [PATCH 07/17] Re-add mocha.opts file --- test/mocha.opts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 test/mocha.opts diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..50afa0d --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,2 @@ +--reporter spec +--compilers js:babel-core/register From aa22b1ae3286d22d8692886e464b4c920fbb3fe2 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 11:47:37 +0200 Subject: [PATCH 08/17] Example cleanup --- examples/express.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/express.js b/examples/express.js index 0c653ad..b4e8879 100644 --- a/examples/express.js +++ b/examples/express.js @@ -1,4 +1,3 @@ -// const http = require('http'); const express = require('express'); // eslint-disable-line import/no-extraneous-dependencies const locale = require('../src'); From dfd47cfcb134c50827e23f740659e1ac08e5a949 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 11:47:50 +0200 Subject: [PATCH 09/17] New License file --- LICENSE.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f13e36b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2017 Florian Lorrain + +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. From 9fefbfc0f651b9f8b6c6894c8b264a079f3b233f Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 11:51:32 +0200 Subject: [PATCH 10/17] Readme update --- README.md | 90 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 8f8be92..bdf5647 100644 --- a/README.md +++ b/README.md @@ -5,58 +5,54 @@ locale is a [node.js][node] module for negotiating HTTP locales for incoming bro It works like this: you (optionally) tell it the languages you support, and it figures out the best one to use for each incoming request from a browser. So if you support `en`, `en_US`, `ja`, `kr`, and `zh_TW`, and a request comes in that accepts `en_UK` or `en`, locale will figure out that `en` is the best language to use. -**Credits to [jed](https://github.com/jed) who passed the ownership of the package.** - Examples -------- ### For the node.js HTTP module ```javascript -var http = require("http") - , locale = require("locale") - , supported = new locale.Locales(["en", "en_US", "ja"]) +const http = require('http'); +const locale = require('locale'); +const supported = new locale.Locales(['en', 'en_US', 'ja']); -http.createServer(function(req, res) { - var locales = new locale.Locales(req.headers["accept-language"]) - res.writeHeader(200, {"Content-Type": "text/plain"}) +http.createServer(function (req, res) { + const locales = new locale.Locales(req.headers['accept-language']); + res.writeHeader(200, { 'Content-Type': 'text/plain' }); res.end( - "You asked for: " + req.headers["accept-language"] + "\n" + - "We support: " + supported + "\n" + - "Our default is: " + locale.Locale["default"] + "\n" + - "The best match is: " + locales.best(supported) + "\n" - ) -}).listen(8000) + `You asked for: ${req.headers['accept-language']} + We support: ${supported} + Our default is: ${locale.Locale.default} + The best match is: ' + ${locales.best(supported)}` + ); +}).listen(8000); ``` ### For Connect/Express ```javascript -var http = require("http") - , express = require("express") - , locale = require("locale") - , supported = ["en", "en_US", "ja"] - , app = express() - -app.use(locale(supported)) +const express = require('express'); +const locale = require('locale'); +const supported = ['en', 'en_US', 'ja']; +const app = express.createServer(locale(supported)); -app.get("/", function(req, res) { - res.header("Content-Type", "text/plain") +app.get('/', function (req, res) { + res.header('Content-Type', 'text/plain'); res.send( - "You asked for: " + req.headers["accept-language"] + "\n" + - "We support: " + supported + "\n" + - "Our default is: " + locale.Locale["default"] + "\n" + - "The best match is: " + req.locale + "\n" - ) -}) - -app.listen(8000) + `You asked for: ${req.headers['accept-language']} + We support: ${supported} + Our default is: ${locale.Locale.default} + The best match is: ${req.locale}` + ); +}); + +app.listen(8000); ``` Install ------- +```bash +$ npm install locale +``` - $ npm install locale - -(Note that although this repo is CoffeeScript, the actual npm library is pre-compiled to pure JavaScript and has no run-time dependencies.) +Note - the package has no dependencies. API --- @@ -81,19 +77,29 @@ The Locales constructor takes a string compliant with the [`Accept-Language` HTT This method takes the target locale and compares it against the optionally provided list of supported locales, and returns the most appropriate locale based on the quality scores of the target locale. If no exact match exists (i.e. language+country) then it will fallback to `language` if supported, or if the language isn't supported it will return the default locale. - supported = new locale.Locales(['en', 'en_US'], 'en'); - (new locale.Locales('en')).best(supported).toString(); // 'en' - (new locale.Locales('en_GB')).best(supported).toString(); // 'en' - (new locale.Locales('en_US')).best(supported).toString(); // 'en_US' - (new locale.Locales('jp')).best(supported); // supported.default || locale.Locale["default"] +```javascript +supported = new locale.Locales(['en', 'en_US'], 'en'); +(new locale.Locales('en')).best(supported).toString(); // 'en' +(new locale.Locales('en_GB')).best(supported).toString(); // 'en' +(new locale.Locales('en_US')).best(supported).toString(); // 'en_US' +(new locale.Locales('jp')).best(supported); // supported.default || locale.Locale["default"] +``` + +Contributing +--- +1. Fork this repo and clone it locally. +2. Make sure you're using Node >= 4 +3. Run `npm install` to install dev dependencies. +4. Run `npm test` and `npm build` and check no error pops up. +5. Now you're ready to rumble! You can use the default `gulp` task to watch and run tests while you're making changes. +Sources are ES2015 compliant and transpiled via Babel. Copyright --------- +This project is licensed under the MIT license, Copyright (c) 2017 Maximilian Stoiber. For more information see LICENSE.md. -Copyright (c) 2012 Jed Schmidt. See LICENSE.txt for details. - -Send any questions or comments [here](http://twitter.com/jedschmidt). +Credits to [jed](https://github.com/jed) who was the initial maintainer of the package. [node]: http://nodejs.org [express]: http://expressjs.com From 1ad84ddcdc09d44995d9b216900214a63f07ea4e Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 11:51:55 +0200 Subject: [PATCH 11/17] Test suite running with Node 4 and latest stable --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f4a973..6b1051a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: - - "0.8" + - "4" - "node" From 7f08aa28eaba40edbf30e0cda2908f2e36b0ea41 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 11:53:28 +0200 Subject: [PATCH 12/17] Precise Node compatibility in Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bdf5647..f99dc8a 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ locale is a [node.js][node] module for negotiating HTTP locales for incoming bro It works like this: you (optionally) tell it the languages you support, and it figures out the best one to use for each incoming request from a browser. So if you support `en`, `en_US`, `ja`, `kr`, and `zh_TW`, and a request comes in that accepts `en_UK` or `en`, locale will figure out that `en` is the best language to use. +Sources should be compatible with Node >= 0.8 but the dev environment needs Node >= 4. + Examples -------- From 31f8d26a97c4d57ac26f4b4c24a998195944c7b8 Mon Sep 17 00:00:00 2001 From: florrain Date: Mon, 3 Apr 2017 15:05:17 +0200 Subject: [PATCH 13/17] Readme license modification --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f99dc8a..275fd87 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Sources are ES2015 compliant and transpiled via Babel. Copyright --------- -This project is licensed under the MIT license, Copyright (c) 2017 Maximilian Stoiber. For more information see LICENSE.md. +This project is licensed under the MIT license. For more information see LICENSE.md. Credits to [jed](https://github.com/jed) who was the initial maintainer of the package. From cd903476b7e3e0d2ddd81a7005cbd7fa19d2a339 Mon Sep 17 00:00:00 2001 From: florrain Date: Thu, 6 Apr 2017 23:02:30 +0200 Subject: [PATCH 14/17] Change the dist configuration and link the main of the package to the compiled source file --- gulpfile.js | 17 +++++++++-------- package.json | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index ca892ea..49d3303 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -11,26 +11,27 @@ var del = require('del'); var paths = { scripts: ['src/**.js'], tests: ['test/tests.js'], + dist: { + folder: 'dist', + file: 'locale.js' + } }; gulp.task('clean', function () { - return del(['build']); + return del([paths.dist.folder]); }); -gulp.task('build', ['clean'], function () { +gulp.task('build', ['lint', 'clean'], function () { return gulp.src(paths.scripts) - .pipe(sourcemaps.init()) .pipe(babel({ presets: ['es2015'], })) - .pipe(uglify()) - .pipe(concat('locale.min.js')) - .pipe(sourcemaps.write('.')) - .pipe(gulp.dest('dist')); + .pipe(concat(paths.dist.file)) + .pipe(gulp.dest(paths.dist.folder)); }); gulp.task('lint', function () { - return gulp.src(['**/*.js', '!node_modules/**', '!dist/**']) + return gulp.src(paths.scripts) .pipe(eslint()) .pipe(eslint.format()) .pipe(eslint.failAfterError()); diff --git a/package.json b/package.json index 2008591..e5cb702 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "type": "git", "url": "git://github.com/florrain/locale.git" }, - "main": "./src", + "main": "./dist/locale.js", "scripts": { "test": "./node_modules/.bin/mocha ./test/tests.js", "prepublish": "gulp build" From 17c8ed60fc3191e30a3a80f5554ce5a110fcbfee Mon Sep 17 00:00:00 2001 From: florrain Date: Thu, 6 Apr 2017 23:03:23 +0200 Subject: [PATCH 15/17] Remove and rebuild dist file --- dist/locale.js | 243 +++++++++++++++++++++++++++++++++++++++++ dist/locale.min.js | 4 - dist/locale.min.js.map | 1 - 3 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 dist/locale.js delete mode 100644 dist/locale.min.js delete mode 100644 dist/locale.min.js.map diff --git a/dist/locale.js b/dist/locale.js new file mode 100644 index 0000000..a33df07 --- /dev/null +++ b/dist/locale.js @@ -0,0 +1,243 @@ +'use strict'; + +var Locale = require('./locale'); +var Locales = require('./locales'); + +var app = function app(supported, def) { + var supportedLocales = supported; + + if (!(supportedLocales instanceof Locales)) { + supportedLocales = new Locales(supportedLocales, def); + supportedLocales.index(); + } + + return function (req, res, next) { + var locales = new Locales(req.headers['accept-language']); + + var bestLocale = locales.best(supportedLocales); + req.locale = String(bestLocale); + req.rawLocale = bestLocale; + next(); + }; +}; + +app.Locales = Locales; +app.Locale = Locale; + +module.exports = app; +'use strict'; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +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"); } } + +var defaultLocaleString = function defaultLocaleString() { + return process.env.LANG || 'en_US'; +}; + +var Locale = function () { + function Locale(str) { + _classCallCheck(this, Locale); + + if (!str) return null; + + var match = str.match(/[a-z]+/gi); + + var _match = _slicedToArray(match, 2), + language = _match[0], + country = _match[1]; + + this.code = str; + this.language = language.toLowerCase(); + var normalized = [this.language]; + + if (country) { + this.country = country.toUpperCase(); + normalized.push(this.country); + } + + this.normalized = normalized.join('_'); + } + + _createClass(Locale, [{ + key: 'serialize', + value: function serialize() { + if (!this.language) return null; + return this.code; + } + }]); + + return Locale; +}(); + +Locale.prototype.toString = Locale.prototype.serialize; +Locale.prototype.toJSON = Locale.prototype.serialize; +Locale.default = new Locale(defaultLocaleString()); + +module.exports = Locale; +'use strict'; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Locale = require('./locale'); + +var Locales = function () { + function Locales(input, def) { + _classCallCheck(this, Locales); + + var elements = []; + + if (input) { + if (typeof input === 'string' || input instanceof String) { + elements = input.split(','); + } else if (input instanceof Array) { + elements = input.slice(); + } + + elements = elements.map(function (item) { + if (!item) return null; + + var _item$split = item.split(';'), + _item$split2 = _slicedToArray(_item$split, 2), + locale = _item$split2[0], + q = _item$split2[1]; + + var locale2 = new Locale(locale.trim()); + var score = 1; + + if (q) { + score = q.slice(2) || 0; + } + + locale2.score = score; + + return locale2; + }).filter(function (e) { + return e instanceof Locale; + }).sort(function (a, b) { + return b.score - a.score; + }); + } + + this.elements = elements; + this._index = null; + if (def) { + this.default = new Locale(def); + } + } + + _createClass(Locales, [{ + key: 'index', + value: function index() { + if (!this._index) { + this._index = {}; + + this.elements.forEach(function (locale, idx) { + this._index[locale.normalized] = idx; + }, this); + } + return this._index; + } + }, { + key: 'best', + value: function best(locales) { + var setLocale = function setLocale(l) { + var r = l; + r.defaulted = false; + return r; + }; + + var locale = Locale.default; + if (locales && locales.default) { + locale = locales.default; + } + locale.defaulted = true; + + if (!locales) { + if (this.elements[0]) { + locale = this.elements[0]; + locale.defaulted = true; + } + return locale; + } + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.elements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var item = _step.value; + // eslint-disable-line no-restricted-syntax + var appropriateLocaleIndex = Locales.appropriateIndex(locales, item); + + if (appropriateLocaleIndex !== null) { + return setLocale(locales.elements[appropriateLocaleIndex]); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return locale; + } + }, { + key: 'serialize', + value: function serialize() { + return [].concat(_toConsumableArray(this.elements)); + } + }, { + key: 'toString', + value: function toString() { + return String(this.toJSON()); + } + }], [{ + key: 'appropriateIndex', + value: function appropriateIndex(locales, locale) { + var index = locales.index(); + + var normalizedIndex = index[locale.normalized]; + var languageIndex = index[locale.language]; + + if (normalizedIndex !== undefined) { + return normalizedIndex; + } else if (languageIndex !== undefined) { + return languageIndex; + } + + var sameLanguageLocaleIndex = locales.elements.findIndex(function (l) { + return l.language === locale.language; + }); + if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex; + + return null; + } + }]); + + return Locales; +}(); + +Locales.prototype.toJSON = Locales.prototype.serialize; +Locales.prototype.sort = Array.prototype.sort; +Locales.prototype.push = Array.prototype.push; + +module.exports = Locales; \ No newline at end of file diff --git a/dist/locale.min.js b/dist/locale.min.js deleted file mode 100644 index 9300998..0000000 --- a/dist/locale.min.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict";var Locale=require("./locale"),Locales=require("./locales"),app=function(e,a){var c=e;return c instanceof Locales||(c=new Locales(c,a),c.index()),function(e,a,l){var o=new Locales(e.headers["accept-language"]),r=o.best(c);e.locale=String(r),e.rawLocale=r,l()}};app.Locales=Locales,app.Locale=Locale,module.exports=app; -"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _slicedToArray=function(){function e(e,t){var r=[],n=!0,a=!1,o=void 0;try{for(var i,l=e[Symbol.iterator]();!(n=(i=l.next()).done)&&(r.push(i.value),!t||r.length!==t);n=!0);}catch(e){a=!0,o=e}finally{try{!n&&l.return&&l.return()}finally{if(a)throw o}}return r}return function(t,r){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass=function(){function e(e,t){for(var r=0;r-1?o:null}}]),e}();Locales.prototype.toJSON=Locales.prototype.serialize,Locales.prototype.sort=Array.prototype.sort,Locales.prototype.push=Array.prototype.push,module.exports=Locales; -//# sourceMappingURL=locale.min.js.map diff --git a/dist/locale.min.js.map b/dist/locale.min.js.map deleted file mode 100644 index 2d5bb81..0000000 --- a/dist/locale.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["index.js","locale.js","locales.js"],"names":["Locale","require","Locales","supported","def","supportedLocales","req","res","next","locales","headers","locale","String","bestLocale","app","defaultLocaleString","process","env","LANG","str","_classCallCheck","this","match","_match","_slicedToArray","language","country","toLowerCase","normalized","toUpperCase","push","join","code","prototype","serialize","toJSON","default","input","elements","split","Array","slice","map","item","_item$split","_item$split2","q","locale2","trim","score","filter","e","sort","b","a","_index","idx","defaulted","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","done","setLocale","r","appropriateIndex","appropriateLocaleIndex","l","err","return","concat","_toConsumableArray","index","normalizedIndex","languageIndex","sameLanguageLocaleIndex","findIndex","module","exports"],"mappings":"YAAA,IAAMA,QAASC,QAAQ,YACjBC,QAAUD,QAAQ,aAAlBC,IAAAA,SAAkBC,EAARC,GAGd,GAAIC,GAAmBF,CAKtB,OALGE,aAAJH,WAGEG,EAAmB,GAAIH,SAAQG,EAAkBD,GADnDC,EAAMA,SAGL,SAAAC,EAAAC,EAAAC,GAGC,GAAMC,GAAU,GAAIP,SAAQI,EAAII,QAAQ,oBAAlCD,EAAcP,EAAQI,KAAII,EAGhCJ,GAAIK,OAASC,OAAOC,GADpBP,EAAMO,UAAAA,EACNP,KAIHQ,KAhBDZ,QAAAA,QAmBAY,IAAId,OAASA,OAAbc,OAAId,QAASA;gzBCtBPe,oBAAsB,WAAA,MAAMC,SAAQC,IAAIC,MAAQ,SAEhDlB,kBACJ,QAAAA,GAAYmB,GACV,GADeC,gBAAAC,KAAArB,IACVmB,EAAK,MAAO,KAEjB,IAAMG,GAAQH,EAAIG,MAAM,YAHTC,EAAAC,eAIaF,EAJb,GAIRG,EAJQF,EAAA,GAIEG,EAJFH,EAAA,EAHSF,MAAML,KAAAA,EAAlCK,KAAAI,SAAAA,EAAAE,aAWI,IAAMC,IAAcP,KAAKI,SAR3BC,KAAiBL,KAAAK,QAAAA,EAAAG,cAYbD,EAAWE,KAAKT,KAAKK,UATvBL,KAAMC,WAAYA,EAAMS,KAAxB,8DAHe,MAIEL,MAAAA,SAgBVL,KAAKW,KApBG,aAQfhC,QAAAiC,UAAML,SAAmBH,OAANQ,UAAnBC,UAgBJlC,OAAOiC,UAAUE,OAASnC,OAAOiC,UAAUC,UAdvClC,OAAAoC,QAAa,GAAApC,QAAAe,uBAEXa,OAAAA,QAAWE;y7BCfX9B,OAASC,QAAQ,YAEjBC,mBACJ,QAAAA,GAAYmC,EAAOjC,GAAKgB,gBAAAC,KAAAnB,EACtB,IAAIoC,KAEAD,KACmB,gBAAVA,IAAsBA,YAAiBzB,QAChD0B,EAAWD,EAAME,MAAM,KACdF,YAAiBG,SAT5BxC,EAASC,EAAQwC,SAGrBH,EAAAA,EAAwBI,IAAA,SAAAC,GAYhB,IAAKA,EAAM,MAAO,KAZF,IAAAC,GAcID,EAAKJ,MAAM,KAdfM,EAAArB,eAAAoB,EAAA,GAcTjC,EAdSkC,EAAA,GAcDC,EAdCD,EAAA,GAGXE,EAAA,GAAA/C,QAAAW,EAAAqC,QACLC,EAAA,CAoBA,OAlBGH,KACLR,EAAWD,EAAAA,MAAMI,IAAjB,GAGFH,EAAWA,MACRI,EAaQK,IAbYG,OAAA,SAAAC,GAAA,MAAAA,aAAAnD,UAAAoD,KAGZzC,SAAAA,EAHY0C,GAGZ1C,MAHY0C,GAAAJ,MAAAK,EAAAL,SAInB5B,KAAAiB,SAAMS,EACN1B,KAAAkC,OAAIN,KAgBN7C,IAdEiB,KAAAe,QAAO,GAAApC,QAAAI,yDAUZ,MAUIiB,MAAKkC,SAdJlC,KAAAkC,UAEMlC,KAAAiB,SAAKa,QAAanD,SAAlBW,EAAA6C,GAhBCnC,KAAAkC,OAiBH5C,EAAI0C,YAAJG,GAAAnC,OACTA,KAAAkC,oCAGD9C,GACA,GAuBIE,GAASX,OAAOoC,OAbhB,IAcA3B,GAAWA,EAAQ2B,UAlBvBzB,EAAKF,EAAL2B,SAqBAzB,EAAO8C,WAAY,GAjBfhD,EAwBF,MAzBAY,MAAAiB,SAAA,KAGD3B,EAAAU,KAAAiB,SAAA,GACD3B,EAAO8C,WAAP,GAqBS9C,CAnCT,IAAA+C,IAAA,EAAAC,GAAA,EAAAC,MAAAC,EAAA,KAkBA,IAAA,GAAAC,GAAAC,EAAkB1C,KAAAiB,SAAlB0B,OAAAC,cAAAP,GAAAI,EAAAC,EAAAvD,QAAA0D,MAAAR,GAAA,EAAMS,CAAAA,GAAAA,GAAAA,EAAAA,MACEC,EAANlE,EAAAmE,iBAAA5D,EAAAkC,EAEA,IAAA,OAAA2B,EAHF,MAjBS,UAAAC,GACP,GAAKnC,GAAAA,CAER,OADEgC,GAAAX,WAAA,EACFW,GAcC3D,EAAA6B,SAAAgC,KAlBA,MAAAE,GAAAb,GAAA,EAAAC,EAAAY,EAAA,QAAA,KAAAd,GAAAK,EAAAU,QAAAV,EAAAU,SAAA,QAAA,GAAAd,EAAA,KAAAC,IA0BEjD,MAAAA,uCAeA,SAAA+D,OAAAC,mBAAIL,KAAAA,8CAxBM,MAAA1D,QAAAS,KAAAc,qDAgCU1B,EAASE,GAnB/B,GAAIiE,GAAJnE,EAAcmE,QAEVjE,EAAc2B,EAAL3B,EAATiB,YACAjB,EAAAiE,EAAmBjE,EAAnBc,SAEF,QAAAoC,KAAAgB,EACD,MAAAA,EAqBM,QAAsBhB,KAAlBiB,EAxCC,MAAAA,EA4CZ,IAAMC,GAA0BtE,EAAQ6B,SAAS0C,UAAU,SAAAT,GAAA,MAAKA,GAAE9C,WAAad,EAAOc,UA5C1E,OAAAsD,IAAA,EAAAA,EAqBsB,aArBtB7E,SAAA+B,UAAAE,OAAAjC,QAAA+B,UAAAC,UAAAhC,QAAA+B,UAAAmB,KAAAZ,MAAAP,UAAAmB,KAAAlD,QAAA+B,UAAAH,KAAAU,MAAAP,UAAAH,KAAAmD,OAAAC,QAAAhF","file":"locale.min.js","sourcesContent":["const Locale = require('./locale');\nconst Locales = require('./locales');\n\nconst app = function (supported, def) {\n let supportedLocales = supported;\n\n if (!(supportedLocales instanceof Locales)) {\n supportedLocales = new Locales(supportedLocales, def);\n supportedLocales.index();\n }\n\n return (req, res, next) => {\n const locales = new Locales(req.headers['accept-language']);\n\n const bestLocale = locales.best(supportedLocales);\n req.locale = String(bestLocale);\n req.rawLocale = bestLocale;\n next();\n };\n};\n\napp.Locales = Locales;\napp.Locale = Locale;\n\nmodule.exports = app;\n","const defaultLocaleString = () => process.env.LANG || 'en_US';\n\nclass Locale {\n constructor(str) {\n if (!str) return null;\n\n const match = str.match(/[a-z]+/gi);\n const [language, country] = match;\n\n this.code = str;\n this.language = language.toLowerCase();\n const normalized = [this.language];\n\n if (country) {\n this.country = country.toUpperCase();\n normalized.push(this.country);\n }\n\n this.normalized = normalized.join('_');\n }\n\n serialize() {\n if (!this.language) return null;\n return this.code;\n }\n}\nLocale.prototype.toString = Locale.prototype.serialize;\nLocale.prototype.toJSON = Locale.prototype.serialize;\nLocale.default = new Locale(defaultLocaleString());\n\nmodule.exports = Locale;\n","const Locale = require('./locale');\n\nclass Locales {\n constructor(input, def) {\n let elements = [];\n\n if (input) {\n if (typeof input === 'string' || input instanceof String) {\n elements = input.split(',');\n } else if (input instanceof Array) {\n elements = input.slice();\n }\n\n elements = elements\n .map(function (item) {\n if (!item) return null;\n\n const [locale, q] = item.split(';');\n const locale2 = new Locale(locale.trim());\n let score = 1;\n\n if (q) {\n score = q.slice(2) || 0;\n }\n\n locale2.score = score;\n\n return locale2;\n })\n .filter(e => e instanceof Locale)\n .sort((a, b) => b.score - a.score);\n }\n\n this.elements = elements;\n this._index = null;\n if (def) {\n this.default = new Locale(def);\n }\n }\n\n index() {\n if (!this._index) {\n this._index = {};\n\n this.elements.forEach(function (locale, idx) {\n this._index[locale.normalized] = idx;\n }, this);\n }\n return this._index;\n }\n\n best(locales) {\n const setLocale = function (l) {\n const r = l;\n r.defaulted = false;\n return r;\n };\n\n let locale = Locale.default;\n if (locales && locales.default) {\n locale = locales.default;\n }\n locale.defaulted = true;\n\n if (!locales) {\n if (this.elements[0]) {\n locale = this.elements[0];\n locale.defaulted = true;\n }\n return locale;\n }\n\n for (const item of this.elements) { // eslint-disable-line no-restricted-syntax\n const appropriateLocaleIndex = Locales.appropriateIndex(locales, item);\n\n if (appropriateLocaleIndex !== null) {\n return setLocale(locales.elements[appropriateLocaleIndex]);\n }\n }\n\n return locale;\n }\n\n static appropriateIndex(locales, locale) {\n const index = locales.index();\n\n const normalizedIndex = index[locale.normalized];\n const languageIndex = index[locale.language];\n\n if (normalizedIndex !== undefined) {\n return normalizedIndex;\n } else if (languageIndex !== undefined) {\n return languageIndex;\n }\n\n const sameLanguageLocaleIndex = locales.elements.findIndex(l => l.language === locale.language);\n if (sameLanguageLocaleIndex > -1) return sameLanguageLocaleIndex;\n\n return null;\n }\n\n serialize() {\n return [...this.elements];\n }\n\n toString() {\n return String(this.toJSON());\n }\n}\nLocales.prototype.toJSON = Locales.prototype.serialize;\nLocales.prototype.sort = Array.prototype.sort;\nLocales.prototype.push = Array.prototype.push;\n\nmodule.exports = Locales;\n"]} \ No newline at end of file From bef7a76abac41f2c6254559e4dc4b4a746100fe3 Mon Sep 17 00:00:00 2001 From: florrain Date: Thu, 6 Apr 2017 23:47:53 +0200 Subject: [PATCH 16/17] Remove gulp-sourcemaps --- gulpfile.js | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 49d3303..69a3c2d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,7 +1,6 @@ var gulp = require('gulp'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); -var sourcemaps = require('gulp-sourcemaps'); var babel = require('gulp-babel'); var mocha = require('gulp-mocha'); var gutil = require('gulp-util'); diff --git a/package.json b/package.json index e5cb702..8ba001e 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "gulp-concat": "^2.6.1", "gulp-eslint": "^3.0.1", "gulp-mocha": "^4.1.0", - "gulp-sourcemaps": "^2.4.1", "gulp-uglify": "^2.1.2", "gulp-util": "^3.0.8", "mocha": "^3.2.0" From 09966e97509149304fb99b2357b0909eca4b8ac7 Mon Sep 17 00:00:00 2001 From: florrain Date: Thu, 6 Apr 2017 23:50:28 +0200 Subject: [PATCH 17/17] Add bugs URL in package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8ba001e..f3a422b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Browser locale negotiation for node.js", "version": "0.1.0", "homepage": "https://github.com/florrain/locale", + "bugs": "https://github.com/florrain/locale/issues", "repository": { "type": "git", "url": "git://github.com/florrain/locale.git"