index.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import "source-map-support/register";
  2. import axios from "axios";
  3. import { createReadStream, createWriteStream, readdirSync, readFileSync, writeFileSync } from "fs";
  4. import { ensureDirSync } from "fs-extra";
  5. import { MongoClient } from "mongodb";
  6. import { basename } from "path";
  7. import { Extract } from "unzipper";
  8. import * as core from "@actions/core";
  9. import { Octokit } from "@octokit/rest";
  10. const octokit = new Octokit();
  11. try {
  12. require("dotenv").config({ path: "../.env" });
  13. } catch (e) {}
  14. core.info("Updating Translations");
  15. //* Create API Base
  16. //* Run updater
  17. const base = axios.create({
  18. baseURL: "https://api.crowdin.com/api/project/premid/"
  19. }),
  20. crowdinName = "[PreMiD.Localization] main";
  21. run();
  22. async function run() {
  23. //* Get latest translations
  24. //* Read translations/master/
  25. //* Map through lang folders
  26. await getLatestTranslations();
  27. core.info("Transforming result");
  28. const folders = readdirSync(`translations/${crowdinName}/`);
  29. const translations = folders.map(f => {
  30. //* Read projects inside lang Folder
  31. //* return mapped through projects
  32. const projects = readdirSync(`translations/${crowdinName}/${f}`);
  33. return projects.map(p => {
  34. //* Get files in project
  35. //* Return mapped through files
  36. const files = readdirSync(`translations/${crowdinName}/${f}/${p}`);
  37. return {
  38. //* If lang === de_DE > de else keep it
  39. //* Project
  40. //* Translations (Object assign to move into one big object)
  41. lang: f.slice(0, 2) === f.slice(3, 5).toLowerCase() ? f.slice(0, 2) : f,
  42. project: p.toLowerCase(),
  43. translations: Object.assign(
  44. {},
  45. //* Map through files
  46. ...files.map(file => {
  47. //* Read json of file
  48. //* Return Object.assign > .map > 1 big object of all files
  49. const json = JSON.parse(
  50. readFileSync(
  51. `translations/${crowdinName}/${f}/${p}/${file}`,
  52. "utf-8"
  53. )
  54. );
  55. return Object.assign(
  56. {},
  57. //* Map through json and replace . with _ (MongoDB doesn't allow . key)
  58. ...Object.keys(json).map(k => {
  59. return { [k.replace(/[.]/g, "_")]: json[k].message };
  60. })
  61. );
  62. })
  63. )
  64. };
  65. });
  66. });
  67. //* Connect to MongoDB
  68. //* Promise.all
  69. core.info("Connecting to MongoDB");
  70. const client = (await MongoClient.connect(
  71. process.env.MONGOURL,
  72. { appname: "PreMiD - Translation Updater", useUnifiedTopology: true }
  73. ).catch(err => {
  74. core.setFailed(`Failed to connect to MongoDB: ${err.message}`);
  75. process.exit();
  76. })) as MongoClient;
  77. Promise.all(
  78. translations
  79. .reduce((a, b) => [...a, ...b])
  80. .map(t =>
  81. client
  82. .db("PreMiD")
  83. .collection("langFiles")
  84. .replaceOne({ lang: t.lang, project: t.project }, t, { upsert: true })
  85. )
  86. ).then(() => {
  87. core.info("Done!");
  88. client.close();
  89. });
  90. }
  91. async function getLatestTranslations() {
  92. //* Build project
  93. //* If error or no new translations, exit
  94. //* Else download them
  95. //* Unzip them
  96. const res = (
  97. await base("export", {
  98. params: { key: process.env.CROWDIN_API_TOKEN, json: true }
  99. })
  100. ).data;
  101. /* if (!res.success || res.success.status === "skipped") {
  102. core.info("Already up to date");
  103. process.exit();
  104. } */
  105. core.info("Downloading translations...");
  106. const tZIPresponse = await base("download/all.zip", {
  107. responseType: "stream",
  108. params: { key: process.env.CROWDIN_API_TOKEN, json: true }
  109. }),
  110. zipFile = tZIPresponse.data.pipe(createWriteStream("translations.zip"));
  111. await new Promise((resolve, reject) => {
  112. zipFile.on("finish", resolve);
  113. zipFile.on("error", reject);
  114. });
  115. const extract = createReadStream("translations.zip").pipe(
  116. Extract({ path: "translations" })
  117. );
  118. await new Promise(resolve => extract.once("finish", resolve));
  119. await getSourceLanguage();
  120. core.info("Downloaded translations");
  121. }
  122. async function getSourceLanguage() {
  123. const srcFolder = (
  124. await octokit.repos.getContent({
  125. owner: "PreMiD",
  126. repo: "Localization",
  127. path: "src"
  128. })
  129. ).data
  130. // @ts-ignore
  131. .map(f => f.path);
  132. await Promise.all(
  133. srcFolder.map(async p => {
  134. const projFolder = (
  135. await octokit.repos.getContent({
  136. owner: "PreMiD",
  137. repo: "Localization",
  138. path: p
  139. })
  140. ).data
  141. // @ts-ignore
  142. .map(f => f.path);
  143. ensureDirSync(`translations/${crowdinName}/en/${basename(p)}`);
  144. await Promise.all(
  145. projFolder.map(async f => {
  146. writeFileSync(
  147. `translations/${crowdinName}/en/${basename(p)}/${basename(f)}`,
  148. JSON.stringify(
  149. (
  150. await axios.get(
  151. `https://raw.githubusercontent.com/PreMiD/Localization/master/${f}`
  152. )
  153. ).data
  154. )
  155. );
  156. })
  157. );
  158. })
  159. );
  160. }