{this.renderButtons(queryLogEnabled)}
diff --git a/client/src/helpers/translations/download.js b/client/src/helpers/translations/download.js
new file mode 100644
index 00000000..63919b7e
--- /dev/null
+++ b/client/src/helpers/translations/download.js
@@ -0,0 +1,107 @@
+const fs = require('fs');
+const path = require('path');
+const crypto = require('crypto');
+const requestPromise = require('request-promise');
+
+const LOCALES_DIR = '../../__locales';
+const LOCALES_LIST = ['en', 'ru', 'vi'];
+
+/**
+ * Hash content
+ * @param {string} content
+ */
+const hashString = content => crypto.createHash('md5').update(content, 'utf8').digest('hex');
+
+/**
+ * Prepare params to get translations from oneskyapp
+ * @param {string} locale language shortcut
+ * @param {object} oneskyapp config oneskyapp
+ */
+const prepare = (locale, oneskyapp) => {
+ const timestamp = Math.round(new Date().getTime() / 1000);
+
+ let url = [];
+ url.push(oneskyapp.url + oneskyapp.projectId);
+ url.push(`/translations?locale=${locale}`);
+ url.push('&source_file_name=en.json');
+ url.push(`&export_file_name=${locale}.json`);
+ url.push(`&api_key=${oneskyapp.apiKey}`);
+ url.push(`×tamp=${timestamp}`);
+ url.push(`&dev_hash=${hashString(timestamp + oneskyapp.secretKey)}`);
+ url = url.join('');
+
+ return url;
+};
+
+/**
+ * Promise wrapper for writing in file
+ * @param {string} filename
+ * @param {any} body
+ */
+function writeInFile(filename, body) {
+ return new Promise((resolve, reject) => {
+ if (typeof body !== 'string') {
+ try {
+ body = JSON.stringify(body, null, 4); // eslint-disable-line
+ } catch (err) {
+ reject(err);
+ }
+ }
+
+ fs.writeFile(filename, body, (err) => {
+ if (err) reject(err);
+ resolve('Ok');
+ });
+ });
+}
+
+/**
+ * Request to server onesky
+ * @param {string} url
+ * @param {string} locale
+ */
+const request = (url, locale) => (
+ requestPromise.get(url)
+ .then((res) => {
+ if (res.length) {
+ const pathToFile = path.join(LOCALES_DIR, `${locale}.json`);
+ return writeInFile(pathToFile, res);
+ }
+ return null;
+ })
+ .then((res) => {
+ let result = locale;
+ result += res ? ' - OK' : ' - Empty';
+ return result;
+ })
+ .catch((err) => {
+ console.log(err);
+ return `${locale} - Not OK`;
+ }));
+
+/**
+ * Download locales
+ */
+const download = () => {
+ const locales = LOCALES_LIST;
+ let oneskyapp;
+ try {
+ oneskyapp = JSON.parse(fs.readFileSync('./oneskyapp.json'));
+ } catch (err) {
+ throw new Error(err);
+ }
+
+ const requests = locales.map((locale) => {
+ const url = prepare(locale, oneskyapp);
+ return request(url, locale);
+ });
+
+ Promise
+ .all(requests)
+ .then((res) => {
+ res.forEach(item => console.log(item));
+ })
+ .catch(err => console.log(err));
+};
+
+download();
diff --git a/client/src/helpers/translations/oneskyapp.json.dist b/client/src/helpers/translations/oneskyapp.json.dist
new file mode 100644
index 00000000..d36a2935
--- /dev/null
+++ b/client/src/helpers/translations/oneskyapp.json.dist
@@ -0,0 +1,6 @@
+{
+ "url": "https://platform.api.onesky.io/1/projects/",
+ "projectId": "",
+ "apiKey": "",
+ "secretKey": ""
+}
\ No newline at end of file
diff --git a/client/src/helpers/translations/package-lock.json b/client/src/helpers/translations/package-lock.json
new file mode 100644
index 00000000..058540bf
--- /dev/null
+++ b/client/src/helpers/translations/package-lock.json
@@ -0,0 +1,61 @@
+{
+ "name": "translations",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "bluebird": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
+ "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ },
+ "psl": {
+ "version": "1.1.29",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
+ "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "request-promise": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
+ "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
+ "requires": {
+ "bluebird": "^3.5.0",
+ "request-promise-core": "1.1.1",
+ "stealthy-require": "^1.1.0",
+ "tough-cookie": ">=2.3.3"
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
+ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+ "requires": {
+ "lodash": "^4.13.1"
+ }
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+}
diff --git a/client/src/helpers/translations/package.json b/client/src/helpers/translations/package.json
new file mode 100644
index 00000000..8f49816b
--- /dev/null
+++ b/client/src/helpers/translations/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "translations",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "download-locales": "node download.js",
+ "upload-locales": "node upload.js"
+ },
+ "dependencies": {
+ "request-promise": "^4.2.2"
+ }
+}
diff --git a/client/src/helpers/translations/upload.js b/client/src/helpers/translations/upload.js
new file mode 100644
index 00000000..08b5411d
--- /dev/null
+++ b/client/src/helpers/translations/upload.js
@@ -0,0 +1,51 @@
+const path = require('path');
+const fs = require('fs');
+const crypto = require('crypto');
+const request = require('request-promise');
+
+const LOCALES_DIR = '../../__locales';
+
+/**
+ * Hash content
+ *
+ * @param {string} content
+ */
+const hashString = content => crypto.createHash('md5').update(content, 'utf8').digest('hex');
+
+/**
+ * Prepare post params
+ */
+const prepare = () => {
+ let oneskyapp;
+ try {
+ oneskyapp = JSON.parse(fs.readFileSync('./oneskyapp.json'));
+ } catch (err) {
+ throw new Error(err);
+ }
+
+ const url = `${oneskyapp.url}${oneskyapp.projectId}/files`;
+ const timestamp = Math.round(new Date().getTime() / 1000);
+ const formData = {
+ timestamp,
+ file: fs.createReadStream(path.resolve(LOCALES_DIR, 'en.json')),
+ file_format: 'HIERARCHICAL_JSON',
+ locale: 'en',
+ is_keeping_all_strings: 'false',
+ api_key: oneskyapp.apiKey,
+ dev_hash: hashString(timestamp + oneskyapp.secretKey),
+ };
+
+ return { url, formData };
+};
+
+/**
+ * Make request to onesky to upload new json
+ */
+const upload = () => {
+ const { url, formData } = prepare();
+ request
+ .post({ url, formData })
+ .catch(err => console.log(err));
+};
+
+upload();
diff --git a/client/src/i18n.js b/client/src/i18n.js
index 28b53b34..26e0c73a 100644
--- a/client/src/i18n.js
+++ b/client/src/i18n.js
@@ -1,31 +1,38 @@
-
import i18n from 'i18next';
import { reactI18nextModule } from 'react-i18next';
import { initReactI18n } from 'react-i18next/hooks';
import langDetect from 'i18next-browser-languagedetector';
-import vi from './__locales/vi';
-import en from './__locales/en';
+
+import vi from './__locales/vi.json';
+import en from './__locales/en.json';
export const languages = [
+ {
+ key: 'en',
+ name: 'English',
+ },
{
key: 'vi',
name: 'Tiếng Việt',
},
{
- key: 'en',
- name: 'English',
+ key: 'ru',
+ name: 'Русский',
},
];
-
i18n
.use(langDetect)
.use(initReactI18n)
.use(reactI18nextModule) // passes i18n down to react-i18next
.init({
resources: {
- vi,
- en,
+ vi: {
+ translation: vi,
+ },
+ en: {
+ translation: en,
+ },
},
fallbackLng: 'en',
keySeparator: false, // we use content as keys