Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/adopt tool #44

Merged
merged 5 commits into from
May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Tool for generating localization files for iOS and Android",
"main": "./src/index.js",
"bin": {
"mirrorrim": "./src/index.js"
"mirrorrim": "./src/index.js",
"migration": "./src/migration.js"
},
"author": "Johnny Gu <[email protected]> (https://github.com/jhonny-me)",
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions src/lib/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const generateFile = (data, basePath) => {
const formatValue = (input) => {
var input = String(input)
var input = input.replace(/'/g, '\\\'')
input = input.replace(/(\r\n|\r|\n)/g, "") // remove breakline
input = input.replace(/&/g, '&amp;')
input = input.replace(/"/g, '\\\"')
input = input.replace(/</g, '&lt;')
Expand Down
1 change: 1 addition & 0 deletions src/lib/ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const generateFile = (data, basePath) => {
const formatValue = (input) => {
var input = String(input)
var input = input.replace(/"/g, '\\\"')
input = input.replace(/(\r\n|\r|\n)/g, "") // remove breakline
input = input.replace(/%s/g, '%@')
return input
}
Expand Down
71 changes: 71 additions & 0 deletions src/migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env node

const { Command } = require("commander");
const { version } = require("../package.json");
const filehit = require("./migration/filehit");
const path = require("path");
var XLSX = require("xlsx");

const DEFAULT_OPTIONS = {
// local
inputDir: "./",

outputDir: "./",
};

const getOptions = async (argv) => {
let options = new Command()
.option(
"--output-dir <string>",
`output excel base directory, default: ${DEFAULT_OPTIONS.outputDir}`
)
.option(
"--input-dir <string>",
`directory of all wording resources, default: ${DEFAULT_OPTIONS.inputDir}`
)
.version(version)
.parse(argv);

return {
...DEFAULT_OPTIONS,
...options._optionValues
};
};

const run = async (argv) => {
const options = await getOptions(argv);
try {
if (options.inputDir) {
let rows = await filehit.hit(options.inputDir);
if (rows.length < 1) {
console.warn("Warning: No string files found in input directory");
return
}
const sheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, sheet, "DEFAULT");
/* calculate column width */
const keys = Object.keys(rows[0]);
const columnWidthes = keys.map(key => {
const width = rows.reduce((w, r) => Math.min(60, Math.max(w, r[key].length + 1)), 10);
return { wch: width }
})
sheet["!cols"] = columnWidthes;

const outputPath = path.join(options.outputDir, "strings.xlsx");
XLSX.writeFile(workbook, outputPath);
console.log(`Success! Xlsx file generated at ${outputPath}`);
} else {
console.log('Error: To run this app, you need to specify the input directory of string resources');
process.exit();
}
} catch (err) {
console.log(err);
}
};

run(process.argv).catch((error) => {
console.log("\n");
console.error(error);
process.exit(1);
});
67 changes: 67 additions & 0 deletions src/migration/filehit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const fs = require('fs');
const path = require('path');
const ios = require('./reader/ios');
const android = require('./reader/android');
const R = require("ramda");

const sortByKey = R.sortBy(R.prop('KEY'));

async function exists (path) {
try {
await fs.access(path)
return true
} catch {
return false
}
}

const concat = (oldArray, newArray) => {
const oldKeys = oldArray.map(obj => obj.KEY);
const newKeys = newArray.map(obj => obj.KEY);
const concatedKeys = Array.from(new Set([...oldKeys, ...newKeys]));
const concatedArray = concatedKeys.map(key => {
let oldObj = oldArray.find(obj => obj.KEY === key);
let newObj = newArray.find(obj => obj.KEY === key);
return {
...oldObj,
...newObj
}
});
return concatedArray;
}

const filehit = async (inputDir) => {
let keyValues = [];
let iOSen = path.join(inputDir, "en.lproj/Localizable.strings");
if (fs.existsSync(iOSen)) {
// parse ios en
console.log('found: ', iOSen)
keyValues = await ios.read(iOSen, 'EN');
}

let iOSzh = path.join(inputDir, "zh-Hans.lproj/Localizable.strings");
if (fs.existsSync(iOSzh)) {
// parse ios zh
console.log('found: ', iOSzh)
keyValues = concat(keyValues, await ios.read(iOSzh, 'ZH'));
}

let androidEn = path.join(inputDir, "values/strings.xml");
if (fs.existsSync(androidEn)) {
// parse android en
console.log('found: ', androidEn)
keyValues = concat(keyValues, await android.read(androidEn, 'EN'));
}

let androidZh = path.join(inputDir, "values-zh/strings.xml");
if (fs.existsSync(androidZh)) {
// parse andoird zh
console.log('found: ', androidZh)
keyValues = concat(keyValues, await android.read(androidZh, 'ZH'));
}
return sortByKey(keyValues);
}

module.exports = {
hit: filehit
}
43 changes: 43 additions & 0 deletions src/migration/reader/android.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const events = require('events');
const fs = require('fs');
const readline = require('readline');

const read = async (filepath, languageKey) => {
try {
const rl = readline.createInterface({
input: fs.createReadStream(filepath),
crlfDelay: Infinity
});
let outputs = [];
rl.on('line', (line) => {
if (!line.endsWith("<\/string>")) { return }
const value = line.replace(/[\s]+<string name="[^>]+">/, "").replace("<\/string>", "");

const key = line.slice(line.indexOf("\"") + 1, line.indexOf("\">"));

outputs.push({
KEY: key,
[languageKey]: formatValue(value)
});
});

await events.once(rl, 'close');
return outputs;
} catch (err) {
console.error(err);
}
}

const formatValue = (input) => {
var input = String(input)
var input = input.replace(/(\\\\'|\\')/g, '\'')
input = input.replace(/(&amp;amp;|&amp;)/g, '&')
input = input.replace(/(\\\\"|\\\")/g, '\"')
input = input.replace(/(&amp;lt;|&lt;)/g, '<')
input = input.replace(/(&amp;gt;|&gt;)/g, '>')
return input
}

module.exports = {
read
}
44 changes: 44 additions & 0 deletions src/migration/reader/ios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const events = require('events');
const fs = require('fs');
const readline = require('readline');

const read = async (filepath, languageKey) => {
try {
const rl = readline.createInterface({
input: fs.createReadStream(filepath),
crlfDelay: Infinity
});
let outputs = [];
rl.on('line', (line) => {
const array = line.split(" = ", 2);
if (array.length < 2) { return }
const key = array[0].slice(1, -1);
const value = array[1].slice(1, -2);

outputs.push({
KEY: key,
[languageKey]: formatValue(value)
});
});

await events.once(rl, 'close');
return outputs;
} catch (err) {
console.error(err);
}
}

const formatValue = (input) => {
var input = String(input)
var input = input.replace(/\\'/g, '\'')
input = input.replace(/&amp;/g, '&')
input = input.replace(/\\\\"/g, '\"')
input = input.replace(/&lt;/g, '<')
input = input.replace(/&gt;/g, '>')
input = input.replace(/%@/g, '%s')
return input
}

module.exports = {
read
}