@formatjs/intl-localematcher 0.2.28 → 0.2.29

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.
Files changed (80) hide show
  1. package/BUILD +73 -0
  2. package/CHANGELOG.md +150 -0
  3. package/LICENSE.md +0 -0
  4. package/README.md +0 -0
  5. package/abstract/BestAvailableLocale.ts +24 -0
  6. package/abstract/BestFitMatcher.ts +80 -0
  7. package/abstract/CanonicalizeLocaleList.ts +8 -0
  8. package/abstract/LookupMatcher.ts +39 -0
  9. package/abstract/LookupSupportedLocales.ts +28 -0
  10. package/abstract/ResolveLocale.ts +100 -0
  11. package/abstract/UnicodeExtensionValue.ts +44 -0
  12. package/abstract/types.ts +5 -0
  13. package/abstract/utils.ts +11 -0
  14. package/index.ts +32 -0
  15. package/package.json +2 -2
  16. package/tests/BestFitMatcher.test.ts +23 -0
  17. package/tests/LookupMatcher.test.ts +17 -0
  18. package/tests/ResolveLocale.test.ts +47 -0
  19. package/tests/index.test.ts +242 -0
  20. package/tsconfig.json +5 -0
  21. package/abstract/BestAvailableLocale.d.ts +0 -7
  22. package/abstract/BestAvailableLocale.d.ts.map +0 -1
  23. package/abstract/BestAvailableLocale.js +0 -25
  24. package/abstract/BestFitMatcher.d.ts +0 -9
  25. package/abstract/BestFitMatcher.d.ts.map +0 -1
  26. package/abstract/BestFitMatcher.js +0 -65
  27. package/abstract/CanonicalizeLocaleList.d.ts +0 -6
  28. package/abstract/CanonicalizeLocaleList.d.ts.map +0 -1
  29. package/abstract/CanonicalizeLocaleList.js +0 -12
  30. package/abstract/LookupMatcher.d.ts +0 -9
  31. package/abstract/LookupMatcher.d.ts.map +0 -1
  32. package/abstract/LookupMatcher.js +0 -29
  33. package/abstract/LookupSupportedLocales.d.ts +0 -7
  34. package/abstract/LookupSupportedLocales.d.ts.map +0 -1
  35. package/abstract/LookupSupportedLocales.js +0 -23
  36. package/abstract/ResolveLocale.d.ts +0 -15
  37. package/abstract/ResolveLocale.d.ts.map +0 -1
  38. package/abstract/ResolveLocale.js +0 -78
  39. package/abstract/UnicodeExtensionValue.d.ts +0 -7
  40. package/abstract/UnicodeExtensionValue.d.ts.map +0 -1
  41. package/abstract/UnicodeExtensionValue.js +0 -50
  42. package/abstract/types.d.ts +0 -6
  43. package/abstract/types.d.ts.map +0 -1
  44. package/abstract/types.js +0 -2
  45. package/abstract/utils.d.ts +0 -3
  46. package/abstract/utils.d.ts.map +0 -1
  47. package/abstract/utils.js +0 -11
  48. package/index.d.ts +0 -7
  49. package/index.d.ts.map +0 -1
  50. package/index.js +0 -19
  51. package/lib/abstract/BestAvailableLocale.d.ts +0 -7
  52. package/lib/abstract/BestAvailableLocale.d.ts.map +0 -1
  53. package/lib/abstract/BestAvailableLocale.js +0 -21
  54. package/lib/abstract/BestFitMatcher.d.ts +0 -9
  55. package/lib/abstract/BestFitMatcher.d.ts.map +0 -1
  56. package/lib/abstract/BestFitMatcher.js +0 -61
  57. package/lib/abstract/CanonicalizeLocaleList.d.ts +0 -6
  58. package/lib/abstract/CanonicalizeLocaleList.d.ts.map +0 -1
  59. package/lib/abstract/CanonicalizeLocaleList.js +0 -8
  60. package/lib/abstract/LookupMatcher.d.ts +0 -9
  61. package/lib/abstract/LookupMatcher.d.ts.map +0 -1
  62. package/lib/abstract/LookupMatcher.js +0 -25
  63. package/lib/abstract/LookupSupportedLocales.d.ts +0 -7
  64. package/lib/abstract/LookupSupportedLocales.d.ts.map +0 -1
  65. package/lib/abstract/LookupSupportedLocales.js +0 -19
  66. package/lib/abstract/ResolveLocale.d.ts +0 -15
  67. package/lib/abstract/ResolveLocale.d.ts.map +0 -1
  68. package/lib/abstract/ResolveLocale.js +0 -74
  69. package/lib/abstract/UnicodeExtensionValue.d.ts +0 -7
  70. package/lib/abstract/UnicodeExtensionValue.d.ts.map +0 -1
  71. package/lib/abstract/UnicodeExtensionValue.js +0 -46
  72. package/lib/abstract/types.d.ts +0 -6
  73. package/lib/abstract/types.d.ts.map +0 -1
  74. package/lib/abstract/types.js +0 -1
  75. package/lib/abstract/utils.d.ts +0 -3
  76. package/lib/abstract/utils.d.ts.map +0 -1
  77. package/lib/abstract/utils.js +0 -7
  78. package/lib/index.d.ts +0 -7
  79. package/lib/index.d.ts.map +0 -1
  80. package/lib/index.js +0 -13
