浏览代码

Added translation converting system and frontend translation system.

KrisVos130 7 年之前
父节点
当前提交
486bc5a7af

+ 7 - 1
.gitignore

@@ -21,8 +21,14 @@ frontend/node_modules
 frontend/dist
 frontend/config/default.js
 
+# Translation
+translation/node_modules
+translation/config/default.json
+
 npm
 
 # Logs
 log
-.env
+.env
+
+locales/

+ 17 - 1
backend/index.js

@@ -206,6 +206,22 @@ async.waterfall([
 			app.listen(config.get("frontendPort"));
 			const rootDir = __dirname.substr(0, __dirname.lastIndexOf("backend")) + "frontend/dist/";
 			const rootDirAssets = __dirname.substr(0, __dirname.lastIndexOf("backend")) + "frontend/app/";
+			const rootDirLocales = __dirname.substr(0, __dirname.lastIndexOf("backend"));
+
+			app.get("/locales/*", (req, res) => {
+				let path = req.path;
+				path = path.replace(/\//g, "\\");
+				path = path.replace("\\locales", "locales");
+				console.log(rootDirLocales, path, rootDirLocales + path);
+				fs.access(rootDirLocales + path, function(err) {
+					console.log("Error: ", !!err);
+					if (!err) {
+						res.sendFile(rootDirLocales + path);
+					} else {
+						res.redirect("/");
+					}
+				});
+			});
 
 			app.get("/assets/*", (req, res) => {
 				const path = req.path;
@@ -213,7 +229,7 @@ async.waterfall([
 				fs.access(rootDirAssets + path, function(err) {
 					console.log("Error: ", !!err);
 					if (!err) {
-						res.sendFile(rootDirAssets + path);
+						res.sendJSON({});
 					} else {
 						res.redirect("/");
 					}

+ 32 - 0
frontend/app/js/i18n.js

@@ -0,0 +1,32 @@
+import i18next from "i18next";
+import XHR from 'i18next-xhr-backend';
+import config from "config";
+
+const i18n = i18next
+	.use(XHR)
+	.init({
+		lng: "en",
+		debug: true,
+		fallbackLng: "en",
+		referenceLng: "en",
+		backend: {
+			loadPath: '/locales/{{lng}}/{{ns}}.json',
+			addPath: 'locales/add/{{lng}}/{{ns}}',
+			allowMultiLoading: false,
+			crossDomain: false,
+			withCredentials: false,
+			queryStringParams: { v: config.version }
+		},
+		ns: ["general"],
+		defaultNS: "general",
+		keySeparator: false, // we use content as keys
+		interpolation: {
+			escapeValue: false, // not needed for react!!
+			formatSeparator: ",",
+		},
+		react: {
+			wait: true,
+		},
+	});
+
+export default i18n;

+ 10 - 6
frontend/app/js/index.js

@@ -2,12 +2,14 @@ import React from "react";
 import ReactDOM from "react-dom";
 import { Provider } from "react-redux";
 import { createStore, applyMiddleware } from "redux";
-import { BrowserRouter, Route } from "react-router-dom";
+import { BrowserRouter } from "react-router-dom";
+import { I18nextProvider } from "react-i18next";
 import thunk from "redux-thunk";
 import "babel-polyfill";
 
 import rootReducer from "reducers";
 
+import i18n from "./i18n";
 import App from "./app";
 
 import "../styles/main.scss";
@@ -22,10 +24,12 @@ store = createStore(
 );
 
 ReactDOM.render(
-	<Provider store={ store }>
-		<BrowserRouter>
-			<App />
-		</BrowserRouter>
-	</Provider>,
+	<I18nextProvider i18n={ i18n }>
+		<Provider store={ store }>
+			<BrowserRouter>
+				<App />
+			</BrowserRouter>
+		</Provider>
+	</I18nextProvider>,
 	document.getElementById("root")
 );

+ 18 - 1
frontend/app/js/views/Home/index.jsx

@@ -1,10 +1,27 @@
 import React, { Component } from "react";
+import PropTypes from "prop-types";
+import { translate } from "react-i18next";
 
+@translate(["home"], { wait: true })
 export default class Home extends Component {
+	static propTypes = {
+		t: PropTypes.func,
+	};
+
+	static defaultProps = {
+		t: () => {},
+	};
+
 	render() {
+		const { t } = this.props;
+
 		return (
 			<div>
-				<h2>Welcome to Musare!</h2>
+				<h2>{ t("home:title") }</h2>
+				<h2>{ t("home:officialStations") }</h2>
+				<h2>{ t("home:communityStations") }</h2>
+				<h2>{ t("home:users", { context: "male", count: 5 }) }</h2>
+				<h2>{ t("home:users", { context: "female", count: 1 }) }</h2>
 			</div>
 		);
 	}

+ 6 - 0
frontend/config/template.js

@@ -8,4 +8,10 @@ export default {
 		"secure": false,
 		"sidName": "SID",
 	},
+	"locize": {
+		"projectId": "fb8c7f34-4a49-4e07-876e-ee941f2b5a2c",
+		"apiKey": "32c144d5-55cb-4da9-a3f9-9cb13e639c4a",
+		"version": "latest",
+	},
+	"version": "2.3.0-REACT"
 };

+ 23 - 0
frontend/package-lock.json

@@ -3880,6 +3880,21 @@
       "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=",
       "dev": true
     },
+    "i18next": {
+      "version": "8.4.3",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-8.4.3.tgz",
+      "integrity": "sha1-Nrb/UWxPmSAQ7tzOJKNsRgnox9w="
+    },
+    "i18next-locize-backend": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/i18next-locize-backend/-/i18next-locize-backend-1.0.0.tgz",
+      "integrity": "sha1-udFyrMVh1KTpW6RBINlmljiukcA="
+    },
+    "i18next-xhr-backend": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-1.4.2.tgz",
+      "integrity": "sha1-eqdmKSxGyoP/ZHe7VQdLNjpkamI="
+    },
     "iconv-lite": {
       "version": "0.4.18",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
@@ -5811,6 +5826,14 @@
         "prop-types": "15.5.10"
       }
     },
+    "react-i18next": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-4.8.0.tgz",
+      "integrity": "sha1-kvDSgcXzmsjzw/OBVi1SPp2DAlQ=",
+      "requires": {
+        "hoist-non-react-statics": "1.2.0"
+      }
+    },
     "react-json-tree": {
       "version": "0.10.9",
       "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.10.9.tgz",

+ 4 - 0
frontend/package.json

@@ -55,12 +55,16 @@
     "dom-serializer": "^0.1.0",
     "domelementtype": "^1.3.0",
     "es6-promise": "^3.3.1",
+    "i18next": "^8.4.3",
+    "i18next-locize-backend": "^1.0.0",
+    "i18next-xhr-backend": "^1.4.2",
     "immutable": "^3.8.1",
     "isomorphic-fetch": "^2.2.1",
     "lodash": "^4.17.4",
     "prop-types": "^15.5.10",
     "react": "^15.5.4",
     "react-dom": "^15.5.4",
+    "react-i18next": "^4.8.0",
     "react-redux": "^4.4.8",
     "react-router-dom": "^4.1.2",
     "redux": "^3.6.0",

+ 0 - 3
tools/windows/open-in-browser.cmd

@@ -1,3 +0,0 @@
-:: Opens the web app in the browser for you
-@ECHO OFF
-FOR /F "delims=" %%i IN ('docker-machine ip') DO explorer http://%%i:8080

+ 0 - 3
tools/windows/setup-environment.cmd

@@ -1,3 +0,0 @@
-:: Sets up the environment for docker
-@ECHO OFF
-@FOR /f "tokens=*" %%i IN ('docker-machine env default') DO @%%i

+ 6 - 0
translation/config/template.json

@@ -0,0 +1,6 @@
+{
+  "poeditor": {
+	"api_token": "",
+	"project_id": ""
+  }
+}

+ 99 - 0
translation/index.js

@@ -0,0 +1,99 @@
+const fs = require("fs");
+const config = require("config");
+const request = require("request");
+const async = require("async");
+
+const localesFolder = __dirname.substr(0, __dirname.lastIndexOf("translation")) + "locales/";
+const deleteFolderRecursive = (path) => {
+	if (fs.existsSync(path)) {
+		fs.readdirSync(path).forEach((file,index) => {
+			const curPath = path + "/" + file;
+			if (fs.lstatSync(curPath).isDirectory()) {
+				deleteFolderRecursive(curPath);
+			} else {
+				fs.unlinkSync(curPath);
+			}
+		});
+		fs.rmdirSync(path);
+	}
+};
+deleteFolderRecursive(localesFolder);
+
+async.waterfall([
+	(next) => {
+		fs.mkdirSync(localesFolder);
+		next();
+	},
+
+	(next) => {
+		request.post(`https://api.poeditor.com/v2/languages/list`, {form: {api_token: config.get("poeditor.api_token"), id: config.get("poeditor.project_id")}}, next);
+	},
+
+	(res, body, next) => {
+		body = JSON.parse(body);
+		if (body.response.status !== "success") return next(body.response.message);
+		let languages = body.result.languages.map((language) => {
+			return language.code;
+		});
+		next(null, languages);
+	},
+
+	(languages, next) => {
+		async.each(
+			languages,
+			(language, next) => {
+				async.waterfall([
+					(next) => {
+						fs.mkdirSync(`${localesFolder}${language}`);
+						next();
+					},
+
+					(next) => {
+						request.post(`https://api.poeditor.com/v2/projects/export`, {form: {api_token: config.get("poeditor.api_token"), id: config.get("poeditor.project_id"), language, type: "key_value_json", filters: "translated"}}, next);
+					},
+
+					(res, body, next) => {
+						body = JSON.parse(body);
+						if (body.response.status !== "success") return next(body.response.message);
+						request(body.result.url, next);
+					},
+
+					(res, body, next) => {
+						if (!body) body = "{}";
+						body = JSON.parse(body);
+						const files = [];
+						Object.keys(body).forEach((namespace) => {
+							files.push({
+								namespace,
+								content: body[namespace]
+							});
+						});
+						next(null, files);
+					},
+
+					(files, next) => {
+						async.each(
+							files,
+							(file, next) => {
+								fs.writeFile(`${localesFolder}${language}/${file.namespace}.json`, JSON.stringify(file.content), function(err) {
+									if(err) console.err(`Failed to write namespace ${file.namespace} for language ${language}.`);
+									next();
+								});
+							},
+							() => {
+								next();
+							}
+						);
+					}
+				], () => {
+					next();
+				});
+			},
+			() => {
+				next();
+			}
+		);
+	}
+], (err, res) => {
+	console.log(err, res);
+});

+ 434 - 0
translation/package-lock.json

@@ -0,0 +1,434 @@
+{
+  "name": "musaretranslation",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "ajv": {
+      "version": "4.11.8",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+      "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+      "requires": {
+        "co": "4.6.0",
+        "json-stable-stringify": "1.0.1"
+      }
+    },
+    "asn1": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+    },
+    "assert-plus": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+      "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
+    },
+    "async": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
+      "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==",
+      "requires": {
+        "lodash": "4.17.4"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "aws-sign2": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+      "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
+    },
+    "aws4": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+      "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+      "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+      "optional": true,
+      "requires": {
+        "tweetnacl": "0.14.5"
+      }
+    },
+    "boom": {
+      "version": "2.10.1",
+      "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+      "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+      "requires": {
+        "hoek": "2.16.3"
+      }
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+    },
+    "combined-stream": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+      "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
+      "requires": {
+        "delayed-stream": "1.0.0"
+      }
+    },
+    "config": {
+      "version": "1.26.1",
+      "resolved": "https://registry.npmjs.org/config/-/config-1.26.1.tgz",
+      "integrity": "sha1-9kfOMsNF6AunOo6qeppLTlspDKE=",
+      "requires": {
+        "json5": "0.4.0",
+        "os-homedir": "1.0.2"
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "cryptiles": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+      "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+      "requires": {
+        "boom": "2.10.1"
+      }
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "requires": {
+        "assert-plus": "1.0.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+    },
+    "ecc-jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+      "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+      "optional": true,
+      "requires": {
+        "jsbn": "0.1.1"
+      }
+    },
+    "extend": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+      "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+    },
+    "form-data": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+      "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+      "requires": {
+        "asynckit": "0.4.0",
+        "combined-stream": "1.0.5",
+        "mime-types": "2.1.16"
+      }
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "requires": {
+        "assert-plus": "1.0.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "har-schema": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
+      "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4="
+    },
+    "har-validator": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
+      "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+      "requires": {
+        "ajv": "4.11.8",
+        "har-schema": "1.0.5"
+      }
+    },
+    "hawk": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+      "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+      "requires": {
+        "boom": "2.10.1",
+        "cryptiles": "2.0.5",
+        "hoek": "2.16.3",
+        "sntp": "1.0.9"
+      }
+    },
+    "hoek": {
+      "version": "2.16.3",
+      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+      "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
+    },
+    "http-signature": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+      "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+      "requires": {
+        "assert-plus": "0.2.0",
+        "jsprim": "1.4.1",
+        "sshpk": "1.13.1"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "optional": true
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+    },
+    "json-stable-stringify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+      "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+      "requires": {
+        "jsonify": "0.0.0"
+      }
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+    },
+    "json5": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz",
+      "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0="
+    },
+    "jsonify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "lodash": {
+      "version": "4.17.4",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+      "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
+    },
+    "mime-db": {
+      "version": "1.29.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
+      "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg="
+    },
+    "mime-types": {
+      "version": "2.1.16",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
+      "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=",
+      "requires": {
+        "mime-db": "1.29.0"
+      }
+    },
+    "oauth-sign": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+      "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+    },
+    "performance-now": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
+      "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+    },
+    "qs": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
+      "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
+    },
+    "request": {
+      "version": "2.81.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
+      "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+      "requires": {
+        "aws-sign2": "0.6.0",
+        "aws4": "1.6.0",
+        "caseless": "0.12.0",
+        "combined-stream": "1.0.5",
+        "extend": "3.0.1",
+        "forever-agent": "0.6.1",
+        "form-data": "2.1.4",
+        "har-validator": "4.2.1",
+        "hawk": "3.1.3",
+        "http-signature": "1.1.1",
+        "is-typedarray": "1.0.0",
+        "isstream": "0.1.2",
+        "json-stringify-safe": "5.0.1",
+        "mime-types": "2.1.16",
+        "oauth-sign": "0.8.2",
+        "performance-now": "0.2.0",
+        "qs": "6.4.0",
+        "safe-buffer": "5.1.1",
+        "stringstream": "0.0.5",
+        "tough-cookie": "2.3.2",
+        "tunnel-agent": "0.6.0",
+        "uuid": "3.1.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+    },
+    "sntp": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+      "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+      "requires": {
+        "hoek": "2.16.3"
+      }
+    },
+    "sshpk": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
+      "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
+      "requires": {
+        "asn1": "0.2.3",
+        "assert-plus": "1.0.0",
+        "bcrypt-pbkdf": "1.0.1",
+        "dashdash": "1.14.1",
+        "ecc-jsbn": "0.1.1",
+        "getpass": "0.1.7",
+        "jsbn": "0.1.1",
+        "tweetnacl": "0.14.5"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "stringstream": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+      "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
+    },
+    "tough-cookie": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
+      "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
+      "requires": {
+        "punycode": "1.4.1"
+      }
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "optional": true
+    },
+    "uuid": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
+      "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "1.3.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    }
+  }
+}

+ 17 - 0
translation/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "musaretranslation",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "dependencies": {
+    "async": "^2.5.0",
+    "config": "^1.26.1",
+    "request": "^2.81.0"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC"
+}