I18n.js 9.1 KB

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