/* eslint-env node */ 'use strict'; class PotMaker { constructor (options) { this.options = options; } /** * Check if variable is a empty object * * @param {object} obj * * @return {boolean} */ static isEmptyObject (obj) { return Object.keys(obj).length === 0; } /** * Escape unescaped double quotes * * @param {string} text * @return string */ static escapeQuotes (text) { text = text.replace(/\\([\s\S])|(")/g, '\\$1$2'); return text; } /** * Get msgid lines in pot format * * @param {string} msgid * @param {Boolean} [plural] * * @return {Array} */ static getPotMsgId (msgid, plural) { const output = []; const idKey = (plural ? 'msgid_plural' : 'msgid'); if (msgid !== undefined) { msgid = PotMaker.escapeQuotes(msgid); if (/\n/.test(msgid)) { output.push(`${idKey} ""`); const rows = msgid.split(/\n/); for (let rowId = 0; rowId < rows.length; rowId++) { const lineBreak = rowId === (rows.length - 1) ? '' : '\\n'; output.push(`"${rows[rowId] + lineBreak}"`); } } else { output.push(`${idKey} "${msgid}"`); } } return output; } /** * Get msgstr lines in pot format * * @param {Boolean} plural * * @return {Array} */ static getPotMsgStr (plural) { if (!plural) { return ['msgstr ""\n']; } else { return ['msgstr[0] ""', 'msgstr[1] ""\n']; } } /** * Write translation to array with pot format. * * @param {object} translations * @param {bool} noFilePaths * * @return {Array} */ static translationToPot (translations, noFilePaths) { // Write translation rows. let output = []; if (translations) { for (const translationElement of Object.keys(translations)) { if (translations[translationElement].comment) { // Set removes duplicates for (const comment of [...new Set(translations[translationElement].comment)]) { output.push(`#. ${comment}`); } } if (!noFilePaths) { // Unify paths for Unix and Windows output.push(`#: ${translations[translationElement].info.replace(/\\/g, '/')}`); } if (translations[translationElement].msgctxt) { output.push(`msgctxt "${PotMaker.escapeQuotes(translations[translationElement].msgctxt)}"`); } output = output.concat(PotMaker.getPotMsgId(translations[translationElement].msgid)); output = output.concat(PotMaker.getPotMsgId(translations[translationElement].msgid_plural, true)); output = output.concat(PotMaker.getPotMsgStr(Boolean(translations[translationElement].msgid_plural))); } } return output; } /** * Sort object by key name * * @param {object} obj */ sortObject (obj) { return Object.keys(obj).sort().reduce(function (result, key) { result[key] = obj[key]; return result; }, {}); } /** * Generate pot contents * * @param {object} translations * * @return {string} */ generatePot (translations) { const copyrightText = typeof this.options.copyrightText === 'function' ? this.options.copyrightText(this.options) : this.options.copyrightText; const startingHeaders = { 'Project-Id-Version': this.options.package, 'MIME-Version': '1.0', 'Content-Type': 'text/plain; charset=UTF-8', 'Content-Transfer-Encoding': '8bit' }; if (this.options.headers && !PotMaker.isEmptyObject(this.options.headers)) { for (const key of Object.keys(startingHeaders)) { if (typeof this.options.headers[key] !== 'undefined') { startingHeaders[key] = this.options.headers[key]; delete this.options.headers[key]; } } } let contents = ( `${copyrightText} msgid "" msgstr "" "Project-Id-Version: ${startingHeaders['Project-Id-Version']}\\n" "MIME-Version: ${startingHeaders['MIME-Version']}\\n" "Content-Type: ${startingHeaders['Content-Type']}\\n" "Content-Transfer-Encoding: ${startingHeaders['Content-Transfer-Encoding']}\\n"\n`); if (this.options.headers && !PotMaker.isEmptyObject(this.options.headers)) { this.options.headers = this.sortObject(this.options.headers); for (const key of Object.keys(this.options.headers)) { contents += `"${key}: ${this.options.headers[key]}\\n"\n`; } } contents += '"Plural-Forms: nplurals=2; plural=(n != 1);\\n"\n'; contents += '\n'; const translationLines = PotMaker.translationToPot(translations, this.options.noFilePaths); contents += translationLines.join('\n'); return contents; } } module.exports = PotMaker;