locale.service.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**
  2. * @file Provides a service to handle languages and localizations.
  3. * @author Inigo Valentin
  4. * @since 4.0.0
  5. */
  6. /**
  7. * Handles localization of elements.
  8. */
  9. class LocaleService {
  10. /**
  11. * Database connection.
  12. */
  13. #db;
  14. /**
  15. * List of available languages.
  16. *
  17. * The one at index 0 is the default language.
  18. */
  19. #availableLanguages = Array();
  20. /**
  21. * Constructor.
  22. *
  23. * @param db Database connection.
  24. * @constructor
  25. */
  26. constructor(db){
  27. this.#db = db;
  28. this.#init();
  29. }
  30. /**
  31. * Initializes the service.
  32. *
  33. * Called automatically from the constructor.
  34. */
  35. async #init(){
  36. var result = await this.#db.sequelize.query('SELECT code FROM langs WHERE active = 1 ORDER by PRIORITY ASC ', { type: this.#db.sequelize.QueryTypes.SELECT })
  37. for (const r of result) this.#availableLanguages.push(r.code.toLowerCase().substring(0, 2));
  38. }
  39. /**
  40. * Selects the language to use.
  41. *
  42. * If the language is not in the request, using the GET parameter "lang", the default one set
  43. * in the database will be used.
  44. *
  45. * @param req The request received by the server.
  46. * @return Two letter language code to use.
  47. */
  48. selectLanguage(req){
  49. if (!req.query.lang) return this.#availableLanguages[0];
  50. var requestedLang = req.query.lang.toLowerCase().substring(0, 2)
  51. if (this.#availableLanguages.indexOf(requestedLang) != -1) return requestedLang;
  52. return this.#availableLanguages[0];
  53. }
  54. /**
  55. * Decodes a text from the database.
  56. *
  57. * @param result Result of a query to the table 'texts'. Must have at least the columns 'text' and 'file'.
  58. * @return The text.
  59. */
  60. async #decodeText(key, lang){
  61. var result = await this.#db.sequelize.query('SELECT text, file FROM texts WHERE lang = ? AND id = ?', { replacements: [lang, key], type: this.#db.sequelize.QueryTypes.SELECT })
  62. for (const r of result) {
  63. if (r.text) return "" + r.text;
  64. if (r.file) return "" + r.file; // TODO: Return file CONTENTS
  65. }
  66. return "";
  67. }
  68. /**
  69. * Generates a localized object for text storing in database.
  70. *
  71. * @param obj The object with the text in multiple languages. Language codes must be keys.
  72. * @param key The key to assign to the text.
  73. * @param section The section identifier for the text.
  74. * @return An object with those values:
  75. * - valid: True if the object is valid and can be stored in database.
  76. * - key: Identifier for the text.
  77. * - section: Identifier fot the text section.
  78. * - texts{}: An array for the text in different languages. Language codes are keys.
  79. */
  80. generateLocalizedObject(obj, key, section){
  81. let l = {
  82. valid: true,
  83. key: key,
  84. section: section,
  85. texts: {}
  86. };
  87. if (!key) l.valid = false;
  88. if (!section) l.valid = false;
  89. l.key = key;
  90. l.section = section;
  91. let body;
  92. try{
  93. body = JSON.parse(obj);
  94. for (let i = 0; i < this.#availableLanguages.length; i ++)
  95. if (body[this.#availableLanguages[i]] != undefined) l.texts[this.#availableLanguages[i]] = body[this.#availableLanguages[i]];
  96. if (l.texts.length == 0) l.valid = false;
  97. }
  98. catch(err){
  99. l.valid = false;
  100. }
  101. return l;
  102. }
  103. /**
  104. * Saves a localized object in the database.
  105. *
  106. * @param obj The object, as provided by {@see generateLocalizedObject}.
  107. * @return True on success, false on error.
  108. */
  109. async saveLocalizedObject(obj, key, section){
  110. if (!obj.valid || obj.valid != true || !obj.texts || obj.texts.length < 1) return false;
  111. for (const [lang, text] of Object.entries(obj.texts))
  112. let res = await this.#db.sequelize.query('INSERT INTO texts (id, lang, section, text, file) VALUES (?, ?, ?, ?, ?)', {replacements: [obj.key, lang, obj.section, text, null], type: this.#db.sequelize.QueryTypes.INSERT});
  113. return true;
  114. }
  115. /**
  116. * Localizes a project.
  117. *
  118. * Localizes all localizable items in a project, using the language provided in the request or
  119. * the default one.
  120. *
  121. * @param data The project object to localize.
  122. * @param req The request received by the server.
  123. * @return The project object, with all of the fields localized.
  124. */
  125. async localizeProject(data, req){
  126. var lang = this.selectLanguage(req);
  127. data.dataValues.title = await this.#decodeText(data.dataValues.title, lang);
  128. data.dataValues.header = await this.#decodeText(data.dataValues.header, lang);
  129. data.dataValues.text = await this.#decodeText(data.dataValues.text, lang);
  130. data.dataValues.comment = await this.#decodeText(data.dataValues.comment, lang);
  131. if (data.dataValues.type){
  132. data.dataValues.type.title = await this.#decodeText(data.dataValues.type.title, lang);
  133. data.dataValues.type.summary = await this.#decodeText(data.dataValues.type.summary, lang);
  134. }
  135. if (data.dataValues.license){
  136. data.dataValues.license.summary = await this.#decodeText(data.dataValues.license.summary, lang);
  137. data.dataValues.license.legal = await this.#decodeText(data.dataValues.license.legal, lang);
  138. }
  139. for (var i = 0; i < data.dataValues.tags.length; i ++)
  140. data.dataValues.tags[i].tag = await this.#decodeText(data.dataValues.tags[i].tag, lang);
  141. for (var i = 0; i < data.dataValues["project-urls"].length; i ++){
  142. data.dataValues["project-urls"][i].dataValues.type.dataValues.title = await this.#decodeText(data.dataValues["project-urls"][i].dataValues.type.dataValues.title, lang);
  143. data.dataValues["project-urls"][i].dataValues.type.dataValues.summary = await this.#decodeText(data.dataValues["project-urls"][i].dataValues.type.dataValues.summary, lang);
  144. }
  145. for (var i = 0; i < data.dataValues["project-images"].length; i ++)
  146. data.dataValues["project-images"][i].dataValues.alt = await this.#decodeText(data.dataValues["project-images"][i].dataValues.alt, lang);
  147. //console.log(data.dataValues.projectUrls)
  148. return data;
  149. }
  150. /**
  151. * Localizes a list of projects.
  152. *
  153. * Localizes all localizable items in all projects, using the language provided in the request or
  154. * the default one.
  155. *
  156. * @param data The project object list to localize.
  157. * @param req The request received by the server.
  158. * @return The project list, with all of their fields localized.
  159. */
  160. async localizeProjects(data, req){
  161. for (var d of data) d = await this.localizeProject(d, req);
  162. return data;
  163. }
  164. /**
  165. * Localizes a license.
  166. *
  167. * Localizes all localizable items in a license, using the language provided in the request or
  168. * the default one.
  169. *
  170. * @param data The license object to localize.
  171. * @param req The request received by the server.
  172. * @return The license object, with all of the fields localized.
  173. */
  174. async localizeLicense(data, req){
  175. var lang = this.selectLanguage(req);
  176. data.dataValues.summary = await this.#decodeText(data.dataValues.summary, lang);
  177. data.dataValues.legal = await this.#decodeText(data.dataValues.legal, lang);
  178. return data;
  179. }
  180. /**
  181. * Localizes a list of projects licenses.
  182. *
  183. * Localizes all localizable items in all licenses, using the language provided in the request or
  184. * the default one.
  185. *
  186. * @param data The license object list to localize.
  187. * @param req The request received by the server.
  188. * @return The license list, with all of their fields localized.
  189. */
  190. async localizeLicenses(data, req){
  191. for (var d of data) d = await this.localizeLicense(d, req);
  192. return data;
  193. }
  194. /**
  195. * Localizes a project type.
  196. *
  197. * Localizes all localizable items in a project type, using the language provided in the request or
  198. * the default one.
  199. *
  200. * @param data The project type object to localize.
  201. * @param req The request received by the server.
  202. * @return The project type object, with all of the fields localized.
  203. */
  204. async localizeProjectType(data, req){
  205. var lang = this.selectLanguage(req);
  206. data.dataValues.title = await this.#decodeText(data.dataValues.title, lang);
  207. data.dataValues.summary = await this.#decodeText(data.dataValues.summary, lang);
  208. return data;
  209. }
  210. /**
  211. * Localizes a list of projects project types.
  212. *
  213. * Localizes all localizable items in all project types, using the language provided in the request or
  214. * the default one.
  215. *
  216. * @param data The project type object list to localize.
  217. * @param req The request received by the server.
  218. * @return The project type list, with all of their fields localized.
  219. */
  220. async localizeProjectTypes(data, req){
  221. for (var d of data) d = await this.localizeProjectType(d, req);
  222. return data;
  223. }
  224. /**
  225. * Localizes a user.
  226. *
  227. * Localizes all localizable items in a user, using the language provided in the request or
  228. * the default one.
  229. *
  230. * @param data The user object to localize.
  231. * @param req The request received by the server.
  232. * @return The user object, with all of the fields localized.
  233. */
  234. async localizeUser(data, req){
  235. var lang = this.selectLanguage(req);
  236. // TODO
  237. //data.dataValues.title = await this.#decodeText(data.dataValues.title, lang);
  238. //data.dataValues.summary = await this.#decodeText(data.dataValues.summary, lang);
  239. return data;
  240. }
  241. /**
  242. * Localize a list of users project types.
  243. *
  244. * Localize all localizable items in all users, using the language provided in the request or
  245. * the default one.
  246. *
  247. * @param data The user object list to localize.
  248. * @param req The request received by the server.
  249. * @return The user list, with all of their fields localized.
  250. */
  251. async localizeUserss(data, req){
  252. for (var d of data) d = await this.localizeUser(d, req);
  253. return data;
  254. }
  255. }
  256. module.exports = LocaleService;