I18n.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. 'use strict';
  2. var common = require('../common');
  3. describe('I18n', function () {
  4. describe('translate', function () {
  5. this.timeout(30000);
  6. before(function () {
  7. $.PrivateBin.I18n.reset();
  8. });
  9. jsc.property(
  10. 'replaces %s in strings with first given parameter into an element, encoding all, when no link is in the messageID',
  11. 'string',
  12. '(small nearray) string',
  13. 'string',
  14. function (prefix, params, postfix) {
  15. prefix = prefix.replace(/%(s|d)/g, '%%');
  16. params[0] = params[0].replace(/%(s|d)/g, '%%').replace(/<a/g, '');
  17. postfix = postfix.replace(/%(s|d)/g, '%%');
  18. const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
  19. params.unshift(prefix + '%s' + postfix);
  20. let clean = jsdom();
  21. $('body').html('<div id="i18n"></div>');
  22. params.unshift($('#i18n'));
  23. $.PrivateBin.I18n.translate.apply(this, params);
  24. const result = $('#i18n').text();
  25. $.PrivateBin.I18n.reset();
  26. clean();
  27. clean = jsdom();
  28. $('body').html('<div id="i18n"></div>');
  29. params[0] = $('#i18n');
  30. $.PrivateBin.I18n._.apply(this, params);
  31. const alias = $('#i18n').text();
  32. $.PrivateBin.I18n.reset();
  33. clean();
  34. return translation === result && translation === alias;
  35. }
  36. );
  37. jsc.property(
  38. 'replaces %s in strings with first given parameter into an element, encoding params only, when a link is part of the messageID inserted',
  39. 'string',
  40. '(small nearray) string',
  41. 'string',
  42. function (prefix, params, postfix) {
  43. prefix = prefix.replace(/%(s|d)/g, '%%');
  44. params[0] = params[0].replace(/%(s|d)/g, '%%');
  45. postfix = postfix.replace(/%(s|d)/g, '%%');
  46. const translation = $('<div>').html(DOMPurify.sanitize(
  47. prefix + $.PrivateBin.Helper.htmlEntities(params[0]) + '<a></a>' + postfix, {
  48. ALLOWED_TAGS: ['a', 'br', 'i', 'span'],
  49. ALLOWED_ATTR: ['href', 'id']
  50. }
  51. )).html();
  52. let args = Array.prototype.slice.call(params);
  53. args.unshift(prefix + '%s<a></a>' + postfix);
  54. let clean = jsdom();
  55. $('body').html('<div id="i18n"></div>');
  56. args.unshift($('#i18n'));
  57. $.PrivateBin.I18n.translate.apply(this, args);
  58. const result = $('#i18n').html();
  59. $.PrivateBin.I18n.reset();
  60. clean();
  61. clean = jsdom();
  62. $('body').html('<div id="i18n"></div>');
  63. args[0] = $('#i18n');
  64. $.PrivateBin.I18n._.apply(this, args);
  65. const alias = $('#i18n').html();
  66. $.PrivateBin.I18n.reset();
  67. clean();
  68. return translation === result && translation === alias;
  69. }
  70. );
  71. });
  72. describe('translate2string', function () {
  73. this.timeout(30000);
  74. before(function () {
  75. $.PrivateBin.I18n.reset();
  76. });
  77. jsc.property(
  78. 'returns message ID unchanged if no translation found',
  79. 'string',
  80. function (messageId) {
  81. messageId = messageId.replace(/%(s|d)/g, '%%');
  82. let plurals = [messageId, messageId + 's'],
  83. fake = [messageId],
  84. clean = jsdom(),
  85. result = $.PrivateBin.I18n.translate2string(messageId);
  86. $.PrivateBin.I18n.reset();
  87. var pluralResult = $.PrivateBin.I18n.translate2string(plurals);
  88. $.PrivateBin.I18n.reset();
  89. var fakeResult = $.PrivateBin.I18n.translate2string(fake);
  90. $.PrivateBin.I18n.reset();
  91. clean();
  92. messageId = $.PrivateBin.Helper.htmlEntities(messageId);
  93. return messageId === result && messageId === pluralResult && messageId === fakeResult;
  94. }
  95. );
  96. jsc.property(
  97. 'replaces %s in strings with first given parameter, encoding all, when no link is in the messageID',
  98. 'string',
  99. '(small nearray) string',
  100. 'string',
  101. function (prefix, params, postfix) {
  102. prefix = prefix.replace(/%(s|d)/g, '%%');
  103. params[0] = params[0].replace(/%(s|d)/g, '%%').replace(/<a/g, '');
  104. postfix = postfix.replace(/%(s|d)/g, '%%');
  105. const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
  106. params.unshift(prefix + '%s' + postfix);
  107. const result = $.PrivateBin.I18n.translate2string.apply(this, params);
  108. $.PrivateBin.I18n.reset();
  109. return translation === result;
  110. }
  111. );
  112. jsc.property(
  113. 'replaces %s in strings with first given parameter, encoding params only, when a link is part of the messageID',
  114. 'string',
  115. '(small nearray) string',
  116. 'string',
  117. function (prefix, params, postfix) {
  118. prefix = prefix.replace(/%(s|d)/g, '%%');
  119. params[0] = params[0].replace(/%(s|d)/g, '%%');
  120. postfix = postfix.replace(/%(s|d)/g, '%%');
  121. const translation = DOMPurify.sanitize(
  122. prefix + $.PrivateBin.Helper.htmlEntities(params[0]) + '<a></a>' + postfix, {
  123. ALLOWED_TAGS: ['a', 'br', 'i', 'span'],
  124. ALLOWED_ATTR: ['href', 'id']
  125. }
  126. );
  127. params.unshift(prefix + '%s<a></a>' + postfix);
  128. const result = $.PrivateBin.I18n.translate2string.apply(this, params);
  129. $.PrivateBin.I18n.reset();
  130. return translation === result;
  131. }
  132. );
  133. });
  134. describe('getPluralForm', function () {
  135. before(function () {
  136. $.PrivateBin.I18n.reset();
  137. });
  138. jsc.property(
  139. 'returns valid key for plural form',
  140. common.jscSupportedLanguages(),
  141. 'integer',
  142. function(language, n) {
  143. $.PrivateBin.I18n.reset(language);
  144. var result = $.PrivateBin.I18n.getPluralForm(n);
  145. // arabic seems to have the highest plural count with 6 forms
  146. return result >= 0 && result <= 5;
  147. }
  148. );
  149. });
  150. // loading of JSON via AJAX needs to be tested in the browser, this just mocks it
  151. // TODO: This needs to be tested using a browser.
  152. describe('loadTranslations', function () {
  153. this.timeout(30000);
  154. before(function () {
  155. $.PrivateBin.I18n.reset();
  156. });
  157. jsc.property(
  158. 'downloads and handles any supported language',
  159. common.jscSupportedLanguages(),
  160. function(language) {
  161. // cleanup
  162. var clean = jsdom('', {cookie: ['lang=en']});
  163. $.PrivateBin.I18n.reset('en');
  164. $.PrivateBin.I18n.loadTranslations();
  165. clean();
  166. // mock
  167. clean = jsdom('', {cookie: ['lang=' + language]});
  168. $.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
  169. var result = $.PrivateBin.I18n.translate2string('en');
  170. clean();
  171. return language === result;
  172. }
  173. );
  174. jsc.property(
  175. 'should default to en',
  176. function() {
  177. var clean = jsdom('', {url: 'https://privatebin.net/'});
  178. // when navigator.userLanguage is undefined and no default language
  179. // is specified, it would throw an error
  180. [ 'language', 'userLanguage' ].forEach(function (key) {
  181. Object.defineProperty(navigator, key, {
  182. value: undefined,
  183. writeable: false
  184. });
  185. });
  186. $.PrivateBin.I18n.reset('en');
  187. $.PrivateBin.I18n.loadTranslations();
  188. var result = $.PrivateBin.I18n.translate2string('en');
  189. clean();
  190. return 'en' === result;
  191. }
  192. );
  193. });
  194. });