ilib-localematcher 1.0.0 → 1.0.1
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.
- package/README.md +11 -2
- package/docs/LocaleMatcher.html +1 -1
- package/docs/LocaleMatcher.js.html +1 -1
- package/docs/ilibLocaleMatcher.md +235 -0
- package/docs/index.html +1 -1
- package/lib/LocaleMatcher.js +1 -1
- package/lib/LocaleMatcher.js.map +1 -1
- package/lib/ilib-localematcher-web.js +11 -11
- package/package.json +28 -26
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ for specifics.
|
|
|
48
48
|
|
|
49
49
|
## License
|
|
50
50
|
|
|
51
|
-
Copyright © 2021, JEDLSoft
|
|
51
|
+
Copyright © 2021-2022, JEDLSoft
|
|
52
52
|
|
|
53
53
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
54
54
|
you may not use this file except in compliance with the License.
|
|
@@ -65,7 +65,16 @@ limitations under the License.
|
|
|
65
65
|
|
|
66
66
|
## Release Notes
|
|
67
67
|
|
|
68
|
+
### v1.0.2
|
|
69
|
+
|
|
70
|
+
- updated dependencies
|
|
71
|
+
- added docs in markdown format as well
|
|
72
|
+
|
|
73
|
+
### v1.0.1
|
|
74
|
+
|
|
75
|
+
- updated dependencies
|
|
76
|
+
|
|
68
77
|
### v1.0.0
|
|
69
78
|
|
|
70
79
|
- initial version
|
|
71
|
-
- copied from ilib 14.9.0
|
|
80
|
+
- copied from ilib 14.9.0
|
package/docs/LocaleMatcher.html
CHANGED
|
@@ -1225,7 +1225,7 @@ current locale and other locale
|
|
|
1225
1225
|
<br class="clear">
|
|
1226
1226
|
|
|
1227
1227
|
<footer>
|
|
1228
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.
|
|
1228
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.10</a> on Mon Mar 14 2022 16:28:47 GMT-0700 (Pacific Daylight Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1229
1229
|
</footer>
|
|
1230
1230
|
|
|
1231
1231
|
<script>prettyPrint();</script>
|
|
@@ -451,7 +451,7 @@ export default LocaleMatcher;
|
|
|
451
451
|
<br class="clear">
|
|
452
452
|
|
|
453
453
|
<footer>
|
|
454
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.
|
|
454
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.10</a> on Mon Mar 14 2022 16:28:47 GMT-0700 (Pacific Daylight Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
455
455
|
</footer>
|
|
456
456
|
|
|
457
457
|
<script>prettyPrint();</script>
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<a name="LocaleMatcher"></a>
|
|
2
|
+
|
|
3
|
+
## LocaleMatcher
|
|
4
|
+
Represent a locale matcher instance, which is used
|
|
5
|
+
to see which locales can be matched with each other in
|
|
6
|
+
various ways.
|
|
7
|
+
|
|
8
|
+
**Kind**: global class
|
|
9
|
+
|
|
10
|
+
* [LocaleMatcher](#LocaleMatcher)
|
|
11
|
+
* [new LocaleMatcher(options)](#new_LocaleMatcher_new)
|
|
12
|
+
* [.getLocale()](#LocaleMatcher+getLocale) ⇒ <code>Locale</code> \| <code>undefined</code>
|
|
13
|
+
* [.getLikelyLocale()](#LocaleMatcher+getLikelyLocale) ⇒ <code>Locale</code>
|
|
14
|
+
* [.getLikelyLocaleMinimal()](#LocaleMatcher+getLikelyLocaleMinimal) ⇒ <code>Locale</code>
|
|
15
|
+
* [.match(locale)](#LocaleMatcher+match) ⇒ <code>number</code>
|
|
16
|
+
* [.getMacroLanguage()](#LocaleMatcher+getMacroLanguage) ⇒ <code>string</code>
|
|
17
|
+
* [.getRegionContainment()](#LocaleMatcher+getRegionContainment) ⇒ <code>Array.<string></code>
|
|
18
|
+
* [.smallestCommonRegion(otherLocale)](#LocaleMatcher+smallestCommonRegion) ⇒ <code>string</code>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
* * *
|
|
22
|
+
|
|
23
|
+
<a name="new_LocaleMatcher_new"></a>
|
|
24
|
+
|
|
25
|
+
### new LocaleMatcher(options)
|
|
26
|
+
Create a new locale matcher instance. This is used
|
|
27
|
+
to see which locales can be matched with each other in
|
|
28
|
+
various ways.<p>
|
|
29
|
+
|
|
30
|
+
The options object may contain any of the following properties:
|
|
31
|
+
|
|
32
|
+
<ul>
|
|
33
|
+
<li><i>locale</i> - the locale instance or locale spec to match
|
|
34
|
+
</ul>
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
| Param | Type | Description |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| options | <code>Object</code> | parameters to initialize this matcher |
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
* * *
|
|
43
|
+
|
|
44
|
+
<a name="LocaleMatcher+getLocale"></a>
|
|
45
|
+
|
|
46
|
+
### localeMatcher.getLocale() ⇒ <code>Locale</code> \| <code>undefined</code>
|
|
47
|
+
Return the locale used to construct this instance.
|
|
48
|
+
|
|
49
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
50
|
+
**Returns**: <code>Locale</code> \| <code>undefined</code> - the locale for this matcher
|
|
51
|
+
|
|
52
|
+
* * *
|
|
53
|
+
|
|
54
|
+
<a name="LocaleMatcher+getLikelyLocale"></a>
|
|
55
|
+
|
|
56
|
+
### localeMatcher.getLikelyLocale() ⇒ <code>Locale</code>
|
|
57
|
+
Return an Locale instance that is fully specified based on partial information
|
|
58
|
+
given to the constructor of this locale matcher instance. For example, if the locale
|
|
59
|
+
spec given to this locale matcher instance is simply "ru" (for the Russian language),
|
|
60
|
+
then it will fill in the missing region and script tags and return a locale with
|
|
61
|
+
the specifier "ru-Cyrl-RU". (ie. Russian language, Cyrillic, Russian Federation).
|
|
62
|
+
Any one or two of the language, script, or region parts may be left unspecified,
|
|
63
|
+
and the other one or two parts will be filled in automatically. If this
|
|
64
|
+
class has no information about the given locale, then the locale of this
|
|
65
|
+
locale matcher instance is returned unchanged.
|
|
66
|
+
|
|
67
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
68
|
+
**Returns**: <code>Locale</code> - the most likely completion of the partial locale given
|
|
69
|
+
to the constructor of this locale matcher instance
|
|
70
|
+
|
|
71
|
+
* * *
|
|
72
|
+
|
|
73
|
+
<a name="LocaleMatcher+getLikelyLocaleMinimal"></a>
|
|
74
|
+
|
|
75
|
+
### localeMatcher.getLikelyLocaleMinimal() ⇒ <code>Locale</code>
|
|
76
|
+
Return an Locale instance that is specified based on partial information
|
|
77
|
+
given to the constructor of this locale matcher instance but which leaves out any
|
|
78
|
+
part of the locale specifier that is so common that it is understood. For example,
|
|
79
|
+
if the locale
|
|
80
|
+
spec given to this locale matcher instance is simply "ru" (for the Russian language),
|
|
81
|
+
then it will fill in the missing region and/or script tags and return a locale with
|
|
82
|
+
the specifier "ru-RU". (ie. Russian language, Russian Federation). Note that the
|
|
83
|
+
default script "Cyrl" is left out because the vast majority of text written in
|
|
84
|
+
Russian is written with the Cyrllic script, so that part of the locale is understood
|
|
85
|
+
and is commonly left out.<p>
|
|
86
|
+
|
|
87
|
+
Any one or two of the language, script, or region parts may be left unspecified,
|
|
88
|
+
and the other one or two parts will be filled in automatically. If this
|
|
89
|
+
class has no information about the given locale, then the locale of this
|
|
90
|
+
locale matcher instance is returned unchanged.<p>
|
|
91
|
+
|
|
92
|
+
This method returns the same information as getLikelyLocale but with the very common
|
|
93
|
+
parts left out.
|
|
94
|
+
|
|
95
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
96
|
+
**Returns**: <code>Locale</code> - the most likely "minimal" completion of the partial locale given
|
|
97
|
+
to the constructor of this locale matcher instance where the commonly understood
|
|
98
|
+
parts are left out.
|
|
99
|
+
|
|
100
|
+
* * *
|
|
101
|
+
|
|
102
|
+
<a name="LocaleMatcher+match"></a>
|
|
103
|
+
|
|
104
|
+
### localeMatcher.match(locale) ⇒ <code>number</code>
|
|
105
|
+
Return the degree that the given locale matches the current locale of this
|
|
106
|
+
matcher. This method returns an integer from 0 to 100. A value of 100 is
|
|
107
|
+
a 100% match, meaning that the two locales are exactly equivalent to each
|
|
108
|
+
other. (eg. "ja-JP" and "ja-JP") A value of 0 means that there 0% match or
|
|
109
|
+
that the two locales have nothing in common. (eg. "en-US" and "ja-JP") <p>
|
|
110
|
+
|
|
111
|
+
Locale matching is not the same as equivalence, as the degree of matching
|
|
112
|
+
is returned. (See Locale.equals for equivalence.)<p>
|
|
113
|
+
|
|
114
|
+
The match score is calculated based on matching the 4 locale components,
|
|
115
|
+
weighted by importance:
|
|
116
|
+
|
|
117
|
+
<ul>
|
|
118
|
+
<li> language - this accounts for 50% of the match score
|
|
119
|
+
<li> region - accounts for 25% of the match score
|
|
120
|
+
<li> script - accounts for 20% of the match score
|
|
121
|
+
<li> variant - accounts for 5% of the match score
|
|
122
|
+
</ul>
|
|
123
|
+
|
|
124
|
+
The score is affected by the following things:
|
|
125
|
+
|
|
126
|
+
<ul>
|
|
127
|
+
<li> A large language score is given when the language components of the locales
|
|
128
|
+
match exactly.
|
|
129
|
+
<li> Higher language scores are given when the languages are linguistically
|
|
130
|
+
close to each other, such as dialects.
|
|
131
|
+
<li> A small score is given when two languages are in the same
|
|
132
|
+
linguistic family, but one is not a dialect of the other, such as German
|
|
133
|
+
and Dutch.
|
|
134
|
+
<li> A large region score is given when two locales share the same region.
|
|
135
|
+
<li> A smaller region score is given when one region is contained within
|
|
136
|
+
another. For example, Hong Kong is part of China, so a moderate score is
|
|
137
|
+
given instead of a full score.
|
|
138
|
+
<li> A small score is given if two regions are geographically close to
|
|
139
|
+
each other or are tied by history. For example, Ireland and Great Britain
|
|
140
|
+
are both adjacent and tied by history, so they receive a moderate score.
|
|
141
|
+
<li> A high script score is given if the two locales share the same script.
|
|
142
|
+
The legibility of a common script means that there is some small kinship of the
|
|
143
|
+
different languages.
|
|
144
|
+
<li> A high variant score is given if the two locales share the same
|
|
145
|
+
variant. Full score is given when both locales have no variant at all.
|
|
146
|
+
<li> Locale components that are unspecified in both locales are given high
|
|
147
|
+
scores.
|
|
148
|
+
<li> Locales where a particular locale component is missing in only one
|
|
149
|
+
locale can still match when the default for that locale component matches
|
|
150
|
+
the component in the other locale. The
|
|
151
|
+
default value for the missing component is determined using the likely locales
|
|
152
|
+
data. (See getLikelyLocale()) For example, "en-US" and "en-Latn-US" receive
|
|
153
|
+
a high script score because the default script for "en" is "Latn".
|
|
154
|
+
</ul>
|
|
155
|
+
|
|
156
|
+
The intention of this method is that it can be used to determine
|
|
157
|
+
compatibility of locales. For example, when a user signs up for an
|
|
158
|
+
account on a web site, the locales that the web site supports and
|
|
159
|
+
the locale of the user's browser may differ, and the site needs to
|
|
160
|
+
pick the best locale to show the user. Let's say the
|
|
161
|
+
web site supports a selection of European languages such as "it-IT",
|
|
162
|
+
"fr-FR", "de-DE", and "en-GB". The user's
|
|
163
|
+
browser may be set to "it-CH". The web site code can then match "it-CH"
|
|
164
|
+
against each of the supported locales to find the one with the
|
|
165
|
+
highest score. In
|
|
166
|
+
this case, the best match would be "it-IT" because it shares a
|
|
167
|
+
language and script in common with "it-CH" and differs only in the region
|
|
168
|
+
component. It is not a 100% match, but it is pretty good. The web site
|
|
169
|
+
may decide if the match scores all fall
|
|
170
|
+
below a chosen threshold (perhaps 50%?), it should show the user the
|
|
171
|
+
default language "en-GB", because that is probably a better choice
|
|
172
|
+
than any other supported locale.<p>
|
|
173
|
+
|
|
174
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
175
|
+
**Returns**: <code>number</code> - an integer from 0 to 100 that indicates the degree to
|
|
176
|
+
which these locales match each other
|
|
177
|
+
|
|
178
|
+
| Param | Type | Description |
|
|
179
|
+
| --- | --- | --- |
|
|
180
|
+
| locale | <code>Locale</code> | the other locale to match against the current one |
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
* * *
|
|
184
|
+
|
|
185
|
+
<a name="LocaleMatcher+getMacroLanguage"></a>
|
|
186
|
+
|
|
187
|
+
### localeMatcher.getMacroLanguage() ⇒ <code>string</code>
|
|
188
|
+
Return the macrolanguage associated with this locale. If the
|
|
189
|
+
locale's language is not part of a macro-language, then the
|
|
190
|
+
locale's language is returned as-is.
|
|
191
|
+
|
|
192
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
193
|
+
**Returns**: <code>string</code> - the ISO code for the macrolanguage associated
|
|
194
|
+
with this locale, or language of the locale
|
|
195
|
+
|
|
196
|
+
* * *
|
|
197
|
+
|
|
198
|
+
<a name="LocaleMatcher+getRegionContainment"></a>
|
|
199
|
+
|
|
200
|
+
### localeMatcher.getRegionContainment() ⇒ <code>Array.<string></code>
|
|
201
|
+
Return the list of regions that this locale is contained within. Regions are
|
|
202
|
+
nested, so locales can be in multiple regions. (eg. US is in Northern North
|
|
203
|
+
America, North America, the Americas, the World.) Most regions are specified
|
|
204
|
+
using UN.49 region numbers, though some, like "EU", are letters. If the
|
|
205
|
+
locale is underspecified, this method will use the most likely locale method
|
|
206
|
+
to get the region first. For example, the locale "ja" (Japanese) is most
|
|
207
|
+
likely "ja-JP" (Japanese for Japan), and the region containment info for Japan
|
|
208
|
+
is returned.
|
|
209
|
+
|
|
210
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
211
|
+
**Returns**: <code>Array.<string></code> - an array of region specifiers that this locale is within
|
|
212
|
+
|
|
213
|
+
* * *
|
|
214
|
+
|
|
215
|
+
<a name="LocaleMatcher+smallestCommonRegion"></a>
|
|
216
|
+
|
|
217
|
+
### localeMatcher.smallestCommonRegion(otherLocale) ⇒ <code>string</code>
|
|
218
|
+
Find the smallest region that contains both the current locale and the other locale.
|
|
219
|
+
If the current or other locales are underspecified, this method will use the most
|
|
220
|
+
likely locale method
|
|
221
|
+
to get their regions first. For example, the locale "ja" (Japanese) is most
|
|
222
|
+
likely "ja-JP" (Japanese for Japan), and the region containment info for Japan
|
|
223
|
+
is checked against the other locale's region containment info.
|
|
224
|
+
|
|
225
|
+
**Kind**: instance method of [<code>LocaleMatcher</code>](#LocaleMatcher)
|
|
226
|
+
**Returns**: <code>string</code> - the region specifier of the smallest region containing both the
|
|
227
|
+
current locale and other locale
|
|
228
|
+
|
|
229
|
+
| Param | Type | Description |
|
|
230
|
+
| --- | --- | --- |
|
|
231
|
+
| otherLocale | <code>string</code> \| <code>Locale</code> | a locale specifier or a Locale instance to compare against |
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
* * *
|
|
235
|
+
|
package/docs/index.html
CHANGED
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
<br class="clear">
|
|
69
69
|
|
|
70
70
|
<footer>
|
|
71
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.
|
|
71
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.10</a> on Mon Mar 14 2022 16:28:47 GMT-0700 (Pacific Daylight Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
72
72
|
</footer>
|
|
73
73
|
|
|
74
74
|
<script>prettyPrint();</script>
|
package/lib/LocaleMatcher.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports["default"]=void 0;var _ilibCommon=require("ilib-common");var _ilibLocale=_interopRequireDefault(require("ilib-locale"));var _localematch=_interopRequireDefault(require("../locale/localematch.json"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{"default":obj}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor}var componentWeights=[0.5,0.2,0.25,0.05];var multiScriptLanguages={"az":true,"kk":true,"ku":true,"ky":true,"pa":true,"sr":true,"tg":true,"uz":true,"zh":true};var LocaleMatcher=function(){function LocaleMatcher(options){_classCallCheck(this,LocaleMatcher);this.locale=new _ilibLocale["default"];if(options&&typeof options.locale!=="undefined"){this.locale=typeof options.locale==="string"?new _ilibLocale["default"](options.locale):options.locale}}_createClass(LocaleMatcher,[{key:"getLocale",value:function getLocale(){return this.locale}},{key:"_getLikelyLocale",value:function _getLikelyLocale(locale){if(locale.language&&locale.script&&locale.region)return locale;if(typeof _localematch["default"].likelyLocales[locale.getSpec()]==="undefined"){var partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,undefined,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,locale.script,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,undefined,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,locale.script,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,undefined,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,locale.script,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);return locale}return new _ilibLocale["default"](_localematch["default"].likelyLocales[locale.getSpec()])}},{key:"getLikelyLocale",value:function getLikelyLocale(){return this._getLikelyLocale(this.locale)}},{key:"getLikelyLocaleMinimal",value:function getLikelyLocaleMinimal(){var fullLocale=this._getLikelyLocale(this.locale);var langLocale=this._getLikelyLocale(new _ilibLocale["default"](fullLocale.language));return fullLocale.script===langLocale.script&&!multiScriptLanguages[fullLocale.language]?new _ilibLocale["default"](fullLocale.language,undefined,fullLocale.region):fullLocale}},{key:"match",value:function match(locale){var other=new _ilibLocale["default"](locale);var scores=[0,0,0,0];var thisfull,otherfull,i;if(this.locale.language===other.language){scores[0]=100}else{if(!this.locale.language||!other.language){thisfull=this.getLikelyLocale();otherfull=new _ilibLocale["default"](_localematch["default"].likelyLocales[other.getSpec()]||other.getSpec());if(thisfull.language===otherfull.language){scores[0]=100}}else{var mlthis=_localematch["default"].macroLanguagesReverse[this.locale.language]||this.locale.language;var mlother=_localematch["default"].macroLanguagesReverse[other.language]||other.language;if(mlthis===mlother){scores[0]=90}else{var pair=this.locale.language+"-"+other.language;scores[0]=_localematch["default"].mutualIntelligibility[pair]||0}}}if(this.locale.script===other.script){scores[1]=100}else{if(!this.locale.script||!other.script){thisfull=this.locale.script?this.locale:new _ilibLocale["default"](_localematch["default"].likelyLocales[this.locale.language]);otherfull=other.script?other:new _ilibLocale["default"](_localematch["default"].likelyLocales[other.language]);if(thisfull.script===otherfull.script){scores[1]=100}}}if(this.locale.region===other.region){scores[2]=100}else{if(!this.locale.region||!other.region){thisfull=this.getLikelyLocale();otherfull=new _ilibLocale["default"](_localematch["default"].likelyLocales[other.getSpec()]||other.getSpec());if(thisfull.region===otherfull.region){scores[2]=100}}else{var containers=_localematch["default"].territoryContainmentReverse[this.locale.region]||[];for(i=containers.length-1;i>0;i--){var container=_localematch["default"].territoryContainment[containers[i]];if(container&&container.indexOf(other.region)>-1){scores[2]=(i+1)*100/containers.length*0.2;break}}}}if(this.locale.variant===other.variant){scores[3]=100}var total=0;for(i=0;i<4;i++){total+=scores[i]*componentWeights[i]}return Math.round(total)}},{key:"getMacroLanguage",value:function getMacroLanguage(){return _localematch["default"].macroLanguagesReverse[this.locale.language]||this.locale.language}},{key:"_getRegionContainment",value:function _getRegionContainment(region){return _localematch["default"].territoryContainmentReverse[region]||[]}},{key:"getRegionContainment",value:function getRegionContainment(){var region=this.locale.region||this.getLikelyLocale().region;return this._getRegionContainment(region)}},{key:"smallestCommonRegion",value:function smallestCommonRegion(otherLocale){if(typeof otherLocale==="undefined")return"001";var thisRegion=this.locale.region||this.getLikelyLocale().region;var otherLoc=typeof otherLocale==="string"?new _ilibLocale["default"](otherLocale):otherLocale;var otherRegion=this._getLikelyLocale(otherLoc).region;var thisRegions=this._getRegionContainment(thisRegion);var otherRegions=this._getRegionContainment(otherRegion);for(var i=thisRegions.length-1;i>0;i--){if(otherRegions.indexOf(thisRegions[i])>-1){return thisRegions[i]}}return"001"}}]);return LocaleMatcher}();;var _default=LocaleMatcher;exports["default"]=_default;module.exports=exports.default;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports["default"]=void 0;var _ilibCommon=require("ilib-common");var _ilibLocale=_interopRequireDefault(require("ilib-locale"));var _localematch=_interopRequireDefault(require("../locale/localematch.json"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{"default":obj}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);Object.defineProperty(Constructor,"prototype",{writable:false});return Constructor}var componentWeights=[0.5,0.2,0.25,0.05];var multiScriptLanguages={"az":true,"kk":true,"ku":true,"ky":true,"pa":true,"sr":true,"tg":true,"uz":true,"zh":true};var LocaleMatcher=function(){function LocaleMatcher(options){_classCallCheck(this,LocaleMatcher);this.locale=new _ilibLocale["default"];if(options&&typeof options.locale!=="undefined"){this.locale=typeof options.locale==="string"?new _ilibLocale["default"](options.locale):options.locale}}_createClass(LocaleMatcher,[{key:"getLocale",value:function getLocale(){return this.locale}},{key:"_getLikelyLocale",value:function _getLikelyLocale(locale){if(locale.language&&locale.script&&locale.region)return locale;if(typeof _localematch["default"].likelyLocales[locale.getSpec()]==="undefined"){var partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,undefined,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,locale.script,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](locale.language,undefined,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,locale.script,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,undefined,locale.region).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);partial=_localematch["default"].likelyLocales[new _ilibLocale["default"](undefined,locale.script,undefined).getSpec()];if(typeof partial!=="undefined")return new _ilibLocale["default"](partial);return locale}return new _ilibLocale["default"](_localematch["default"].likelyLocales[locale.getSpec()])}},{key:"getLikelyLocale",value:function getLikelyLocale(){return this._getLikelyLocale(this.locale)}},{key:"getLikelyLocaleMinimal",value:function getLikelyLocaleMinimal(){var fullLocale=this._getLikelyLocale(this.locale);var langLocale=this._getLikelyLocale(new _ilibLocale["default"](fullLocale.language));return fullLocale.script===langLocale.script&&!multiScriptLanguages[fullLocale.language]?new _ilibLocale["default"](fullLocale.language,undefined,fullLocale.region):fullLocale}},{key:"match",value:function match(locale){var other=new _ilibLocale["default"](locale);var scores=[0,0,0,0];var thisfull,otherfull,i;if(this.locale.language===other.language){scores[0]=100}else{if(!this.locale.language||!other.language){thisfull=this.getLikelyLocale();otherfull=new _ilibLocale["default"](_localematch["default"].likelyLocales[other.getSpec()]||other.getSpec());if(thisfull.language===otherfull.language){scores[0]=100}}else{var mlthis=_localematch["default"].macroLanguagesReverse[this.locale.language]||this.locale.language;var mlother=_localematch["default"].macroLanguagesReverse[other.language]||other.language;if(mlthis===mlother){scores[0]=90}else{var pair=this.locale.language+"-"+other.language;scores[0]=_localematch["default"].mutualIntelligibility[pair]||0}}}if(this.locale.script===other.script){scores[1]=100}else{if(!this.locale.script||!other.script){thisfull=this.locale.script?this.locale:new _ilibLocale["default"](_localematch["default"].likelyLocales[this.locale.language]);otherfull=other.script?other:new _ilibLocale["default"](_localematch["default"].likelyLocales[other.language]);if(thisfull.script===otherfull.script){scores[1]=100}}}if(this.locale.region===other.region){scores[2]=100}else{if(!this.locale.region||!other.region){thisfull=this.getLikelyLocale();otherfull=new _ilibLocale["default"](_localematch["default"].likelyLocales[other.getSpec()]||other.getSpec());if(thisfull.region===otherfull.region){scores[2]=100}}else{var containers=_localematch["default"].territoryContainmentReverse[this.locale.region]||[];for(i=containers.length-1;i>0;i--){var container=_localematch["default"].territoryContainment[containers[i]];if(container&&container.indexOf(other.region)>-1){scores[2]=(i+1)*100/containers.length*0.2;break}}}}if(this.locale.variant===other.variant){scores[3]=100}var total=0;for(i=0;i<4;i++){total+=scores[i]*componentWeights[i]}return Math.round(total)}},{key:"getMacroLanguage",value:function getMacroLanguage(){return _localematch["default"].macroLanguagesReverse[this.locale.language]||this.locale.language}},{key:"_getRegionContainment",value:function _getRegionContainment(region){return _localematch["default"].territoryContainmentReverse[region]||[]}},{key:"getRegionContainment",value:function getRegionContainment(){var region=this.locale.region||this.getLikelyLocale().region;return this._getRegionContainment(region)}},{key:"smallestCommonRegion",value:function smallestCommonRegion(otherLocale){if(typeof otherLocale==="undefined")return"001";var thisRegion=this.locale.region||this.getLikelyLocale().region;var otherLoc=typeof otherLocale==="string"?new _ilibLocale["default"](otherLocale):otherLocale;var otherRegion=this._getLikelyLocale(otherLoc).region;var thisRegions=this._getRegionContainment(thisRegion);var otherRegions=this._getRegionContainment(otherRegion);for(var i=thisRegions.length-1;i>0;i--){if(otherRegions.indexOf(thisRegions[i])>-1){return thisRegions[i]}}return"001"}}]);return LocaleMatcher}();;var _default=LocaleMatcher;exports["default"]=_default;module.exports=exports.default;
|
|
2
2
|
//# sourceMappingURL=LocaleMatcher.js.map
|
package/lib/LocaleMatcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/LocaleMatcher.js"],"names":["componentWeights","multiScriptLanguages","LocaleMatcher","options","locale","Locale","language","script","region","matchdata","likelyLocales","getSpec","partial","undefined","_getLikelyLocale","fullLocale","langLocale","other","scores","thisfull","otherfull","i","getLikelyLocale","mlthis","macroLanguagesReverse","mlother","pair","mutualIntelligibility","containers","territoryContainmentReverse","length","container","territoryContainment","indexOf","variant","total","Math","round","_getRegionContainment","otherLocale","thisRegion","otherLoc","otherRegion","thisRegions","otherRegions"],"mappings":"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","sourcesContent":["/*\n * LocaleMatcher.js - Locale matcher definition\n *\n * Copyright © 2013-2015, 2018-2019, 2021 JEDLSoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// !data localematch\n\nimport { Utils } from 'ilib-common';\nimport Locale from 'ilib-locale';\n\nimport matchdata from '../locale/localematch.json';\n\nconst componentWeights = [\n 0.5, // language\n 0.2, // script\n 0.25, // region\n 0.05 // variant\n];\n\n// these are languages where you have to put the script all the time,\n// as none of the scripts are default for the language\nconst multiScriptLanguages = {\n \"az\": true, // Azerbaijani\n \"kk\": true, // Kazakh\n \"ku\": true, // Kurdish\n \"ky\": true, // Kyrgyz\n \"pa\": true, // Panjabi\n \"sr\": true, // Serbian\n \"tg\": true, // Tajik\n \"uz\": true, // Uzbek\n \"zh\": true // Chinese\n};\n\n/**\n * @class Represent a locale matcher instance, which is used\n * to see which locales can be matched with each other in\n * various ways.\n */\nclass LocaleMatcher {\n /**\n * Create a new locale matcher instance. This is used\n * to see which locales can be matched with each other in\n * various ways.<p>\n *\n * The options object may contain any of the following properties:\n *\n * <ul>\n * <li><i>locale</i> - the locale instance or locale spec to match\n * </ul>\n *\n * @constructor\n * @param {Object} options parameters to initialize this matcher\n */\n constructor(options) {\n this.locale = new Locale();\n\n if (options && typeof(options.locale) !== 'undefined') {\n this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;\n }\n }\n\n /**\n * Return the locale used to construct this instance.\n * @return {Locale|undefined} the locale for this matcher\n */\n getLocale() {\n return this.locale;\n }\n\n /**\n * Do the work\n * @private\n */\n _getLikelyLocale(locale) {\n // already full specified\n if (locale.language && locale.script && locale.region) return locale;\n\n if (typeof(matchdata.likelyLocales[locale.getSpec()]) === 'undefined') {\n // try various partials before giving up\n let partial = matchdata.likelyLocales[new Locale(locale.language, undefined, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(locale.language, locale.script, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(locale.language, undefined, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, locale.script, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, undefined, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, locale.script, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n return locale;\n }\n\n return new Locale(matchdata.likelyLocales[locale.getSpec()]);\n }\n\n /**\n * Return an Locale instance that is fully specified based on partial information\n * given to the constructor of this locale matcher instance. For example, if the locale\n * spec given to this locale matcher instance is simply \"ru\" (for the Russian language),\n * then it will fill in the missing region and script tags and return a locale with\n * the specifier \"ru-Cyrl-RU\". (ie. Russian language, Cyrillic, Russian Federation).\n * Any one or two of the language, script, or region parts may be left unspecified,\n * and the other one or two parts will be filled in automatically. If this\n * class has no information about the given locale, then the locale of this\n * locale matcher instance is returned unchanged.\n *\n * @returns {Locale} the most likely completion of the partial locale given\n * to the constructor of this locale matcher instance\n */\n getLikelyLocale() {\n return this._getLikelyLocale(this.locale);\n }\n\n /**\n * Return an Locale instance that is specified based on partial information\n * given to the constructor of this locale matcher instance but which leaves out any\n * part of the locale specifier that is so common that it is understood. For example,\n * if the locale\n * spec given to this locale matcher instance is simply \"ru\" (for the Russian language),\n * then it will fill in the missing region and/or script tags and return a locale with\n * the specifier \"ru-RU\". (ie. Russian language, Russian Federation). Note that the\n * default script \"Cyrl\" is left out because the vast majority of text written in\n * Russian is written with the Cyrllic script, so that part of the locale is understood\n * and is commonly left out.<p>\n *\n * Any one or two of the language, script, or region parts may be left unspecified,\n * and the other one or two parts will be filled in automatically. If this\n * class has no information about the given locale, then the locale of this\n * locale matcher instance is returned unchanged.<p>\n *\n * This method returns the same information as getLikelyLocale but with the very common\n * parts left out.\n *\n * @returns {Locale} the most likely \"minimal\" completion of the partial locale given\n * to the constructor of this locale matcher instance where the commonly understood\n * parts are left out.\n */\n getLikelyLocaleMinimal() {\n const fullLocale = this._getLikelyLocale(this.locale);\n const langLocale = this._getLikelyLocale(new Locale(fullLocale.language));\n return fullLocale.script === langLocale.script && !multiScriptLanguages[fullLocale.language] ?\n new Locale(fullLocale.language, undefined, fullLocale.region) :\n fullLocale;\n }\n\n /**\n * Return the degree that the given locale matches the current locale of this\n * matcher. This method returns an integer from 0 to 100. A value of 100 is\n * a 100% match, meaning that the two locales are exactly equivalent to each\n * other. (eg. \"ja-JP\" and \"ja-JP\") A value of 0 means that there 0% match or\n * that the two locales have nothing in common. (eg. \"en-US\" and \"ja-JP\") <p>\n *\n * Locale matching is not the same as equivalence, as the degree of matching\n * is returned. (See Locale.equals for equivalence.)<p>\n *\n * The match score is calculated based on matching the 4 locale components,\n * weighted by importance:\n *\n * <ul>\n * <li> language - this accounts for 50% of the match score\n * <li> region - accounts for 25% of the match score\n * <li> script - accounts for 20% of the match score\n * <li> variant - accounts for 5% of the match score\n * </ul>\n *\n * The score is affected by the following things:\n *\n * <ul>\n * <li> A large language score is given when the language components of the locales\n * match exactly.\n * <li> Higher language scores are given when the languages are linguistically\n * close to each other, such as dialects.\n * <li> A small score is given when two languages are in the same\n * linguistic family, but one is not a dialect of the other, such as German\n * and Dutch.\n * <li> A large region score is given when two locales share the same region.\n * <li> A smaller region score is given when one region is contained within\n * another. For example, Hong Kong is part of China, so a moderate score is\n * given instead of a full score.\n * <li> A small score is given if two regions are geographically close to\n * each other or are tied by history. For example, Ireland and Great Britain\n * are both adjacent and tied by history, so they receive a moderate score.\n * <li> A high script score is given if the two locales share the same script.\n * The legibility of a common script means that there is some small kinship of the\n * different languages.\n * <li> A high variant score is given if the two locales share the same\n * variant. Full score is given when both locales have no variant at all.\n * <li> Locale components that are unspecified in both locales are given high\n * scores.\n * <li> Locales where a particular locale component is missing in only one\n * locale can still match when the default for that locale component matches\n * the component in the other locale. The\n * default value for the missing component is determined using the likely locales\n * data. (See getLikelyLocale()) For example, \"en-US\" and \"en-Latn-US\" receive\n * a high script score because the default script for \"en\" is \"Latn\".\n * </ul>\n *\n * The intention of this method is that it can be used to determine\n * compatibility of locales. For example, when a user signs up for an\n * account on a web site, the locales that the web site supports and\n * the locale of the user's browser may differ, and the site needs to\n * pick the best locale to show the user. Let's say the\n * web site supports a selection of European languages such as \"it-IT\",\n * \"fr-FR\", \"de-DE\", and \"en-GB\". The user's\n * browser may be set to \"it-CH\". The web site code can then match \"it-CH\"\n * against each of the supported locales to find the one with the\n * highest score. In\n * this case, the best match would be \"it-IT\" because it shares a\n * language and script in common with \"it-CH\" and differs only in the region\n * component. It is not a 100% match, but it is pretty good. The web site\n * may decide if the match scores all fall\n * below a chosen threshold (perhaps 50%?), it should show the user the\n * default language \"en-GB\", because that is probably a better choice\n * than any other supported locale.<p>\n *\n * @param {Locale} locale the other locale to match against the current one\n * @return {number} an integer from 0 to 100 that indicates the degree to\n * which these locales match each other\n */\n match(locale) {\n const other = new Locale(locale);\n let scores = [0, 0, 0, 0];\n let thisfull, otherfull, i;\n\n if (this.locale.language === other.language) {\n scores[0] = 100;\n } else {\n if (!this.locale.language || !other.language) {\n // check for default language\n thisfull = this.getLikelyLocale();\n otherfull = new Locale(matchdata.likelyLocales[other.getSpec()] || other.getSpec());\n if (thisfull.language === otherfull.language) {\n scores[0] = 100;\n }\n } else {\n // check for macro languages\n const mlthis = matchdata.macroLanguagesReverse[this.locale.language] || this.locale.language;\n const mlother = matchdata.macroLanguagesReverse[other.language] || other.language;\n if (mlthis === mlother) {\n scores[0] = 90;\n } else {\n // check for mutual intelligibility\n const pair = this.locale.language + \"-\" + other.language;\n scores[0] = matchdata.mutualIntelligibility[pair] || 0;\n }\n }\n }\n\n if (this.locale.script === other.script) {\n scores[1] = 100;\n } else {\n if (!this.locale.script || !other.script) {\n // check for default script\n thisfull = this.locale.script ? this.locale : new Locale(matchdata.likelyLocales[this.locale.language]);\n otherfull = other.script ? other : new Locale(matchdata.likelyLocales[other.language]);\n if (thisfull.script === otherfull.script) {\n scores[1] = 100;\n }\n }\n }\n\n if (this.locale.region === other.region) {\n scores[2] = 100;\n } else {\n if (!this.locale.region || !other.region) {\n // check for default region\n thisfull = this.getLikelyLocale();\n otherfull = new Locale(matchdata.likelyLocales[other.getSpec()] || other.getSpec());\n if (thisfull.region === otherfull.region) {\n scores[2] = 100;\n }\n } else {\n // check for containment\n const containers = matchdata.territoryContainmentReverse[this.locale.region] || [];\n // end at 1 because 0 is \"001\" which is \"the whole world\" -- which is not useful\n for (i = containers.length-1; i > 0; i--) {\n const container = matchdata.territoryContainment[containers[i]];\n if (container && container.indexOf(other.region) > -1) {\n // same area only accounts for 20% of the region score\n scores[2] = ((i+1) * 100 / containers.length) * 0.2;\n break;\n }\n }\n }\n }\n\n if (this.locale.variant === other.variant) {\n scores[3] = 100;\n }\n\n let total = 0;\n\n for (i = 0; i < 4; i++) {\n total += scores[i] * componentWeights[i];\n }\n\n return Math.round(total);\n }\n\n /**\n * Return the macrolanguage associated with this locale. If the\n * locale's language is not part of a macro-language, then the\n * locale's language is returned as-is.\n *\n * @returns {string} the ISO code for the macrolanguage associated\n * with this locale, or language of the locale\n */\n getMacroLanguage() {\n return matchdata.macroLanguagesReverse[this.locale.language] || this.locale.language;\n }\n\n /**\n * Return the containment array for the given region code.\n * @private\n */\n _getRegionContainment(region) {\n return matchdata.territoryContainmentReverse[region] || [];\n }\n\n /**\n * Return the list of regions that this locale is contained within. Regions are\n * nested, so locales can be in multiple regions. (eg. US is in Northern North\n * America, North America, the Americas, the World.) Most regions are specified\n * using UN.49 region numbers, though some, like \"EU\", are letters. If the\n * locale is underspecified, this method will use the most likely locale method\n * to get the region first. For example, the locale \"ja\" (Japanese) is most\n * likely \"ja-JP\" (Japanese for Japan), and the region containment info for Japan\n * is returned.\n *\n * @returns {Array.<string>} an array of region specifiers that this locale is within\n */\n getRegionContainment() {\n const region = this.locale.region || this.getLikelyLocale().region;\n return this._getRegionContainment(region);\n }\n\n /**\n * Find the smallest region that contains both the current locale and the other locale.\n * If the current or other locales are underspecified, this method will use the most\n * likely locale method\n * to get their regions first. For example, the locale \"ja\" (Japanese) is most\n * likely \"ja-JP\" (Japanese for Japan), and the region containment info for Japan\n * is checked against the other locale's region containment info.\n *\n * @param {string|Locale} otherLocale a locale specifier or a Locale instance to\n * compare against\n * @returns {string} the region specifier of the smallest region containing both the\n * current locale and other locale\n */\n smallestCommonRegion(otherLocale) {\n if (typeof(otherLocale) === \"undefined\") return \"001\";\n\n const thisRegion = this.locale.region || this.getLikelyLocale().region;\n const otherLoc = typeof(otherLocale) === \"string\" ? new Locale(otherLocale) : otherLocale;\n const otherRegion = this._getLikelyLocale(otherLoc).region;\n\n const thisRegions = this._getRegionContainment(thisRegion);\n const otherRegions = this._getRegionContainment(otherRegion);\n\n // region containment arrays are arranged from largest to smallest, so start\n // at the end of the array\n for (let i = thisRegions.length-1; i > 0; i--) {\n if (otherRegions.indexOf(thisRegions[i]) > -1) {\n return thisRegions[i];\n }\n }\n\n // this default should never be reached because the world should be common to all regions\n return \"001\";\n }\n};\n\nexport default LocaleMatcher;\n"],"file":"LocaleMatcher.js"}
|
|
1
|
+
{"version":3,"sources":["../src/LocaleMatcher.js"],"names":["componentWeights","multiScriptLanguages","LocaleMatcher","options","locale","Locale","language","script","region","matchdata","likelyLocales","getSpec","partial","undefined","_getLikelyLocale","fullLocale","langLocale","other","scores","thisfull","otherfull","i","getLikelyLocale","mlthis","macroLanguagesReverse","mlother","pair","mutualIntelligibility","containers","territoryContainmentReverse","length","container","territoryContainment","indexOf","variant","total","Math","round","_getRegionContainment","otherLocale","thisRegion","otherLoc","otherRegion","thisRegions","otherRegions"],"mappings":"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","sourcesContent":["/*\n * LocaleMatcher.js - Locale matcher definition\n *\n * Copyright © 2013-2015, 2018-2019, 2021 JEDLSoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// !data localematch\n\nimport { Utils } from 'ilib-common';\nimport Locale from 'ilib-locale';\n\nimport matchdata from '../locale/localematch.json';\n\nconst componentWeights = [\n 0.5, // language\n 0.2, // script\n 0.25, // region\n 0.05 // variant\n];\n\n// these are languages where you have to put the script all the time,\n// as none of the scripts are default for the language\nconst multiScriptLanguages = {\n \"az\": true, // Azerbaijani\n \"kk\": true, // Kazakh\n \"ku\": true, // Kurdish\n \"ky\": true, // Kyrgyz\n \"pa\": true, // Panjabi\n \"sr\": true, // Serbian\n \"tg\": true, // Tajik\n \"uz\": true, // Uzbek\n \"zh\": true // Chinese\n};\n\n/**\n * @class Represent a locale matcher instance, which is used\n * to see which locales can be matched with each other in\n * various ways.\n */\nclass LocaleMatcher {\n /**\n * Create a new locale matcher instance. This is used\n * to see which locales can be matched with each other in\n * various ways.<p>\n *\n * The options object may contain any of the following properties:\n *\n * <ul>\n * <li><i>locale</i> - the locale instance or locale spec to match\n * </ul>\n *\n * @constructor\n * @param {Object} options parameters to initialize this matcher\n */\n constructor(options) {\n this.locale = new Locale();\n\n if (options && typeof(options.locale) !== 'undefined') {\n this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;\n }\n }\n\n /**\n * Return the locale used to construct this instance.\n * @return {Locale|undefined} the locale for this matcher\n */\n getLocale() {\n return this.locale;\n }\n\n /**\n * Do the work\n * @private\n */\n _getLikelyLocale(locale) {\n // already full specified\n if (locale.language && locale.script && locale.region) return locale;\n\n if (typeof(matchdata.likelyLocales[locale.getSpec()]) === 'undefined') {\n // try various partials before giving up\n let partial = matchdata.likelyLocales[new Locale(locale.language, undefined, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(locale.language, locale.script, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(locale.language, undefined, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, locale.script, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, undefined, locale.region).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n partial = matchdata.likelyLocales[new Locale(undefined, locale.script, undefined).getSpec()];\n if (typeof(partial) !== 'undefined') return new Locale(partial);\n\n return locale;\n }\n\n return new Locale(matchdata.likelyLocales[locale.getSpec()]);\n }\n\n /**\n * Return an Locale instance that is fully specified based on partial information\n * given to the constructor of this locale matcher instance. For example, if the locale\n * spec given to this locale matcher instance is simply \"ru\" (for the Russian language),\n * then it will fill in the missing region and script tags and return a locale with\n * the specifier \"ru-Cyrl-RU\". (ie. Russian language, Cyrillic, Russian Federation).\n * Any one or two of the language, script, or region parts may be left unspecified,\n * and the other one or two parts will be filled in automatically. If this\n * class has no information about the given locale, then the locale of this\n * locale matcher instance is returned unchanged.\n *\n * @returns {Locale} the most likely completion of the partial locale given\n * to the constructor of this locale matcher instance\n */\n getLikelyLocale() {\n return this._getLikelyLocale(this.locale);\n }\n\n /**\n * Return an Locale instance that is specified based on partial information\n * given to the constructor of this locale matcher instance but which leaves out any\n * part of the locale specifier that is so common that it is understood. For example,\n * if the locale\n * spec given to this locale matcher instance is simply \"ru\" (for the Russian language),\n * then it will fill in the missing region and/or script tags and return a locale with\n * the specifier \"ru-RU\". (ie. Russian language, Russian Federation). Note that the\n * default script \"Cyrl\" is left out because the vast majority of text written in\n * Russian is written with the Cyrllic script, so that part of the locale is understood\n * and is commonly left out.<p>\n *\n * Any one or two of the language, script, or region parts may be left unspecified,\n * and the other one or two parts will be filled in automatically. If this\n * class has no information about the given locale, then the locale of this\n * locale matcher instance is returned unchanged.<p>\n *\n * This method returns the same information as getLikelyLocale but with the very common\n * parts left out.\n *\n * @returns {Locale} the most likely \"minimal\" completion of the partial locale given\n * to the constructor of this locale matcher instance where the commonly understood\n * parts are left out.\n */\n getLikelyLocaleMinimal() {\n const fullLocale = this._getLikelyLocale(this.locale);\n const langLocale = this._getLikelyLocale(new Locale(fullLocale.language));\n return fullLocale.script === langLocale.script && !multiScriptLanguages[fullLocale.language] ?\n new Locale(fullLocale.language, undefined, fullLocale.region) :\n fullLocale;\n }\n\n /**\n * Return the degree that the given locale matches the current locale of this\n * matcher. This method returns an integer from 0 to 100. A value of 100 is\n * a 100% match, meaning that the two locales are exactly equivalent to each\n * other. (eg. \"ja-JP\" and \"ja-JP\") A value of 0 means that there 0% match or\n * that the two locales have nothing in common. (eg. \"en-US\" and \"ja-JP\") <p>\n *\n * Locale matching is not the same as equivalence, as the degree of matching\n * is returned. (See Locale.equals for equivalence.)<p>\n *\n * The match score is calculated based on matching the 4 locale components,\n * weighted by importance:\n *\n * <ul>\n * <li> language - this accounts for 50% of the match score\n * <li> region - accounts for 25% of the match score\n * <li> script - accounts for 20% of the match score\n * <li> variant - accounts for 5% of the match score\n * </ul>\n *\n * The score is affected by the following things:\n *\n * <ul>\n * <li> A large language score is given when the language components of the locales\n * match exactly.\n * <li> Higher language scores are given when the languages are linguistically\n * close to each other, such as dialects.\n * <li> A small score is given when two languages are in the same\n * linguistic family, but one is not a dialect of the other, such as German\n * and Dutch.\n * <li> A large region score is given when two locales share the same region.\n * <li> A smaller region score is given when one region is contained within\n * another. For example, Hong Kong is part of China, so a moderate score is\n * given instead of a full score.\n * <li> A small score is given if two regions are geographically close to\n * each other or are tied by history. For example, Ireland and Great Britain\n * are both adjacent and tied by history, so they receive a moderate score.\n * <li> A high script score is given if the two locales share the same script.\n * The legibility of a common script means that there is some small kinship of the\n * different languages.\n * <li> A high variant score is given if the two locales share the same\n * variant. Full score is given when both locales have no variant at all.\n * <li> Locale components that are unspecified in both locales are given high\n * scores.\n * <li> Locales where a particular locale component is missing in only one\n * locale can still match when the default for that locale component matches\n * the component in the other locale. The\n * default value for the missing component is determined using the likely locales\n * data. (See getLikelyLocale()) For example, \"en-US\" and \"en-Latn-US\" receive\n * a high script score because the default script for \"en\" is \"Latn\".\n * </ul>\n *\n * The intention of this method is that it can be used to determine\n * compatibility of locales. For example, when a user signs up for an\n * account on a web site, the locales that the web site supports and\n * the locale of the user's browser may differ, and the site needs to\n * pick the best locale to show the user. Let's say the\n * web site supports a selection of European languages such as \"it-IT\",\n * \"fr-FR\", \"de-DE\", and \"en-GB\". The user's\n * browser may be set to \"it-CH\". The web site code can then match \"it-CH\"\n * against each of the supported locales to find the one with the\n * highest score. In\n * this case, the best match would be \"it-IT\" because it shares a\n * language and script in common with \"it-CH\" and differs only in the region\n * component. It is not a 100% match, but it is pretty good. The web site\n * may decide if the match scores all fall\n * below a chosen threshold (perhaps 50%?), it should show the user the\n * default language \"en-GB\", because that is probably a better choice\n * than any other supported locale.<p>\n *\n * @param {Locale} locale the other locale to match against the current one\n * @return {number} an integer from 0 to 100 that indicates the degree to\n * which these locales match each other\n */\n match(locale) {\n const other = new Locale(locale);\n let scores = [0, 0, 0, 0];\n let thisfull, otherfull, i;\n\n if (this.locale.language === other.language) {\n scores[0] = 100;\n } else {\n if (!this.locale.language || !other.language) {\n // check for default language\n thisfull = this.getLikelyLocale();\n otherfull = new Locale(matchdata.likelyLocales[other.getSpec()] || other.getSpec());\n if (thisfull.language === otherfull.language) {\n scores[0] = 100;\n }\n } else {\n // check for macro languages\n const mlthis = matchdata.macroLanguagesReverse[this.locale.language] || this.locale.language;\n const mlother = matchdata.macroLanguagesReverse[other.language] || other.language;\n if (mlthis === mlother) {\n scores[0] = 90;\n } else {\n // check for mutual intelligibility\n const pair = this.locale.language + \"-\" + other.language;\n scores[0] = matchdata.mutualIntelligibility[pair] || 0;\n }\n }\n }\n\n if (this.locale.script === other.script) {\n scores[1] = 100;\n } else {\n if (!this.locale.script || !other.script) {\n // check for default script\n thisfull = this.locale.script ? this.locale : new Locale(matchdata.likelyLocales[this.locale.language]);\n otherfull = other.script ? other : new Locale(matchdata.likelyLocales[other.language]);\n if (thisfull.script === otherfull.script) {\n scores[1] = 100;\n }\n }\n }\n\n if (this.locale.region === other.region) {\n scores[2] = 100;\n } else {\n if (!this.locale.region || !other.region) {\n // check for default region\n thisfull = this.getLikelyLocale();\n otherfull = new Locale(matchdata.likelyLocales[other.getSpec()] || other.getSpec());\n if (thisfull.region === otherfull.region) {\n scores[2] = 100;\n }\n } else {\n // check for containment\n const containers = matchdata.territoryContainmentReverse[this.locale.region] || [];\n // end at 1 because 0 is \"001\" which is \"the whole world\" -- which is not useful\n for (i = containers.length-1; i > 0; i--) {\n const container = matchdata.territoryContainment[containers[i]];\n if (container && container.indexOf(other.region) > -1) {\n // same area only accounts for 20% of the region score\n scores[2] = ((i+1) * 100 / containers.length) * 0.2;\n break;\n }\n }\n }\n }\n\n if (this.locale.variant === other.variant) {\n scores[3] = 100;\n }\n\n let total = 0;\n\n for (i = 0; i < 4; i++) {\n total += scores[i] * componentWeights[i];\n }\n\n return Math.round(total);\n }\n\n /**\n * Return the macrolanguage associated with this locale. If the\n * locale's language is not part of a macro-language, then the\n * locale's language is returned as-is.\n *\n * @returns {string} the ISO code for the macrolanguage associated\n * with this locale, or language of the locale\n */\n getMacroLanguage() {\n return matchdata.macroLanguagesReverse[this.locale.language] || this.locale.language;\n }\n\n /**\n * Return the containment array for the given region code.\n * @private\n */\n _getRegionContainment(region) {\n return matchdata.territoryContainmentReverse[region] || [];\n }\n\n /**\n * Return the list of regions that this locale is contained within. Regions are\n * nested, so locales can be in multiple regions. (eg. US is in Northern North\n * America, North America, the Americas, the World.) Most regions are specified\n * using UN.49 region numbers, though some, like \"EU\", are letters. If the\n * locale is underspecified, this method will use the most likely locale method\n * to get the region first. For example, the locale \"ja\" (Japanese) is most\n * likely \"ja-JP\" (Japanese for Japan), and the region containment info for Japan\n * is returned.\n *\n * @returns {Array.<string>} an array of region specifiers that this locale is within\n */\n getRegionContainment() {\n const region = this.locale.region || this.getLikelyLocale().region;\n return this._getRegionContainment(region);\n }\n\n /**\n * Find the smallest region that contains both the current locale and the other locale.\n * If the current or other locales are underspecified, this method will use the most\n * likely locale method\n * to get their regions first. For example, the locale \"ja\" (Japanese) is most\n * likely \"ja-JP\" (Japanese for Japan), and the region containment info for Japan\n * is checked against the other locale's region containment info.\n *\n * @param {string|Locale} otherLocale a locale specifier or a Locale instance to\n * compare against\n * @returns {string} the region specifier of the smallest region containing both the\n * current locale and other locale\n */\n smallestCommonRegion(otherLocale) {\n if (typeof(otherLocale) === \"undefined\") return \"001\";\n\n const thisRegion = this.locale.region || this.getLikelyLocale().region;\n const otherLoc = typeof(otherLocale) === \"string\" ? new Locale(otherLocale) : otherLocale;\n const otherRegion = this._getLikelyLocale(otherLoc).region;\n\n const thisRegions = this._getRegionContainment(thisRegion);\n const otherRegions = this._getRegionContainment(otherRegion);\n\n // region containment arrays are arranged from largest to smallest, so start\n // at the end of the array\n for (let i = thisRegions.length-1; i > 0; i--) {\n if (otherRegions.indexOf(thisRegions[i]) > -1) {\n return thisRegions[i];\n }\n }\n\n // this default should never be reached because the world should be common to all regions\n return \"001\";\n }\n};\n\nexport default LocaleMatcher;\n"],"file":"LocaleMatcher.js"}
|