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/google docs #1

Merged
merged 2 commits into from
Jun 21, 2020
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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ dist
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
.pnp.*

# Custom
token.json
credentials.json
17 changes: 11 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"name": "multi-language-mobile",
"version": "0.0.0",
"description": "Tool for generating localization files for iOS and Android",
"main": "index.js",
"main": "./src/index.js",
"bin": {
"multi-language": "./src/index.js"
},
"author": "Johnny Gu <[email protected]>",
"license": "MIT",
"scripts": {
Expand Down Expand Up @@ -30,19 +33,21 @@
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"auto-changelog": "^2.0.0",
"babel-eslint": "^10.0.3",
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
"eslint": "^7.2.0",
"husky": "^4.2.5",
"prettier": "^2.0.5",
"jest": "^24.9.0",
"eslint-config-prettier": "^6.5.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jest": "^23.0.2",
"eslint-plugin-prettier": "^3.1.1",
"babel-eslint": "^10.0.3",
"babel-plugin-transform-inline-environment-variables": "^0.4.3"
"husky": "^4.2.5",
"jest": "^24.9.0",
"prettier": "^2.0.5"
},
"dependencies": {
"commander": "^5.1.0",
"csv-parser": "^2.3.3",
"googleapis": "39",
"write": "^2.0.0"
}
}
4 changes: 4 additions & 0 deletions resources/google.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
key,en,zh
home title,This is home,首页
alert_ok,OK,好的
count number,There are %d of them,一共有%d个
22 changes: 22 additions & 0 deletions src/downloader/google.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const google = require('../vendor/google');
const path = require('path');
const write = require("write");

const outputFileName = 'google.csv';
const DEFAULT_PATH = path.join(__dirname, '../../output');
// const fileId = '13PRkyoSfdpRJhTlY8xtyX8jrXuhzAZmS1iPL2c9L8Ek';

const downloadCsv = ({destPath = DEFAULT_PATH, credentials, fileId}) => {
const fullPath = path.join(destPath, outputFileName);
return google.generateDrive({destPath, credentials})
.then(drive => drive.files.export({
fileId,
mimeType: 'text/csv'
}))
.then(({data}) => write(fullPath, data))
.then(() => Promise.resolve(fullPath))
}

module.exports = {
downloadCsv
}
53 changes: 7 additions & 46 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,9 @@
const csv = require("csv-parser");
const fs = require("fs");
const ios = require("./lib/ios");
const android = require("./lib/android");
#!/usr/bin/env node

const generators = [ios, android];
const { run } = require('./run')

const formatKey = (key) => {
const removespace = key.replace(/[_ ]/, "&&&");
const words = removespace.split("&&&").map((s) => s.toLowerCase());
return words.join("_");
};

const readFromCsv = (filepath) => {
const results = [];
return new Promise((resolve, reject) => {
fs.createReadStream(filepath)
.pipe(csv())
.on("data", (data) => {
var { key } = data;
results.push({
...data,
key: formatKey(key),
});
})
.on("end", () => {
results.sort((lhs, rhs) => lhs.key > rhs.key);
resolve(results);
})
.on("error", (err) => {
reject(err);
});
});
};

const main = async (input) => {
const path = input || "./resources/test.csv";
try {
const array = await readFromCsv(path);
for (var i = 0; i < generators.length; i++) {
await generators[i].generateFile(array);
}
} catch (err) {
console.log(err);
}
};

main();
run(process.argv).catch(error => {
console.log('\n')
console.error(error)
process.exit(1)
})
9 changes: 5 additions & 4 deletions src/lib/android.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const generateHeader = require("./header");
const write = require("write");
const path = require("path");

const generateFilePath = (key) => {
switch (key) {
Expand All @@ -15,12 +16,12 @@ const generateFilePath = (key) => {
}
};

const generateFile = (array) => {
const generateFile = (data, basePath) => {
const header = generateHeader();
const languages = Object.keys(array[0]).filter((k) => k !== "key");
const languages = Object.keys(data[0]).filter((k) => k !== "key");
const generators = languages.map((l) => {
const filepath = generateFilePath(l);
const content = array.reduce((result, next) => {
const filepath = path.join(basePath, generateFilePath(l));
const content = data.reduce((result, next) => {
return result + ` <string name="${next.key}">${next[l]}</string>\n`;
}, "");
const fullContent = `<resources>\n${content}\n</resources>`;
Expand Down
9 changes: 5 additions & 4 deletions src/lib/ios.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const generateHeader = require("./header");
const write = require("write");
const path = require("path");

const generateFilePath = (key) => {
switch (key) {
Expand All @@ -15,12 +16,12 @@ const generateFilePath = (key) => {
}
};

const generateFile = (array) => {
const generateFile = (data, basePath) => {
const header = generateHeader();
const languages = Object.keys(array[0]).filter((k) => k !== "key");
const languages = Object.keys(data[0]).filter((k) => k !== "key");
const generators = languages.map((l) => {
const filepath = generateFilePath(l);
const content = array.reduce((result, next) => {
const filepath = path.join(basePath, generateFilePath(l));
const content = data.reduce((result, next) => {
return result + `"${next.key}" = "${next[l]}";\n`;
}, "");
return write(filepath, `${header}\n${content}`);
Expand Down
118 changes: 118 additions & 0 deletions src/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const { Command } = require('commander');
const { version } = require('../package.json');
const csv = require("csv-parser");
const fs = require("fs");
const ios = require("./lib/ios");
const android = require("./lib/android");
const google = require("./downloader/google");
const readJson = require("./utils/readJson");

const DEFAULT_OPTIONS = {
// local
inputPath: null,
// google
googleFileId: null,
googleCredential: './credentials.json',

outputDir: './output',
platforms: ['ios', 'android'],
config: '.multi-language'
}
const PACKAGE_FILE = 'package.json';
const PACKAGE_OPTIONS_KEY = 'multi-language';

const platformMap = {
'ios': ios,
'android': android
};

const collect = (value, previous) => {
return previous.concat([value]);
}

const getOptions = async (argv) => {
const options = new Command()
.option('--output-dir <string>', `output file base directory, default: ${DEFAULT_OPTIONS.outputDir}`)
.option('--platforms <string>', `output platforms, default: ${DEFAULT_OPTIONS.platforms}`, collect, [])
// .option('--downloader <string>', `downloader for input, default: ${DEFAULT_OPTIONS.downloader}`)
.option('--input-path <file>', `file for local csv input, default: ${DEFAULT_OPTIONS.inputPath}`)
.option('--google-file-id <string>', 'google file id, you can find it in the url')
.option('--google-credential <file>', `file for google credentials, default: ${DEFAULT_OPTIONS.googleCredential}`)
.version(version)
.parse(argv)

const pkg = await readJson(PACKAGE_FILE);
const packageOptions = pkg ? pkg[PACKAGE_OPTIONS_KEY] : null;
const dotOptions = await readJson(options.config || DEFAULT_OPTIONS.config);

return {
...DEFAULT_OPTIONS,
...dotOptions,
...packageOptions,
...options
}
}

const formatKey = (key) => {
const removespace = key.replace(/[_ ]/, "&&&");
const words = removespace.split("&&&").map((s) => s.toLowerCase());
return words.join("_");
};

const readFromCsv = (filepath) => {
const results = [];
return new Promise((resolve, reject) => {
fs.createReadStream(filepath)
.pipe(csv())
.on("data", (data) => {
var { key } = data;
results.push({
...data,
key: formatKey(key),
});
})
.on("end", () => {
results.sort((lhs, rhs) => lhs.key > rhs.key);
resolve(results);
})
.on("error", (err) => {
reject(err);
});
});
};

const run = async (argv) => {
// const path = input || "./resources/test.csv";
const options = await getOptions(argv);
try {
let path;
if (options.inputPath) {
path = options.inputPath
} else if (options.googleFileId) {
path = await google.downloadCsv({
destPath: options.outputDir,
credentials: options.googleCredential,
fileId: options.googleFileId
})
} else {
console.log(`Error: To run this app, you need one of these:
- path to local csv with input-path param
- google file id with google-file-id param
`)
process.exit()
}
const array = await readFromCsv(path);
const platforms = options.platforms;
for (var i = 0; i < platforms.length; i++) {
const generator = platformMap[platforms[i]];
if (!generator) continue;
await generator.generateFile(array, options.outputDir);
}
} catch (err) {
console.log(err);
}
};

module.exports = {
run
}
14 changes: 14 additions & 0 deletions src/utils/readJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const fs = require('fs')

const readJson = (path) => {
return new Promise((resolve) => {
fs.readFile(path, (err, content) => {
if (err) {
return resolve()
}
resolve(JSON.parse(content))
})
})
}

module.exports = readJson
Loading