1- /* eslint no-magic-numbers: 0 */
1+ function convertMasks ( locale : string ) : string {
2+ let result ;
3+ if ( locale [ 0 ] === "*" ) {
4+ result = "und" + locale . substr ( 1 ) ;
5+ } else {
6+ result = locale ;
7+ } ;
8+ return result . replace ( / \- \* / g, "" ) ;
9+ }
210
3- const languageCodeRe = "([a-z]{2,3}|\\*)" ;
4- const scriptCodeRe = "(?:-([a-z]{4}|\\*))" ;
5- const regionCodeRe = "(?:-([a-z]{2}|\\*))" ;
6- const variantCodeRe = "(?:-(([0-9][a-z0-9]{3}|[a-z0-9]{5,8})|\\*))" ;
11+ function getVisibleLangTagLength ( language : any , script : any , region : any ) {
12+ let result = 0 ;
13+ result += language ? language . length : "und" . length ;
14+ result += script ? script . length + 1 : 0 ;
15+ result += region ? region . length + 1 : 0 ;
16+ return result ;
17+ }
718
8- /**
9- * Regular expression splitting locale id into four pieces:
10- *
11- * Example: `en-Latn-US-macos`
12- *
13- * language: en
14- * script: Latn
15- * region: US
16- * variant: macos
17- *
18- * It can also accept a range `*` character on any position.
19- */
20- const localeRe = new RegExp (
21- `^${ languageCodeRe } ${ scriptCodeRe } ?${ regionCodeRe } ?${ variantCodeRe } ?$` ,
22- "i"
23- ) ;
19+ function getExtensionStart ( locale : string ) : number | undefined {
20+ let pos = locale . search ( / - [ a - z A - Z ] - / ) ;
21+ if ( pos === - 1 ) {
22+ return undefined ;
23+ }
24+ return pos ;
25+ }
2426
2527export class Locale {
2628 isWellFormed : boolean ;
27- language ? : string ;
29+ language : string ;
2830 script ?: string ;
2931 region ?: string ;
3032 variant ?: string ;
@@ -39,29 +41,55 @@ export class Locale {
3941 * properly parsed as `en-*-US-*`.
4042 */
4143 constructor ( locale : string ) {
42- const result = localeRe . exec ( locale . replace ( / _ / g, "-" ) ) ;
43- if ( ! result ) {
44+ let result ;
45+ let normalized = convertMasks ( locale . replace ( / _ / g, "-" ) ) ;
46+ try {
47+ result = new Intl . Locale ( normalized ) ;
48+ } catch ( e ) {
4449 this . isWellFormed = false ;
50+ this . language = "und" ;
4551 return ;
4652 }
4753
48- let [ , language , script , region , variant ] = result ;
54+ this . language = result . language ;
55+ this . script = result . script ;
56+ this . region = result . region ;
4957
50- if ( language ) {
51- this . language = language . toLowerCase ( ) ;
58+ let visiblelangTagLength = getVisibleLangTagLength ( this . language , this . script , this . region ) ;
59+
60+ if ( normalized . length > visiblelangTagLength ) {
61+ let extStart = getExtensionStart ( locale ) ;
62+ this . variant = locale . substring ( visiblelangTagLength + 1 , extStart ) ;
63+ }
64+
65+ this . isWellFormed = true ;
66+ }
67+
68+ static fromComponents ( { language, script, region, variant} : {
69+ language ?: string ,
70+ script ?: string ,
71+ region ?: string ,
72+ variant ?: string ,
73+ } ) : Locale {
74+ let result = new Locale ( "und" ) ;
75+ if ( language && language !== "*" ) {
76+ result . language = language ;
5277 }
53- if ( script ) {
54- this . script = script [ 0 ] . toUpperCase ( ) + script . slice ( 1 ) ;
78+ if ( script && script !== "*" ) {
79+ result . script = script ;
5580 }
56- if ( region ) {
57- this . region = region . toUpperCase ( ) ;
81+ if ( region && region !== "*" ) {
82+ result . region = region ;
5883 }
59- this . variant = variant ;
60- this . isWellFormed = true ;
84+ if ( variant && variant !== "*" ) {
85+ result . variant = variant ;
86+ }
87+ return result ;
6188 }
6289
6390 isEqual ( other : Locale ) : boolean {
6491 return (
92+ this . isWellFormed === other . isWellFormed &&
6593 this . language === other . language &&
6694 this . script === other . script &&
6795 this . region === other . region &&
@@ -71,9 +99,10 @@ export class Locale {
7199
72100 matches ( other : Locale , thisRange = false , otherRange = false ) : boolean {
73101 return (
102+ this . isWellFormed && other . isWellFormed &&
74103 ( this . language === other . language ||
75- ( thisRange && this . language === undefined ) ||
76- ( otherRange && other . language === undefined ) ) &&
104+ ( thisRange && this . language === "und" ) ||
105+ ( otherRange && other . language === "und" ) ) &&
77106 ( this . script === other . script ||
78107 ( thisRange && this . script === undefined ) ||
79108 ( otherRange && other . script === undefined ) ) &&
0 commit comments