diff --git a/js/lang.js b/js/lang.js new file mode 100644 index 0000000000..fee99ec266 --- /dev/null +++ b/js/lang.js @@ -0,0 +1,266 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +if (process.argv.length < 2) { + throw new Error('No dir argument passed'); +} + +const fs = require('fs'); +const nodePath = require('path'); + +const PO = require('pofile'); +const os = require('os'); + + +var onlyModuleName = null; +if (process.argv.length > 2) { + for (var i in process.argv) { + if (~process.argv[i].indexOf('--module=')) { + onlyModuleName = process.argv[i].substr(('--module=').length); + } + } +} + + +/*var deleteFolderRecursive = function (path) { + var files = []; + if (fs.existsSync(path)) { + files = fs.readdirSync(path); + files.forEach(function(file,index){ + var curPath = path + "/" + file; + if(fs.lstatSync(curPath).isDirectory()) { + deleteFolderRecursive(curPath); + } else { + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(path); + } +};*/ + +class Lang +{ + constructor (language, poPath, espoPath, onlyModuleName) { + this.language = language; + this.poPath = poPath; + + this.espoPath = espoPath; + if (this.espoPath.substr(-1) != '/') { + this.espoPath += '/'; + } + + this.moduleList = ['Crm']; + if (onlyModuleName) { + this.moduleList = [onlyModuleName]; + } + + this.baseLanguage = 'en_US'; + + var dirNames = this.dirNames = {}; + + var resDirNames = this.resDirNames = {}; + + var coreDir = this.espoPath + 'application/Espo/Resources/i18n/' + this.baseLanguage + '/'; + var dirs = [coreDir]; + dirNames[coreDir] = 'application/Espo/Resources/i18n/' + this.language + '/'; + + var installDir = this.espoPath + 'install/core/i18n/' + this.baseLanguage + '/'; + dirs.push(installDir); + dirNames[installDir] = 'install/core/i18n/' + this.language + '/'; + + var templatesDir = this.espoPath + 'application/Espo/Core/Templates/i18n/' + this.baseLanguage + '/'; + dirs.push(templatesDir); + dirNames[templatesDir] = 'application/Espo/Core/Templates/i18n/' + this.language + '/'; + + if (onlyModuleName) { + dirs = []; + } + + this.moduleList.forEach(function (moduleName) { + var dir = this.espoPath + 'application/Espo/Modules/' + moduleName + '/Resources/i18n/' + this.baseLanguage + '/'; + dirs.push(dir); + dirNames[dir] = 'application/Espo/Modules/' + moduleName + '/Resources/i18n/' + this.language + '/'; + }, this); + + this.dirs = dirs; + + this.isWin = /^win/.test(os.platform()); + } + + escape (string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + run () { + var translationData = {}; + var dirs = this.dirs; + const isWin = this.isWin; + const language = this.language; + + PO.load(this.poPath, function (err, po) { + if (err) throw new Error("Could not parse " + this.poPath + "."); + + po.items.forEach(function (item) { + if (!item.msgctxt) return; + var key = item.msgctxt + '__' + item.msgid; + var file = item.msgctxt.split('.')[0]; + var path = item.msgctxt.split('.').slice(1); + + var o = { + stringOriginal: item.msgid, + stringTranslated: item.msgstr[0], + context: item.msgctxt, + file: file, + path: path + }; + translationData[file] = translationData[file] || []; + translationData[file].push(o); + }); + + dirs.forEach(function (path) { + var resDirPath = this.dirNames[path]; + var resPath = this.espoPath + 'build/' + language + '/' + resDirPath; + + if (!fs.existsSync(resPath)) { + var d = ''; + resPath.split('/').forEach(function (f) { + if (!f) { + return; + } + if (isWin) { + d = nodePath.join(d, f); + } else { + d += '/' + f; + } + if (!fs.existsSync(d)) { + fs.mkdirSync(d); + } + }); + } + + var list = fs.readdirSync(path); + list.forEach(function (fileName) { + + var filePath = path + fileName; + var resFilePath = resPath + '/' + fileName; + + var contents = fs.readFileSync(filePath, 'utf8'); + + var fileKey = fileName.split('.')[0]; + + var fileObject = JSON.parse(contents); + var targetFileObject = {}; + + if (!(fileKey in translationData)) return; + + translationData[fileKey].forEach(function (item) { + var isArray = false; + var isMet = true; + var c = fileObject; + var path = item.path.slice(0); + + for (var i in item.path) { + var key = item.path[i]; + if (key in c) { + c = c[key]; + if (Array.isArray(c)) { + isArray = true; + break; + } + } else { + isMet = false; + } + } + + var pathList = []; + + if (isMet) { + if (!isArray) { + var isMet = false; + for (var k in c) { + if (c[k] === item.stringOriginal) { + var p = path.slice(0); + p.push(k); + pathList.push(p); + isMet = true; + } + } + } else { + pathList.push(path); + } + } + + if (!isMet) return; + + var targetValue = item.stringTranslated; + if (targetValue === '') { + return; + } else { + if (item.stringOriginal === item.stringTranslated) { + return; + } + } + if (isArray) { + try { + var targetValue = JSON.parse('[' + targetValue + ']'); + } catch (e) { + targetValue = null; + } + } + if (targetValue == null) return; + + pathList.forEach(function (path) { + var c = targetFileObject; + path.forEach(function (pathKey, i) { + if (i < path.length - 1) { + c[pathKey] = c[pathKey] || {}; + c = c[pathKey]; + } else { + c[pathKey] = targetValue; + } + }, this); + }, this); + }, this); + + var contents = JSON.stringify(targetFileObject, null, ' '); + + if (fs.existsSync(resFilePath)) { + fs.unlinkSync(resFilePath); + } + fs.writeFileSync(resFilePath, contents); + + return; + }, this); + + }, this); + + }.bind(this)) + } +} + +module.exports = Lang; diff --git a/js/po.js b/js/po.js index f7c3b306e5..364d845ad0 100644 --- a/js/po.js +++ b/js/po.js @@ -33,8 +33,7 @@ const fs = require('fs'); */ class PO { - constructor (espoPath, language, onlyModuleName) - { + constructor (espoPath, language, onlyModuleName) { this.espoPath = espoPath; this.onlyModuleName = onlyModuleName; diff --git a/lang.js b/lang.js index d4873dfa01..0213077522 100644 --- a/lang.js +++ b/lang.js @@ -26,19 +26,18 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/  -if (process.argv.length < 2) { - throw new Error('No dir argument passed'); +const Lang = require('./js/lang'); +const path = require('path'); +const fs = require('fs'); + +if (process.argv.length < 3) { + throw new Error('You need to pass a language code as a second parameter.'); } -var path = require('path'); -var fs = require('fs'); -var nodePath = require('path'); -var os = require('os'); -var PO = require('pofile'); -var isWin = /^win/.test(os.platform()); - var espoPath = path.dirname(fs.realpathSync(__filename)) + ''; -var resLang = process.argv[2] || 'lang_LANG'; +var language = process.argv[2]; + +var poPath = null; var onlyModuleName = null; if (process.argv.length > 2) { @@ -46,24 +45,21 @@ if (process.argv.length > 2) { if (~process.argv[i].indexOf('--module=')) { onlyModuleName = process.argv[i].substr(('--module=').length); } - } -} - -var poPath = espoPath + '/build/' + 'espocrm-' + resLang; -if (onlyModuleName) { - poPath += '-' + onlyModuleName; -} -poPath += '.po'; - -if (process.argv.length > 2) { - for (var i in process.argv) { if (~process.argv[i].indexOf('--path=')) { poPath = process.argv[i].substr(('--path=').length); } } } -var deleteFolderRecursive = function (path) { +if (!poPath) { + poPath = espoPath + '/build/' + 'espocrm-' + language; + if (onlyModuleName) { + poPath += '-' + onlyModuleName; + } + poPath += '.po'; +} + +/*var deleteFolderRecursive = function (path) { var files = []; if (fs.existsSync(path)) { files = fs.readdirSync(path); @@ -77,203 +73,8 @@ var deleteFolderRecursive = function (path) { }); fs.rmdirSync(path); } -}; - -function Lang (poPath, espoPath) { - this.poPath = poPath; - - this.espoPath = espoPath; - if (this.espoPath.substr(-1) != '/') { - this.espoPath += '/'; - } - - this.currentPath = path.dirname(fs.realpathSync(__filename)) + '/'; - - this.moduleList = ['Crm']; - if (onlyModuleName) { - this.moduleList = [onlyModuleName]; - } - - this.baseLanguage = 'en_US'; - - var dirNames = this.dirNames = {}; - - var resDirNames = this.resDirNames = {}; - - var coreDir = this.espoPath + 'application/Espo/Resources/i18n/' + this.baseLanguage + '/'; - var dirs = [coreDir]; - dirNames[coreDir] = 'application/Espo/Resources/i18n/' + resLang + '/'; +};*/ - var installDir = this.espoPath + 'install/core/i18n/' + this.baseLanguage + '/'; - dirs.push(installDir); - dirNames[installDir] = 'install/core/i18n/' + resLang + '/'; - - - var templatesDir = this.espoPath + 'application/Espo/Core/Templates/i18n/' + this.baseLanguage + '/'; - dirs.push(templatesDir); - dirNames[templatesDir] = 'application/Espo/Core/Templates/i18n/' + resLang + '/'; - - if (onlyModuleName) { - dirs = []; - } - - this.moduleList.forEach(function (moduleName) { - var dir = this.espoPath + 'application/Espo/Modules/' + moduleName + '/Resources/i18n/' + this.baseLanguage + '/'; - dirs.push(dir); - dirNames[dir] = 'application/Espo/Modules/' + moduleName + '/Resources/i18n/' + resLang + '/'; - }, this); - - this.dirs = dirs; -}; - -Lang.prototype.escape = function(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); -}; - -Lang.prototype.run = function () { - var translationData = {}; - var dirs = this.dirs; - - PO.load(this.poPath, function (err, po) { - if (err) throw new Error("Could not parse " + this.poPath); - - po.items.forEach(function (item) { - if (!item.msgctxt) return; - var key = item.msgctxt + '__' + item.msgid; - var file = item.msgctxt.split('.')[0]; - var path = item.msgctxt.split('.').slice(1); - - var o = { - stringOriginal: item.msgid, - stringTranslated: item.msgstr[0], - context: item.msgctxt, - file: file, - path: path - }; - translationData[file] = translationData[file] || []; - translationData[file].push(o); - }); - - dirs.forEach(function (path) { - var resDirPath = this.dirNames[path]; - var resPath = this.currentPath + 'build/' + resLang + '/' + resDirPath; - - if (!fs.existsSync(resPath)) { - var d = ''; - resPath.split('/').forEach(function (f) { - if (!f) { - return; - } - if (isWin) { - d = nodePath.join(d, f); - } else { - d += '/' + f; - } - if (!fs.existsSync(d)) { - fs.mkdirSync(d); - } - }); - } - - var list = fs.readdirSync(path); - list.forEach(function (fileName) { - - var filePath = path + fileName; - var resFilePath = resPath + '/' + fileName; - - var contents = fs.readFileSync(filePath, 'utf8'); - - var fileKey = fileName.split('.')[0]; - - var fileObject = JSON.parse(contents); - var targetFileObject = {}; - - if (!(fileKey in translationData)) return; - - translationData[fileKey].forEach(function (item) { - var isArray = false; - var isMet = true; - var c = fileObject; - var path = item.path.slice(0); - - for (var i in item.path) { - var key = item.path[i]; - if (key in c) { - c = c[key]; - if (Array.isArray(c)) { - isArray = true; - break; - } - } else { - isMet = false; - } - } - - var pathList = []; - - if (isMet) { - if (!isArray) { - var isMet = false; - for (var k in c) { - if (c[k] === item.stringOriginal) { - var p = path.slice(0); - p.push(k); - pathList.push(p); - isMet = true; - } - } - } else { - pathList.push(path); - } - } - - if (!isMet) return; - - var targetValue = item.stringTranslated; - if (targetValue === '') { - return; - } else { - if (item.stringOriginal === item.stringTranslated) { - return; - } - } - if (isArray) { - try { - var targetValue = JSON.parse('[' + targetValue + ']'); - } catch (e) { - targetValue = null; - } - } - if (targetValue == null) return; - - pathList.forEach(function (path) { - var c = targetFileObject; - path.forEach(function (pathKey, i) { - if (i < path.length - 1) { - c[pathKey] = c[pathKey] || {}; - c = c[pathKey]; - } else { - c[pathKey] = targetValue; - } - }, this); - }, this); - }, this); - - var contents = JSON.stringify(targetFileObject, null, ' '); - - if (fs.existsSync(resFilePath)) { - fs.unlinkSync(resFilePath); - } - fs.writeFileSync(resFilePath, contents); - - return; - }, this); - - }, this); - - }.bind(this)) -}; - -var lang = new Lang(poPath, espoPath); +var lang = new Lang(language, poPath, espoPath, onlyModuleName); lang.run();