1/** 2 * CLDR JavaScript Library v0.5.4 3 * http://jquery.com/ 4 * 5 * Copyright 2013 Rafael Xavier de Souza 6 * Released under the MIT license 7 * http://jquery.org/license 8 * 9 * Date: 2020-10-22T15:56Z 10 */ 11/*! 12 * CLDR JavaScript Library v0.5.4 2020-10-22T15:56Z MIT license © Rafael Xavier 13 * http://git.io/h4lmVg 14 */ 15(function( root, factory ) { 16 17 if ( typeof define === "function" && define.amd ) { 18 // AMD. 19 define( factory ); 20 } else if ( typeof module === "object" && typeof module.exports === "object" ) { 21 // Node. CommonJS. 22 module.exports = factory(); 23 } else { 24 // Global 25 root.Cldr = factory(); 26 } 27 28}( this, function() { 29 30 31 var arrayIsArray = Array.isArray || function( obj ) { 32 return Object.prototype.toString.call( obj ) === "[object Array]"; 33 }; 34 35 36 37 38 var pathNormalize = function( path, attributes ) { 39 if ( arrayIsArray( path ) ) { 40 path = path.join( "/" ); 41 } 42 if ( typeof path !== "string" ) { 43 throw new Error( "invalid path \"" + path + "\"" ); 44 } 45 // 1: Ignore leading slash `/` 46 // 2: Ignore leading `cldr/` 47 path = path 48 .replace( /^\// , "" ) /* 1 */ 49 .replace( /^cldr\// , "" ); /* 2 */ 50 51 // Replace {attribute}'s 52 path = path.replace( /{[a-zA-Z]+}/g, function( name ) { 53 name = name.replace( /^{([^}]*)}$/, "$1" ); 54 return attributes[ name ]; 55 }); 56 57 return path.split( "/" ); 58 }; 59 60 61 62 63 var arraySome = function( array, callback ) { 64 var i, length; 65 if ( array.some ) { 66 return array.some( callback ); 67 } 68 for ( i = 0, length = array.length; i < length; i++ ) { 69 if ( callback( array[ i ], i, array ) ) { 70 return true; 71 } 72 } 73 return false; 74 }; 75 76 77 78 79 /** 80 * Return the maximized language id as defined in 81 * http://www.unicode.org/reports/tr35/#Likely_Subtags 82 * 1. Canonicalize. 83 * 1.1 Make sure the input locale is in canonical form: uses the right 84 * separator, and has the right casing. 85 * TODO Right casing? What df? It seems languages are lowercase, scripts are 86 * Capitalized, territory is uppercase. I am leaving this as an exercise to 87 * the user. 88 * 89 * 1.2 Replace any deprecated subtags with their canonical values using the 90 * <alias> data in supplemental metadata. Use the first value in the 91 * replacement list, if it exists. Language tag replacements may have multiple 92 * parts, such as "sh" â "sr_Latn" or mo" â "ro_MD". In such a case, the 93 * original script and/or region are retained if there is one. Thus 94 * "sh_Arab_AQ" â "sr_Arab_AQ", not "sr_Latn_AQ". 95 * TODO What <alias> data? 96 * 97 * 1.3 If the tag is grandfathered (see <variable id="$grandfathered" 98 * type="choice"> in the supplemental data), then return it. 99 * TODO grandfathered? 100 * 101 * 1.4 Remove the script code 'Zzzz' and the region code 'ZZ' if they occur. 102 * 1.5 Get the components of the cleaned-up source tag (languages, scripts, 103 * and regions), plus any variants and extensions. 104 * 2. Lookup. Lookup each of the following in order, and stop on the first 105 * match: 106 * 2.1 languages_scripts_regions 107 * 2.2 languages_regions 108 * 2.3 languages_scripts 109 * 2.4 languages 110 * 2.5 und_scripts 111 * 3. Return 112 * 3.1 If there is no match, either return an error value, or the match for 113 * "und" (in APIs where a valid language tag is required). 114 * 3.2 Otherwise there is a match = languagem_scriptm_regionm 115 * 3.3 Let xr = xs if xs is not empty, and xm otherwise. 116 * 3.4 Return the language tag composed of languager _ scriptr _ regionr + 117 * variants + extensions. 118 * 119 * @subtags [Array] normalized language id subtags tuple (see init.js). 120 */ 121 var coreLikelySubtags = function( Cldr, cldr, subtags, options ) { 122 var match, matchFound, 123 language = subtags[ 0 ], 124 script = subtags[ 1 ], 125 sep = Cldr.localeSep, 126 territory = subtags[ 2 ], 127 variants = subtags.slice( 3, 4 ); 128 options = options || {}; 129 130 // Skip if (language, script, territory) is not empty [3.3] 131 if ( language !== "und" && script !== "Zzzz" && territory !== "ZZ" ) { 132 return [ language, script, territory ].concat( variants ); 133 } 134 135 // Skip if no supplemental likelySubtags data is present 136 if ( typeof cldr.get( "supplemental/likelySubtags" ) === "undefined" ) { 137 return; 138 } 139 140 // [2] 141 matchFound = arraySome([ 142 [ language, script, territory ], 143 [ language, territory ], 144 [ language, script ], 145 [ language ], 146 [ "und", script ] 147 ], function( test ) { 148 return match = !(/\b(Zzzz|ZZ)\b/).test( test.join( sep ) ) /* [1.4] */ && cldr.get( [ "supplemental/likelySubtags", test.join( sep ) ] ); 149 }); 150 151 // [3] 152 if ( matchFound ) { 153 // [3.2 .. 3.4] 154 match = match.split( sep ); 155 return [ 156 language !== "und" ? language : match[ 0 ], 157 script !== "Zzzz" ? script : match[ 1 ], 158 territory !== "ZZ" ? territory : match[ 2 ] 159 ].concat( variants ); 160 } else if ( options.force ) { 161 // [3.1.2] 162 return cldr.get( "supplemental/likelySubtags/und" ).split( sep ); 163 } else { 164 // [3.1.1] 165 return; 166 } 167 }; 168 169 170 171 /** 172 * Given a locale, remove any fields that Add Likely Subtags would add. 173 * http://www.unicode.org/reports/tr35/#Likely_Subtags 174 * 1. First get max = AddLikelySubtags(inputLocale). If an error is signaled, 175 * return it. 176 * 2. Remove the variants from max. 177 * 3. Then for trial in {language, language _ region, language _ script}. If 178 * AddLikelySubtags(trial) = max, then return trial + variants. 179 * 4. If you do not get a match, return max + variants. 180 * 181 * @maxLanguageId [Array] maxLanguageId tuple (see init.js). 182 */ 183 var coreRemoveLikelySubtags = function( Cldr, cldr, maxLanguageId ) { 184 var match, matchFound, 185 language = maxLanguageId[ 0 ], 186 script = maxLanguageId[ 1 ], 187 territory = maxLanguageId[ 2 ], 188 variants = maxLanguageId[ 3 ]; 189 190 // [3] 191 matchFound = arraySome([ 192 [ [ language, "Zzzz", "ZZ" ], [ language ] ], 193 [ [ language, "Zzzz", territory ], [ language, territory ] ], 194 [ [ language, script, "ZZ" ], [ language, script ] ] 195 ], function( test ) { 196 var result = coreLikelySubtags( Cldr, cldr, test[ 0 ] ); 197 match = test[ 1 ]; 198 return result && result[ 0 ] === maxLanguageId[ 0 ] && 199 result[ 1 ] === maxLanguageId[ 1 ] && 200 result[ 2 ] === maxLanguageId[ 2 ]; 201 }); 202 203 if ( matchFound ) { 204 if ( variants ) { 205 match.push( variants ); 206 } 207 return match; 208 } 209 210 // [4] 211 return maxLanguageId; 212 }; 213 214 215 216
217 /** 218 * subtags( locale ) 219 * 220 * @locale [String] 221 */ 222 var coreSubtags = function( locale ) { 223 var aux, unicodeLanguageId, 224 subtags = []; 225 226 locale = locale.replace( /_/, "-" ); 227 228 // Unicode locale extensions. 229 aux = locale.split( "-u-" ); 230 if ( aux[ 1 ] ) { 231 aux[ 1 ] = aux[ 1 ].split( "-t-" ); 232 locale = aux[ 0 ] + ( aux[ 1 ][ 1 ] ? "-t-" + aux[ 1 ][ 1 ] : ""); 233 subtags[ 4 /* unicodeLocaleExtensions */ ] = aux[ 1 ][ 0 ]; 234 } 235 236 // TODO normalize transformed extensions. Currently, skipped. 237 // subtags[ x ] = locale.split( "-t-" )[ 1 ]; 238 unicodeLanguageId = locale.split( "-t-" )[ 0 ]; 239 240 // unicode_language_id = "root" 241 // | unicode_language_subtag 242 // (sep unicode_script_subtag)? 243 // (sep unicode_region_subtag)? 244 // (sep unicode_variant_subtag)* ; 245 // 246 // Although unicode_language_subtag = alpha{2,8}, I'm using alpha{2,3}. Because, there's no language on CLDR lengthier than 3. 247 aux = unicodeLanguageId.match( /^(([a-z]{2,3})(-([A-Z][a-z]{3}))?(-([A-Z]{2}|[0-9]{3}))?)((-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3}))*)$|^(root)$/ ); 248 if ( aux === null ) { 249 return [ "und", "Zzzz", "ZZ" ]; 250 } 251 subtags[ 0 /* language */ ] = aux[ 10 ] /* root */ || aux[ 2 ] || "und"; 252 subtags[ 1 /* script */ ] = aux[ 4 ] || "Zzzz"; 253 subtags[ 2 /* territory */ ] = aux[ 6 ] || "ZZ"; 254 if ( aux[ 7 ] && aux[ 7 ].length ) { 255 subtags[ 3 /* variant */ ] = aux[ 7 ].slice( 1 ) /* remove leading "-" */; 256 } 257 258 // 0: language 259 // 1: script 260 // 2: territory (aka region) 261 // 3: variant 262 // 4: unicodeLocaleExtensions 263 return subtags; 264 }; 265 266 267 268 269 var arrayForEach = function( array, callback ) { 270 var i, length; 271 if ( array.forEach ) { 272 return array.forEach( callback ); 273 } 274 for ( i = 0, length = array.length; i < length; i++ ) { 275 callback( array[ i ], i, array ); 276 } 277 }; 278 279 280 281 282 /** 283 * bundleLookup( minLanguageId ) 284 * 285 * @Cldr [Cldr class] 286 * 287 * @cldr [Cldr instance] 288 * 289 * @minLanguageId [String] requested languageId after applied remove likely subtags. 290 */ 291 var bundleLookup = function( Cldr, cldr, minLanguageId ) { 292 var availableBundleMap = Cldr._availableBundleMap, 293 availableBundleMapQueue = Cldr._availableBundleMapQueue; 294 295 if ( availableBundleMapQueue.length ) { 296 arrayForEach( availableBundleMapQueue, function( bundle, i ) { 297 var existing, maxBundle, minBundle, subtags; 298 subtags = coreSubtags( bundle ); 299 maxBundle = coreLikelySubtags( Cldr, cldr, subtags ); 300 if ( maxBundle === undefined ) { 301 availableBundleMapQueue.splice( i, 1 ); 302 throw new Error( "Could not find likelySubtags for " + bundle ); 303 } 304 minBundle = coreRemoveLikelySubtags( Cldr, cldr, maxBundle ); 305 minBundle = minBundle.join( Cldr.localeSep ); 306 existing = availableBundleMap[ minBundle ]; 307 if ( existing && existing.length < bundle.length ) { 308 return; 309 } 310 availableBundleMap[ minBundle ] = bundle; 311 }); 312 Cldr._availableBundleMapQueue = []; 313 } 314 315 return availableBundleMap[ minLanguageId ] || null; 316 }; 317 318 319 320 321 var objectKeys = function( object ) { 322 var i, 323 result = []; 324 325 if ( Object.keys ) { 326 return Object.keys( object ); 327 } 328 329 for ( i in object ) { 330 result.push( i ); 331 } 332 333 return result; 334 }; 335 336 337 338 339 var createError = function( code, attributes ) { 340 var error, message; 341 342 message = code + ( attributes && JSON ? ": " + JSON.stringify( attributes ) : "" ); 343 error = new Error( message ); 344 error.code = code; 345 346 // extend( error, attributes ); 347 arrayForEach( objectKeys( attributes ), function( attribute ) { 348 error[ attribute ] = attributes[ attribute ]; 349 }); 350 351 return error; 352 }; 353 354 355 356 357 var validate = function( code, check, attributes ) { 358 if ( !check ) { 359 throw createError( code, attributes ); 360 } 361 }; 362 363 364 365 366 var validatePresence = function( value, name ) { 367 validate( "E_MISSING_PARAMETER", typeof value !== "undefined", { 368 name: name 369 }); 370 }; 371 372 373 374 375 var validateType = function( value, name, check, expected ) { 376 validate( "E_INVALID_PAR_TYPE", check, { 377 expected: expected, 378 name: name, 379 value: value 380 }); 381 }; 382 383 384 385 386 var validateTypePath = function( value, name ) { 387 validateType( value, name, typeof value === "string" || arrayIsArray( value ), "String or Array" ); 388 }; 389 390 391 392
393 /** 394 * Function inspired by jQuery Core, but reduced to our use case. 395 */ 396 var isPlainObject = function( obj ) { 397 return obj !== null && "" + obj === "[object Object]"; 398 }; 399 400 401 402 403 var validateTypePlainObject = function( value, name ) { 404 validateType( value, name, typeof value === "undefined" || isPlainObject( value ), "Plain Object" ); 405 }; 406 407 408 409 410 var validateTypeString = function( value, name ) { 411 validateType( value, name, typeof value === "string", "a string" ); 412 }; 413 414 415 416 417 // @path: normalized path 418 var resourceGet = function( data, path ) { 419 var i, 420 node = data, 421 length = path.length; 422 423 for ( i = 0; i < length - 1; i++ ) { 424 node = node[ path[ i ] ]; 425 if ( !node ) { 426 return undefined; 427 } 428 } 429 return node[ path[ i ] ]; 430 }; 431 432 433 434 435 /** 436 * setAvailableBundles( Cldr, json ) 437 * 438 * @Cldr [Cldr class] 439 * 440 * @json resolved/unresolved cldr data. 441 * 442 * Set available bundles queue based on passed json CLDR data. Considers a bundle as any String at /main/{bundle}. 443 */ 444 var coreSetAvailableBundles = function( Cldr, json ) { 445 var bundle, 446 availableBundleMapQueue = Cldr._availableBundleMapQueue, 447 main = resourceGet( json, [ "main" ] ); 448 449 if ( main ) { 450 for ( bundle in main ) { 451 if ( main.hasOwnProperty( bundle ) && bundle !== "root" && 452 availableBundleMapQueue.indexOf( bundle ) === -1 ) { 453 availableBundleMapQueue.push( bundle ); 454 } 455 } 456 } 457 }; 458 459 460 461 var alwaysArray = function( somethingOrArray ) { 462 return arrayIsArray( somethingOrArray ) ? somethingOrArray : [ somethingOrArray ]; 463 }; 464 465 466 var jsonMerge = (function() { 467 468 // Returns new deeply merged JSON. 469 // 470 // Eg. 471 // merge( { a: { b: 1, c: 2 } }, { a: { b: 3, d: 4 } } ) 472 // -> { a: { b: 3, c: 2, d: 4 } } 473 // 474 // @arguments JSON's 475 // 476 var merge = function() { 477 var destination = {}, 478 sources = [].slice.call( arguments, 0 ); 479 arrayForEach( sources, function( source ) { 480 var prop; 481 for ( prop in source ) { 482 if ( prop in destination && typeof destination[ prop ] === "object" && !arrayIsArray( destination[ prop ] ) ) { 483 484 // Merge Objects 485 destination[ prop ] = merge( destination[ prop ], source[ prop ] ); 486 487 } else { 488 489 // Set new values 490 destination[ prop ] = source[ prop ]; 491 492 } 493 } 494 }); 495 return destination; 496 }; 497 498 return merge; 499 500}()); 501 502 503 /** 504 * load( Cldr, source, jsons ) 505 * 506 * @Cldr [Cldr class] 507 * 508 * @source [Object] 509 * 510 * @jsons [arguments] 511 */ 512 var coreLoad = function( Cldr, source, jsons ) { 513 var i, j, json; 514 515 validatePresence( jsons[ 0 ], "json" ); 516 517 // Support arbitrary parameters, e.g., `Cldr.load({...}, {...})`. 518 for ( i = 0; i < jsons.length; i++ ) { 519 520 // Support array parameters, e.g., `Cldr.load([{...}, {...}])`. 521 json = alwaysArray( jsons[ i ] ); 522 523 for ( j = 0; j < json.length; j++ ) { 524 validateTypePlainObject( json[ j ], "json" ); 525 source = jsonMerge( source, json[ j ] ); 526 coreSetAvailableBundles( Cldr, json[ j ] ); 527 } 528 } 529 530 return source; 531 }; 532 533 534 535 var itemGetResolved = function( Cldr, path, attributes ) { 536 // Resolve path 537 var normalizedPath = pathNormalize( path, attributes ); 538 539 return resourceGet( Cldr._resolved, normalizedPath ); 540 }; 541 542 543 544 545 /** 546 * new Cldr() 547 */ 548 var Cldr = function( locale ) { 549 this.init( locale ); 550 }; 551 552 // Build optimization hack to avoid duplicating functions across modules. 553 Cldr._alwaysArray = alwaysArray; 554 Cldr._coreLoad = coreLoad; 555 Cldr._createError = createError; 556 Cldr._itemGetResolved = itemGetResolved; 557 Cldr._jsonMerge = jsonMerge; 558 Cldr._pathNormalize = pathNormalize; 559 Cldr._resourceGet = resourceGet; 560 Cldr._validatePresence = validatePresence; 561 Cldr._validateType = validateType; 562 Cldr._validateTypePath = validateTypePath; 563 Cldr._validateTypePlainObject = validateTypePlainObject; 564 565 Cldr._availableBundleMap = {}; 566 Cldr._availableBundleMapQueue = []; 567 Cldr._resolved = {}; 568 569 // Allow user to override locale separator "-" (default) | "_". According to http://www.unicode.org/reports/tr35/#Unicode_language_identifier, both "-" and "_" are valid locale separators (eg. "en_GB", "en-GB"). According to http://unicode.org/cldr/trac/ticket/6786 its usage must be consistent throughout the data set. 570 Cldr.localeSep = "-"; 571 572 /** 573 * Cldr.load( json [, json, ...] ) 574 * 575 * @json [JSON] CLDR data or [Array] Array of @json's. 576 * 577 * Load resolved cldr data. 578 */ 579 Cldr.load = function() { 580 Cldr._resolved = coreLoad( Cldr, Cldr._resolved, arguments ); 581 }; 582 583 /** 584 * .init() automatically run on instantiation/construction. 585 */ 586 Cldr.prototype.init = function( locale ) { 587 var attributes, language, maxLanguageId, minLanguageId, script, subtags, territory, unicodeLocaleExtensions, variant, 588 sep = Cldr.localeSep, 589 unicodeLocaleExtensionsRaw = ""; 590 591 validatePresence( locale, "locale" ); 592 validateTypeString( locale, "locale" ); 593 594 subtags = coreSubtags( locale ); 595 596 if ( subtags.length === 5 ) { 597 unicodeLocaleExtensions = subtags.pop(); 598 unicodeLocaleExtensionsRaw = sep + "u" + sep + unicodeLocaleExtensions; 599 // Remove trailing null when there is unicodeLocaleExtensions but no variants. 600 if ( !subtags[ 3 ] ) { 601 subtags.pop(); 602 } 603 } 604 variant = subtags[ 3 ]; 605 606 // Normalize locale code. 607 // Get (or deduce) the "triple subtags": language, territory (also aliased as region), and script subtags. 608 // Get the variant subtags (calendar, collation, currency, etc). 609 // refs: 610 // - http://www.unicode.org/reports/tr35/#Field_Definitions 611 // - http://www.unicode.org/reports/tr35/#Language_and_Locale_IDs 612 // - http://www.unicode.org/reports/tr35/#Unicode_locale_identifier 613 614 // When a locale id does not specify a language, or territory (region), or script, they are obtained by Likely Subtags. 615 maxLanguageId = coreLikelySubtags( Cldr, this, subtags, { force: true } ) || subtags; 616 language = maxLanguageId[ 0 ]; 617 script = maxLanguageId[ 1 ]; 618 territory = maxLanguageId[ 2 ]; 619 620 minLanguageId = coreRemoveLikelySubtags( Cldr, this, maxLanguageId ).join( sep ); 621 622 // Set attributes 623 this.attributes = attributes = {
624 bundle: bundleLookup( Cldr, this, minLanguageId ), 625 626 // Unicode Language Id 627 minLanguageId: minLanguageId + unicodeLocaleExtensionsRaw, 628 maxLanguageId: maxLanguageId.join( sep ) + unicodeLocaleExtensionsRaw, 629 630 // Unicode Language Id Subtabs 631 language: language, 632 script: script, 633 territory: territory, 634 region: territory, /* alias */ 635 variant: variant 636 }; 637 638 // Unicode locale extensions. 639 unicodeLocaleExtensions && ( "-" + unicodeLocaleExtensions ).replace( /-[a-z]{3,8}|(-[a-z]{2})-([a-z]{3,8})/g, function( attribute, key, type ) { 640 641 if ( key ) { 642 643 // Extension is in the `keyword` form. 644 attributes[ "u" + key ] = type; 645 } else { 646 647 // Extension is in the `attribute` form. 648 attributes[ "u" + attribute ] = true; 649 } 650 }); 651 652 this.locale = locale; 653 }; 654 655 /** 656 * .get() 657 */ 658 Cldr.prototype.get = function( path ) { 659 660 validatePresence( path, "path" ); 661 validateTypePath( path, "path" ); 662 663 return itemGetResolved( Cldr, path, this.attributes ); 664 }; 665 666 /** 667 * .main() 668 */ 669 Cldr.prototype.main = function( path ) { 670 validatePresence( path, "path" ); 671 validateTypePath( path, "path" ); 672 673 validate( "E_MISSING_BUNDLE", this.attributes.bundle !== null, { 674 locale: this.locale 675 }); 676 677 path = alwaysArray( path ); 678 return this.get( [ "main/{bundle}" ].concat( path ) ); 679 }; 680 681 return Cldr; 682 683 684 685 686}));
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.