phrasebook.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const translation = require("./translation.js").translation;
  2. /**
  3. * This class repesents phrasebook, which is something like dictionary,
  4. * but not for words, for all phrases in app. It give functions which
  5. * could find and translates phrases.
  6. */
  7. class phrasebook {
  8. /**
  9. * @var {Map}
  10. * This store phrases in flat notation.
  11. */
  12. #phrases;
  13. /**
  14. * @var {?object}
  15. * This store object for nested object notation.
  16. */
  17. #objects;
  18. /**
  19. * This create new phrasebook from phrases map, and optional object
  20. * for phrases in object notation.
  21. *
  22. * @param {Map} phrases - This contain phrases in flat notation.
  23. * @param {?object} objects - This contain phrases in object notation.
  24. */
  25. constructor(phrases, objects = null) {
  26. if (!(phrases instanceof Map)) {
  27. throw new TypeError("Phrases must an map.");
  28. }
  29. if (objects !== null && typeof(objects) !== "object") {
  30. throw new TypeError("Objects must be null or object.");
  31. }
  32. this.#phrases = phrases;
  33. this.#objects = objects;
  34. }
  35. /**
  36. * This translate given phrase. When phrase is in the nested object
  37. * notation, then try to find phrase in objects. When not, try to find
  38. * phrase in the flat phrases. When could not find phrase, then return
  39. * not translated phrase. Content always is returned as translation
  40. * object, which could be also formated wich numbers, dates and
  41. * much more.
  42. *
  43. * @param {string} phrase - Phrase to translate.
  44. * @returns {translation} - Translated phrase.
  45. */
  46. translate(phrase) {
  47. if (typeof(phrase) !== "string") {
  48. throw new TypeError("Phrase to translate must be an string.");
  49. }
  50. if (this.#is_nested(phrase)) {
  51. return this.#translate_nested(phrase);
  52. }
  53. return this.#translate_flat(phrase);
  54. }
  55. /**
  56. * This translate given phrase. When phrase is in the nested object
  57. * notation, then try to find phrase in objects. When not, try to find
  58. * phrase in the flat phrases. When could not find phrase, then return
  59. * not translated phrase. Content always is returned as translation
  60. * object, which could be also formated wich numbers, dates and
  61. * much more.
  62. *
  63. * @param {string} phrase - Phrase to translate.
  64. * @returns {translation} - Translated phrase.
  65. */
  66. get(phrase) {
  67. return this.translate(phrase);
  68. }
  69. /**
  70. * Check that phrase is nested or not.
  71. *
  72. * @param {string} phrase - Phrase to check that is nested
  73. * @returns {bool} - True when nested, false when not
  74. */
  75. #is_nested(phrase) {
  76. return phrase.indexOf(".") !== -1;
  77. }
  78. /**
  79. * This translate object notated phrase.
  80. *
  81. * @param {string} phrase - Phrase to translate.
  82. * @returns {translation} - Translated phrase.
  83. */
  84. #translate_nested(phrase) {
  85. if (this.#objects === null) {
  86. return this.#translate_flat(phrase);
  87. }
  88. const parts = phrase.trim().split(".");
  89. let current = this.#objects;
  90. for (const count in parts) {
  91. const part = parts[count];
  92. if (!(part in current)) {
  93. return new translation(phrase, false);
  94. }
  95. current = current[part];
  96. }
  97. if (typeof(current) !== "string") {
  98. return new translation(phrase, false);
  99. }
  100. return new translation(current, true);
  101. }
  102. /**
  103. * This set phrasebook as default. That mean, it would add own translate
  104. * function to global scope, and create _({string}) function in the global
  105. * scope. It is useable to minify code with translations. It is not
  106. * avairable in the NodeJS, only in the browser.
  107. *
  108. * @returns {phrasebook} - Object itself to chain loading.
  109. */
  110. set_as_default() {
  111. NODE: throw new Error("Could not create global function in NodeJS.");
  112. const translate = (content) => {
  113. return this.translate(content);
  114. };
  115. window._ = translate;
  116. window.translate = translate;
  117. }
  118. /**
  119. * This translate flat phrase.
  120. *
  121. * @param {string} phrase - Phrase to translate.
  122. * @returns {translation} - Translated phrase.
  123. */
  124. #translate_flat(phrase) {
  125. const prepared = phrasebook.prepare(phrase);
  126. const found = this.#phrases.has(prepared);
  127. const translated = found ? this.#phrases.get(prepared) : phrase;
  128. return new translation(translated, found);
  129. }
  130. /**
  131. * This prepars phrase, that mean replece all spaces with "_", trim
  132. * and also replace all big letters with lowwer.
  133. *
  134. * @param {string} content - Phrase to preapre.
  135. * @return {string} - Prepared phrase.
  136. */
  137. static prepare(content) {
  138. if (typeof(content) !== "string") {
  139. throw new TypeError("Content to prepare must be an string.");
  140. }
  141. return content
  142. .trim()
  143. .replaceAll(" ", "_")
  144. .replaceAll(".", "_")
  145. .toLowerCase();
  146. }
  147. }
  148. exports.phrasebook = phrasebook;