preferences.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. const languages = require("./languages.js").languages;
  2. const phrasebook = require("./phrasebook.js").phrasebook;
  3. const selector = require("./selector.js").selector;
  4. const autotranslate = require("./autotranslate.js").autotranslate;
  5. /**
  6. * This class is responsible for saving and loading user language preferences
  7. * in the browser localStorage. It is not avairable, when using library in
  8. * the NodeJS enviroment.
  9. */
  10. class preferences {
  11. /**
  12. * @var {languages}
  13. * This store loaded languages object.
  14. */
  15. #languages;
  16. /**
  17. * @var {?selector}
  18. * This store selector for preferences.
  19. */
  20. #selector;
  21. /**
  22. * @var {?autotranslate}
  23. * This store autotranslator, or null.
  24. */
  25. #autotranslate;
  26. /**
  27. * This create new language preferences manager from loaded languages
  28. * object.
  29. *
  30. * @throws {Error} - When trying to use it in NodeJS.
  31. *
  32. * @param {languages} target - loaded languages object.
  33. */
  34. constructor(target) {
  35. NODE: throw new Error("It could be used only in browser.");
  36. this.#selector = null;
  37. this.#autotranslate = null;
  38. this.#languages = target;
  39. }
  40. /**
  41. * This return name of language key in localStorage.
  42. *
  43. * @returns {string} - Name of key in localStorage.
  44. */
  45. get #setting_name() {
  46. return "cx_libtranslate_lang";
  47. }
  48. /**
  49. * This return current saved language name, or null if any language
  50. * is not selected yet.
  51. *
  52. * @returns {?string} - Saved language or null.
  53. */
  54. get #state() {
  55. return localStorage.getItem(this.#setting_name);
  56. }
  57. /**
  58. * This return selector, which could being used in the ui.
  59. *
  60. * @returns {selector} - New UI selector of the languages.
  61. */
  62. get selector() {
  63. if (this.#selector !== null) {
  64. return this.#selector;
  65. }
  66. this.#selector = new selector(this.#languages)
  67. .set_selection(this.current)
  68. .add_listener(target => {
  69. this.update(target);
  70. })
  71. .add_listener(async target => {
  72. if (this.#autotranslate === null) {
  73. return;
  74. }
  75. this.#reload_autotranslate();
  76. });
  77. return this.#selector;
  78. }
  79. async #reload_autotranslate() {
  80. const connected = this.#autotranslate.is_connected;
  81. if (connected) {
  82. this.#autotranslate.disconnect();
  83. }
  84. this.#autotranslate = null;
  85. const created = await this.get_autotranslate();
  86. if (connected) {
  87. created.connect();
  88. }
  89. }
  90. /**
  91. * This load phrasebook for selected language, create autotranslate
  92. * for it, and returns it. Autotranslate is cached in this object.
  93. *
  94. * @returns {autotranslate} - Autotranslate for phrasebook.
  95. */
  96. async get_autotranslate() {
  97. if (this.#autotranslate !== null) {
  98. return this.#autotranslate;
  99. }
  100. const phrasebook = await this.load_choosen_phrasebook();
  101. this.#autotranslate = new autotranslate(phrasebook);
  102. this.#autotranslate.update();
  103. return this.#autotranslate;
  104. }
  105. /**
  106. * This save new selected language name to localStorage, or remove it
  107. * from there if null given.
  108. *
  109. * @param {?string} content - Name of selected language or null.
  110. */
  111. set #state(content) {
  112. if (content === null) {
  113. localStorage.removeItem(this.#setting_name);
  114. return;
  115. }
  116. localStorage.setItem(this.#setting_name, content);
  117. }
  118. /**
  119. * This return current language from localStorage. When any language is
  120. * not loaded yet, then return default language. It also check that value
  121. * value from localStorage, and if it not avairable in languages storage,
  122. * then also return default language.
  123. *
  124. * @return {string} - Name of the current language.
  125. */
  126. get current() {
  127. const saved = this.#state;
  128. if (saved === null) {
  129. return this.#languages.default;
  130. }
  131. if (this.#languages.has(saved)) {
  132. return saved;
  133. }
  134. return this.#languages.default;
  135. }
  136. /**
  137. * This load phrasebook for current selected language.
  138. *
  139. * @returns {phrasebook} - Phrasebook for current language.
  140. */
  141. async load_choosen_phrasebook() {
  142. return await this.#languages.select(this.current);
  143. }
  144. /**
  145. * This return loaded languages container.
  146. *
  147. * @returns {languages} - Languages container.
  148. */
  149. get languages() {
  150. return this.#languages;
  151. }
  152. /**
  153. * This set new language for user. It also check that language exists
  154. * in the language container. When not exists, throws error.
  155. *
  156. * @throws {Error} - When language not exists in container.
  157. *
  158. * @param {string} name - New language to select.
  159. * @returns {preferences} - This object to chain.
  160. */
  161. update(name) {
  162. DEBUG: if (!this.#languages.has(name)) {
  163. let error = "Can not set language \"" + name + "\" ";
  164. error += "because not exists in languages container.";
  165. throw new Error(error);
  166. }
  167. this.#state = name;
  168. return this;
  169. }
  170. }
  171. exports.preferences = preferences;