Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: build/csv-export.js

Issue 29636585: Issue 6171 - create CSV exporter and importer for translations (Closed)
Left Patch Set: used disable-eslint comment Created June 5, 2018, 2:13 p.m.
Right Patch Set: Created June 18, 2018, 2:49 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « README.md ('k') | package.json » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 10 matching lines...) Expand all
21 21
22 const fs = require("fs"); 22 const fs = require("fs");
23 const path = require("path"); 23 const path = require("path");
24 const csv = require("csv"); 24 const csv = require("csv");
25 const {promisify} = require("util"); 25 const {promisify} = require("util");
26 const execFile = promisify(require("child_process").execFile); 26 const execFile = promisify(require("child_process").execFile);
27 const csvParser = promisify(csv.parse); 27 const csvParser = promisify(csv.parse);
28 const readFile = promisify(fs.readFile); 28 const readFile = promisify(fs.readFile);
29 const writeFile = promisify(fs.writeFile); 29 const writeFile = promisify(fs.writeFile);
30 const glob = promisify(require("glob").glob); 30 const glob = promisify(require("glob").glob);
31 const readJsonPromised = promisify(readJson);
32 31
33 const localesDir = "locale"; 32 const localesDir = "locale";
34 const defaultLocale = "en_US"; 33 const defaultLocale = "en_US";
35 34
36 const headers = ["Filename", "StringID", "Description", "Placeholders", 35 const headers = ["Filename", "StringID", "Description", "Placeholders",
37 defaultLocale]; 36 defaultLocale];
38 let outputFileName = "translations.csv"; 37 let outputFileName = "translations.csv";
39 38
40 /** 39 /**
41 * Export existing translation - files into CSV file 40 * Export existing translation - files into CSV file
42 */ 41 */
43 function exportTranslations() 42 function exportTranslations()
44 { 43 {
45 glob(`${localesDir}/**/*.json`).then((filePaths) => 44 glob(`${localesDir}/**/*.json`).then((filePaths) =>
46 { 45 {
47 // Reading all existing translations files 46 // Reading all existing translations files
48 return Promise.all(filePaths.map((filePath) => readJsonPromised(filePath))); 47 return Promise.all(filePaths.map((filePath) => readJson(filePath)));
49 }).then(csvFromJsonFileObjects); 48 }).then(csvFromJsonFileObjects);
50 } 49 }
51 50
52 /** 51 /**
53 * Creating Matrix which reflects output CSV file 52 * Creating Matrix which reflects output CSV file
54 * @param {Object[]} fileObjects - array of file objects created by readJson 53 * @param {Object[]} fileObjects - array of file objects created by readJson
55 */ 54 */
56 function csvFromJsonFileObjects(fileObjects) 55 function csvFromJsonFileObjects(fileObjects)
57 { 56 {
58 const locales = []; 57 const locales = [];
59 const fileNames = []; 58 const fileNames = [];
60 // Create Object tree from the Objects array, for easier search 59 // Create Object tree from the Objects array, for easier search
61 // ex.: {dektop-options.json: {en_US: {...}, {de: {...}, {ru: {...}}} 60 // ex.: {dektop-options.json: {en_US: {...}, {de: {...}, {ru: {...}}}
62 const dataTreeObj = Object.create(null); 61 const dataTreeObj = Object.create(null);
63 for (const fileObject of fileObjects) 62 for (const fileObject of fileObjects)
64 { 63 {
65 const {fileName, locale, strings} = fileObject; 64 const {fileName, locale, strings} = fileObject;
66 65
67 if (locale != defaultLocale && !locales.includes(locale)) 66 if (locale != defaultLocale && !locales.includes(locale))
68 locales.push(locale); 67 locales.push(locale);
69 68
70 if (!filesFilter.length || filesFilter.includes(fileName)) 69 if ((!filesFilter.length || filesFilter.includes(fileName)) &&
70 !fileNames.includes(fileName))
71 fileNames.push(fileName); 71 fileNames.push(fileName);
72 72
73 if (!(fileName in dataTreeObj)) 73 if (!(fileName in dataTreeObj))
74 dataTreeObj[fileName] = Object.create(null); 74 dataTreeObj[fileName] = Object.create(null);
75 75
76 dataTreeObj[fileName][locale] = strings; 76 dataTreeObj[fileName][locale] = strings;
77 } 77 }
78 // Create two dimensional strings array that reflects CSV structure 78 // Create two dimensional strings array that reflects CSV structure
79 const csvArray = [headers.concat(locales)]; 79 const csvArray = [headers.concat(locales)];
80 for (const fileName of fileNames) 80 for (const fileName of fileNames)
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 }).catch((error) => 218 }).catch((error) =>
219 { 219 {
220 console.error(error); 220 console.error(error);
221 }); 221 });
222 }); 222 });
223 } 223 }
224 224
225 /** 225 /**
226 * Reads JSON file and assign filename and locale to it 226 * Reads JSON file and assign filename and locale to it
227 * @param {string} filePath - ex.: "locales/en_US/desktop-options.json" 227 * @param {string} filePath - ex.: "locales/en_US/desktop-options.json"
228 * @param {function} callback - fileName, locale and strings of locale file 228 * @returns {Promise<Object>} resolves fileName, locale and strings of the
229 * Parameters: 229 * locale file
230 * * Error message 230 */
231 * * Object containing fileName, locale and strings 231 function readJson(filePath)
232 */ 232 {
233 function readJson(filePath, callback) 233 return readFile(filePath, "utf8").then((data) =>
234 { 234 {
235 const {dir, base} = path.parse(filePath); 235 const {dir, base} = path.parse(filePath);
236 readFile(filePath, "utf8").then((data) =>
237 {
238 const locale = dir.split(path.sep).pop(); 236 const locale = dir.split(path.sep).pop();
239 const strings = JSON.parse(data); 237 const strings = JSON.parse(data);
240 callback(null, {fileName: base, locale, strings}); 238 return {fileName: base, locale, strings};
241 }).catch((err) =>
242 {
243 callback(err);
244 }); 239 });
245 } 240 }
246 241
247 /** 242 /**
248 * Exit process and log error message 243 * Exit process and log error message
249 * @param {String} error error message 244 * @param {String} error error message
250 */ 245 */
251 function exitProcess(error) 246 function exitProcess(error)
252 { 247 {
253 console.error(error); 248 console.error(error);
254 process.exit(1); 249 process.exit(1);
255 } 250 }
256 251
257 // CLI 252 // CLI
258 const helpText = ` 253 const helpText = `
259 About: Converts locale files between CSV and JSON formats 254 About: Converts locale files between CSV and JSON formats
260 Usage: csv-export.js [option] [argument] 255 Usage: csv-export.js [option] [argument]
261 Options: 256 Options:
262 -f [FILENAME] Name of the files to be exported ex.: -f firstRun.json 257 -f [FILENAME] Name of the files to be exported ex.: -f firstRun.json
263 option can be used multiple times. 258 option can be used multiple times.
264 If omitted all files are being exported 259 If omitted all files are being exported
265 260
266 -o [FILENAME] Output filename ex.: 261 -o [FILENAME] Output filename ex.:
267 -f firstRun.json -o {hash}-firstRun.csv 262 -f firstRun.json -o firstRun.csv
268 Placeholders:
269 {hash} - Mercurial current revision hash
270 If omitted the output fileName is set to 263 If omitted the output fileName is set to
271 translations-{repo}-{hash}.csv 264 translations.csv
272 265
273 -i [FILENAME] Import file path ex: -i issue-reporter.csv 266 -i [FILENAME] Import file path ex: -i issue-reporter.csv
274 `; 267 `;
275 268
276 const argv = process.argv.slice(2); 269 const argv = process.argv.slice(2);
277 let stopExportScript = false; 270 let stopExportScript = false;
278 // Filter to be used export to the fileNames inside 271 // Filter to be used export to the fileNames inside
279 const filesFilter = []; 272 const filesFilter = [];
280 273
281 for (let i = 0; i < argv.length; i++) 274 for (let i = 0; i < argv.length; i++)
(...skipping 25 matching lines...) Expand all
307 } 300 }
308 const importFile = argv[i + 1]; 301 const importFile = argv[i + 1];
309 importTranslations(importFile); 302 importTranslations(importFile);
310 stopExportScript = true; 303 stopExportScript = true;
311 break; 304 break;
312 } 305 }
313 } 306 }
314 307
315 if (!stopExportScript) 308 if (!stopExportScript)
316 exportTranslations(filesFilter); 309 exportTranslations(filesFilter);
LEFTRIGHT

Powered by Google App Engine
This is Rietveld