|
import _defineProperty from "@babel/runtime/helpers/defineProperty";import _classCallCheck from "@babel/runtime/helpers/classCallCheck";import _createClass from "@babel/runtime/helpers/createClass";import _inherits from "@babel/runtime/helpers/inherits";import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";function _createForOfIteratorHelper(o, allowArrayLike) {var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];if (!it) {if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {if (it) o = it;var i = 0;var F = function F() {};return { s: F, n: function n() {if (i >= o.length) return { done: true };return { done: false, value: o[i++] };}, e: function e(_e) {throw _e;}, f: F };}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}var normalCompletion = true,didErr = false,err;return { s: function s() {it = it.call(o);}, n: function n() {var step = it.next();normalCompletion = step.done;return step;}, e: function e(_e2) {didErr = true;err = _e2;}, f: function f() {try {if (!normalCompletion && it["return"] != null) it["return"]();} finally {if (didErr) throw err;}} };}function _unsupportedIterableToArray(o, minLen) {if (!o) return;if (typeof o === "string") return _arrayLikeToArray(o, minLen);var n = Object.prototype.toString.call(o).slice(8, -1);if (n === "Object" && o.constructor) n = o.constructor.name;if (n === "Map" || n === "Set") return Array.from(o);if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);}function _arrayLikeToArray(arr, len) {if (len == null || len > arr.length) len = arr.length;for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];return arr2;}function ownKeys(e, r) {var t = Object.keys(e);if (Object.getOwnPropertySymbols) {var o = Object.getOwnPropertySymbols(e);r && (o = o.filter(function (r) {return Object.getOwnPropertyDescriptor(e, r).enumerable;})), t.push.apply(t, o);}return t;}function _objectSpread(e) {for (var r = 1; r < arguments.length; r++) {var t = null != arguments[r] ? arguments[r] : {};r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {_defineProperty(e, r, t[r]);}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));});}return e;}function _createSuper(Derived) {var hasNativeReflectConstruct = _isNativeReflectConstruct();return function _createSuperInternal() {var Super = _getPrototypeOf(Derived),result;if (hasNativeReflectConstruct) {var NewTarget = _getPrototypeOf(this).constructor;result = Reflect.construct(Super, arguments, NewTarget);} else {result = Super.apply(this, arguments);}return _possibleConstructorReturn(this, result);};}function _isNativeReflectConstruct() {try {var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));} catch (t) {}return (_isNativeReflectConstruct = function _isNativeReflectConstruct() {return !!t;})();}import { Transform } from 'stream'; |
|
import eol from 'eol'; |
|
import fs from 'fs'; |
|
import path from 'path'; |
|
import VirtualFile from 'vinyl'; |
|
import yaml from 'js-yaml'; |
|
import i18next from 'i18next'; |
|
import sortKeys from 'sort-keys'; |
|
|
|
import { |
|
dotPathToHash, |
|
mergeHashes, |
|
transferValues, |
|
makeDefaultSort } from |
|
'./helpers.js'; |
|
import Parser from './parser.js';var |
|
|
|
i18nTransform = function (_Transform) {_inherits(i18nTransform, _Transform);var _super = _createSuper(i18nTransform); |
|
function i18nTransform() {var _this;var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};_classCallCheck(this, i18nTransform); |
|
options.objectMode = true; |
|
_this = _super.call(this, options); |
|
|
|
_this.defaults = { |
|
contextSeparator: '_', |
|
createOldCatalogs: true, |
|
defaultNamespace: 'translation', |
|
defaultValue: '', |
|
indentation: 2, |
|
keepRemoved: false, |
|
keySeparator: '.', |
|
lexers: {}, |
|
lineEnding: 'auto', |
|
locales: ['en', 'fr'], |
|
namespaceSeparator: ':', |
|
pluralSeparator: '_', |
|
output: 'locales/$LOCALE/$NAMESPACE.json', |
|
resetDefaultValueLocale: null, |
|
sort: false, |
|
verbose: false, |
|
customValueTemplate: null, |
|
failOnWarnings: false, |
|
yamlOptions: null |
|
}; |
|
|
|
_this.options = _objectSpread(_objectSpread({}, _this.defaults), options); |
|
_this.options.i18nextOptions = _objectSpread(_objectSpread({}, |
|
options.i18nextOptions), {}, { |
|
pluralSeparator: _this.options.pluralSeparator, |
|
nsSeparator: _this.options.namespaceSeparator }); |
|
|
|
|
|
if (_this.options.keySeparator === false) { |
|
_this.options.keySeparator = '__!NO_KEY_SEPARATOR!__'; |
|
} |
|
if (_this.options.namespaceSeparator === false) { |
|
_this.options.namespaceSeparator = '__!NO_NAMESPACE_SEPARATOR!__'; |
|
} |
|
_this.entries = []; |
|
|
|
_this.parserHadWarnings = false; |
|
_this.parserHadUpdate = false; |
|
_this.parser = new Parser(_this.options); |
|
_this.parser.on('error', function (error) {return _this.error(error);}); |
|
_this.parser.on('warning', function (warning) {return _this.warn(warning);}); |
|
|
|
_this.localeRegex = /\$LOCALE/g; |
|
_this.namespaceRegex = /\$NAMESPACE/g; |
|
|
|
_this.i18next = i18next.createInstance(); |
|
_this.i18next.init(_this.options.i18nextOptions); |
|
|
|
|
|
|
|
_this.keyToFilePaths = {};return _this; |
|
}_createClass(i18nTransform, [{ key: "error", value: |
|
|
|
function error(_error) { |
|
this.emit('error', _error); |
|
if (this.options.verbose) { |
|
console.error('\x1b[31m%s\x1b[0m', _error); |
|
} |
|
} }, { key: "warn", value: |
|
|
|
function warn(warning) { |
|
this.emit('warning', warning); |
|
this.parserHadWarnings = true; |
|
if (this.options.verbose) { |
|
console.warn('\x1b[33m%s\x1b[0m', warning); |
|
} |
|
} }, { key: "_transform", value: |
|
|
|
function _transform(file, encoding, done) { |
|
var content; |
|
if (file.isBuffer()) { |
|
content = file.contents.toString('utf8'); |
|
} else if (fs.lstatSync(file.path).isDirectory()) { |
|
var warning = "".concat(file.path, " is a directory: skipping"); |
|
this.warn(warning); |
|
done(); |
|
return; |
|
} else { |
|
content = fs.readFileSync(file.path, encoding || 'utf-8'); |
|
} |
|
|
|
this.emit('reading', file); |
|
if (this.options.verbose) { |
|
console.log("Parsing ".concat(file.path)); |
|
} |
|
|
|
var filename = path.basename(file.path); |
|
var entries = this.parser.parse(content, filename);var _iterator = _createForOfIteratorHelper( |
|
|
|
entries),_step;try {for (_iterator.s(); !(_step = _iterator.n()).done;) {var entry = _step.value; |
|
var key = entry.key; |
|
|
|
if (entry.keyPrefix) { |
|
key = entry.keyPrefix + this.options.keySeparator + key; |
|
} |
|
|
|
var parts = key.split(this.options.namespaceSeparator); |
|
|
|
|
|
if (parts.length > 1 && key !== entry.defaultValue) { |
|
entry.namespace = parts.shift(); |
|
} |
|
entry.namespace = entry.namespace || this.options.defaultNamespace; |
|
|
|
key = parts.join(this.options.namespaceSeparator); |
|
key = key.replace(/\\('|"|`)/g, '$1'); |
|
key = key.replace(/\\n/g, '\n'); |
|
key = key.replace(/\\r/g, '\r'); |
|
key = key.replace(/\\t/g, '\t'); |
|
key = key.replace(/\\\\/g, '\\'); |
|
entry.key = key; |
|
entry.keyWithNamespace = entry.namespace + this.options.keySeparator + key; |
|
|
|
this.keyToFilePaths[key] = this.keyToFilePaths[key] || []; |
|
if (!this.keyToFilePaths[key].includes(file.path)) { |
|
this.keyToFilePaths[key].push(file.path); |
|
} |
|
entry.filePaths = this.keyToFilePaths[key]; |
|
|
|
this.addEntry(entry); |
|
}} catch (err) {_iterator.e(err);} finally {_iterator.f();} |
|
|
|
done(); |
|
} }, { key: "_flush", value: |
|
|
|
function _flush(done) {var _this2 = this; |
|
var maybeSortedLocales = this.options.locales; |
|
if (this.options.resetDefaultValueLocale) { |
|
|
|
maybeSortedLocales.sort(function (a) {return ( |
|
a === _this2.options.resetDefaultValueLocale ? -1 : 1);} |
|
); |
|
} |
|
|
|
|
|
var resetValues = {};var _iterator2 = _createForOfIteratorHelper( |
|
|
|
maybeSortedLocales),_step2;try {var _loop = function _loop() {var locale = _step2.value; |
|
var catalog = {}; |
|
var resetAndFlag = _this2.options.resetDefaultValueLocale === locale; |
|
|
|
var uniqueCount = {}; |
|
var uniquePluralsCount = {}; |
|
|
|
var transformEntry = function transformEntry(entry, suffix) { |
|
if (uniqueCount[entry.namespace] === undefined) { |
|
uniqueCount[entry.namespace] = 0; |
|
} |
|
if (uniquePluralsCount[entry.namespace] === undefined) { |
|
uniquePluralsCount[entry.namespace] = 0; |
|
} |
|
|
|
var _dotPathToHash = dotPathToHash(entry, catalog, { |
|
suffix: suffix, |
|
locale: locale, |
|
separator: _this2.options.keySeparator, |
|
pluralSeparator: _this2.options.pluralSeparator, |
|
value: _this2.options.defaultValue, |
|
customValueTemplate: _this2.options.customValueTemplate |
|
}),duplicate = _dotPathToHash.duplicate,conflict = _dotPathToHash.conflict; |
|
|
|
if (duplicate) { |
|
if (conflict === 'key') { |
|
_this2.warn( |
|
"Found translation key already mapped to a map or parent of " + "new key already mapped to a string: ".concat( |
|
entry.key) |
|
); |
|
} else if (conflict === 'value') { |
|
_this2.warn("Found same keys with different values: ".concat(entry.key)); |
|
} |
|
} else { |
|
uniqueCount[entry.namespace] += 1; |
|
if (suffix) { |
|
uniquePluralsCount[entry.namespace] += 1; |
|
} |
|
} |
|
}; |
|
|
|
|
|
var _iterator3 = _createForOfIteratorHelper(_this2.entries),_step3;try {var _loop2 = function _loop2() {var entry = _step3.value; |
|
if ( |
|
_this2.options.pluralSeparator !== false && |
|
entry.count !== undefined) |
|
{ |
|
_this2.i18next.services.pluralResolver. |
|
getSuffixes(locale, { ordinal: entry.ordinal }). |
|
forEach(function (suffix) { |
|
transformEntry(entry, suffix); |
|
}); |
|
} else { |
|
transformEntry(entry); |
|
} |
|
};for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {_loop2();}} catch (err) {_iterator3.e(err);} finally {_iterator3.f();} |
|
|
|
var outputPath = path.resolve(_this2.options.output); |
|
|
|
for (var namespace in catalog) { |
|
var namespacePath = outputPath; |
|
namespacePath = namespacePath.replace(_this2.localeRegex, locale); |
|
namespacePath = namespacePath.replace(_this2.namespaceRegex, namespace); |
|
|
|
var parsedNamespacePath = path.parse(namespacePath); |
|
|
|
var namespaceOldPath = path.join( |
|
parsedNamespacePath.dir, "".concat( |
|
parsedNamespacePath.name, "_old").concat(parsedNamespacePath.ext) |
|
); |
|
|
|
var existingCatalog = _this2.getCatalog(namespacePath); |
|
var existingOldCatalog = _this2.getCatalog(namespaceOldPath); |
|
|
|
|
|
var _mergeHashes = |
|
|
|
|
|
|
|
|
|
|
|
|
|
mergeHashes( |
|
existingCatalog, |
|
catalog[namespace], _objectSpread(_objectSpread({}, |
|
|
|
_this2.options), {}, { |
|
resetAndFlag: resetAndFlag, |
|
fullKeyPrefix: namespace + _this2.options.namespaceSeparator }), |
|
|
|
resetValues[namespace] |
|
),newCatalog = _mergeHashes["new"],oldKeys = _mergeHashes.old,mergeCount = _mergeHashes.mergeCount,oldCount = _mergeHashes.oldCount,resetFlags = _mergeHashes.reset,resetCount = _mergeHashes.resetCount; |
|
|
|
|
|
|
|
if (resetAndFlag && !resetValues[namespace]) { |
|
resetValues[namespace] = resetFlags; |
|
} |
|
|
|
|
|
var _mergeHashes2 = mergeHashes( |
|
existingOldCatalog, |
|
newCatalog, _objectSpread(_objectSpread({}, |
|
_this2.options), {}, { keepRemoved: false }) |
|
),oldCatalog = _mergeHashes2.old,restoreCount = _mergeHashes2.mergeCount; |
|
|
|
|
|
transferValues(oldKeys, oldCatalog); |
|
|
|
if (_this2.options.verbose) { |
|
console.log("[".concat(locale, "] ").concat(namespace)); |
|
console.log("Unique keys: ".concat( |
|
uniqueCount[namespace], " (").concat(uniquePluralsCount[namespace], " are plurals)") |
|
); |
|
var addCount = uniqueCount[namespace] - mergeCount; |
|
console.log("Added keys: ".concat(addCount)); |
|
console.log("Restored keys: ".concat(restoreCount)); |
|
if (_this2.options.keepRemoved) { |
|
console.log("Unreferenced keys: ".concat(oldCount)); |
|
} else { |
|
console.log("Removed keys: ".concat(oldCount)); |
|
} |
|
if (_this2.options.resetDefaultValueLocale) { |
|
console.log("Reset keys: ".concat(resetCount)); |
|
} |
|
console.log(''); |
|
} |
|
|
|
if (_this2.options.failOnUpdate) { |
|
var _addCount = uniqueCount[namespace] - mergeCount; |
|
var refCount = |
|
_addCount + restoreCount + (_this2.options.keepRemoved ? 0 : oldCount); |
|
if (refCount !== 0) { |
|
_this2.parserHadUpdate = true; |
|
continue; |
|
} |
|
} |
|
|
|
if (_this2.options.failOnWarnings && _this2.parserHadWarnings) { |
|
continue; |
|
} |
|
|
|
var maybeSortedNewCatalog = newCatalog; |
|
var maybeSortedOldCatalog = oldCatalog; |
|
var sort = _this2.options.sort; |
|
if (sort) { |
|
var compare = |
|
typeof sort === 'function' ? |
|
sort : |
|
makeDefaultSort(_this2.options.pluralSeparator); |
|
maybeSortedNewCatalog = sortKeys(newCatalog, { |
|
deep: true, |
|
compare: compare |
|
}); |
|
|
|
maybeSortedOldCatalog = sortKeys(oldCatalog, { deep: true, compare: compare }); |
|
|
|
if (_this2.options.failOnUpdate && !_this2.parserHadUpdate) { |
|
|
|
|
|
|
|
_this2.parserHadSortUpdate = |
|
JSON.stringify(maybeSortedNewCatalog) !== |
|
JSON.stringify(existingCatalog); |
|
} |
|
} |
|
|
|
|
|
_this2.pushFile(namespacePath, maybeSortedNewCatalog); |
|
if ( |
|
_this2.options.createOldCatalogs && ( |
|
Object.keys(oldCatalog).length || existingOldCatalog)) |
|
{ |
|
_this2.pushFile(namespaceOldPath, maybeSortedOldCatalog); |
|
} |
|
} |
|
};for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {_loop();}} catch (err) {_iterator2.e(err);} finally {_iterator2.f();} |
|
|
|
if (this.options.failOnWarnings && this.parserHadWarnings) { |
|
this.emit( |
|
'error', |
|
'Warnings were triggered and failOnWarnings option is enabled. Exiting...' |
|
); |
|
process.exit(1); |
|
} |
|
|
|
if (this.options.failOnUpdate) { |
|
if (this.parserHadUpdate) { |
|
this.emit( |
|
'error', |
|
'Some translations was updated and failOnUpdate option is enabled. Exiting...' |
|
); |
|
process.exit(1); |
|
} |
|
if (this.parserHadSortUpdate) { |
|
this.emit( |
|
'error', |
|
'Some keys were sorted and failOnUpdate option is enabled. Exiting...' |
|
); |
|
process.exit(1); |
|
} |
|
} |
|
|
|
done(); |
|
} }, { key: "addEntry", value: |
|
|
|
function addEntry(entry) { |
|
if (entry.context) { |
|
var contextEntry = Object.assign({}, entry); |
|
delete contextEntry.context; |
|
contextEntry.key += this.options.contextSeparator + entry.context; |
|
contextEntry.keyWithNamespace += |
|
this.options.contextSeparator + entry.context; |
|
this.entries.push(contextEntry); |
|
} else { |
|
this.entries.push(entry); |
|
} |
|
} }, { key: "getCatalog", value: |
|
|
|
function getCatalog(path) { |
|
try { |
|
var content; |
|
if (path.endsWith('yml')) { |
|
content = yaml.load(fs.readFileSync(path).toString()); |
|
} else { |
|
content = JSON.parse(fs.readFileSync(path)); |
|
} |
|
return content; |
|
} catch (error) { |
|
if (error.code !== 'ENOENT') { |
|
this.emit('error', error); |
|
} |
|
} |
|
|
|
return null; |
|
} }, { key: "pushFile", value: |
|
|
|
function pushFile(path, contents) { |
|
var text; |
|
if (path.endsWith('yml')) { |
|
text = yaml.dump(contents, _objectSpread({ |
|
indent: this.options.indentation }, |
|
this.options.yamlOptions) |
|
); |
|
} else { |
|
text = JSON.stringify(contents, null, this.options.indentation) + '\n'; |
|
|
|
|
|
text = text.replace(/(?:[\0- \x7F-\xA0\xAD\u0600-\u0605\u061C\u06DD\u070F\u0890\u0891\u08E2\u1680\u180E\u2000-\u200F\u2028-\u202F\u205F-\u2064\u2066-\u206F\u3000\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC3F]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F])/g, function (chr) { |
|
var n = chr.charCodeAt(0); |
|
return n < 128 ? chr : "\\u".concat("0000".concat(n.toString(16)).substr(-4)); |
|
}); |
|
} |
|
|
|
if (this.options.lineEnding === 'auto') { |
|
text = eol.auto(text); |
|
} else if ( |
|
this.options.lineEnding === '\r\n' || |
|
this.options.lineEnding === 'crlf') |
|
{ |
|
text = eol.crlf(text); |
|
} else if ( |
|
this.options.lineEnding === '\r' || |
|
this.options.lineEnding === 'cr') |
|
{ |
|
text = eol.cr(text); |
|
} else { |
|
|
|
text = eol.lf(text); |
|
} |
|
|
|
var file = new VirtualFile({ |
|
path: path, |
|
contents: Buffer.from(text) |
|
}); |
|
this.push(file); |
|
} }]);return i18nTransform;}(Transform);export { i18nTransform as default }; |
|
|