first commit
commit
15864d180d
|
@ -0,0 +1,15 @@
|
||||||
|
*.seed
|
||||||
|
*.log
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
*.gz
|
||||||
|
|
||||||
|
pids
|
||||||
|
logs
|
||||||
|
results
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
coverage/
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules/
|
||||||
|
coverage/
|
||||||
|
.tmp/
|
||||||
|
.git/
|
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
// JSHint Default Configuration File (as on JSHint website)
|
||||||
|
// See http://jshint.com/docs/ for more details
|
||||||
|
|
||||||
|
"maxerr" : 50, // {int} Maximum error before stopping
|
||||||
|
|
||||||
|
// Enforcing
|
||||||
|
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
|
||||||
|
"camelcase" : false, // true: Identifiers must be in camelCase
|
||||||
|
"curly" : true, // true: Require {} for every new block or scope
|
||||||
|
"eqeqeq" : true, // true: Require triple equals (===) for comparison
|
||||||
|
"forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
|
||||||
|
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
|
||||||
|
"indent" : false, // {int} Number of spaces to use for indentation
|
||||||
|
"latedef" : false, // true: Require variables/functions to be defined before being used
|
||||||
|
"newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||||
|
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
|
||||||
|
"noempty" : true, // true: Prohibit use of empty blocks
|
||||||
|
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
|
||||||
|
"plusplus" : false, // true: Prohibit use of `++` & `--`
|
||||||
|
"quotmark" : false, // Quotation mark consistency:
|
||||||
|
// false : do nothing (default)
|
||||||
|
// true : ensure whatever is used is consistent
|
||||||
|
// "single" : require single quotes
|
||||||
|
// "double" : require double quotes
|
||||||
|
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
|
||||||
|
"unused" : true, // true: Require all defined variables be used
|
||||||
|
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
|
||||||
|
"trailing" : false, // true: Prohibit trailing whitespaces
|
||||||
|
"maxparams" : false, // {int} Max number of formal params allowed per function
|
||||||
|
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
|
||||||
|
"maxstatements" : false, // {int} Max number statements per function
|
||||||
|
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
|
||||||
|
"maxlen" : false, // {int} Max number of characters per line
|
||||||
|
|
||||||
|
// Relaxing
|
||||||
|
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
|
||||||
|
"boss" : true, // true: Tolerate assignments where comparisons would be expected
|
||||||
|
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
|
||||||
|
"eqnull" : false, // true: Tolerate use of `== null`
|
||||||
|
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
|
||||||
|
"esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`)
|
||||||
|
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
|
||||||
|
// (ex: `for each`, multiple try/catch, function expression…)
|
||||||
|
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
|
||||||
|
"expr" : true, // true: Tolerate `ExpressionStatement` as Programs
|
||||||
|
"funcscope" : false, // true: Tolerate defining variables inside control statements"
|
||||||
|
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
|
||||||
|
"iterator" : false, // true: Tolerate using the `__iterator__` property
|
||||||
|
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
|
||||||
|
"laxbreak" : true, // true: Tolerate possibly unsafe line breakings
|
||||||
|
"laxcomma" : false, // true: Tolerate comma-first style coding
|
||||||
|
"loopfunc" : false, // true: Tolerate functions being defined in loops
|
||||||
|
"multistr" : true, // true: Tolerate multi-line strings
|
||||||
|
"proto" : false, // true: Tolerate using the `__proto__` property
|
||||||
|
"scripturl" : false, // true: Tolerate script-targeted URLs
|
||||||
|
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
|
||||||
|
"shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
|
||||||
|
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
|
||||||
|
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
|
||||||
|
"validthis" : false, // true: Tolerate using this in a non-constructor function
|
||||||
|
|
||||||
|
// Environments
|
||||||
|
"browser" : true, // Web Browser (window, document, etc)
|
||||||
|
"couch" : false, // CouchDB
|
||||||
|
"devel" : true, // Development/debugging (alert, confirm, etc)
|
||||||
|
"dojo" : false, // Dojo Toolkit
|
||||||
|
"jquery" : false, // jQuery
|
||||||
|
"mootools" : false, // MooTools
|
||||||
|
"node" : true, // Node.js
|
||||||
|
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
|
||||||
|
"prototypejs" : false, // Prototype and Scriptaculous
|
||||||
|
"rhino" : false, // Rhino
|
||||||
|
"worker" : false, // Web Workers
|
||||||
|
"wsh" : false, // Windows Scripting Host
|
||||||
|
"yui" : false, // Yahoo User Interface
|
||||||
|
"noyield" : true, // allow generators without a yield
|
||||||
|
|
||||||
|
// Legacy
|
||||||
|
"nomen" : false, // true: Prohibit dangling `_` in variables
|
||||||
|
"onevar" : false, // true: Allow only one `var` statement per function
|
||||||
|
"passfail" : false, // true: Stop on first error
|
||||||
|
"white" : false, // true: Check against strict whitespace and indentation rules
|
||||||
|
|
||||||
|
// Custom Globals
|
||||||
|
"globals" : { // additional predefined global variables
|
||||||
|
// mocha
|
||||||
|
"describe": true,
|
||||||
|
"it": true,
|
||||||
|
"before": true,
|
||||||
|
"afterEach": true,
|
||||||
|
"beforeEach": true,
|
||||||
|
"after": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 'iojs-1'
|
||||||
|
- '0.12'
|
||||||
|
- '0.10'
|
||||||
|
script: "npm run test-travis"
|
||||||
|
after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
|
|
@ -0,0 +1,21 @@
|
||||||
|
This software is licensed under the MIT License.
|
||||||
|
|
||||||
|
Copyright (c) 2015 koajs and other contributors
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,118 @@
|
||||||
|
koa-locales
|
||||||
|
=======
|
||||||
|
|
||||||
|
[![NPM version][npm-image]][npm-url]
|
||||||
|
[![build status][travis-image]][travis-url]
|
||||||
|
[![Test coverage][coveralls-image]][coveralls-url]
|
||||||
|
[![Gittip][gittip-image]][gittip-url]
|
||||||
|
[![David deps][david-image]][david-url]
|
||||||
|
[![iojs version][iojs-image]][iojs-url]
|
||||||
|
[![node version][node-image]][node-url]
|
||||||
|
[![npm download][download-image]][download-url]
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/koa-locales.svg?style=flat-square
|
||||||
|
[npm-url]: https://npmjs.org/package/koa-locales
|
||||||
|
[travis-image]: https://img.shields.io/travis/koajs/locales.svg?style=flat-square
|
||||||
|
[travis-url]: https://travis-ci.org/koajs/locales
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/koajs/locales.svg?style=flat-square
|
||||||
|
[coveralls-url]: https://coveralls.io/r/koajs/locales?branch=master
|
||||||
|
[gittip-image]: https://img.shields.io/gittip/fengmk2.svg?style=flat-square
|
||||||
|
[gittip-url]: https://www.gittip.com/fengmk2/
|
||||||
|
[david-image]: https://img.shields.io/david/koajs/locales.svg?style=flat-square
|
||||||
|
[david-url]: https://david-dm.org/koajs/locales
|
||||||
|
[iojs-image]: https://img.shields.io/badge/io.js-%3E=_1.0-yellow.svg?style=flat-square
|
||||||
|
[iojs-url]: http://iojs.org/
|
||||||
|
[node-image]: https://img.shields.io/badge/node.js-%3E=_0.12-green.svg?style=flat-square
|
||||||
|
[node-url]: http://nodejs.org/download/
|
||||||
|
[download-image]: https://img.shields.io/npm/dm/koa-locales.svg?style=flat-square
|
||||||
|
[download-url]: https://npmjs.org/package/koa-locales
|
||||||
|
|
||||||
|
koa locales, i18n solution for koa:
|
||||||
|
|
||||||
|
1. All locales resources location on `options.dir`.
|
||||||
|
2. One api: `__(key[, value, ...])`
|
||||||
|
3. Auto detect request locale from `query`, `cookie` and `header: Accept-Language`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install koa-locales --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```js
|
||||||
|
var koa = require('koa');
|
||||||
|
var locales = require('koa-locales');
|
||||||
|
|
||||||
|
var app = koa();
|
||||||
|
app.use(locales({
|
||||||
|
dir: __dirname + '/locales'
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### `locales(app, options)`
|
||||||
|
|
||||||
|
Patch locales functions to koa app.
|
||||||
|
|
||||||
|
- {Application} app: koa app instance.
|
||||||
|
- {Object} options: optional params
|
||||||
|
- {String} functionName: locale function name patch on koa context. Optional, default is `__`.
|
||||||
|
- {String} dir: locales resources store directory. Optional, default is `$PWD/locales`.
|
||||||
|
- {String} defaultLocale: default locale. Optional, default is `en-US`.
|
||||||
|
- {String} queryField: locale field name on query. Optional, default is `locale`.
|
||||||
|
- {String} cookieField: locale field name on cookie. Optional, default is `locale`.
|
||||||
|
- {String|Number} cookieMaxAge: set locale cookie value max age. Optional, default is `1y`, expired after one year.
|
||||||
|
|
||||||
|
```js
|
||||||
|
locales({
|
||||||
|
app: app,
|
||||||
|
dir: __dirname + '/app/locales',
|
||||||
|
defaultLocale: 'zh-CN'
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
### `context.__(key[, value1[, value2, ...]])`
|
||||||
|
|
||||||
|
Get current request locale text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
function* home() {
|
||||||
|
this.body = {
|
||||||
|
message: this.__('Hello, %s', 'fengmk2')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```js
|
||||||
|
__('Hello, %s. %s', 'fengmk2', 'koa rock!')
|
||||||
|
=>
|
||||||
|
'Hello fengmk2. koa rock!'
|
||||||
|
|
||||||
|
__('{0} {0} {1} {1} {1}', ['foo', 'bar'])
|
||||||
|
=>
|
||||||
|
'foo foo bar bar bar'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage on template
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.locales.__ = this.__.bind(this);
|
||||||
|
```
|
||||||
|
|
||||||
|
[nunjucks] example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{ __('Hello, %s', user.name) }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
|
||||||
|
[nunjucks]: https://www.npmjs.com/package/nunjucks
|
|
@ -0,0 +1,23 @@
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- nodejs_version: "1.3"
|
||||||
|
- nodejs_version: "0.12"
|
||||||
|
- nodejs_version: "0.10"
|
||||||
|
|
||||||
|
# Install scripts. (runs after repo cloning)
|
||||||
|
install:
|
||||||
|
# Get the latest stable version of Node.js or io.js
|
||||||
|
- ps: Install-Product node $env:nodejs_version
|
||||||
|
# install modules
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
# Post-install test scripts.
|
||||||
|
test_script:
|
||||||
|
# Output useful info for debugging.
|
||||||
|
- node --version
|
||||||
|
- npm --version
|
||||||
|
# run tests
|
||||||
|
- npm test
|
||||||
|
|
||||||
|
# Don't actually build.
|
||||||
|
build: off
|
|
@ -0,0 +1,177 @@
|
||||||
|
/**!
|
||||||
|
* koa-locales - index.js
|
||||||
|
*
|
||||||
|
* Copyright(c) koajs and other contributors.
|
||||||
|
* MIT Licensed
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* fengmk2 <m@fengmk2.com> (http://fengmk2.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var debug = require('debug')('koa-locales');
|
||||||
|
var util = require('util');
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var ms = require('humanize-ms');
|
||||||
|
|
||||||
|
module.exports = function (app, options) {
|
||||||
|
options = options || {};
|
||||||
|
var defaultLocale = formatLocale(options.defaultLocale || 'en-US');
|
||||||
|
var queryField = options.queryField || 'locale';
|
||||||
|
var cookieField = options.cookieField || 'locale';
|
||||||
|
var cookieMaxAge = ms(options.cookieMaxAge || '1y');
|
||||||
|
var localeDir = options.dir || path.join(process.cwd(), 'locales');
|
||||||
|
var functionName = options.functionName || '__';
|
||||||
|
var resources = {};
|
||||||
|
|
||||||
|
if (fs.existsSync(localeDir)) {
|
||||||
|
var names = fs.readdirSync(localeDir);
|
||||||
|
for (var i = 0; i < names.length; i++) {
|
||||||
|
var name = names[i];
|
||||||
|
if (!/\.(js|json)$/.test(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var filepath = path.join(localeDir, name);
|
||||||
|
// support en_US.js => en-US.js
|
||||||
|
var locale = formatLocale(name.split('.')[0]);
|
||||||
|
resources[locale] = require(filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('init locales with %j, got %j resources', options, Object.keys(resources));
|
||||||
|
|
||||||
|
var ARRAY_INDEX_RE = /\{(\d+)\}/g;
|
||||||
|
function formatWithArray(text, values) {
|
||||||
|
return text.replace(ARRAY_INDEX_RE, function (orignal, matched) {
|
||||||
|
var index = parseInt(matched);
|
||||||
|
if (index < values.length) {
|
||||||
|
return values[index];
|
||||||
|
}
|
||||||
|
// not match index, return orignal text
|
||||||
|
return orignal;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.context[functionName] = function (key, value, value2, value3, value4) {
|
||||||
|
if (arguments.length === 0) {
|
||||||
|
// __()
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var locale = this.__getLocale();
|
||||||
|
var resource = resources[locale] || {};
|
||||||
|
var text = resource[key] || key;
|
||||||
|
debug('%s: %j => %j', locale, key, text);
|
||||||
|
if (!text) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// for performance reason
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
// __(key)
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
if (arguments.length === 2) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
// __(key, array)
|
||||||
|
// __('{0} {1} {1} {0}', ['foo', 'bar'])
|
||||||
|
// =>
|
||||||
|
// foo bar bar foo
|
||||||
|
return formatWithArray(text, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// __(key, value)
|
||||||
|
return util.format(text, value);
|
||||||
|
}
|
||||||
|
if (arguments.length === 3) {
|
||||||
|
// __(key, value1, value2)
|
||||||
|
return util.format(text, value, value2);
|
||||||
|
}
|
||||||
|
if (arguments.length === 4) {
|
||||||
|
// __(key, value1, value2, value3)
|
||||||
|
return util.format(text, value, value2, value3);
|
||||||
|
}
|
||||||
|
if (arguments.length === 5) {
|
||||||
|
// __(key, value1, value2, value3, value4)
|
||||||
|
return util.format(text, value, value2, value3, value4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// __(key, value1, value2, value3, value4, value5, ...)
|
||||||
|
var args = Array.prototype.slice.call(arguments, 1);
|
||||||
|
args.unshift(text);
|
||||||
|
return util.format.apply(util, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. query: /?locale=en-US
|
||||||
|
// 2. cookie: locale=zh-TW
|
||||||
|
// 3. header: Accept-Language: zh-CN,zh;q=0.5
|
||||||
|
app.context.__getLocale = function () {
|
||||||
|
if (this.__locale) {
|
||||||
|
return this.__locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cookieLocale = this.cookies.get(cookieField);
|
||||||
|
var locale = this.query[queryField] || cookieLocale;
|
||||||
|
if (!locale) {
|
||||||
|
// Accept-Language: zh-CN,zh;q=0.5
|
||||||
|
// Accept-Language: zh-CN
|
||||||
|
var languages = this.acceptsLanguages();
|
||||||
|
if (languages) {
|
||||||
|
if (Array.isArray(languages)) {
|
||||||
|
if (languages[0] === '*') {
|
||||||
|
languages = languages.slice(1);
|
||||||
|
}
|
||||||
|
if (languages.length > 0) {
|
||||||
|
for (var i = 0; i < languages.length; i++) {
|
||||||
|
var lang = formatLocale(languages[i]);
|
||||||
|
if (resources[lang]) {
|
||||||
|
locale = lang;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!locale) {
|
||||||
|
// set the first one
|
||||||
|
locale = languages[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
locale = languages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// all missing, set it to defaultLocale
|
||||||
|
if (!locale) {
|
||||||
|
locale = defaultLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
locale = formatLocale(locale);
|
||||||
|
|
||||||
|
// validate locale
|
||||||
|
if (!resources[locale]) {
|
||||||
|
locale = defaultLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cookieLocale !== locale) {
|
||||||
|
// locale change, need to set cookie
|
||||||
|
this.cookies.set(cookieField, locale, {
|
||||||
|
// make sure brower javascript can read the cookie
|
||||||
|
httpOnly: false,
|
||||||
|
maxAge: cookieMaxAge,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.__locale = locale;
|
||||||
|
return locale;
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatLocale(locale) {
|
||||||
|
// support zh_CN, en_US => zh-CN, en-US
|
||||||
|
return locale.replace('_', '-').toLowerCase();
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"name": "koa-locales",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "koa locales, i18n solution for koa",
|
||||||
|
"main": "index.js",
|
||||||
|
"files": [
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --check-leaks -R spec -t 5000 test/*.test.js",
|
||||||
|
"test-cov": "node node_modules/.bin/istanbul cover node_modules/.bin/_mocha -- --check-leaks -t 5000 test/*.test.js",
|
||||||
|
"test-travis": "node node_modules/.bin/istanbul cover node_modules/.bin/_mocha --report lcovonly -- --check-leaks -t 5000 test/*.test.js",
|
||||||
|
"jshint": "jshint .",
|
||||||
|
"autod": "autod -w --prefix '~'",
|
||||||
|
"cnpm": "npm install --registry=https://registry.npm.taobao.org",
|
||||||
|
"contributors": "contributors -f plain -o AUTHORS"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "~2.2.0",
|
||||||
|
"humanize-ms": "~1.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autod": "*",
|
||||||
|
"contributors": "*",
|
||||||
|
"istanbul-harmony": "*",
|
||||||
|
"jshint": "*",
|
||||||
|
"koa": "~0.20.0",
|
||||||
|
"mm": "~1.1.0",
|
||||||
|
"mocha": "*",
|
||||||
|
"pedding": "~1.0.0",
|
||||||
|
"supertest": "~1.0.1"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/koajs/locales",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/koajs/locales.git",
|
||||||
|
"web": "https://github.com/koajs/locales"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/koajs/locales/issues",
|
||||||
|
"email": "m@fengmk2.com"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"koa-locales",
|
||||||
|
"i18n",
|
||||||
|
"locales",
|
||||||
|
"koa-i18n",
|
||||||
|
"koa"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0",
|
||||||
|
"iojs": ">=1.0.0"
|
||||||
|
},
|
||||||
|
"author": "fengmk2 <m@fengmk2.com> (http://fengmk2.com)",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
|
@ -0,0 +1,354 @@
|
||||||
|
/**!
|
||||||
|
* koa-locales - test/index.test.js
|
||||||
|
*
|
||||||
|
* Copyright(c) koajs and other contributors.
|
||||||
|
* MIT Licensed
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* fengmk2 <m@fengmk2.com> (http://fengmk2.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var koa = require('koa');
|
||||||
|
var request = require('supertest');
|
||||||
|
var pedding = require('pedding');
|
||||||
|
var mm = require('mm');
|
||||||
|
var locales = require('../');
|
||||||
|
|
||||||
|
describe('koa-locales.test.js', function () {
|
||||||
|
|
||||||
|
afterEach(mm.restore);
|
||||||
|
|
||||||
|
describe('default options', function () {
|
||||||
|
var app = createApp();
|
||||||
|
|
||||||
|
it('should use default locale: en-US', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('custom options', function () {
|
||||||
|
var app = createApp({
|
||||||
|
dir: __dirname + '/locales'
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use default locale: en-US', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('query.locale', function () {
|
||||||
|
it('should use query locale: zh-CN', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=zh-CN')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use query locale and change cookie locale', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=zh-CN')
|
||||||
|
.set('cookie', 'locale=zh-TW')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore invalid locale value', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=xss')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cookie.locale', function () {
|
||||||
|
it('should use cookie locale: zh-CN', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.set('cookie', 'locale=zh-cn')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect(function (res) {
|
||||||
|
assert(!res.headers['set-cookie']);
|
||||||
|
})
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Accept-Language', function () {
|
||||||
|
it('should use Accept-Language: zh-CN', function (done) {
|
||||||
|
done = pedding(3, done);
|
||||||
|
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.set('Accept-Language', 'zh-CN')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.set('Accept-Language', 'zh-CN,zh;q=0.8')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.set('Accept-Language', 'en;q=0.8, es, zh_CN')
|
||||||
|
.expect({
|
||||||
|
email: '邮箱',
|
||||||
|
hello: 'fengmk2,今天过得如何?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with "Accept-Language: " header', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.set('Accept-Language', '')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with "Accept-Language: en"', function (done) {
|
||||||
|
request(app.callback())
|
||||||
|
.get('/')
|
||||||
|
.set('Accept-Language', 'en')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mock acceptsLanguages return string', function (done) {
|
||||||
|
mm(app.request, 'acceptsLanguages', function () {
|
||||||
|
return 'zh-TW';
|
||||||
|
});
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=zh\-tw; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mock acceptsLanguages return null', function (done) {
|
||||||
|
mm(app.request, 'acceptsLanguages', function () {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
request(app.callback())
|
||||||
|
.get('/?locale=')
|
||||||
|
.expect({
|
||||||
|
email: 'Email',
|
||||||
|
hello: 'Hello fengmk2, how are you today?',
|
||||||
|
message: 'Hello fengmk2, how are you today? How was your 18.',
|
||||||
|
empty: '',
|
||||||
|
notexists_key: 'key not exists',
|
||||||
|
empty_string: '',
|
||||||
|
novalue: 'key %s ok',
|
||||||
|
arguments3: '1 2 3',
|
||||||
|
arguments4: '1 2 3 4',
|
||||||
|
arguments5: '1 2 3 4 5',
|
||||||
|
arguments6: '1 2 3 4 5. 6',
|
||||||
|
values: 'foo bar foo bar {2} {100}',
|
||||||
|
})
|
||||||
|
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function createApp(options) {
|
||||||
|
var app = koa();
|
||||||
|
locales(app, options);
|
||||||
|
var fname = options && options.functionName || '__';
|
||||||
|
|
||||||
|
app.use(function* () {
|
||||||
|
this.body = {
|
||||||
|
email: this[fname]('Email'),
|
||||||
|
hello: this[fname]('Hello %s, how are you today?', 'fengmk2'),
|
||||||
|
message: this[fname]('Hello %s, how are you today? How was your %s.', 'fengmk2', 18),
|
||||||
|
empty: this[fname](),
|
||||||
|
notexists_key: this[fname]('key not exists'),
|
||||||
|
empty_string: this[fname](''),
|
||||||
|
novalue: this[fname]('key %s ok'),
|
||||||
|
arguments3: this[fname]('%s %s %s', 1, 2, 3),
|
||||||
|
arguments4: this[fname]('%s %s %s %s', 1, 2, 3, 4),
|
||||||
|
arguments5: this[fname]('%s %s %s %s %s', 1, 2, 3, 4, 5),
|
||||||
|
arguments6: this[fname]('%s %s %s %s %s.', 1, 2, 3, 4, 5, 6),
|
||||||
|
values: this[fname]('{0} {1} {0} {1} {2} {100}', ['foo', 'bar']),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
should not load this file
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = {
|
||||||
|
'Email': '邮箱',
|
||||||
|
'Hello %s, how are you today?': '%s,今天过得如何?',
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue