-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.js
executable file
·125 lines (106 loc) · 4.79 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env node
"use strict";
const fs = require("fs").promises;
const path = require("path");
const { program } = require('commander');
const {Translate} = require('@google-cloud/translate').v2;
const pino = require('pino');
const logger = pino({
transport: {
target: 'pino-pretty',
options: {
timestampKey: false,
ignore: 'pid,hostname'
}
}
});
program
.option('-m, --missing-translation-place-holder <place holder>', 'missing translation place holder', "!!MISSING_TRANSLATION")
.option('-p, --messages-base-path <path>', 'folder path of messages base', "./i18n")
.option('-t, --translate', 'translate with google translator')
.option('-c, --clean', 'delete messages that do not exist in the base file of the language files')
.option('-g, --google-api-key <key>', 'google api key for Cloud Translation API')
.option('-e, --env-file <path>', 'read in a file of environment variables');
program.parse(process.argv);
const options = program.opts();
let dotEnvOptions = {};
if(options.envFile) dotEnvOptions.path = options.envFile;
require('dotenv').config(dotEnvOptions);
const messagesBaseName = "messages.json";
const messagesBasePath = options.messagesBasePath;
const missingTranslationPlaceHolder = options.missingTranslationPlaceHolder;
const googleApiKey = options.googleApiKey || process.env.GOOGLE_TRANSLATE_CREDENTIALS;
const translate = new Translate({key: googleApiKey});
async function main() {
try {
logger.info("checking ",messagesBasePath);
const messagesBase = await readFileMessages(messagesBaseName);
await validateMessageJSONFormat(messagesBaseName, messagesBase);
const messageFiles = await fs.readdir(messagesBasePath);
for(const languageFileMessages of messageFiles){
if (languageFileMessages !== messagesBaseName){
await generateMessages(messagesBase, languageFileMessages);
}
}
logger.info("All done.");
} catch (error) {
logger.error(error);
}
}
async function generateMessages(messagesBase, languageFileMessages){
try {
let hasChanges = false;
const messages = await readFileMessages(languageFileMessages);
await validateMessageJSONFormat(languageFileMessages, messages);
for(const messageBaseKey in messagesBase.translations){
if(!messages.translations[messageBaseKey]){
hasChanges = true;
let translation;
if(options.translate) translation = await translateText(messagesBase.translations[messageBaseKey], messages.locale);
messages.translations[messageBaseKey] = translation || `${missingTranslationPlaceHolder}${missingTranslationPlaceHolder?':':''}${messagesBase.translations[messageBaseKey]}`;
}
}
// CHECK MESSAGES INTO LANGUAGE FILE THAT NOT EXISTS INTO BASE:
for(const messageLanguageKey in messages.translations){
if(!messagesBase.translations[messageLanguageKey]){
if(options.clean){
hasChanges = true;
delete messages.translations[messageLanguageKey];
logger.warn(`Message "${messageLanguageKey}" removed from ${languageFileMessages} because it does not exist in the base file.`);
}else{
logger.warn(`Message "${messageLanguageKey}" found in ${languageFileMessages} file that does not exist in messages base file.`);
}
}
}
if(hasChanges){
writeFileMessages(languageFileMessages, messages);
}
} catch (error) {
logger.error(`Error into ${languageFileMessages}: ${error}`);
}
}
async function writeFileMessages(file, messages){
const filePath = path.join(messagesBasePath, file)
const data = JSON.stringify(messages, null, 2);
await fs.writeFile(filePath, data);
}
async function readFileMessages(file){
const filePath = path.join(messagesBasePath, file);
const messagesBaseRaw = await fs.readFile(filePath);
return JSON.parse(messagesBaseRaw);
}
async function validateMessageJSONFormat(id, message){
if(!message.hasOwnProperty('locale')) throw new Error(`Missing locale into ${id}`);
if(!message.hasOwnProperty('translations')) throw new Error(`Missing translations into ${id}`);
if(typeof message['locale'] !== 'string') throw new Error(`locale value is not valid into ${id}`);
if(typeof message['translations'] !== 'object') throw new Error(`translations value is not valid into ${id}`);
}
async function translateText(text, languaje) {
try {
const [translations] = await translate.translate(text, languaje);
return Array.isArray(translations) ? translations[0] : translations;
} catch (error) {
logger.error(`Error in translation: ${languaje}/${text}: ${error}`);
}
}
main();