package/BUILD ADDED
@@ -0,0 +1,73 @@
1
+ load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files")
2
+ load("@aspect_rules_js//npm/private:npm_package.bzl", "npm_package")
3
+ load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
4
+ load("//tools:index.bzl", "check_format", "package_json_test", "ts_compile")
5
+ load("//tools:jest.bzl", "jest_test")
6
+
7
+ PACKAGE_NAME = "intl-localematcher"
8
+
9
+ npm_package(
10
+ name = PACKAGE_NAME,
11
+ srcs = [
12
+ "LICENSE.md",
13
+ "README.md",
14
+ "package.json",
15
+ ":dist",
16
+ ],
17
+ package = "@formatjs/%s" % PACKAGE_NAME,
18
+ visibility = ["//visibility:public"],
19
+ )
20
+
21
+ SRCS = glob(
22
+ ["**/*.ts"],
23
+ exclude = ["tests/*"],
24
+ )
25
+
26
+ ts_compile(
27
+ name = "dist",
28
+ srcs = SRCS,
29
+ package = "@formatjs/%s" % PACKAGE_NAME,
30
+ skip_esm = False,
31
+ )
32
+
33
+ jest_test(
34
+ name = "unit",
35
+ srcs = SRCS + glob([
36
+ "tests/**/*.ts",
37
+ "tests/**/*.tsx",
38
+ "tests/**/*.snap",
39
+ ]),
40
+ )
41
+
42
+ # Test262
43
+ ts_project(
44
+ name = "test262-main-bundle",
45
+ srcs = SRCS,
46
+ declaration = True,
47
+ declaration_map = True,
48
+ extends = "//:tsconfig",
49
+ out_dir = "test262",
50
+ resolve_json_module = True,
51
+ tsconfig = "//:tsconfig.es6",
52
+ )
53
+
54
+ write_source_files(
55
+ name = "tsconfig_json",
56
+ files = {"tsconfig.json": "//tools:tsconfig.golden.json"},
57
+ )
58
+
59
+ check_format(
60
+ name = "prettier",
61
+ srcs = glob(
62
+ [
63
+ "**/*",
64
+ ],
65
+ exclude = [
66
+ "CHANGELOG.md",
67
+ ],
68
+ ),
69
+ )
70
+
71
+ package_json_test(
72
+ name = "package_json_test",
73
+ )
package/CHANGELOG.md ADDED
@@ -0,0 +1,150 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [0.2.29](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.28...@formatjs/intl-localematcher@0.2.29) (2022-08-18)
7
+
8
+ **Note:** Version bump only for package @formatjs/intl-localematcher
9
+
10
+ ## [0.2.28](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.27...@formatjs/intl-localematcher@0.2.28) (2022-06-06)
11
+
12
+ **Note:** Version bump only for package @formatjs/intl-localematcher
13
+
14
+ ## [0.2.27](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.26...@formatjs/intl-localematcher@0.2.27) (2022-05-19)
15
+
16
+ **Note:** Version bump only for package @formatjs/intl-localematcher
17
+
18
+ ## [0.2.26](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.25...@formatjs/intl-localematcher@0.2.26) (2022-05-19)
19
+
20
+ ### Bug Fixes
21
+
22
+ * **react-intl:** fix type issue with react18, fix [#3550](https://github.com/formatjs/formatjs/issues/3550) ([2567b93](https://github.com/formatjs/formatjs/commit/2567b932c5d18b097a43842563046c20ce0c49f1))
23
+
24
+ ## [0.2.25](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.24...@formatjs/intl-localematcher@0.2.25) (2022-03-26)
25
+
26
+ ### Bug Fixes
27
+
28
+ * **@formatjs/intl-localematcher:** adds module field to package.json, fixes [#3456](https://github.com/formatjs/formatjs/issues/3456) ([#3457](https://github.com/formatjs/formatjs/issues/3457)) ([e805d9e](https://github.com/formatjs/formatjs/commit/e805d9e29bae0298a081f760e90c8c5d2dd1aa7c))
29
+
30
+ ## [0.2.24](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.23...@formatjs/intl-localematcher@0.2.24) (2022-02-06)
31
+
32
+ ### Bug Fixes
33
+
34
+ * **@formatjs/intl-localematcher:** prioritize locale in front of canonicalized/minimized locale, fix [#3405](https://github.com/formatjs/formatjs/issues/3405) ([81fa22a](https://github.com/formatjs/formatjs/commit/81fa22a87d42362f4d4d8406429f3161a977cd42))
35
+
36
+ ## [0.2.23](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.22...@formatjs/intl-localematcher@0.2.23) (2022-01-24)
37
+
38
+ ### Bug Fixes
39
+
40
+ * **@formatjs/intl-localematcher:** fix best fit to account for canonicalization ([cacad92](https://github.com/formatjs/formatjs/commit/cacad921ed4eb2f608979fe03b8cdcd3d1719766))
41
+
42
+ ## [0.2.22](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.21...@formatjs/intl-localematcher@0.2.22) (2022-01-03)
43
+
44
+ ### Bug Fixes
45
+
46
+ * **@formatjs/intl-localematcher:** iterate through set instead of Array.from so we dont rely on polyfill ([2114518](https://github.com/formatjs/formatjs/commit/211451805d09aae543a8a0aeae1b62a179aaae07))
47
+
48
+ ## [0.2.21](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.20...@formatjs/intl-localematcher@0.2.21) (2021-09-27)
49
+
50
+ **Note:** Version bump only for package @formatjs/intl-localematcher
51
+
52
+ ## [0.2.20](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.19...@formatjs/intl-localematcher@0.2.20) (2021-08-15)
53
+
54
+ **Note:** Version bump only for package @formatjs/intl-localematcher
55
+
56
+ ## [0.2.19](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.18...@formatjs/intl-localematcher@0.2.19) (2021-08-06)
57
+
58
+ **Note:** Version bump only for package @formatjs/intl-localematcher
59
+
60
+ ## [0.2.18](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.17...@formatjs/intl-localematcher@0.2.18) (2021-07-24)
61
+
62
+ ### Bug Fixes
63
+
64
+ * **@formatjs/intl-localematcher:** fix best fit algo, fix [#3058](https://github.com/formatjs/formatjs/issues/3058) ([c9dad00](https://github.com/formatjs/formatjs/commit/c9dad0081ba57792b3cdcf6bc1a02c5dc3f57dc1))
65
+ * **@formatjs/intl-localematcher:** refactor and consolidate files ([1d1a4bc](https://github.com/formatjs/formatjs/commit/1d1a4bc6e5ccbf7be774d4f0f4b2ef2c7fa334b5))
66
+
67
+ ## [0.2.17](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.16...@formatjs/intl-localematcher@0.2.17) (2021-07-20)
68
+
69
+ ### Bug Fixes
70
+
71
+ * **@formatjs/intl-localematcher:** Correct path to main file for @formatjs/intl-localematcher ([#3057](https://github.com/formatjs/formatjs/issues/3057)) ([e2267bb](https://github.com/formatjs/formatjs/commit/e2267bbc2645d007ccbae8dfa77bc7ad422cfde2))
72
+
73
+ ## [0.2.16](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.15...@formatjs/intl-localematcher@0.2.16) (2021-06-26)
74
+
75
+ **Note:** Version bump only for package @formatjs/intl-localematcher
76
+
77
+ ## [0.2.15](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.14...@formatjs/intl-localematcher@0.2.15) (2021-06-05)
78
+
79
+ **Note:** Version bump only for package @formatjs/intl-localematcher
80
+
81
+ ## [0.2.14](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.13...@formatjs/intl-localematcher@0.2.14) (2021-06-01)
82
+
83
+ **Note:** Version bump only for package @formatjs/intl-localematcher
84
+
85
+ ## [0.2.13](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.12...@formatjs/intl-localematcher@0.2.13) (2021-05-23)
86
+
87
+ **Note:** Version bump only for package @formatjs/intl-localematcher
88
+
89
+ ## [0.2.12](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.11...@formatjs/intl-localematcher@0.2.12) (2021-05-20)
90
+
91
+ **Note:** Version bump only for package @formatjs/intl-localematcher
92
+
93
+ ## [0.2.11](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.10...@formatjs/intl-localematcher@0.2.11) (2021-05-17)
94
+
95
+ **Note:** Version bump only for package @formatjs/intl-localematcher
96
+
97
+ ## [0.2.10](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.9...@formatjs/intl-localematcher@0.2.10) (2021-05-10)
98
+
99
+ **Note:** Version bump only for package @formatjs/intl-localematcher
100
+
101
+ ## [0.2.9](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.8...@formatjs/intl-localematcher@0.2.9) (2021-04-26)
102
+
103
+ **Note:** Version bump only for package @formatjs/intl-localematcher
104
+
105
+ ## [0.2.8](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.7...@formatjs/intl-localematcher@0.2.8) (2021-04-12)
106
+
107
+ **Note:** Version bump only for package @formatjs/intl-localematcher
108
+
109
+ ## [0.2.7](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.6...@formatjs/intl-localematcher@0.2.7) (2021-03-26)
110
+
111
+ **Note:** Version bump only for package @formatjs/intl-localematcher
112
+
113
+ ## [0.2.6](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.5...@formatjs/intl-localematcher@0.2.6) (2021-03-15)
114
+
115
+ **Note:** Version bump only for package @formatjs/intl-localematcher
116
+
117
+ ## [0.2.5](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.4...@formatjs/intl-localematcher@0.2.5) (2021-03-01)
118
+
119
+ **Note:** Version bump only for package @formatjs/intl-localematcher
120
+
121
+ ## [0.2.4](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.3...@formatjs/intl-localematcher@0.2.4) (2021-02-25)
122
+
123
+ ### Bug Fixes
124
+
125
+ * bump tslib version dep ([37577d2](https://github.com/formatjs/formatjs/commit/37577d22bf28d23de1d8013ba0047cf221ad8840)), closes [#2645](https://github.com/formatjs/formatjs/issues/2645)
126
+
127
+ ## [0.2.3](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.2...@formatjs/intl-localematcher@0.2.3) (2021-02-25)
128
+
129
+ **Note:** Version bump only for package @formatjs/intl-localematcher
130
+
131
+ ## [0.2.2](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.1...@formatjs/intl-localematcher@0.2.2) (2021-02-22)
132
+
133
+ **Note:** Version bump only for package @formatjs/intl-localematcher
134
+
135
+ ## [0.2.1](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.2.0...@formatjs/intl-localematcher@0.2.1) (2021-02-21)
136
+
137
+ **Note:** Version bump only for package @formatjs/intl-localematcher
138
+
139
+ # [0.2.0](https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.1.0...@formatjs/intl-localematcher@0.2.0) (2021-02-08)
140
+
141
+ ### Features
142
+
143
+ * **@formatjs/intl-localematcher:** switch entry point to prepackaged UMD file ([a0481cc](https://github.com/formatjs/formatjs/commit/a0481cc79e95960b540cafc541d555a5c228851f))
144
+
145
+ # 0.1.0 (2021-02-08)
146
+
147
+ ### Features
148
+
149
+ * **@formatjs/intl-localematcher:** add ponyfill for Intl.LocaleMatcher ([e479543](https://github.com/formatjs/formatjs/commit/e479543e92e9b6c6d08f68848f25bcb9ba558ab3))
150
+ * **@formatjs/intl-localematcher:** reset version ([7684b54](https://github.com/formatjs/formatjs/commit/7684b543fa7c3db3aad839bae8485ec7de4ee495))
package/LICENSE.md CHANGED
File without changes
package/README.md CHANGED
File without changes
@@ -0,0 +1,24 @@
1
+ /**
2
+ * https://tc39.es/ecma402/#sec-bestavailablelocale
3
+ * @param availableLocales
4
+ * @param locale
5
+ */
6
+ export function BestAvailableLocale(
7
+ availableLocales: Set<String>,
8
+ locale: string
9
+ ) {
10
+ let candidate = locale
11
+ while (true) {
12
+ if (availableLocales.has(candidate)) {
13
+ return candidate
14
+ }
15
+ let pos = candidate.lastIndexOf('-')
16
+ if (!~pos) {
17
+ return undefined
18
+ }
19
+ if (pos >= 2 && candidate[pos - 2] === '-') {
20
+ pos -= 2
21
+ }
22
+ candidate = candidate.slice(0, pos)
23
+ }
24
+ }
@@ -0,0 +1,80 @@
1
+ import {BestAvailableLocale} from './BestAvailableLocale'
2
+ import {LookupMatcherResult} from './types'
3
+ import {UNICODE_EXTENSION_SEQUENCE_REGEX} from './utils'
4
+
5
+ /**
6
+ * https://tc39.es/ecma402/#sec-bestfitmatcher
7
+ * @param availableLocales
8
+ * @param requestedLocales
9
+ * @param getDefaultLocale
10
+ */
11
+ export function BestFitMatcher(
12
+ availableLocales: Set<string>,
13
+ requestedLocales: string[],
14
+ getDefaultLocale: () => string
15
+ ): LookupMatcherResult {
16
+ const minimizedAvailableLocaleMap: Record<string, string> = {}
17
+ const availableLocaleMap: Record<string, string> = {}
18
+ const canonicalizedLocaleMap: Record<string, string> = {}
19
+ const minimizedAvailableLocales: Set<string> = new Set()
20
+ availableLocales.forEach(locale => {
21
+ const minimizedLocale = new (Intl as any).Locale(locale)
22
+ .minimize()
23
+ .toString()
24
+
25
+ const canonicalizedLocale =
26
+ (Intl as any).getCanonicalLocales(locale)[0] || locale
27
+
28
+ minimizedAvailableLocaleMap[minimizedLocale] = locale
29
+ availableLocaleMap[locale] = locale
30
+ canonicalizedLocaleMap[canonicalizedLocale] = locale
31
+ minimizedAvailableLocales.add(minimizedLocale)
32
+ minimizedAvailableLocales.add(locale)
33
+ minimizedAvailableLocales.add(canonicalizedLocale)
34
+ })
35
+
36
+ let foundLocale: string | undefined
37
+ for (const l of requestedLocales) {
38
+ if (foundLocale) {
39
+ break
40
+ }
41
+ const noExtensionLocale = l.replace(UNICODE_EXTENSION_SEQUENCE_REGEX, '')
42
+
43
+ if (availableLocales.has(noExtensionLocale)) {
44
+ foundLocale = noExtensionLocale
45
+ break
46
+ }
47
+
48
+ if (minimizedAvailableLocales.has(noExtensionLocale)) {
49
+ foundLocale = noExtensionLocale
50
+ break
51
+ }
52
+
53
+ const locale = new (Intl as any).Locale(noExtensionLocale)
54
+
55
+ const maximizedRequestedLocale = locale.maximize().toString()
56
+ const minimizedRequestedLocale = locale.minimize().toString()
57
+
58
+ // Check minimized locale
59
+ if (minimizedAvailableLocales.has(minimizedRequestedLocale)) {
60
+ foundLocale = minimizedRequestedLocale
61
+ break
62
+ }
63
+
64
+ // Lookup algo on maximized locale
65
+ foundLocale = BestAvailableLocale(
66
+ minimizedAvailableLocales,
67
+ maximizedRequestedLocale
68
+ )
69
+ }
70
+ if (!foundLocale) {
71
+ return {locale: getDefaultLocale()}
72
+ }
73
+ return {
74
+ locale:
75
+ availableLocaleMap[foundLocale] ||
76
+ canonicalizedLocaleMap[foundLocale] ||
77
+ minimizedAvailableLocaleMap[foundLocale] ||
78
+ foundLocale,
79
+ }
80
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * http://ecma-international.org/ecma-402/7.0/index.html#sec-canonicalizelocalelist
3
+ * @param locales
4
+ */
5
+ export function CanonicalizeLocaleList(locales?: string | string[]): string[] {
6
+ // TODO
7
+ return ((Intl as any).getCanonicalLocales as any)(locales)
8
+ }
@@ -0,0 +1,39 @@
1
+ import {UNICODE_EXTENSION_SEQUENCE_REGEX} from './utils'
2
+ import {BestAvailableLocale} from './BestAvailableLocale'
3
+ import {LookupMatcherResult} from './types'
4
+
5
+ /**
6
+ * https://tc39.es/ecma402/#sec-lookupmatcher
7
+ * @param availableLocales
8
+ * @param requestedLocales
9
+ * @param getDefaultLocale
10
+ */
11
+ export function LookupMatcher(
12
+ availableLocales: Set<string>,
13
+ requestedLocales: string[],
14
+ getDefaultLocale: () => string
15
+ ): LookupMatcherResult {
16
+ const result: LookupMatcherResult = {locale: ''}
17
+ for (const locale of requestedLocales) {
18
+ const noExtensionLocale = locale.replace(
19
+ UNICODE_EXTENSION_SEQUENCE_REGEX,
20
+ ''
21
+ )
22
+ const availableLocale = BestAvailableLocale(
23
+ availableLocales,
24
+ noExtensionLocale
25
+ )
26
+ if (availableLocale) {
27
+ result.locale = availableLocale
28
+ if (locale !== noExtensionLocale) {
29
+ result.extension = locale.slice(
30
+ noExtensionLocale.length + 1,
31
+ locale.length
32
+ )
33
+ }
34
+ return result
35
+ }
36
+ }
37
+ result.locale = getDefaultLocale()
38
+ return result
39
+ }
@@ -0,0 +1,28 @@
1
+ import {UNICODE_EXTENSION_SEQUENCE_REGEX} from './utils'
2
+ import {BestAvailableLocale} from './BestAvailableLocale'
3
+
4
+ /**
5
+ * https://tc39.es/ecma402/#sec-lookupsupportedlocales
6
+ * @param availableLocales
7
+ * @param requestedLocales
8
+ */
9
+ export function LookupSupportedLocales(
10
+ availableLocales: Set<string>,
11
+ requestedLocales: string[]
12
+ ) {
13
+ const subset: string[] = []
14
+ for (const locale of requestedLocales) {
15
+ const noExtensionLocale = locale.replace(
16
+ UNICODE_EXTENSION_SEQUENCE_REGEX,
17
+ ''
18
+ )
19
+ const availableLocale = BestAvailableLocale(
20
+ availableLocales,
21
+ noExtensionLocale
22
+ )
23
+ if (availableLocale) {
24
+ subset.push(availableLocale)
25
+ }
26
+ }
27
+ return subset
28
+ }
@@ -0,0 +1,100 @@
1
+ import {LookupMatcherResult} from './types'
2
+ import {LookupMatcher} from './LookupMatcher'
3
+ import {BestFitMatcher} from './BestFitMatcher'
4
+ import {invariant} from './utils'
5
+ import {UnicodeExtensionValue} from './UnicodeExtensionValue'
6
+
7
+ export interface ResolveLocaleResult {
8
+ locale: string
9
+ dataLocale: string
10
+ [k: string]: any
11
+ }
12
+
13
+ /**
14
+ * https://tc39.es/ecma402/#sec-resolvelocale
15
+ */
16
+ export function ResolveLocale<K extends string, D extends {[k in K]: any}>(
17
+ availableLocales: Set<string>,
18
+ requestedLocales: string[],
19
+ options: {localeMatcher: string; [k: string]: string},
20
+ relevantExtensionKeys: K[],
21
+ localeData: Record<string, D | undefined>,
22
+ getDefaultLocale: () => string
23
+ ): ResolveLocaleResult {
24
+ const matcher = options.localeMatcher
25
+ let r: LookupMatcherResult
26
+ if (matcher === 'lookup') {
27
+ r = LookupMatcher(availableLocales, requestedLocales, getDefaultLocale)
28
+ } else {
29
+ r = BestFitMatcher(availableLocales, requestedLocales, getDefaultLocale)
30
+ }
31
+ let foundLocale = r.locale
32
+ const result: ResolveLocaleResult = {locale: '', dataLocale: foundLocale}
33
+ let supportedExtension = '-u'
34
+ for (const key of relevantExtensionKeys) {
35
+ invariant(
36
+ foundLocale in localeData,
37
+ `Missing locale data for ${foundLocale}`
38
+ )
39
+ const foundLocaleData = localeData[foundLocale]
40
+ invariant(
41
+ typeof foundLocaleData === 'object' && foundLocaleData !== null,
42
+ `locale data ${key} must be an object`
43
+ )
44
+ const keyLocaleData = foundLocaleData[key]
45
+ invariant(
46
+ Array.isArray(keyLocaleData),
47
+ `keyLocaleData for ${key} must be an array`
48
+ )
49
+ let value = keyLocaleData[0]
50
+ invariant(
51
+ typeof value === 'string' || value === null,
52
+ `value must be string or null but got ${typeof value} in key ${key}`
53
+ )
54
+ let supportedExtensionAddition = ''
55
+ if (r.extension) {
56
+ const requestedValue = UnicodeExtensionValue(r.extension, key)
57
+ if (requestedValue !== undefined) {
58
+ if (requestedValue !== '') {
59
+ if (~keyLocaleData.indexOf(requestedValue)) {
60
+ value = requestedValue
61
+ supportedExtensionAddition = `-${key}-${value}`
62
+ }
63
+ } else if (~requestedValue.indexOf('true')) {
64
+ value = 'true'
65
+ supportedExtensionAddition = `-${key}`
66
+ }
67
+ }
68
+ }
69
+ if (key in options) {
70
+ const optionsValue = options[key]
71
+ invariant(
72
+ typeof optionsValue === 'string' ||
73
+ typeof optionsValue === 'undefined' ||
74
+ optionsValue === null,
75
+ 'optionsValue must be String, Undefined or Null'
76
+ )
77
+ if (~keyLocaleData.indexOf(optionsValue)) {
78
+ if (optionsValue !== value) {
79
+ value = optionsValue
80
+ supportedExtensionAddition = ''
81
+ }
82
+ }
83
+ }
84
+ result[key] = value
85
+ supportedExtension += supportedExtensionAddition
86
+ }
87
+ if (supportedExtension.length > 2) {
88
+ const privateIndex = foundLocale.indexOf('-x-')
89
+ if (privateIndex === -1) {
90
+ foundLocale = foundLocale + supportedExtension
91
+ } else {
92
+ const preExtension = foundLocale.slice(0, privateIndex)
93
+ const postExtension = foundLocale.slice(privateIndex, foundLocale.length)
94
+ foundLocale = preExtension + supportedExtension + postExtension
95
+ }
96
+ foundLocale = (Intl as any).getCanonicalLocales(foundLocale)[0]
97
+ }
98
+ result.locale = foundLocale
99
+ return result
100
+ }
@@ -0,0 +1,44 @@
1
+ import {invariant} from './utils'
2
+
3
+ /**
4
+ * https://tc39.es/ecma402/#sec-unicodeextensionvalue
5
+ * @param extension
6
+ * @param key
7
+ */
8
+ export function UnicodeExtensionValue(extension: string, key: string) {
9
+ invariant(key.length === 2, 'key must have 2 elements')
10
+ const size = extension.length
11
+ let searchValue = `-${key}-`
12
+ let pos = extension.indexOf(searchValue)
13
+ if (pos !== -1) {
14
+ const start = pos + 4
15
+ let end = start
16
+ let k = start
17
+ let done = false
18
+ while (!done) {
19
+ const e = extension.indexOf('-', k)
20
+ let len
21
+ if (e === -1) {
22
+ len = size - k
23
+ } else {
24
+ len = e - k
25
+ }
26
+ if (len === 2) {
27
+ done = true
28
+ } else if (e === -1) {
29
+ end = size
30
+ done = true
31
+ } else {
32
+ end = e
33
+ k = e + 1
34
+ }
35
+ }
36
+ return extension.slice(start, end)
37
+ }
38
+ searchValue = `-${key}`
39
+ pos = extension.indexOf(searchValue)
40
+ if (pos !== -1 && pos + 3 === size) {
41
+ return ''
42
+ }
43
+ return undefined
44
+ }
@@ -0,0 +1,5 @@
1
+ export interface LookupMatcherResult {
2
+ locale: string
3
+ extension?: string
4
+ nu?: string
5
+ }
@@ -0,0 +1,11 @@
1
+ export const UNICODE_EXTENSION_SEQUENCE_REGEX = /-u(?:-[0-9a-z]{2,8})+/gi
2
+
3
+ export function invariant(
4
+ condition: boolean,
5
+ message: string,
6
+ Err: any = Error
7
+ ): asserts condition {
8
+ if (!condition) {
9
+ throw new Err(message)
10
+ }
11
+ }
package/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ import {CanonicalizeLocaleList} from './abstract/CanonicalizeLocaleList'
2
+ import {ResolveLocale} from './abstract/ResolveLocale'
3
+
4
+ export interface Opts {
5
+ algorithm: 'lookup' | 'best fit'
6
+ }
7
+
8
+ export function match(
9
+ requestedLocales: string[],
10
+ availableLocales: string[],
11
+ defaultLocale: string,
12
+ opts?: Opts
13
+ ): string {
14
+ const locales = availableLocales.reduce((all, l) => {
15
+ all.add(l)
16
+ return all
17
+ }, new Set<string>())
18
+
19
+ return ResolveLocale(
20
+ locales,
21
+ CanonicalizeLocaleList(requestedLocales),
22
+ {
23
+ localeMatcher: opts?.algorithm || 'best fit',
24
+ },
25
+ [],
26
+ {},
27
+ () => defaultLocale
28
+ ).locale
29
+ }
30
+
31
+ export {LookupSupportedLocales} from './abstract/LookupSupportedLocales'
32
+ export {ResolveLocale} from './abstract/ResolveLocale'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formatjs/intl-localematcher",
3
- "version": "0.2.28",
3
+ "version": "0.2.29",
4
4
  "description": "Intl.LocaleMatcher ponyfill",
5
5
  "keywords": [
6
6
  "intl",
@@ -27,4 +27,4 @@
27
27
  "dependencies": {
28
28
  "tslib": "2.4.0"
29
29
  }
30
- }
30
+ }
@@ -0,0 +1,23 @@
1
+ import {BestFitMatcher} from '../abstract/BestFitMatcher'
2
+
3
+ test('BestFitMatcher', function () {
4
+ expect(
5
+ BestFitMatcher(new Set(['fr', 'en']), ['fr-XX', 'en'], () => 'en')
6
+ ).toEqual({
7
+ locale: 'fr',
8
+ })
9
+ })
10
+
11
+ test('BestFitMatcher zh-TW', function () {
12
+ expect(
13
+ BestFitMatcher(new Set(['zh', 'zh-Hant']), ['zh-TW'], () => 'en')
14
+ ).toEqual({
15
+ locale: 'zh-Hant',
16
+ })
17
+ })
18
+
19
+ test('BestFitMatcher en', function () {
20
+ expect(BestFitMatcher(new Set(['en', 'und']), ['en'], () => 'en')).toEqual({
21
+ locale: 'en',
22
+ })
23
+ })
@@ -0,0 +1,17 @@
1
+ import {LookupMatcher} from '../abstract/LookupMatcher'
2
+
3
+ test('LookupMatcher', function () {
4
+ expect(
5
+ LookupMatcher(new Set(['fr', 'en']), ['fr-XX', 'en'], () => 'en')
6
+ ).toEqual({
7
+ locale: 'fr',
8
+ })
9
+ })
10
+
11
+ test('LookupMatcher', function () {
12
+ expect(
13
+ LookupMatcher(new Set(['zh', 'zh-Hant']), ['zh-Hans'], () => 'en')
14
+ ).toEqual({
15
+ locale: 'zh',
16
+ })
17
+ })