@formatjs/intl-getcanonicallocales 1.2.1 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ import {
12
12
  SEPARATOR,
13
13
  } from './parser';
14
14
  import * as likelySubtags from 'cldr-core/supplemental/likelySubtags.json';
15
+ import {emitUnicodeLanguageId} from './emitter';
15
16
 
16
17
  function canonicalizeAttrs(strs: string[]): string[] {
17
18
  return Object.keys(
@@ -47,6 +48,16 @@ function compareExtension(e1: Extension, e2: Extension): number {
47
48
  return e1.type < e2.type ? -1 : e1.type > e2.type ? 1 : 0;
48
49
  }
49
50
 
51
+ function mergeVariants(v1: string[], v2: string[]): string[] {
52
+ const result = [...v1];
53
+ for (const v of v2) {
54
+ if (v1.indexOf(v) < 0) {
55
+ result.push(v);
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+
50
61
  /**
51
62
  * CAVEAT: We don't do this section in the spec bc they have no JSON data
52
63
  * Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms. See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The aliases are in the alias attribute value, while the canonical is in the name attribute value. For example,
@@ -56,30 +67,132 @@ We get the following transformation:
56
67
  en-u-ms-imperial ⇒ en-u-ms-uksystem
57
68
  * @param lang
58
69
  */
59
- export function canonicalizeUnicodeLanguageId(lang: UnicodeLanguageId): void {
70
+ export function canonicalizeUnicodeLanguageId(
71
+ unicodeLanguageId: UnicodeLanguageId
72
+ ): UnicodeLanguageId {
60
73
  /**
61
- * If the language subtag matches the type attribute of a languageAlias element in Supplemental Data,
62
- * replace the language subtag with the replacement value.
63
- * - If there are additional subtags in the replacement value, add them to the result, but only if there is no corresponding subtag already in the tag.
64
- * - Five special deprecated grandfathered codes (such as i-default) are in type attributes, and are also replaced.
74
+ * If the language subtag matches the type attribute of a languageAlias element in Supplemental Data, replace the language subtag with the replacement value.
75
+ * 1. If there are additional subtags in the replacement value, add them to the result, but only if there is no corresponding subtag already in the tag.
76
+ * 2. Five special deprecated grandfathered codes (such as i-default) are in type attributes, and are also replaced.
65
77
  */
66
- let sourceLang = lang.lang.toLowerCase();
67
- const langAlias = languageAlias[sourceLang];
68
- if (langAlias) {
69
- const langAliasAst = parseUnicodeLanguageId(langAlias.split('-'));
70
- lang.lang = langAliasAst.lang;
71
- lang.script = lang.script || langAliasAst.script;
72
- lang.region = lang.region || langAliasAst.region;
78
+
79
+ // From https://github.com/unicode-org/icu/blob/master/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java#L1246
80
+
81
+ // Try language _ variant
82
+ let finalLangAst = unicodeLanguageId;
83
+ if (unicodeLanguageId.variants.length) {
84
+ let replacedLang: string = '';
85
+ for (const variant of unicodeLanguageId.variants) {
86
+ if (
87
+ (replacedLang =
88
+ languageAlias[
89
+ emitUnicodeLanguageId({
90
+ lang: unicodeLanguageId.lang,
91
+ variants: [variant],
92
+ })
93
+ ])
94
+ ) {
95
+ const replacedLangAst = parseUnicodeLanguageId(
96
+ replacedLang.split(SEPARATOR)
97
+ );
98
+ finalLangAst = {
99
+ lang: replacedLangAst.lang,
100
+ script: finalLangAst.script || replacedLangAst.script,
101
+ region: finalLangAst.region || replacedLangAst.region,
102
+ variants: mergeVariants(
103
+ finalLangAst.variants,
104
+ replacedLangAst.variants
105
+ ),
106
+ };
107
+ break;
108
+ }
109
+ }
73
110
  }
74
- if (lang.region) {
75
- const region = lang.region.toUpperCase();
111
+
112
+ // language _ script _ country
113
+ // ug-Arab-CN -> ug-CN
114
+ if (finalLangAst.script && finalLangAst.region) {
115
+ const replacedLang =
116
+ languageAlias[
117
+ emitUnicodeLanguageId({
118
+ lang: finalLangAst.lang,
119
+ script: finalLangAst.script,
120
+ region: finalLangAst.region,
121
+ variants: [],
122
+ })
123
+ ];
124
+ if (replacedLang) {
125
+ const replacedLangAst = parseUnicodeLanguageId(
126
+ replacedLang.split(SEPARATOR)
127
+ );
128
+ finalLangAst = {
129
+ lang: replacedLangAst.lang,
130
+ script: replacedLangAst.script,
131
+ region: replacedLangAst.region,
132
+ variants: finalLangAst.variants,
133
+ };
134
+ }
135
+ }
136
+
137
+ // language _ country
138
+ // eg. az_AZ -> az_Latn_A
139
+ if (finalLangAst.region) {
140
+ const replacedLang =
141
+ languageAlias[
142
+ emitUnicodeLanguageId({
143
+ lang: finalLangAst.lang,
144
+ region: finalLangAst.region,
145
+ variants: [],
146
+ })
147
+ ];
148
+ if (replacedLang) {
149
+ const replacedLangAst = parseUnicodeLanguageId(
150
+ replacedLang.split(SEPARATOR)
151
+ );
152
+ finalLangAst = {
153
+ lang: replacedLangAst.lang,
154
+ script: finalLangAst.script || replacedLangAst.script,
155
+ region: replacedLangAst.region,
156
+ variants: finalLangAst.variants,
157
+ };
158
+ }
159
+ }
160
+ // only language
161
+ // e.g. twi -> ak
162
+ const replacedLang =
163
+ languageAlias[
164
+ emitUnicodeLanguageId({
165
+ lang: finalLangAst.lang,
166
+ variants: [],
167
+ })
168
+ ];
169
+ if (replacedLang) {
170
+ const replacedLangAst = parseUnicodeLanguageId(
171
+ replacedLang.split(SEPARATOR)
172
+ );
173
+ finalLangAst = {
174
+ lang: replacedLangAst.lang,
175
+ script: finalLangAst.script || replacedLangAst.script,
176
+ region: finalLangAst.region || replacedLangAst.region,
177
+ variants: finalLangAst.variants,
178
+ };
179
+ }
180
+
181
+ if (finalLangAst.region) {
182
+ const region = finalLangAst.region.toUpperCase();
76
183
  const regionAlias = territoryAlias[region];
77
184
  let replacedRegion: string | undefined;
78
185
  if (regionAlias) {
79
186
  const regions = regionAlias.split(' ');
80
187
  replacedRegion = regions[0];
81
188
  const likelySubtag =
82
- likelySubtags.supplemental.likelySubtags[lang.lang as 'aa'];
189
+ likelySubtags.supplemental.likelySubtags[
190
+ emitUnicodeLanguageId({
191
+ lang: finalLangAst.lang,
192
+ script: finalLangAst.script,
193
+ variants: [],
194
+ }) as 'aa'
195
+ ];
83
196
  if (likelySubtag) {
84
197
  const {region: likelyRegion} = parseUnicodeLanguageId(
85
198
  likelySubtag.split(SEPARATOR)
@@ -90,32 +203,35 @@ export function canonicalizeUnicodeLanguageId(lang: UnicodeLanguageId): void {
90
203
  }
91
204
  }
92
205
  if (replacedRegion) {
93
- lang.region = replacedRegion;
206
+ finalLangAst.region = replacedRegion;
94
207
  }
208
+ finalLangAst.region = finalLangAst.region.toUpperCase();
95
209
  }
96
- if (lang.script) {
97
- lang.script =
98
- lang.script[0].toUpperCase() + lang.script.slice(1).toLowerCase();
99
- if (scriptAlias[lang.script]) {
100
- lang.script = scriptAlias[lang.script];
210
+ if (finalLangAst.script) {
211
+ finalLangAst.script =
212
+ finalLangAst.script[0].toUpperCase() +
213
+ finalLangAst.script.slice(1).toLowerCase();
214
+ if (scriptAlias[finalLangAst.script]) {
215
+ finalLangAst.script = scriptAlias[finalLangAst.script];
101
216
  }
102
217
  }
103
218
 
104
- if (lang.variants.length) {
105
- for (let i = 0; i < lang.variants.length; i++) {
106
- let variant = lang.variants[i].toLowerCase();
219
+ if (finalLangAst.variants.length) {
220
+ for (let i = 0; i < finalLangAst.variants.length; i++) {
221
+ let variant = finalLangAst.variants[i].toLowerCase();
107
222
  if (variantAlias[variant]) {
108
223
  const alias = variantAlias[variant];
109
224
  if (isUnicodeVariantSubtag(alias)) {
110
- lang.variants[i] = alias;
225
+ finalLangAst.variants[i] = alias;
111
226
  } else if (isUnicodeLanguageSubtag(alias)) {
112
227
  // Yes this can happen per the spec
113
- lang.lang = alias;
228
+ finalLangAst.lang = alias;
114
229
  }
115
230
  }
116
231
  }
117
- lang.variants.sort();
232
+ finalLangAst.variants.sort();
118
233
  }
234
+ return finalLangAst;
119
235
  }
120
236
 
121
237
  /**
@@ -128,7 +244,7 @@ export function canonicalizeUnicodeLanguageId(lang: UnicodeLanguageId): void {
128
244
  export function canonicalizeUnicodeLocaleId(
129
245
  locale: UnicodeLocaleId
130
246
  ): UnicodeLocaleId {
131
- canonicalizeUnicodeLanguageId(locale.lang);
247
+ locale.lang = canonicalizeUnicodeLanguageId(locale.lang);
132
248
  if (locale.extensions) {
133
249
  for (const extension of locale.extensions) {
134
250
  switch (extension.type) {
@@ -140,7 +256,7 @@ export function canonicalizeUnicodeLocaleId(
140
256
  break;
141
257
  case 't':
142
258
  if (extension.lang) {
143
- canonicalizeUnicodeLanguageId(extension.lang);
259
+ extension.lang = canonicalizeUnicodeLanguageId(extension.lang);
144
260
  }
145
261
  extension.fields = canonicalizeKVs(extension.fields);
146
262
  break;
package/src/polyfill.ts CHANGED
@@ -1,5 +1,22 @@
1
- import {getCanonicalLocales} from './';
2
- if (!('getCanonicalLocales' in Intl)) {
1
+ import {getCanonicalLocales} from '.';
2
+ if (typeof Intl === 'undefined') {
3
+ if (typeof window !== 'undefined') {
4
+ Object.defineProperty(window, 'Intl', {
5
+ value: {},
6
+ });
7
+ } else if (typeof global !== 'undefined') {
8
+ Object.defineProperty(global, 'Intl', {
9
+ value: {},
10
+ });
11
+ }
12
+ }
13
+ if (
14
+ !('getCanonicalLocales' in Intl) ||
15
+ // Native Intl.getCanonicalLocales is just buggy
16
+ ((Intl as any).getCanonicalLocales as typeof getCanonicalLocales)(
17
+ 'und-x-private'
18
+ )[0] === 'x-private'
19
+ ) {
3
20
  Object.defineProperty(Intl, 'getCanonicalLocales', {
4
21
  value: getCanonicalLocales,
5
22
  writable: true,