%PDF- %PDF-
| Direktori : /home/opti/workflow/node_modules/@ladjs/i18n/lib/ |
| Current File : /home/opti/workflow/node_modules/@ladjs/i18n/lib/index.js |
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
const _require = require('path'),
extname = _require.extname,
resolve = _require.resolve;
const Boom = require('@hapi/boom');
const autoBind = require('auto-bind');
const boolean = require('boolean');
const debug = require('debug')('ladjs:i18n');
const i18n = require('i18n');
const locales = require('i18n-locales');
const moment = require('moment');
const titleize = require('titleize');
const _require2 = require('country-language'),
getLanguage = _require2.getLanguage;
const _require3 = require('lodash'),
isEmpty = _require3.isEmpty,
sortBy = _require3.sortBy,
every = _require3.every,
isFunction = _require3.isFunction;
const _require4 = require('qs'),
stringify = _require4.stringify; // expose global
i18n.api = {};
class I18N {
constructor(config = {}) {
this.config = Object.assign({
phrases: {},
logger: console,
directory: resolve('locales'),
locales: ['en', 'es', 'zh'],
cookie: 'locale',
indent: ' ',
defaultLocale: 'en',
syncFiles: boolean(process.env.I18N_SYNC_FILES || true),
autoReload: boolean(process.env.I18N_AUTO_RELOAD || false),
updateFiles: boolean(process.env.I18N_UPDATE_FILES || true),
api: {
__: 't',
__n: 'tn',
__l: 'tl',
__h: 'th',
__mf: 'tmf'
},
register: i18n.api,
lastLocaleField: 'last_locale'
}, config); // validate locales against available ones
if (!every(this.config.locales, l => locales.includes(l))) throw new Error(`Invalid locales: ${this.config.locales.filter(str => !locales.includes(str)).join(', ')}`); // inherit i18n object
Object.assign(this, i18n); // configure i18n
this.configure(this.config);
autoBind(this);
}
translate(key, locale) {
const phrases = this.config.phrases; // eslint-disable-next-line prefer-rest-params
let args = Object.keys(arguments) // eslint-disable-next-line prefer-rest-params
.map(key => arguments[key]).slice(2);
if (typeof args === 'undefined') args = [];
const phrase = phrases[key];
if (typeof phrase !== 'string') throw new Error(`translation key missing: ${key}`);
args = [{
phrase,
locale
}, ...args];
return i18n.api.t(...args);
}
middleware(ctx, next) {
const _this$config = this.config,
locales = _this$config.locales,
defaultLocale = _this$config.defaultLocale,
phrases = _this$config.phrases,
cookie = _this$config.cookie; // expose api methods to `ctx.request` and `ctx.state`
i18n.init(ctx.request, ctx.state); // expose a helper function to `ctx.state.l`
// which prefixes a link/path with the locale
ctx.state.l = (path = '') => {
return `/${ctx.state.locale}${path}`;
}; // override the existing locale detection with our own
// in order of priority:
//
// 1. check the URL, if === `/de` or starts with `/de/` then locale is `de`
// 2. check the cookie
// 3. check Accept-Language last
//
// also we need to expose `ctx.pathWithoutLocale`
// as the path without locale
let locale = locales.find(l => {
return `/${l}` === ctx.path || ctx.path.indexOf(`/${l}/`) === 0;
});
ctx.pathWithoutLocale = locale ? ctx.path.substring(`/${locale}`.length) : ctx.path;
if (ctx.pathWithoutLocale === '') ctx.pathWithoutLocale = '/';
if (!locale) {
locale = defaultLocale;
if (ctx.cookies.get(cookie) && locales.includes(ctx.cookies.get(cookie))) {
locale = ctx.cookies.get(cookie);
debug('found locale via cookie using %s', locale);
} else if (ctx.request.acceptsLanguages(locales)) {
locale = ctx.request.acceptsLanguages(locales);
debug('found locale via Accept-Language header using %s', locale);
} else {
debug('using default locale');
}
} // set the locale properly
i18n.setLocale([ctx.request, ctx.state], locale);
ctx.locale = ctx.request.locale; // if the locale was not available then redirect user
if (locale !== ctx.state.locale) {
debug('locale was not available redirecting user');
return ctx.redirect(`/${ctx.state.locale}${ctx.pathWithoutLocale}${isEmpty(ctx.query) ? '' : `?${stringify(ctx.query)}`}`);
} // available languages for a dropdown menu to change language
ctx.state.availableLanguages = sortBy(locales.map(locale => {
return {
locale,
url: `/${locale}${ctx.pathWithoutLocale}${isEmpty(ctx.query) ? '' : `?${stringify(ctx.query)}`}`,
name: getLanguage(locale).name[0]
};
}), 'name'); // get the name of the current locale's language in native language
ctx.state.currentLanguage = titleize(getLanguage(ctx.request.locale).nativeName[0]); // bind `ctx.translate` as a helper func
// so you can pass `ctx.translate('SOME_KEY_IN_CONFIG');` and it will lookup
// `phrases['SOMETHING']` to get a specific and constant message
// and then it will call `t` to translate it to the user's locale
ctx.translate = function (...args) {
if (typeof args[0] !== 'string' || typeof phrases[args[0]] !== 'string') return ctx.throw(Boom.badRequest('Translation for your locale failed, try again'));
args[0] = phrases[args[0]];
return ctx.request.t(...args);
};
return next();
}
redirect(ctx, next) {
var _this = this;
return _asyncToGenerator(function* () {
debug('attempting to redirect'); // do not redirect static paths
if (extname(ctx.path) !== '') return next(); // inspired by nodejs.org language support
// <https://github.com/nodejs/nodejs.org/commit/d6cdd942a8fc0fffcf6879eca124295e95991bbc#diff-78c12f5adc1848d13b1c6f07055d996eR59>
const locale = ctx.url.split('/')[1].split('?')[0];
const hasLang = _this.config.locales.includes(locale); // if the URL did not have a valid language found
// then redirect the user to their detected locale
if (!hasLang) {
ctx.status = 302;
let redirect = `/${ctx.request.locale}${ctx.url}`;
if (redirect === `/${ctx.request.locale}/`) redirect = `/${ctx.request.locale}`;
if (!isEmpty(ctx.query)) redirect += `?${stringify(ctx.query)}`;
debug('no valid locale found in URL, redirecting to %s', redirect);
return ctx.redirect(redirect);
}
debug('found valid language "%s"', locale); // set the cookie for future requests
ctx.cookies.set(_this.config.cookie, locale, {
// Disable signed cookies in NODE_ENV=test
signed: process.env.NODE_ENV !== 'test',
expires: moment().add(1, 'year').toDate()
});
debug('set cookies for locale "%s"', locale); // if the user is logged in and ctx.isAuthenticated() exists,
// then save it as `last_locale` (variable based off lastLocaleField)
if (isFunction(ctx.isAuthenticated) && ctx.isAuthenticated()) {
ctx.state.user[_this.config.lastLocaleField] = locale;
try {
yield ctx.state.user.save();
} catch (err) {
_this.config.logger.error(err);
}
}
return next();
})();
}
}
module.exports = I18N;