languages.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. const fs = require("fs-extra");
  2. const jsl = require("svjsl");
  3. const Fuse = require("fuse.js");
  4. const debug = require("./verboseLogging");
  5. const tr = require("./translate");
  6. const settings = require("../settings");
  7. var langs;
  8. /**
  9. * Initializes the language module
  10. */
  11. function init()
  12. {
  13. debug("Languages", `Initializing - loading languages from "${settings.languages.langFilePath}"`);
  14. return new Promise((resolve, reject) => {
  15. fs.readFile(settings.languages.langFilePath, (err, data) => {
  16. if(err)
  17. return reject(err);
  18. else
  19. {
  20. let languages = JSON.parse(data.toString());
  21. debug("Languages", `Found ${Object.keys(languages).length} languages`);
  22. langs = languages;
  23. return resolve(languages);
  24. }
  25. });
  26. });
  27. }
  28. /**
  29. * Checks whether or not a provided language code is ISO 639-1 or ISO 639-2 compatible
  30. * @param {String} langCode Two-character language code
  31. * @param {String} [trLang] For translating the error messages
  32. * @returns {Boolean|String} Returns `true` if code exists, string with error message if not
  33. */
  34. function isValidLang(langCode, trLang)
  35. {
  36. // if trLang not provided or it was provided but is invalid, reset to default lang
  37. if(trLang != "string" || (typeof trLang == "string" && isValidLang(trLang) !== true))
  38. trLang = settings.languages.defaultLanguage;
  39. if(langs == undefined)
  40. return tr(trLang, "langModuleInitError");
  41. if(typeof langCode !== "string" || langCode.length !== 2)
  42. return tr(trLang, "langCodeInvalidValue");
  43. let requested = langs[langCode.toLowerCase()];
  44. if(typeof requested === "string")
  45. return true;
  46. else
  47. return tr(trLang, "langCodeDoesntExist");
  48. }
  49. /**
  50. * Converts a language name (fuzzy) into an ISO 639-1 or ISO 639-2 compatible lang code
  51. * @param {String} language
  52. * @returns {Boolean|String} Returns `false` if no matching language code was found, else returns string with language code
  53. */
  54. function languageToCode(language)
  55. {
  56. if(langs == undefined)
  57. throw new Error("INTERNAL_ERROR: Language module was not correctly initialized (yet)");
  58. if(typeof language !== "string" || language.length < 1)
  59. throw new TypeError("Language is not a string or not two characters in length");
  60. let searchObj = [];
  61. Object.keys(langs).forEach(key => {
  62. searchObj.push({
  63. code: key,
  64. lang: langs[key].toLowerCase()
  65. });
  66. });
  67. let fuzzy = new Fuse(searchObj, {
  68. includeScore: true,
  69. keys: ["code", "lang"],
  70. threshold: 0.4
  71. });
  72. let result = fuzzy.search(language)[0];
  73. if(result)
  74. return result.item.code;
  75. else
  76. return false;
  77. }
  78. /**
  79. * Converts an ISO 639-1 or ISO 639-2 compatible lang code into a language name
  80. * @param {String} code
  81. * @returns {Boolean|String} Returns `false` if no matching language was found, else returns string with language name
  82. */
  83. function codeToLanguage(code)
  84. {
  85. try
  86. {
  87. let jsonObj = JSON.parse(fs.readFileSync(settings.languages.langFilePath).toString());
  88. return jsonObj[code] || false;
  89. }
  90. catch(err)
  91. {
  92. jsl.unused(err);
  93. return false;
  94. }
  95. }
  96. /**
  97. * @typedef {Object} SupLangObj
  98. * @prop {String} code
  99. * @prop {String} name
  100. */
  101. /**
  102. * Returns a list of languages that jokes are available from
  103. * @returns {Array<SupLangObj>}
  104. */
  105. function jokeLangs()
  106. {
  107. let retLangs = [];
  108. fs.readdirSync(settings.jokes.jokesFolderPath).forEach(f => {
  109. if(f == settings.jokes.jokesTemplateFile)
  110. return;
  111. let langCode = f.split("-")[1].substr(0, 2);
  112. retLangs.push({
  113. code: langCode,
  114. name: codeToLanguage(langCode)
  115. });
  116. });
  117. return retLangs;
  118. }
  119. /**
  120. * Returns a list of languages that error messages and maybe other stuff are available as
  121. * @returns {Array<SupLangObj>}
  122. */
  123. function systemLangs()
  124. {
  125. return tr.systemLangs();
  126. }
  127. /**
  128. * Returns all possible language codes
  129. * @returns {Array<String>}
  130. */
  131. function getPossibleCodes()
  132. {
  133. return Object.keys(langs);
  134. }
  135. /**
  136. * Returns all possible languages, mapped as an object where keys are codes and values are language names
  137. * @returns {Object}
  138. */
  139. function getPossibleLanguages()
  140. {
  141. return langs;
  142. }
  143. module.exports = {
  144. init,
  145. isValidLang,
  146. languageToCode,
  147. codeToLanguage,
  148. jokeLangs,
  149. systemLangs,
  150. getPossibleCodes,
  151. getPossibleLanguages
  152. };