1/*! 2 * jQuery Internationalization library 3 * 4 * Copyright (C) 2012 Santhosh Thottingal 5 * 6 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do 7 * anything special to choose one license or the other and you don't have to 8 * notify anyone which license you are using. You are free to use 9 * UniversalLanguageSelector in commercial projects as long as the copyright 10 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. 11 * 12 * @licence GNU General Public Licence 2.0 or later 13 * @licence MIT License 14 */ 15 16(function ($) { 17 'use strict'; 18 19 var I18N, 20 slice = Array.prototype.slice; 21 /** 22 * @constructor 23 * @param {Object} options 24 */ 25 I18N = function (options) { 26 // Load defaults 27 this.options = $.extend({}, I18N.defaults, options); 28 29 this.parser = this.options.parser; 30 this.locale = this.options.locale; 31 this.messageStore = this.options.messageStore; 32 this.languages = {}; 33 }; 34 35 I18N.prototype = { 36 /** 37 * Localize a given messageKey to a locale. 38 * @param {string} messageKey 39 * @return {string} Localized message 40 */ 41 localize: function (messageKey) { 42 var localeParts, localePartIndex, locale, fallbackIndex, 43 tryingLocale, message; 44 45 locale = this.locale; 46 fallbackIndex = 0; 47 48 while (locale) { 49 // Iterate through locales starting at most-specific until 50 // localization is found. As in fi-Latn-FI, fi-Latn and fi. 51 localeParts = locale.split('-'); 52 localePartIndex = localeParts.length; 53 54 do { 55 tryingLocale = localeParts.slice(0, localePartIndex).join('-'); 56 message = this.messageStore.get(tryingLocale, messageKey); 57 58 if (message) { 59 return message; 60 } 61 62 localePartIndex--; 63 } while (localePartIndex); 64 65 if (locale === this.options.fallbackLocale) { 66 break; 67 } 68 69 locale = ($.i18n.fallbacks[ this.locale ] && 70 $.i18n.fallbacks[ this.locale ][ fallbackIndex ]) || 71 this.options.fallbackLocale; 72 $.i18n.log('Trying fallback locale for ' + this.locale + ': ' + locale + ' (' + messageKey + ')'); 73 74 fallbackIndex++; 75 } 76 77 // key not found 78 return ''; 79 }, 80 81 /* 82 * Destroy the i18n instance. 83 */ 84 destroy: function () { 85 $.removeData(document, 'i18n'); 86 }, 87 88 /** 89 * General message loading API This can take a URL string for 90 * the json formatted messages. Example: 91 * <code>load('path/to/all_localizations.json');</code> 92 * 93 * To load a localization file for a locale: 94 * <code> 95 * load('path/to/de-messages.json', 'de' ); 96 * </code> 97 * 98 * To load a localization file from a directory: 99 * <code> 100 * load('path/to/i18n/directory', 'de' ); 101 * </code> 102 * The above method has the advantage of fallback resolution. 103 * ie, it will automatically load the fallback locales for de. 104 * For most usecases, this is the recommended method. 105 * It is optional to have trailing slash at end. 106 * 107 * A data object containing message key- message translation mappings 108 * can also be passed. Example: 109 * <code> 110 * load( { 'hello' : 'Hello' }, optionalLocale ); 111 * </code> 112 * 113 * A source map containing key-value pair of languagename and locations 114 * can also be passed. Example: 115 * <code> 116 * load( { 117 * bn: 'i18n/bn.json', 118 * he: 'i18n/he.json', 119 * en: 'i18n/en.json' 120 * } ) 121 * </code> 122 * 123 * If the data argument is null/undefined/false, 124 * all cached messages for the i18n instance will get reset. 125 * 126 * @param {string|Object} source 127 * @param {string} locale Language tag 128 * @return {jQuery.Promise} 129 */ 130 load: function (source, locale) { 131 var fallbackLocales, locIndex, fallbackLocale, sourceMap = {}; 132 if (!source && !locale) { 133 source = 'i18n/' + $.i18n().locale + '.json'; 134 locale = $.i18n().locale; 135 } 136 if (typeof source === 'string' && 137 // source extension should be json, but can have query params after that. 138 source.split('?')[ 0 ].split('.').pop() !== 'json' 139 ) { 140 // Load specified locale then check for fallbacks when directory is 141 // specified in load() 142 sourceMap[ locale ] = source + '/' + locale + '.json'; 143 fallbackLocales = ($.i18n.fallbacks[ locale ] || []) 144 .concat(this.options.fallbackLocale); 145 for (locIndex = 0; locIndex < fallbackLocales.length; locIndex++) { 146 fallbackLocale = fallbackLocales[ locIndex ]; 147 sourceMap[ fallbackLocale ] = source + '/' + fallbackLocale + '.json'; 148 } 149 return this.load(sourceMap); 150 } else { 151 return this.messageStore.load(source, locale); 152 } 153 154 }, 155 156 /** 157 * Does parameter and magic word substitution. 158 * 159 * @param {string} key Message key 160 * @param {Array} parameters Message parameters 161 * @return {string} 162 */ 163 parse: function (key, parameters) { 164 var message = this.localize(key); 165 // FIXME: This changes the state of the I18N object, 166 // should probably not change the 'this.parser' but just 167 // pass it to the parser. 168 this.parser.language = $.i18n.languages[ $.i18n().locale ] || $.i18n.languages[ 'default' ]; 169 if (message === '') { 170 message = key; 171 } 172 return this.parser.parse(message, parameters); 173 } 174 }; 175 176 /** 177 * Process a message from the $.I18N instance 178 * for the current document, stored in jQuery.data(document). 179 * 180 * @param {string} key Key of the message. 181 * @param {string} param1 [param...] Variadic list of parameters for {key}. 182 * @return {string|$.I18N} Parsed message, or if no key was given 183 * the instance of $.I18N is returned. 184 */ 185 $.i18n = function (key, param1) { 186 var parameters, 187 i18n = $.data(document, 'i18n'), 188 options = typeof key === 'object' && key; 189 190 // If the locale option for this call is different then the setup so far, 191 // update it automatically. This doesn't just change the context for this 192 // call but for all future call as well. 193 // If there is no i18n setup yet, don't do this. It will be taken care of 194 // by the `new I18N` construction below. 195 // NOTE: It should only change language for this one call.
196 // Then cache instances of I18N somewhere. 197 if (options && options.locale && i18n && i18n.locale !== options.locale) { 198 i18n.locale = options.locale; 199 } 200 201 if (!i18n) { 202 i18n = new I18N(options); 203 $.data(document, 'i18n', i18n); 204 } 205 206 if (typeof key === 'string') { 207 if (param1 !== undefined) { 208 parameters = slice.call(arguments, 1); 209 } else { 210 parameters = []; 211 } 212 213 return i18n.parse(key, parameters); 214 } else { 215 // FIXME: remove this feature/bug. 216 return i18n; 217 } 218 }; 219 220 $.fn.i18n = function () { 221 var i18n = $.data(document, 'i18n'); 222 223 if (!i18n) { 224 i18n = new I18N(); 225 $.data(document, 'i18n', i18n); 226 } 227 228 return this.each(function () { 229 var $this = $(this), 230 messageKey = $this.data('i18n'), 231 lBracket, rBracket, type, key; 232 233 if (messageKey) { 234 lBracket = messageKey.indexOf('['); 235 rBracket = messageKey.indexOf(']'); 236 if (lBracket !== -1 && rBracket !== -1 && lBracket < rBracket) { 237 type = messageKey.slice(lBracket + 1, rBracket); 238 key = messageKey.slice(rBracket + 1); 239 if (type === 'html') { 240 $this.html(i18n.parse(key)); 241 } else { 242 $this.attr(type, i18n.parse(key)); 243 } 244 } else { 245 $this.text(i18n.parse(messageKey)); 246 } 247 } else { 248 $this.find('[data-i18n]').i18n(); 249 } 250 }); 251 }; 252 253 function getDefaultLocale() { 254 var locale = $('html').attr('lang'); 255 if (!locale) { 256 locale = navigator.language || navigator.userLanguage || ''; 257 } 258 return locale; 259 } 260 261 $.i18n.languages = {}; 262 $.i18n.messageStore = $.i18n.messageStore || {}; 263 $.i18n.parser = { 264 // The default parser only handles variable substitution 265 parse: function (message, parameters) { 266 return message.replace(/\$(\d+)/g, function (str, match) { 267 var index = parseInt(match, 10) - 1; 268 return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match; 269 }); 270 }, 271 emitter: {} 272 }; 273 $.i18n.fallbacks = {}; 274 $.i18n.debug = false; 275 $.i18n.log = function ( /* arguments */ ) { 276 if (window.console && $.i18n.debug) { 277 window.console.log.apply(window.console, arguments); 278 } 279 }; 280 /* Static members */ 281 I18N.defaults = { 282 locale: getDefaultLocale(), 283 fallbackLocale: 'en', 284 parser: $.i18n.parser, 285 messageStore: $.i18n.messageStore 286 }; 287 288 // Expose constructor 289 $.i18n.constructor = I18N; 290}(jQuery)); 291 292/*! 293 * jQuery Internationalization library - Message Store 294 * 295 * Copyright (C) 2012 Santhosh Thottingal 296 * 297 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do anything special to 298 * choose one license or the other and you don't have to notify anyone which license you are using. 299 * You are free to use UniversalLanguageSelector in commercial projects as long as the copyright 300 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. 301 * 302 * @licence GNU General Public Licence 2.0 or later 303 * @licence MIT License 304 */ 305 306(function ($) { 307 'use strict'; 308 309 var MessageStore = function () { 310 this.messages = {}; 311 this.sources = {}; 312 }; 313 314 function jsonMessageLoader(url) { 315 var deferred = $.Deferred(); 316 317 $.getJSON(url) 318 .done(deferred.resolve) 319 .fail(function (jqxhr, settings, exception) { 320 $.i18n.log('Error in loading messages from ' + url + ' Exception: ' + exception); 321 // Ignore 404 exception, because we are handling fallabacks explicitly 322 deferred.resolve(); 323 }); 324 325 return deferred.promise(); 326 } 327 328 /** 329 * See https://github.com/wikimedia/jquery.i18n/wiki/Specification#wiki-Message_File_Loading 330 */ 331 MessageStore.prototype = { 332 333 /** 334 * General message loading API This can take a URL string for 335 * the json formatted messages. 336 * <code>load('path/to/all_localizations.json');</code> 337 * 338 * This can also load a localization file for a locale <code> 339 * load( 'path/to/de-messages.json', 'de' ); 340 * </code>
341 * A data object containing message key- message translation mappings 342 * can also be passed Eg: 343 * <code> 344 * load( { 'hello' : 'Hello' }, optionalLocale ); 345 * </code> If the data argument is 346 * null/undefined/false, 347 * all cached messages for the i18n instance will get reset. 348 * 349 * @param {string|Object} source 350 * @param {string} locale Language tag 351 * @return {jQuery.Promise} 352 */ 353 load: function (source, locale) { 354 var key = null, 355 deferreds = [], 356 messageStore = this; 357 358 if (typeof source === 'string') { 359 // This is a URL to the messages file. 360 $.i18n.log('Loading messages from: ' + source); 361 return jsonMessageLoader(source) 362 .then(function (localization) { 363 return messageStore.load(localization, locale); 364 }); 365 } 366 367 if (locale) { 368 // source is an key-value pair of messages for given locale 369 messageStore.set(locale, source); 370 371 return $.Deferred().resolve(); 372 } else { 373 // source is a key-value pair of locales and their source 374 for (key in source) { 375 if (Object.prototype.hasOwnProperty.call(source, key)) { 376 locale = key; 377 // No {locale} given, assume data is a group of languages, 378 // call this function again for each language. 379 deferreds.push(messageStore.load(source[ key ], locale)); 380 } 381 } 382 return $.when.apply($, deferreds); 383 } 384 385 }, 386 387 /** 388 * Set messages to the given locale. 389 * If locale exists, add messages to the locale. 390 * 391 * @param {string} locale 392 * @param {Object} messages 393 */ 394 set: function (locale, messages) { 395 if (!this.messages[ locale ]) { 396 this.messages[ locale ] = messages; 397 } else { 398 this.messages[ locale ] = $.extend(this.messages[ locale ], messages); 399 } 400 }, 401 402 /** 403 * 404 * @param {string} locale 405 * @param {string} messageKey 406 * @return {boolean} 407 */ 408 get: function (locale, messageKey) { 409 return this.messages[ locale ] && this.messages[ locale ][ messageKey ]; 410 } 411 }; 412 413 $.extend($.i18n.messageStore, new MessageStore()); 414}(jQuery)); 415 416/*! 417 * jQuery Internationalization library 418 * 419 * Copyright (C) 2012 Santhosh Thottingal 420 * 421 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do anything special to 422 * choose one license or the other and you don't have to notify anyone which license you are using. 423 * You are free to use UniversalLanguageSelector in commercial projects as long as the copyright 424 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. 425 * 426 * @licence GNU General Public Licence 2.0 or later 427 * @licence MIT License 428 */ 429(function ($) { 430 'use strict'; 431 432 $.i18n = $.i18n || {}; 433 $.extend($.i18n.fallbacks, { 434 ab: ['ru'], 435 ace: ['id'], 436 aln: ['sq'], 437 // Not so standard - als is supposed to be Tosk Albanian, 438 // but in Wikipedia it's used for a Germanic language. 439 als: ['gsw', 'de'], 440 an: ['es'], 441 anp: ['hi'], 442 arn: ['es'], 443 arz: ['ar'], 444 av: ['ru'], 445 ay: ['es'], 446 ba: ['ru'], 447 bar: ['de'], 448 'bat-smg': ['sgs', 'lt'], 449 bcc: ['fa'], 450 'be-x-old': ['be-tarask'], 451 bh: ['bho'], 452 bjn: ['id'], 453 bm: ['fr'], 454 bpy: ['bn'], 455 bqi: ['fa'], 456 bug: ['id'], 457 'cbk-zam': ['es'], 458 ce: ['ru'], 459 crh: ['crh-latn'], 460 'crh-cyrl': ['ru'], 461 csb: ['pl'], 462 cv: ['ru'], 463 'de-at': ['de'], 464 'de-ch': ['de'], 465 'de-formal': ['de'], 466 dsb: ['de'], 467 dtp: ['ms'], 468 egl: ['it'], 469 eml: ['it'], 470 ff: ['fr'], 471 fit: ['fi'], 472 'fiu-vro': ['vro', 'et'], 473 frc: ['fr'], 474 frp: ['fr'], 475 frr: ['de'], 476 fur: ['it'], 477 gag: ['tr'], 478 gan: ['gan-hant', 'zh-hant', 'zh-hans'], 479 'gan-hans': ['zh-hans'], 480 'gan-hant': ['zh-hant', 'zh-hans'], 481 gl: ['pt'], 482 glk: ['fa'], 483 gn: ['es'], 484 gsw: ['de'], 485 hif: ['hif-latn'], 486 hsb: ['de'], 487 ht: ['fr'], 488 ii: ['zh-cn', 'zh-hans'], 489 inh: ['ru'], 490 iu: ['ike-cans'], 491 jut: ['da'], 492 jv: ['id'], 493 kaa: ['kk-latn', 'kk-cyrl'], 494 kbd: ['kbd-cyrl'], 495 khw: ['ur'], 496 kiu: ['tr'], 497 kk: ['kk-cyrl'], 498 'kk-arab': ['kk-cyrl'], 499 'kk-latn': ['kk-cyrl'], 500 'kk-cn': ['kk-arab', 'kk-cyrl'], 501 'kk-kz': ['kk-cyrl'], 502 'kk-tr': ['kk-latn', 'kk-cyrl'], 503 kl: ['da'], 504 'ko-kp': ['ko'], 505 koi: ['ru'], 506 krc: ['ru'], 507 ks: ['ks-arab'], 508 ksh: ['de'], 509 ku: ['ku-latn'], 510 'ku-arab': ['ckb'], 511 kv: ['ru'], 512 lad: ['es'], 513 lb: ['de'], 514 lbe: ['ru'], 515 lez: ['ru'], 516 li: ['nl'], 517 lij: ['it'], 518 liv: ['et'], 519 lmo: ['it'], 520 ln: ['fr'], 521 ltg: ['lv'], 522 lzz: ['tr'], 523 mai: ['hi'], 524 'map-bms': ['jv', 'id'], 525 mg: ['fr'], 526 mhr: ['ru'], 527 min: ['id'], 528 mo: ['ro'], 529 mrj: ['ru'], 530 mwl: ['pt'], 531 myv: ['ru'], 532 mzn: ['fa'], 533 nah: ['es'], 534 nap: ['it'], 535 nds: ['de'], 536 'nds-nl': ['nl'], 537 'nl-informal': ['nl'], 538 no: ['nb'], 539 os: ['ru'], 540 pcd: ['fr'], 541 pdc: ['de'], 542 pdt: ['de'], 543 pfl: ['de'], 544 pms: ['it'], 545 pt: ['pt-br'], 546 'pt-br': ['pt'], 547 qu: ['es'], 548 qug: ['qu', 'es'], 549 rgn: ['it'], 550 rmy: ['ro'], 551 'roa-rup': ['rup'], 552 rue: ['uk', 'ru'], 553 ruq: ['ruq-latn', 'ro'], 554 'ruq-cyrl': ['mk'], 555 'ruq-latn': ['ro'], 556 sa: ['hi'], 557 sah: ['ru'], 558 scn: ['it'], 559 sg: ['fr'], 560 sgs: ['lt'], 561 sli: ['de'], 562 sr: ['sr-ec'], 563 srn: ['nl'], 564 stq: ['de'], 565 su: ['id'], 566 szl: ['pl'], 567 tcy: ['kn'], 568 tg: ['tg-cyrl'],
569 tt: ['tt-cyrl', 'ru'], 570 'tt-cyrl': ['ru'], 571 ty: ['fr'], 572 udm: ['ru'], 573 ug: ['ug-arab'], 574 uk: ['ru'], 575 vec: ['it'], 576 vep: ['et'], 577 vls: ['nl'], 578 vmf: ['de'], 579 vot: ['fi'], 580 vro: ['et'], 581 wa: ['fr'], 582 wo: ['fr'], 583 wuu: ['zh-hans'], 584 xal: ['ru'], 585 xmf: ['ka'], 586 yi: ['he'], 587 za: ['zh-hans'], 588 zea: ['nl'], 589 zh: ['zh-hans'], 590 'zh-classical': ['lzh'], 591 'zh-cn': ['zh-hans'], 592 'zh-hant': ['zh-hans'], 593 'zh-hk': ['zh-hant', 'zh-hans'], 594 'zh-min-nan': ['nan'], 595 'zh-mo': ['zh-hk', 'zh-hant', 'zh-hans'], 596 'zh-my': ['zh-sg', 'zh-hans'], 597 'zh-sg': ['zh-hans'], 598 'zh-tw': ['zh-hant', 'zh-hans'], 599 'zh-yue': ['yue'] 600 }); 601}(jQuery)); 602/*! 603 * jQuery Internationalization library 604 * 605 * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar 606 * 607 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do 608 * anything special to choose one license or the other and you don't have to 609 * notify anyone which license you are using. You are free to use 610 * UniversalLanguageSelector in commercial projects as long as the copyright 611 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. 612 * 613 * @licence GNU General Public Licence 2.0 or later 614 * @licence MIT License 615 */ 616 617(function ($) { 618 'use strict'; 619 620 var MessageParser = function (options) { 621 this.options = $.extend({}, $.i18n.parser.defaults, options); 622 this.language = $.i18n.languages[ String.locale ] || $.i18n.languages[ 'default' ]; 623 this.emitter = $.i18n.parser.emitter; 624 }; 625 626 MessageParser.prototype = { 627 628 constructor: MessageParser, 629 630 simpleParse: function (message, parameters) { 631 return message.replace(/\$(\d+)/g, function (str, match) { 632 var index = parseInt(match, 10) - 1; 633 634 return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match; 635 }); 636 }, 637 638 parse: function (message, replacements) { 639 if (message.indexOf('{{') < 0) { 640 return this.simpleParse(message, replacements); 641 } 642 643 this.emitter.language = $.i18n.languages[ $.i18n().locale ] || 644 $.i18n.languages[ 'default' ]; 645 646 return this.emitter.emit(this.ast(message), replacements); 647 }, 648 649 ast: function (message) { 650 var pipe, colon, backslash, anyCharacter, dollar, digits, regularLiteral, 651 regularLiteralWithoutBar, regularLiteralWithoutSpace, escapedOrLiteralWithoutBar, 652 escapedOrRegularLiteral, templateContents, templateName, openTemplate, 653 closeTemplate, expression, paramExpression, result, 654 pos = 0; 655 656 // Try parsers until one works, if none work return null 657 function choice(parserSyntax) { 658 return function () { 659 var i, result; 660 661 for (i = 0; i < parserSyntax.length; i++) { 662 result = parserSyntax[ i ](); 663 664 if (result !== null) { 665 return result; 666 } 667 } 668 669 return null; 670 }; 671 } 672 673 // Try several parserSyntax-es in a row. 674 // All must succeed; otherwise, return null. 675 // This is the only eager one. 676 function sequence(parserSyntax) { 677 var i, res, 678 originalPos = pos, 679 result = []; 680 681 for (i = 0; i < parserSyntax.length; i++) { 682 res = parserSyntax[ i ](); 683 684 if (res === null) { 685 pos = originalPos; 686 687 return null; 688 } 689 690 result.push(res); 691 } 692 693 return result; 694 } 695 696 // Run the same parser over and over until it fails. 697 // Must succeed a minimum of n times; otherwise, return null. 698 function nOrMore(n, p) { 699 return function () { 700 var originalPos = pos, 701 result = [], 702 parsed = p(); 703 704 while (parsed !== null) { 705 result.push(parsed); 706 parsed = p(); 707 } 708 709 if (result.length < n) { 710 pos = originalPos; 711 712 return null; 713 } 714 715 return result; 716 }; 717 } 718 719 // Helpers -- just make parserSyntax out of simpler JS builtin types 720 721 function makeStringParser(s) { 722 var len = s.length; 723 724 return function () { 725 var result = null; 726 727 if (message.slice(pos, pos + len) === s) { 728 result = s; 729 pos += len; 730 } 731 732 return result; 733 }; 734 } 735 736 function makeRegexParser(regex) { 737 return function () { 738 var matches = message.slice(pos).match(regex); 739 740 if (matches === null) { 741 return null; 742 } 743 744 pos += matches[ 0 ].length; 745 746 return matches[ 0 ]; 747 }; 748 } 749 750 pipe = makeStringParser('|'); 751 colon = makeStringParser(':'); 752 backslash = makeStringParser('\\'); 753 anyCharacter = makeRegexParser(/^./); 754 dollar = makeStringParser('$'); 755 digits = makeRegexParser(/^\d+/); 756 regularLiteral = makeRegexParser(/^[^{}[\]$\\]/); 757 regularLiteralWithoutBar = makeRegexParser(/^[^{}[\]$\\|]/); 758 regularLiteralWithoutSpace = makeRegexParser(/^[^{}[\]$\s]/); 759 760 // There is a general pattern: 761 // parse a thing; 762 // if it worked, apply transform, 763 // otherwise return null. 764 // But using this as a combinator seems to cause problems
765 // when combined with nOrMore(). 766 // May be some scoping issue. 767 function transform(p, fn) { 768 return function () { 769 var result = p(); 770 771 return result === null ? null : fn(result); 772 }; 773 } 774 775 // Used to define "literals" within template parameters. The pipe 776 // character is the parameter delimeter, so by default 777 // it is not a literal in the parameter 778 function literalWithoutBar() { 779 var result = nOrMore(1, escapedOrLiteralWithoutBar)(); 780 781 return result === null ? null : result.join(''); 782 } 783 784 function literal() { 785 var result = nOrMore(1, escapedOrRegularLiteral)(); 786 787 return result === null ? null : result.join(''); 788 } 789 790 function escapedLiteral() { 791 var result = sequence([backslash, anyCharacter]); 792 793 return result === null ? null : result[ 1 ]; 794 } 795 796 choice([escapedLiteral, regularLiteralWithoutSpace]); 797 escapedOrLiteralWithoutBar = choice([escapedLiteral, regularLiteralWithoutBar]); 798 escapedOrRegularLiteral = choice([escapedLiteral, regularLiteral]); 799 800 function replacement() { 801 var result = sequence([dollar, digits]); 802 803 if (result === null) { 804 return null; 805 } 806 807 return ['REPLACE', parseInt(result[ 1 ], 10) - 1]; 808 } 809 810 templateName = transform( 811 // see $wgLegalTitleChars 812 // not allowing : due to the need to catch "PLURAL:$1" 813 makeRegexParser(/^[ !"$&'()*,./0-9;=?@A-Z^_`a-z~\x80-\xFF+-]+/), 814 function (result) { 815 return result.toString(); 816 } 817 ); 818 819 function templateParam() { 820 var expr, 821 result = sequence([pipe, nOrMore(0, paramExpression)]); 822 823 if (result === null) { 824 return null; 825 } 826 827 expr = result[ 1 ]; 828 829 // use a "CONCAT" operator if there are multiple nodes, 830 // otherwise return the first node, raw. 831 return expr.length > 1 ? ['CONCAT'].concat(expr) : expr[ 0 ]; 832 } 833 834 function templateWithReplacement() { 835 var result = sequence([templateName, colon, replacement]); 836 837 return result === null ? null : [result[ 0 ], result[ 2 ]]; 838 } 839 840 function templateWithOutReplacement() { 841 var result = sequence([templateName, colon, paramExpression]); 842 843 return result === null ? null : [result[ 0 ], result[ 2 ]]; 844 } 845 846 templateContents = choice([ 847 function () { 848 var res = sequence([ 849 // templates can have placeholders for dynamic 850 // replacement eg: {{PLURAL:$1|one car|$1 cars}} 851 // or no placeholders eg: 852 // {{GRAMMAR:genitive|{{SITENAME}}} 853 choice([templateWithReplacement, templateWithOutReplacement]), 854 nOrMore(0, templateParam) 855 ]); 856 857 return res === null ? null : res[ 0 ].concat(res[ 1 ]); 858 }, 859 function () { 860 var res = sequence([templateName, nOrMore(0, templateParam)]); 861 862 if (res === null) { 863 return null; 864 } 865 866 return [res[ 0 ]].concat(res[ 1 ]); 867 } 868 ]); 869 870 openTemplate = makeStringParser('{{'); 871 closeTemplate = makeStringParser('}}'); 872 873 function template() { 874 var result = sequence([openTemplate, templateContents, closeTemplate]); 875 876 return result === null ? null : result[ 1 ]; 877 } 878 879 expression = choice([template, replacement, literal]); 880 paramExpression = choice([template, replacement, literalWithoutBar]); 881 882 function start() { 883 var result = nOrMore(0, expression)(); 884 885 if (result === null) { 886 return null; 887 } 888 889 return ['CONCAT'].concat(result); 890 } 891 892 result = start(); 893 894 /* 895 * For success, the pos must have gotten to the end of the input 896 * and returned a non-null.
897 * n.b. This is part of language infrastructure, so we do not throw an 898 * internationalizable message. 899 */ 900 if (result === null || pos !== message.length) { 901 throw new Error('Parse error at position ' + pos.toString() + ' in input: ' + message); 902 } 903 904 return result; 905 } 906 907 }; 908 909 $.extend($.i18n.parser, new MessageParser()); 910}(jQuery)); 911 912/*! 913 * jQuery Internationalization library 914 * 915 * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar 916 * 917 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do 918 * anything special to choose one license or the other and you don't have to 919 * notify anyone which license you are using. You are free to use 920 * UniversalLanguageSelector in commercial projects as long as the copyright 921 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. 922 * 923 * @licence GNU General Public Licence 2.0 or later 924 * @licence MIT License 925 */ 926 927(function ($) { 928 'use strict'; 929 930 var MessageParserEmitter = function () { 931 this.language = $.i18n.languages[ String.locale ] || $.i18n.languages[ 'default' ]; 932 }; 933 934 MessageParserEmitter.prototype = { 935 constructor: MessageParserEmitter, 936 937 /** 938 * (We put this method definition here, and not in prototype, to make 939 * sure it's not overwritten by any magic.) Walk entire node structure, 940 * applying replacements and template functions when appropriate 941 * 942 * @param {Mixed} node abstract syntax tree (top node or subnode) 943 * @param {Array} replacements for $1, $2, ... $n 944 * @return {Mixed} single-string node or array of nodes suitable for 945 * jQuery appending. 946 */ 947 emit: function (node, replacements) { 948 var ret, subnodes, operation, 949 messageParserEmitter = this; 950 951 switch (typeof node) { 952 case 'string': 953 case 'number': 954 ret = node; 955 break; 956 case 'object': 957 // node is an array of nodes 958 subnodes = $.map(node.slice(1), function (n) { 959 return messageParserEmitter.emit(n, replacements); 960 }); 961 962 operation = node[ 0 ].toLowerCase(); 963 964 if (typeof messageParserEmitter[ operation ] === 'function') { 965 ret = messageParserEmitter[ operation ](subnodes, replacements); 966 } else { 967 throw new Error('unknown operation "' + operation + '"'); 968 } 969 970 break; 971 case 'undefined': 972 // Parsing the empty string (as an entire expression, or as a 973 // paramExpression in a template) results in undefined 974 // Perhaps a more clever parser can detect this, and return the 975 // empty string? Or is that useful information? 976 // The logical thing is probably to return the empty string here 977 // when we encounter undefined. 978 ret = ''; 979 break; 980 default: 981 throw new Error('unexpected type in AST: ' + typeof node); 982 } 983 984 return ret; 985 }, 986 987 /** 988 * Parsing has been applied depth-first we can assume that all nodes 989 * here are single nodes Must return a single node to parents -- a 990 * jQuery with synthetic span However, unwrap any other synthetic spans 991 * in our children and pass them upwards 992 * 993 * @param {Array} nodes Mixed, some single nodes, some arrays of nodes. 994 * @return {string} 995 */ 996 concat: function (nodes) { 997 var result = ''; 998 999 $.each(nodes, function (i, node) { 1000 // strings, integers, anything else 1001 result += node;
1002 }); 1003 1004 return result; 1005 }, 1006 1007 /** 1008 * Return escaped replacement of correct index, or string if 1009 * unavailable. Note that we expect the parsed parameter to be 1010 * zero-based. i.e. $1 should have become [ 0 ]. if the specified 1011 * parameter is not found return the same string (e.g. "$99" -> 1012 * parameter 98 -> not found -> return "$99" ) TODO throw error if 1013 * nodes.length > 1 ? 1014 * 1015 * @param {Array} nodes One element, integer, n >= 0 1016 * @param {Array} replacements for $1, $2, ... $n 1017 * @return {string} replacement 1018 */ 1019 replace: function (nodes, replacements) { 1020 var index = parseInt(nodes[ 0 ], 10); 1021 1022 if (index < replacements.length) { 1023 // replacement is not a string, don't touch! 1024 return replacements[ index ]; 1025 } else { 1026 // index not found, fallback to displaying variable 1027 return '$' + (index + 1); 1028 } 1029 }, 1030 1031 /** 1032 * Transform parsed structure into pluralization n.b. The first node may 1033 * be a non-integer (for instance, a string representing an Arabic 1034 * number). So convert it back with the current language's 1035 * convertNumber. 1036 * 1037 * @param {Array} nodes List [ {String|Number}, {String}, {String} ... ] 1038 * @return {string} selected pluralized form according to current 1039 * language. 1040 */ 1041 plural: function (nodes) { 1042 var count = parseFloat(this.language.convertNumber(nodes[ 0 ], 10)), 1043 forms = nodes.slice(1); 1044 1045 return forms.length ? this.language.convertPlural(count, forms) : ''; 1046 }, 1047 1048 /** 1049 * Transform parsed structure into gender Usage 1050 * {{gender:gender|masculine|feminine|neutral}}. 1051 * 1052 * @param {Array} nodes List [ {String}, {String}, {String} , {String} ] 1053 * @return {string} selected gender form according to current language 1054 */ 1055 gender: function (nodes) { 1056 var gender = nodes[ 0 ], 1057 forms = nodes.slice(1); 1058 1059 return this.language.gender(gender, forms); 1060 }, 1061 1062 /** 1063 * Transform parsed structure into grammar conversion. Invoked by 1064 * putting {{grammar:form|word}} in a message 1065 * 1066 * @param {Array} nodes List [{Grammar case eg: genitive}, {String word}] 1067 * @return {string} selected grammatical form according to current 1068 * language. 1069 */ 1070 grammar: function (nodes) { 1071 var form = nodes[ 0 ], 1072 word = nodes[ 1 ]; 1073 1074 return word && form && this.language.convertGrammar(word, form); 1075 } 1076 }; 1077 1078 $.extend($.i18n.parser.emitter, new MessageParserEmitter()); 1079}(jQuery)); 1080 1081/*! 1082 * BIDI embedding support for jQuery.i18n 1083 * 1084 * Copyright (C) 2015, David Chan 1085 * 1086 * This code is dual licensed GPLv2 or later and MIT. You don't have to do 1087 * anything special to choose one license or the other and you don't have to 1088 * notify anyone which license you are using. You are free to use this code 1089 * in commercial projects as long as the copyright header is left intact. 1090 * See files GPL-LICENSE and MIT-LICENSE for details. 1091 * 1092 * @licence GNU General Public Licence 2.0 or later 1093 * @licence MIT License 1094 */ 1095 1096(function ($) { 1097 'use strict'; 1098 var strongDirRegExp; 1099 1100 /** 1101 * Matches the first strong directionality codepoint: 1102 * - in group 1 if it is LTR 1103 * - in group 2 if it is RTL 1104 * Does not match if there is no strong directionality codepoint. 1105 * 1106 * Generated by UnicodeJS (see tools/strongDir) from the UCD; see 1107 * https://phabricator.wikimedia.org/diffusion/GUJS/ . 1108 */ 1109 // eslint-disable-next-line no-misleading-character-class 1110 strongDirRegExp = new RegExp( 1111 '(?:' + 1112 '(' + 1113 '[\u0041-\u005a\u0061-\u007a\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u02bb-\u02c1\u02d0\u02d1\u02e0-\u02e4\u02ee\u0370-\u0373\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0482\u048a-\u052f\u0531-\u0556\u0559-\u055f\u0561-\u0587\u0589\u0903-\u0939\u093b\u093d-\u0940\u0949-\u094c\u094e-\u0950\u0958-\u0961\u0964-\u0980\u0982\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c0\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e1\u09e6-\u09f1\u09f4-\u09fa\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a40\u0a59-\u0a5c\u0a5e\u0a66-\u0a6f\u0a72-\u0a74\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0
1113ab9\u0abd-\u0ac0\u0ac9\u0acb\u0acc\u0ad0\u0ae0\u0ae1\u0ae6-\u0af0\u0af9\u0b02\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b3e\u0b40\u0b47\u0b48\u0b4b\u0b4c\u0b57\u0b5c\u0b5d\u0b5f-\u0b61\u0b66-\u0b77\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe\u0bbf\u0bc1\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0be6-\u0bf2\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c41-\u0c44\u0c58-\u0c5a\u0c60\u0c61\u0c66-\u0c6f\u0c7f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca\u0ccb\u0cd5\u0cd6\u0cde\u0ce0\u0ce1\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d40\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d57\u0d5f-\u0d61\u0d66-\u0d75\u0d79-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd1\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e4f-\u0e5b\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0ed0-\u0ed9\u0edc-\u0edf\u0f00-\u0f17\u0f1a-\u0f34\u0f36\u0f38\u0f3e-\u0f47\u0f49-\u0f6c\u0f7f\u0f85\u0f88-\u0f8c\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce-\u0fda\u1000-\u102c\u1031\u1038\u103b\u103c\u103f-\u1057\u105a-\u105d\u1061-\u1070\u1075-\u1081\u1083\u1084\u1087-\u108c\u108e-\u109c\u109e-\u10c5\u10c7\u10cd\u10d0-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1360-\u137c\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u167f\u1681-\u169a\u16a0-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1735\u1736\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17b6\u17be-\u17c5\u17c7\u17c8\u17d4-\u17da\u17dc\u17e0-\u17e9\u1810-\u1819\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1923-\u1926\u1929-\u192b\u1930\u1931\u1933-\u1938\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u1a00-\u1a16\u1a19\u1a1a\u1a1e-\u1a55\u1a57\u1a61\u1a63\u1a64\u1a6d-\u1a72\u1a80-\u1a89\u1a90-\u1a99\u1aa0-\u1aad\u1b04-\u1b33\u1b35\u1b3b\u1b3d-\u1b41\u1b43-\u1b4b\u1b50-\u1b6a\u1b74-\u1b7c\u1b82-\u1ba1\u1ba6\u1ba7\u1baa\u1bae-\u1be5\u1be7\u1bea-\u1bec\u1bee\u1bf2\u1bf3\u1bfc-\u1c2b\u1c34\u1c35\u1c3b-\u1c49\u1c4d-\u1c7f\u1cc0-\u1cc7\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200e\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u214f\u2160-\u2188\u2336-\u237a\u2395\u249c-\u24e9\u26ac\u2800-\u28ff\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d70\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u302e\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u3190-\u31ba\u31f0-\u321c\u3220-\u324f\u3260-\u327b\u327f-\u32b0\u32c0-\u32cb\u32d0-\u32fe\u3300-\u3376\u337b-\u33dd\u33e0-\u33fe\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua60c\ua610-\ua62b\ua640-\ua66e\ua680-\ua69d\ua6a0-\ua6ef\ua6f2-\ua6f7\ua722-\ua787\ua789-\ua7ad\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua824\ua827\ua830-\ua837\ua840-\ua873\ua880-\ua8c3\ua8ce-\ua8d9\ua8f2-\ua8fd\ua900-\ua925\ua92e-\ua946\ua952\ua953\ua95f-\ua97c\ua983-\ua9b2\ua9b4\ua9b5\ua9ba\ua9bb\ua9bd-\ua9cd\ua9cf-\ua9d9\ua9de-\ua9e4\ua9e6-\ua9fe\uaa00-\uaa28\uaa2f\uaa30\uaa33\uaa34\uaa40-\uaa42\uaa44-\uaa4b\uaa4d\uaa50-\uaa59\uaa5c-\uaa7b\uaa7d-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaaeb\uaaee-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab65\uab70-\uabe4\uabe6\uabe7\uabe9-\uabec\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\ue000-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]|\ud800[\udc00-\udc0b]|\ud800[\udc0d-\udc26]|\ud800[\udc28-\udc3a]|\ud800\udc3c|\ud800\udc3d|\ud800[\udc3f-\udc4d]|\ud800[\udc50-\udc5d]|\ud800[\udc80-\udcfa]|\ud800\udd00|\ud800\udd02|\ud800[\udd07-\udd33]|\ud800[\udd37-\udd3f]|\ud800[\uddd0-\uddfc]|\ud800[\ude80-\ude9c]|\ud800[\udea0-\uded0]|\ud800[\udf00-\udf23]|\ud800[\udf30-\udf4a]|\ud800[\udf50-\udf75]|\ud800[\udf80-\udf9d]|\ud800[\udf9f-\udfc3]|\ud800[\udfc8-\udfd5]|\ud801[\udc00-\udc9d]|\ud801[\udca0-\udca9]|\ud801[\udd00-\udd27]|\ud801[\udd30-\udd63]|\ud801\udd6f|\ud801[\ude00-\udf36]|\ud801[\udf40-\udf55]|\ud801[\udf60-\udf67]|\ud804\udc00|\ud804[\udc02-\udc37]|\ud804[\udc47-\udc4d]|\ud804[\udc66-\udc6f]|\ud804[\udc82-\udcb2]|\ud804\udcb7|\ud804\udcb8|\ud804[\udcbb-\udcc1]|\ud804[\udcd0-\udce8]|\ud804[\udcf0-\udcf9]|\ud804[\udd03-\udd26]|\ud804\udd2c|\ud804[\udd36-\udd43]|\ud804[\udd50-\udd72]|\ud804[\udd74-\udd76]|\ud804[\udd82-\uddb5]|\ud804[\uddbf-\uddc9]|\ud804\uddcd|\ud804[\uddd0-\udddf]|\ud804[\udde1-\uddf4]|\ud804[\ude00-\ude11]|\ud804[\ude13-\ude2e]|\ud804\ude32|\ud804\ude33|\ud804\ude35|\ud804[\ude38-\ude3d]|\ud804[\ude80-\ude86]|\ud804\ude88|\ud804[\ude8a-\ude8d]|\ud804[\ude8f-\ude9d]|\ud804[\ude9f-\udea9]|\ud804[\udeb0-\udede]|\ud804[\udee0-\udee2]|\ud804[\udef0-\udef9]|\ud804\udf02|\ud804\udf03|\ud804[\udf05-\udf0c]|\ud804\udf0f|\ud804\udf10|\ud804[\udf13-\udf28]|\ud804[\udf2a-\udf30]|\ud804\udf32|\ud804\udf33|\ud804[\udf35-\udf39]|\ud804[\udf3d-\udf3f]|\ud804[\udf41-\udf44]|\ud804\udf47|\ud804\udf48|\ud804[\udf4b-\udf4d]|\ud804\udf50|\ud804\udf57|\ud804[\udf5d-\udf63]|\ud805[\udc80-\udcb2]|\ud805\udcb9|\ud805[\udcbb-\udcbe]|\ud805\udcc1|\ud805[\udcc4-\udcc7]|\ud805[\udcd0-\udcd9]|\ud805[\udd80-\uddb1]|\ud805[\uddb8-\uddbb]|\ud805\uddbe|\ud805[\uddc1-\udddb]|\ud805[\ude00-\ude32]|\ud805\ude3b|\ud805\ude3c|\ud805\ude3e|\ud805[\ude41-\ude44]|\ud805[\ude50-\ude59]|\ud805[\ude80-\udeaa]|\ud805\udeac|\ud805\udeae|\ud805\udeaf|\ud805\udeb6|\ud805[\udec0-\udec9]|\ud805[\udf00-\udf19]|\ud805\udf20|\ud805\udf21|\ud805\udf26|\ud805[\udf30-\udf3f]|\ud806[\udca0-\udcf2]|\ud806\udcff|\ud806[\udec0-\udef8]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e]|\ud809[\udc70-\udc74]|\ud809[\udc80-\udd43]|\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38]|\ud81a[\ude40-\ude5e]|\ud81a[\ude60-\ude69]|\ud81a\ude6e|\ud81a\ude6f|\ud81a[\uded0-\udeed]|\ud81a\udef5|\ud81a[\udf00-\udf2f]|\ud81a[\udf37-\udf45]|\ud81a[\udf50-\udf59]|\ud81a[\udf5b-\udf61]|\ud81a[\udf63-\udf77]|\ud81a[\udf7d-\udf8f]|\ud81b[\udf00-\udf44]|\ud81b[\udf50-\udf7e]|\ud81b[\udf93-\udf9f]|\ud82c\udc00|\ud82c\udc01|\ud82f[\udc00-\udc6a]|\ud82f[\udc70-\udc7c]|\ud82f[\udc80-\udc88]|\ud82f[\udc90-\udc99]|\ud82f\udc9c|\ud82f\udc9f|\ud834[\udc00-\udcf5]|\ud834[\udd00-\udd26]|\ud834[\udd29-\udd66]|\ud834[\udd6a-\udd72]|\ud834\udd83|\ud834\udd84|\ud834[\udd8c-\udda9]|\ud834[\uddae-\udde8]|\ud834[\udf60-\udf71]|\ud835[\udc00-\udc54]|\ud835[\udc56-\udc9c]|\ud835\udc9e|\ud835\udc9f|\ud835\udca2|\ud835\udca5|\ud835\udca6|\ud835[\udca9-\udcac]|\ud835[\udcae-\udcb9]|\ud835\udcbb|\ud835[\udcbd-\udcc3]|\ud835[\udcc5-\udd05]|\ud835[\udd07-\udd0a]|\ud835[\udd0d-\udd14]|\ud835[\udd16-\udd1c]|\ud835[\udd1e-\udd39]|\ud835[\udd3b-\udd3e]|\ud835[\udd40-\udd44]|\ud835\udd46|\ud835[\udd4a-\udd50
1113]|\ud835[\udd52-\udea5]|\ud835[\udea8-\udeda]|\ud835[\udedc-\udf14]|\ud835[\udf16-\udf4e]|\ud835[\udf50-\udf88]|\ud835[\udf8a-\udfc2]|\ud835[\udfc4-\udfcb]|\ud836[\udc00-\uddff]|\ud836[\ude37-\ude3a]|\ud836[\ude6d-\ude74]|\ud836[\ude76-\ude83]|\ud836[\ude85-\ude8b]|\ud83c[\udd10-\udd2e]|\ud83c[\udd30-\udd69]|\ud83c[\udd70-\udd9a]|\ud83c[\udde6-\ude02]|\ud83c[\ude10-\ude3a]|\ud83c[\ude40-\ude48]|\ud83c\ude50|\ud83c\ude51|[\ud840-\ud868][\udc00-\udfff]|\ud869[\udc00-\uded6]|\ud869[\udf00-\udfff]|[\ud86a-\ud86c][\udc00-\udfff]|\ud86d[\udc00-\udf34]|\ud86d[\udf40-\udfff]|\ud86e[\udc00-\udc1d]|\ud86e[\udc20-\udfff]|[\ud86f-\ud872][\udc00-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]|[\udb80-\udbbe][\udc00-\udfff]|\udbbf[\udc00-\udffd]|[\udbc0-\udbfe][\udc00-\udfff]|\udbff[\udc00-\udffd]' + 1114 ')|(' + 1115 '[\u0590\u05be\u05c0\u05c3\u05c6\u05c8-\u05ff\u07c0-\u07ea\u07f4\u07f5\u07fa-\u0815\u081a\u0824\u0828\u082e-\u0858\u085c-\u089f\u200f\ufb1d\ufb1f-\ufb28\ufb2a-\ufb4f\u0608\u060b\u060d\u061b-\u064a\u066d-\u066f\u0671-\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u0710\u0712-\u072f\u074b-\u07a5\u07b1-\u07bf\u08a0-\u08e2\ufb50-\ufd3d\ufd40-\ufdcf\ufdf0-\ufdfc\ufdfe\ufdff\ufe70-\ufefe]|\ud802[\udc00-\udd1e]|\ud802[\udd20-\ude00]|\ud802\ude04|\ud802[\ude07-\ude0b]|\ud802[\ude10-\ude37]|\ud802[\ude3b-\ude3e]|\ud802[\ude40-\udee4]|\ud802[\udee7-\udf38]|\ud802[\udf40-\udfff]|\ud803[\udc00-\ude5f]|\ud803[\ude7f-\udfff]|\ud83a[\udc00-\udccf]|\ud83a[\udcd7-\udfff]|\ud83b[\udc00-\uddff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\ude00-\udeef]|\ud83b[\udef2-\udeff]' + 1116 ')' + 1117 ')' 1118 ); 1119 1120 /** 1121 * Gets directionality of the first strongly directional codepoint 1122 * 1123 * This is the rule the BIDI algorithm uses to determine the directionality of 1124 * paragraphs ( http://unicode.org/reports/tr9/#The_Paragraph_Level ) and 1125 * FSI isolates ( http://unicode.org/reports/tr9/#Explicit_Directional_Isolates ). 1126 * 1127 * TODO: Does not handle BIDI control characters inside the text. 1128 * TODO: Does not handle unallocated characters. 1129 * 1130 * @param {string} text The text from which to extract initial directionality. 1131 * @return {string} Directionality (either 'ltr' or 'rtl') 1132 */ 1133 function strongDirFromContent(text) { 1134 var m = text.match(strongDirRegExp); 1135 if (!m) { 1136 return null; 1137 } 1138 if (m[ 2 ] === undefined) { 1139 return 'ltr'; 1140 } 1141 return 'rtl'; 1142 } 1143 1144 $.extend($.i18n.parser.emitter, { 1145 /** 1146 * Wraps argument with unicode control characters for directionality safety 1147 * 1148 * This solves the problem where directionality-neutral characters at the edge of 1149 * the argument string get interpreted with the wrong directionality from the 1150 * enclosing context, giving renderings that look corrupted like "(Ben_(WMF". 1151 * 1152 * The wrapping is LRE...PDF or RLE...PDF, depending on the detected 1153 * directionality of the argument string, using the BIDI algorithm's own "First 1154 * strong directional codepoint" rule. Essentially, this works round the fact that 1155 * there is no embedding equivalent of U+2068 FSI (isolation with heuristic 1156 * direction inference). The latter is cleaner but still not widely supported. 1157 * 1158 * @param {string[]} nodes The text nodes from which to take the first item. 1159 * @return {string} Wrapped String of content as needed. 1160 */ 1161 bidi: function (nodes) { 1162 var dir = strongDirFromContent(nodes[ 0 ]); 1163 if (dir === 'ltr') { 1164 // Wrap in LEFT-TO-RIGHT EMBEDDING ... POP DIRECTIONAL FORMATTING 1165 return '\u202A' + nodes[ 0 ] + '\u202C'; 1166 } 1167 if (dir === 'rtl') { 1168 // Wrap in RIGHT-TO-LEFT EMBEDDING ... POP DIRECTIONAL FORMATTING 1169 return '\u202B' + nodes[ 0 ] + '\u202C'; 1170 } 1171 // No strong directionality: do not wrap 1172 return nodes[ 0 ]; 1173 } 1174 }); 1175}(jQuery)); 1176 1177 1178 1179function _(str) 1180{ 1181 var args = Array.prototype.slice.call(arguments); 1182 var tr = $.i18n().messageStore.get($.i18n().locale, str); 1183 if (args.length > 1) 1184 { 1185 var args = [].slice.call(args); 1186 args.shift(); 1187 if (!tr) 1188 { 1189 return $.i18n.parser.parse(str, args); 1190 } 1191 else 1192 { 1193 return $.i18n.parser.parse(tr, args); 1194 } 1195 } else 1196 { 1197 if (!tr) 1198 { 1199 return str; 1200 } 1201 else 1202 { 1203 return tr; 1204 } 1205 } 1206 1207}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.