CoastalCommitsPastes/server/node_modules/strong-globalize/lib/helper.js
2022-03-06 16:46:59 -08:00

926 lines
No EOL
31 KiB
JavaScript

"use strict";
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
// Node module: strong-globalize
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLangAlias = exports.removeDoubleCurlyBraces = exports.loadMsgFromFile = exports.myIntlDir = exports.getLanguageFromRequest = exports.repackArgs = exports.mapArgs = exports.mapPercent = exports.percent = exports.intlDir = exports.headerIncluded = exports.getPackageItem = exports.getPackageVersion = exports.getPackageName = exports.getTrailerAfterDot = exports.getAppLanguages = exports.getSupportedLanguages = exports.isSupportedLanguage = exports.initIntlDirs = exports.sortMsges = exports.scanJsonPriv = exports.replaceJson = exports.scanJson = exports.normalizeKeyArrays = exports.readToJson = exports.resolveDependencies = exports.unsymbolLink = exports.requireResolve = exports.maxDirectoryDepth = exports.directoryDepth = exports.removeObsoleteFile = exports.enumerateMsgSyncPriv = exports.enumerateMsgSync = exports.cloneEnglishTxtSyncDeep = exports.enumerateLanguageSync = exports.enumerateFilesSyncPriv = exports.alreadyScanned = exports.enumerateFilesSync = exports.stripBom = exports.resTagExists = exports.registerResTag = exports.msgFileIdHash = exports.validateAmlValue = exports.isLoadMessages = exports.initGlobForSltGlobalize = exports.isRootPackage = exports.getRootDir = exports.setRootDir = exports.hashKeys = exports.MSG_GPB_UNAVAILABLE = exports.BIG_NUM = exports.AML_DEFAULT = exports.AML_NONE = exports.AML_ALL = exports.HELPTXT_TAG = exports.MSG_TAG = exports.PSEUDO_TAG = exports.PSEUDO_LANG = exports.ENGLISH = void 0;
const dbg = require("debug");
const debug = dbg('strong-globalize');
const acceptLanguage = require("accept-language");
const assert = require("assert");
const fs = require("fs");
const _ = require("lodash");
const md5 = require("md5");
const mkdirp = require("mkdirp");
const path = require("path");
const config_1 = require("./config");
exports.ENGLISH = 'en';
exports.PSEUDO_LANG = 'zz';
exports.PSEUDO_TAG = '♚♛♜♝♞♟';
exports.MSG_TAG = 'message';
exports.HELPTXT_TAG = 'helptxt';
exports.AML_ALL = 'all';
exports.AML_NONE = 'none';
exports.AML_DEFAULT = exports.AML_NONE;
exports.BIG_NUM = 999999999999;
exports.MSG_GPB_UNAVAILABLE = '*** Login to GPB failed or GPB.supportedTranslations error.';
const HASH_KEYS = false;
const KEY_HEADERS = ['msg'];
function hashKeys(p) {
let trailer = null;
return !(headerIncluded(p, KEY_HEADERS) ||
(trailer = getTrailerAfterDot(p)) === 'txt' ||
trailer === 'json' ||
trailer === 'yml' ||
trailer === 'yaml' ||
p.indexOf(exports.PSEUDO_TAG) === 0);
}
exports.hashKeys = hashKeys;
// tslint:disable:no-any
/**
* Supported languages in CLDR notation
*/
let TARGET_LANGS = null;
let MY_ROOT = process.cwd();
let INTL_DIR = path.join(MY_ROOT, 'intl');
/**
* @param {string} Override the root directory path
*/
function setRootDir(rootPath) {
let validPath = true;
let rootStats = undefined;
try {
rootStats = fs.statSync(rootPath);
}
catch (e) {
validPath = false;
}
assert(validPath, '*** setRootDir: Root path invalid: ' + rootPath);
if (!rootStats.isDirectory())
validPath = false;
assert(validPath, '*** setRootDir: Root path is not a directory: ' + rootPath.toString());
let files = undefined;
try {
files = fs.readdirSync(rootPath);
}
catch (e) {
validPath = false;
}
validPath = validPath && !!files;
if (validPath) {
let intlDirFound = false;
files.forEach(function (item) {
if (intlDirFound)
return;
if (item === 'intl')
intlDirFound = true;
});
validPath = intlDirFound;
}
assert(validPath, '*** setRootDir: Intl dir not found under: ' + rootPath.toString());
MY_ROOT = rootPath;
INTL_DIR = path.join(MY_ROOT, 'intl');
}
exports.setRootDir = setRootDir;
function getRootDir() {
return MY_ROOT;
}
exports.getRootDir = getRootDir;
function isRootPackage() {
return MY_ROOT === config_1.STRONGLOOP_GLB.MASTER_ROOT_DIR;
}
exports.isRootPackage = isRootPackage;
function initGlobForSltGlobalize(rootDir) {
if (config_1.STRONGLOOP_GLB.MASTER_ROOT_DIR)
return;
Object.assign(config_1.STRONGLOOP_GLB, {
MASTER_ROOT_DIR: rootDir || getRootDir(),
MSG_RES_LOADED: [],
});
}
exports.initGlobForSltGlobalize = initGlobForSltGlobalize;
function isLoadMessages(rootDir) {
if (!config_1.STRONGLOOP_GLB.MASTER_ROOT_DIR)
return false;
if (path.resolve(rootDir) === path.resolve(config_1.STRONGLOOP_GLB.MASTER_ROOT_DIR))
return true;
if (!config_1.STRONGLOOP_GLB.AUTO_MSG_LOADING)
return false;
if (config_1.STRONGLOOP_GLB.AUTO_MSG_LOADING === exports.AML_NONE)
return false;
if (config_1.STRONGLOOP_GLB.AUTO_MSG_LOADING === exports.AML_ALL)
return true;
const packagesToLoad = config_1.STRONGLOOP_GLB.AUTO_MSG_LOADING;
const packageName = getPackageName(rootDir);
const load = packagesToLoad.indexOf(packageName) >= 0;
return load;
}
exports.isLoadMessages = isLoadMessages;
function validateAmlValue(aml) {
if (aml === exports.AML_ALL || aml === exports.AML_NONE)
return aml;
if (Array.isArray(aml)) {
if (aml.length === 0)
return false;
aml.forEach(function (v) {
if (typeof aml !== 'string')
return false;
});
return aml;
}
return false;
}
exports.validateAmlValue = validateAmlValue;
function msgFileIdHash(fileName, rootDir) {
assert(fileName);
rootDir = rootDir || getRootDir();
const packageName = getPackageName(rootDir);
const packageVersion = getPackageVersion(rootDir);
const msgFileId = fileName + packageName + packageVersion;
return md5(msgFileId);
}
exports.msgFileIdHash = msgFileIdHash;
function registerResTag(fileIdHash, fileName, lang, tagType) {
assert(config_1.STRONGLOOP_GLB);
assert(fileIdHash);
assert(fileName);
assert(lang);
assert(tagType);
if (resTagExists(fileIdHash, fileName, lang, tagType))
return false;
const resTag = {
fileIdHash: fileIdHash,
fileName: fileName,
lang: lang,
tagType: tagType,
};
config_1.STRONGLOOP_GLB.MSG_RES_LOADED.push(resTag);
return true;
}
exports.registerResTag = registerResTag;
function resTagExists(fileIdHash, fileName, lang, tagType) {
assert(config_1.STRONGLOOP_GLB);
assert(fileIdHash);
assert(fileName);
assert(lang);
assert(tagType);
const resTag = {
fileIdHash: fileIdHash,
lang: lang,
tagType: tagType,
};
const exists = _.find(config_1.STRONGLOOP_GLB.MSG_RES_LOADED, resTag) !== undefined;
return exists;
}
exports.resTagExists = resTagExists;
function stripBom(str) {
return str.charCodeAt(0) === 0xfeff ? str.slice(1) : str;
}
exports.stripBom = stripBom;
/**
* Enumerate all JS files in this application
* @param {Function}
* param.content is a UTF8 string of each JS source file.
*/
const showDotCount = 500;
const showCountCount = 10000;
let enumeratedFilesCount = 0;
let scannedFileNameHash = null;
function enumerateFilesSync(rootDir, blackList, targetFileType, verbose, checkNodeModules, callback) {
enumeratedFilesCount = 0;
scannedFileNameHash = [];
return enumerateFilesSyncPriv(rootDir, rootDir, blackList, targetFileType, verbose, checkNodeModules, callback);
}
exports.enumerateFilesSync = enumerateFilesSync;
function alreadyScanned(fileName) {
const realFileName = process.browser ? fileName : fs.realpathSync(fileName);
const fileNameHash = md5(realFileName);
if (scannedFileNameHash.indexOf(fileNameHash) >= 0) {
return true;
}
else {
scannedFileNameHash.push(fileNameHash);
return false;
}
}
exports.alreadyScanned = alreadyScanned;
function enumerateFilesSyncPriv(currentPath, rootDir, blackList, targetFileType, verbose, checkNodeModules, callback) {
if (!currentPath)
currentPath = MY_ROOT;
if (!rootDir)
rootDir = MY_ROOT;
currentPath = path.resolve(currentPath);
if (alreadyScanned(currentPath))
return;
rootDir = path.resolve(rootDir);
blackList = Array.isArray(blackList) ? blackList : [];
if (!Array.isArray(targetFileType))
targetFileType = [targetFileType];
let skipDir = false;
blackList.forEach(function (part) {
if (typeof part !== 'string')
return;
if (currentPath.indexOf(part) >= 0)
skipDir = true;
});
if (skipDir) {
if (verbose)
console.log('*** skipping directory:', currentPath);
return;
}
let files = null;
try {
files = fs.readdirSync(currentPath);
}
catch (e) {
return;
}
files.forEach(function (item) {
if (item.indexOf('.') === 0)
return;
const child = path.join(currentPath, item);
let stats = null;
try {
stats = fs.statSync(child);
}
catch (e) {
return;
}
if (stats.isDirectory()) {
item = item.toLowerCase();
if (item === 'test' || item === 'node_modules' || item === 'coverage')
return;
enumerateFilesSyncPriv(child, rootDir, blackList, targetFileType, verbose, checkNodeModules, callback);
}
else {
const fileType = getTrailerAfterDot(item);
if (!fileType || targetFileType.indexOf(fileType) < 0)
return;
const content = stripBom(fs.readFileSync(child, 'utf8'));
if (verbose)
console.log('~~~ examining file:', child);
if (checkNodeModules) {
enumeratedFilesCount++;
if (enumeratedFilesCount % showDotCount === 0) {
process.stdout.write('.');
if (enumeratedFilesCount % showCountCount === 0) {
process.stdout.write(' ' + enumeratedFilesCount.toString() + '\n');
}
}
}
callback(content, child);
}
});
if (checkNodeModules) {
const depthRoot = directoryDepth(rootDir);
const moduleRootPaths = resolveDependencies(currentPath, rootDir);
if (moduleRootPaths) {
moduleRootPaths.forEach(function (modulePath) {
const depthModule = directoryDepth(modulePath);
if (depthModule - depthRoot > maxDirectoryDepth())
return;
enumerateFilesSyncPriv(modulePath, rootDir, blackList, targetFileType, verbose, checkNodeModules, callback);
});
}
}
}
exports.enumerateFilesSyncPriv = enumerateFilesSyncPriv;
/**
* @param action A function to be invoked for each target language.
* If it returns `true`, the enumeration will be terminated.
*/
function enumerateLanguageSync(action) {
if (!TARGET_LANGS)
TARGET_LANGS = getSupportedLanguages();
for (const lang of TARGET_LANGS) {
const stopEnumeration = action(lang);
if (stopEnumeration)
return;
}
}
exports.enumerateLanguageSync = enumerateLanguageSync;
/**
* @param {string} lang Supported languages in CLDR notation
* @param {Function}
* If callback returns err; if err, stop enumeration.
*/
function cloneEnglishTxtSyncDeep(rootDir) {
if (!rootDir)
rootDir = MY_ROOT;
const enDirPath = path.join(rootDir, 'intl', exports.ENGLISH);
mkdirp.sync(enDirPath);
return enumerateMsgSyncPriv(rootDir, rootDir, exports.ENGLISH, true, true, 0, function () { });
}
exports.cloneEnglishTxtSyncDeep = cloneEnglishTxtSyncDeep;
function enumerateMsgSync(rootDir, lang, checkNodeModules, callback) {
return enumerateMsgSyncPriv(rootDir, rootDir, lang, checkNodeModules, false, 0, callback);
}
exports.enumerateMsgSync = enumerateMsgSync;
function enumerateMsgSyncPriv(currentPath, rootDir, lang, checkNodeModules, cloneEnglishTxt, clonedTxtCount, callback) {
assert(currentPath);
assert(rootDir);
assert(typeof callback === 'function');
let intlDirectory = path.join(currentPath, 'intl');
const langDirPath = path.join(intlDirectory, lang);
let msgFiles = null;
try {
msgFiles = fs.readdirSync(langDirPath);
}
catch (e) {
return clonedTxtCount;
}
const enDirPath = path.join(rootDir, 'intl', exports.ENGLISH);
const clonedFileNames = [];
msgFiles.forEach(function (msgFile) {
if (msgFile.indexOf('.') === 0)
return;
const stats = fs.lstatSync(path.join(langDirPath, msgFile));
if (!stats.isFile())
return;
// commented out to avoid interference with intercept-stdout in test
// debug('enumerating...', path.join(langDirPath, msgFile));
if (cloneEnglishTxt && lang === exports.ENGLISH) {
if (currentPath === rootDir)
return;
if (getTrailerAfterDot(msgFile) !== 'txt')
return;
const sourceTxtFilePath = path.join(langDirPath, msgFile);
const filePathHash = msgFileIdHash(msgFile, currentPath);
if (resTagExists(filePathHash, msgFile, lang, exports.HELPTXT_TAG))
return;
registerResTag(filePathHash, msgFile, lang, exports.HELPTXT_TAG);
const targetTxtFilePath = path.join(enDirPath, msgFile);
clonedFileNames.push(msgFile);
fs.writeFileSync(targetTxtFilePath, fs.readFileSync(sourceTxtFilePath));
clonedTxtCount++;
console.log('--- cloned', sourceTxtFilePath);
}
else {
const jsonObj = readToJson(langDirPath, msgFile, lang);
if (jsonObj) {
callback(jsonObj, path.join(langDirPath, msgFile));
}
}
});
if (cloneEnglishTxt && lang === exports.ENGLISH && clonedFileNames.length > 0) {
removeObsoleteFile(enDirPath, clonedFileNames);
}
if (checkNodeModules) {
const depthRoot = directoryDepth(rootDir);
const moduleRootPaths = resolveDependencies(currentPath, rootDir);
if (moduleRootPaths) {
moduleRootPaths.forEach(function (modulePath) {
const depthModule = directoryDepth(modulePath);
if (depthModule - depthRoot > maxDirectoryDepth())
return;
clonedTxtCount = enumerateMsgSyncPriv(modulePath, rootDir, lang, false, cloneEnglishTxt, clonedTxtCount, callback);
});
}
}
return clonedTxtCount;
}
exports.enumerateMsgSyncPriv = enumerateMsgSyncPriv;
function removeObsoleteFile(dir, fileNames) {
const files = fs.readdirSync(dir);
files.forEach(function (file) {
const matched = file.match(/^([0-9a-f]{32})_(.*\.txt)$/);
if (!matched)
return;
if (fileNames.indexOf(matched[2]) >= 0) {
console.log('--- removed', path.join(dir, file));
fs.unlinkSync(path.join(dir, file));
}
});
}
exports.removeObsoleteFile = removeObsoleteFile;
function directoryDepth(fullPath) {
assert(typeof fullPath === 'string');
return _.compact(fullPath.split(path.sep)).length;
}
exports.directoryDepth = directoryDepth;
function maxDirectoryDepth() {
let depth = parseInt(process.env.STRONGLOOP_GLOBALIZE_MAX_DEPTH, 10);
if (isNaN(depth))
depth = exports.BIG_NUM;
depth = Math.max(1, depth);
return depth;
}
exports.maxDirectoryDepth = maxDirectoryDepth;
function requireResolve(depName, currentDir, rootDir) {
// simulates npm v3 dependency resolution
let depPath = null;
let stats = null;
try {
depPath = path.join(currentDir, 'node_modules', depName);
stats = fs.lstatSync(depPath);
}
catch (e) {
stats = null;
try {
depPath = path.join(rootDir, 'node_modules', depName);
stats = fs.lstatSync(depPath);
}
catch (e) {
return null;
}
}
if (!stats)
return null;
return unsymbolLink(depPath);
}
exports.requireResolve = requireResolve;
function unsymbolLink(filePath) {
if (!filePath)
return null;
let stats = null;
try {
stats = fs.lstatSync(filePath);
}
catch (e) {
return null;
}
if (!stats)
return null;
if (stats.isSymbolicLink()) {
let realPath = null;
try {
realPath = process.browser ? filePath : fs.realpathSync(filePath);
}
catch (e) {
return null;
}
return unsymbolLink(realPath);
}
else {
return stats.isDirectory() ? filePath : null;
}
}
exports.unsymbolLink = unsymbolLink;
function resolveDependencies(currentDir, rootDir, moduleRootPaths) {
moduleRootPaths = moduleRootPaths || [];
const packageJson = path.join(currentDir, 'package.json');
let deps = null;
try {
deps = require(packageJson).dependencies;
}
catch (e) {
return null;
}
if (deps === undefined || !deps)
return null;
deps = Object.keys(deps);
if (deps.length === 0)
return null;
deps.forEach(function (dep) {
const depPath = requireResolve(dep, currentDir, rootDir);
if (depPath && moduleRootPaths.indexOf(depPath) < 0) {
moduleRootPaths.push(depPath);
resolveDependencies(depPath, rootDir, moduleRootPaths);
}
});
moduleRootPaths = _.uniq(_.compact(moduleRootPaths));
return moduleRootPaths;
}
exports.resolveDependencies = resolveDependencies;
/**
* Read a txt or json file and convert to JSON
*/
const acceptableTrailers = ['json', 'txt'];
function readToJson(langDirPath, msgFile, lang) {
const fileType = getTrailerAfterDot(msgFile);
if (!fileType || acceptableTrailers.indexOf(fileType) < 0)
return null;
let jsonObj = null;
const sourceFilePath = path.join(langDirPath, msgFile);
if (fileType === 'json') {
jsonObj = JSON.parse(stripBom(fs.readFileSync(sourceFilePath, 'utf-8')));
}
else {
// txt
const origStr = stripBom(fs.readFileSync(sourceFilePath, 'utf8'));
jsonObj = {};
const re = /^([0-9a-f]{32})_(.*)\.txt/;
const results = re.exec(msgFile);
if (results && results.length === 3) {
// deep-extracted txt file ?
msgFile = results[2] + '.txt';
}
jsonObj[msgFile] = mapPercent(JSON.parse(JSON.stringify(origStr)));
}
if (fileType === 'json' && HASH_KEYS && lang === exports.ENGLISH) {
const keys = Object.keys(jsonObj);
keys.forEach(function (key) {
const newKey = md5(key);
jsonObj[newKey] = jsonObj[key];
delete jsonObj[key];
});
}
return jsonObj;
}
exports.readToJson = readToJson;
function normalizeKeyArrays(keyArrays) {
// keep 0 as "0"
if (keyArrays == null)
return [];
if (typeof keyArrays === 'string' && keyArrays.length === 0)
return [];
if (!Array.isArray(keyArrays))
return [[keyArrays.toString()]];
const retKeyArrays = [];
keyArrays.forEach(function (keyArray) {
if (keyArray === null)
return;
if (typeof keyArray === 'string' && keyArray.length === 0)
return;
if (!Array.isArray(keyArray)) {
retKeyArrays.push([keyArray.toString()]);
return;
}
const retKeyArray = [];
keyArray.forEach(function (key) {
if (key === null)
return;
if (typeof key === 'string' && key.length === 0)
return;
assert(typeof key === 'string' || typeof key === 'number', 'type of key must be a string or a number.');
retKeyArray.push(key.toString());
});
if (retKeyArray.length > 0)
retKeyArrays.push(retKeyArray);
});
return retKeyArrays;
}
exports.normalizeKeyArrays = normalizeKeyArrays;
function scanJson(keys, data, returnErrors) {
return scanJsonPriv(keys, data, null, returnErrors);
}
exports.scanJson = scanJson;
function replaceJson(keys, data, newValues) {
return scanJsonPriv(keys, data, newValues, false);
}
exports.replaceJson = replaceJson;
function scanJsonPriv(keys, data, newValues, returnErrors) {
if (!data || typeof data !== 'object')
return [];
if (newValues)
assert(keys.length === newValues.length);
const keyArrays = normalizeKeyArrays(keys);
const ret = [];
keyArrays.forEach((k, kix) => {
let d = null;
let err = null;
let prevObj = null;
let prevKey = null;
try {
for (let ix = 0; ix < k.length; ix++) {
if (ix === 0)
d = data;
if (typeof d === 'string') {
err = '*** unexpected string value ' + JSON.stringify(k);
if (returnErrors)
ret.push(err);
else
console.log(err);
return;
}
prevObj = d;
prevKey = k[ix];
d = d[k[ix]];
}
if (typeof d === 'string') {
if (newValues)
prevObj[prevKey] = newValues[kix];
else
ret.push(d);
}
else {
err = '*** not a string value ' + JSON.stringify(k);
if (returnErrors)
ret.push(err);
else
console.log(err);
}
}
catch (e) {
err = '*** ' + e.toString() + ' ' + JSON.stringify(k);
if (returnErrors)
ret.push(err);
else
console.log(err);
}
});
return newValues ? data : ret;
}
exports.scanJsonPriv = scanJsonPriv;
function sortMsges(msgs) {
const keys = Object.keys(msgs);
const msgKeys = _.remove(keys, function (key) {
return KEY_HEADERS.some(function (header) {
return key.indexOf(header) === 0;
});
});
const sorted = {};
keys.sort().forEach(function (key) {
sorted[key] = msgs[key];
});
msgKeys.sort().forEach(function (key) {
sorted[key] = msgs[key];
});
return sorted;
}
exports.sortMsges = sortMsges;
/**
* Initialize intl directory structure for non-En languages
* intl/en must exist.
* it returns false if failed.
*/
function initIntlDirs() {
let intlEnStats;
try {
intlEnStats = fs.statSync(path.join(INTL_DIR, exports.ENGLISH));
}
catch (e) {
return false;
}
if (!intlEnStats.isDirectory())
return false;
if (!TARGET_LANGS)
TARGET_LANGS = getSupportedLanguages();
TARGET_LANGS.forEach(function (lang) {
mkdirp.sync(path.join(INTL_DIR, lang));
});
return true;
}
exports.initIntlDirs = initIntlDirs;
/**
* @param {string} lang Supported languages in CLDR notation
* Returns true for 'en' and supported languages
* in CLDR notation.
*/
function isSupportedLanguage(lang) {
lang = lang || 'en';
if (!TARGET_LANGS)
TARGET_LANGS = getSupportedLanguages();
return TARGET_LANGS.indexOf(lang) >= 0 || getAppLanguages().indexOf(lang) > 0;
}
exports.isSupportedLanguage = isSupportedLanguage;
/**
* Returns an array of locales supported by the local cldr data.
*/
function getSupportedLanguages() {
const cldrDir = path.join(__dirname, '..', 'cldr');
let langs = [];
enumerateFilesSync(cldrDir, null, ['json'], false, false, (content, filePath) => {
let cldr = null;
try {
cldr = JSON.parse(content);
}
catch (e) {
throw new Error('*** CLDR read error on ' + process.platform);
}
const theseLangs = Object.keys(cldr.main || {});
langs = _.concat(langs, theseLangs);
});
return _.uniq(langs);
}
exports.getSupportedLanguages = getSupportedLanguages;
function getAppLanguages() {
if (config_1.STRONGLOOP_GLB && config_1.STRONGLOOP_GLB.APP_LANGS) {
return config_1.STRONGLOOP_GLB.APP_LANGS;
}
return [];
}
exports.getAppLanguages = getAppLanguages;
/**
* Returns trailer of file name.
*/
function getTrailerAfterDot(name) {
if (typeof name !== 'string')
return null;
const parts = name.split('.');
if (parts.length < 2)
return null;
return parts[parts.length - 1].toLowerCase();
}
exports.getTrailerAfterDot = getTrailerAfterDot;
/**
* Returns package name defined in package.json.
*/
function getPackageName(root) {
return getPackageItem(root, 'name');
}
exports.getPackageName = getPackageName;
function getPackageVersion(root) {
return getPackageItem(root, 'version');
}
exports.getPackageVersion = getPackageVersion;
function getPackageItem(root, itemName) {
root = root || MY_ROOT;
let item = null;
try {
item = require(path.join(root, 'package.json'))[itemName];
}
catch (e) { }
return item;
}
exports.getPackageItem = getPackageItem;
/**
* @param {string} name to be checked
* @param {Array} headersAllowed a list of strings to check
* Returns directory path for the language.
*/
function headerIncluded(name, headersAllowed) {
if (typeof name !== 'string')
return false;
let matched = false;
if (Array.isArray(headersAllowed)) {
headersAllowed.forEach(function (header) {
if (matched)
return;
matched = name.indexOf(header) === 0;
});
}
else if (typeof headersAllowed === 'string') {
matched = name.indexOf(headersAllowed) === 0;
}
return matched;
}
exports.headerIncluded = headerIncluded;
/**
* @param {string} lang Supported languages in CLDR notation
* Returns directory path for the language.
*/
function intlDir(lang) {
lang = lang || exports.ENGLISH;
return path.join(INTL_DIR, lang);
}
exports.intlDir = intlDir;
/**
* %s is included in the string
*/
function percent(msg) {
return /\%[sdj\%]/.test(msg);
}
exports.percent = percent;
/**
* %replace %s with {N} where N=0,1,2,...
*/
function mapPercent(msg) {
let ix = 0;
const output = msg.replace(/\%[sdj\%]/g, (match) => {
if (match === '%%')
return '';
const str = '{' + ix.toString() + '}';
ix++;
return str;
});
return output;
}
exports.mapPercent = mapPercent;
function mapArgs(p, args) {
let ix = 1;
const output = [];
p.replace(/\%[sdj\%]/g, (match) => {
if (match === '%%')
return '';
let arg = args[ix++];
if (arg === undefined)
arg = 'undefined';
if (arg === null)
arg = 'null';
output.push(match === '%j' ? JSON.stringify(arg) : arg.toString());
return '';
});
return output;
}
exports.mapArgs = mapArgs;
function repackArgs(args, initIx) {
const argsLength = Array.isArray(args)
? args.length
: Object.keys(args).length;
if (initIx >= argsLength)
return [];
const output = [];
for (let ix = initIx; ix < argsLength; ix++) {
output.push(args[ix]);
}
return output;
}
exports.repackArgs = repackArgs;
/**
* Get the language (from the supported languages) that
* best matches the requested Accept-Language expression.
*
* @param req
* @param globalize
* @returns {*}
*/
function getLanguageFromRequest(req, appLanguages, defaultLanguage) {
if (!req || !req.headers || !req.headers['accept-language']) {
return defaultLanguage;
}
let languages = req.headers['accept-language'].split(',');
for (let i = 0; i < languages.length; i++) {
let languageWeighted = languages[i].split(';');
languageWeighted[0] = getLangAlias(languageWeighted[0].trim());
languages[i] = languageWeighted.join(';');
}
const reqLanguage = languages.join(',');
if (!reqLanguage) {
return defaultLanguage;
}
// Copy the array so that it won't be mutated
appLanguages = [defaultLanguage, ...appLanguages];
acceptLanguage.languages(appLanguages);
const bestLanguage = acceptLanguage.get(reqLanguage);
return bestLanguage || defaultLanguage;
}
exports.getLanguageFromRequest = getLanguageFromRequest;
function myIntlDir() {
return INTL_DIR;
}
exports.myIntlDir = myIntlDir;
/**
* Load messages for the language from a given root directory
* @param lang Language for messages
* @param rootDir Root directory
* @param enumerateNodeModules A flag to control if node_modules will be checked
*/
function loadMsgFromFile(lang, rootDir, enumerateNodeModules) {
assert(lang);
rootDir = rootDir || getRootDir();
if (!isLoadMessages(rootDir))
return;
enumerateNodeModules = enumerateNodeModules || false;
const tagType = exports.MSG_TAG;
enumerateMsgSync(rootDir, lang, enumerateNodeModules, (jsonObj, filePath) => {
// writeAllToMsg(lang, jsonObj);
let fileName = path.basename(filePath);
const re = /^([0-9a-f]{32})_(.*)\.txt/;
const results = re.exec(fileName);
let fileIdHash;
if (results && results.length === 3) {
// deep-extracted txt file ?
fileIdHash = results[1];
fileName = results[2] + '.txt';
}
else {
fileIdHash = msgFileIdHash(fileName, rootDir);
fileName = fileName;
}
if (resTagExists(fileIdHash, fileName, lang, tagType)) {
debug('*** loadMsgFromFile(res tag exists): skipping:', lang, fileName);
return;
}
debug('*** loadMsgFromFile(new res tag): loading:', lang, fileName);
removeDoubleCurlyBraces(jsonObj);
const messages = {};
messages[lang] = jsonObj;
config_1.STRONGLOOP_GLB.loadMessages(messages);
registerResTag(fileIdHash, fileName, lang, tagType);
if (config_1.STRONGLOOP_GLB.formatters.has(lang)) {
const formatters = config_1.STRONGLOOP_GLB.formatters.get(lang);
for (const key in jsonObj) {
formatters.delete(key);
}
}
});
}
exports.loadMsgFromFile = loadMsgFromFile;
/**
* Remove `{{` and `}}`
*/
function removeDoubleCurlyBraces(json) {
let count = 0;
Object.keys(json).forEach((key) => {
count++;
if (typeof json[key] !== 'string') {
// The value for `zz` pseudo code is an array, let's skip
return;
}
json[key] = json[key].replace(/}}/g, '').replace(/{{/g, '');
debug(count, key + ' : ' + json[key]);
});
}
exports.removeDoubleCurlyBraces = removeDoubleCurlyBraces;
/**
* If an language has alias name that SG supports, return the alias name.
*
* The known aliases are hard-coded to solve issue
* https://github.com/strongloop/strong-globalize/issues/150
* @param lang
*/
function getLangAlias(lang) {
// The {lang: alias} pairs
let language = _.toLower(lang) || lang;
const ALIAS_MAP = {
'zh-cn': 'zh-Hans',
'zh-tw': 'zh-Hant',
};
if (lang && ALIAS_MAP.hasOwnProperty(language))
return ALIAS_MAP[language];
return lang;
}
exports.getLangAlias = getLangAlias;
//# sourceMappingURL=helper.js.map