@osimatic/helpers-js 1.5.29 → 1.5.30
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/location.js +48 -9
- package/package.json +1 -1
- package/tests/location.test.js +92 -34
package/location.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
const Address = require('ilib/lib/Address');
|
|
3
3
|
const AddressFmt = require('ilib/lib/AddressFmt');
|
|
4
|
+
const { HTTPClient } = require('./http_client');
|
|
4
5
|
const { toEl } = require('./util');
|
|
5
6
|
const isoCountries = require('i18n-iso-countries');
|
|
6
7
|
isoCountries.registerLocale(require('i18n-iso-countries/langs/en.json'));
|
|
@@ -11,10 +12,13 @@ class Country {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
static getFlagPath(countryCode) {
|
|
14
|
-
return
|
|
15
|
+
return typeof Country.flagsPath !== 'undefined' ? Country.flagsPath + countryCode.toLowerCase() + '.png' : null;
|
|
15
16
|
}
|
|
16
|
-
static getFlagImg(countryCode) {
|
|
17
|
-
|
|
17
|
+
static getFlagImg(countryCode, locale='fr-FR') {
|
|
18
|
+
if (typeof Country.flagsPath !== 'undefined') {
|
|
19
|
+
return '<span><img src="'+Country.getFlagPath(countryCode)+'" alt="" title="'+Country.getCountryName(countryCode, locale)+'" class="flag" /></span>';
|
|
20
|
+
}
|
|
21
|
+
return '<span class="fi fi-' + countryCode.toLowerCase() + '"></span>';
|
|
18
22
|
}
|
|
19
23
|
static getFlagEmoji(countryCode) {
|
|
20
24
|
return [...countryCode.toUpperCase()].map(c => String.fromCodePoint(0x1F1E6 - 65 + c.charCodeAt(0))).join('');
|
|
@@ -33,7 +37,7 @@ class Country {
|
|
|
33
37
|
const entries = countriesList != null
|
|
34
38
|
? countriesList.map(code => [code, allCountries[code] || code])
|
|
35
39
|
: Object.entries(allCountries);
|
|
36
|
-
|
|
40
|
+
entries.forEach(([countryCode, countryName]) => {
|
|
37
41
|
let attrs = '';
|
|
38
42
|
if (showFlags) {
|
|
39
43
|
if (typeof Country.flagsPath !== 'undefined') {
|
|
@@ -55,19 +59,23 @@ class Country {
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
static getCountryName(countryCode, locale='fr-FR') {
|
|
58
|
-
const
|
|
62
|
+
const baseLang = Locale.getBaseLang(locale);
|
|
63
|
+
Country.getCountries(locale); // ensure locale is registered
|
|
64
|
+
const name = isoCountries.getName(countryCode, baseLang);
|
|
59
65
|
return name || countryCode;
|
|
60
66
|
}
|
|
61
67
|
static getCountries(locale = 'en') {
|
|
62
|
-
const
|
|
68
|
+
const baseLang = Locale.getBaseLang(locale);
|
|
69
|
+
let names = isoCountries.getNames(baseLang);
|
|
63
70
|
if (!names || Object.keys(names).length === 0) {
|
|
64
71
|
try {
|
|
65
|
-
isoCountries.registerLocale(require('i18n-iso-countries/langs/' +
|
|
72
|
+
isoCountries.registerLocale(require('i18n-iso-countries/langs/' + baseLang + '.json'));
|
|
73
|
+
names = isoCountries.getNames(baseLang);
|
|
66
74
|
} catch (e) {
|
|
67
75
|
// locale not available
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
|
-
return
|
|
78
|
+
return names || {};
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
static getContinents() {
|
|
@@ -529,4 +537,35 @@ class GeographicCoordinates {
|
|
|
529
537
|
|
|
530
538
|
}
|
|
531
539
|
|
|
532
|
-
|
|
540
|
+
class Locale {
|
|
541
|
+
static getBaseLang(locale) {
|
|
542
|
+
return Locale.normalize(locale).split('-')[0];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
static getRegion(locale) {
|
|
546
|
+
const parts = Locale.normalize(locale).split('-');
|
|
547
|
+
return parts.length > 1 ? parts[1] : null;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
static normalize(locale) {
|
|
551
|
+
// Accept both 'fr_FR' and 'fr-fr', output 'fr-FR'
|
|
552
|
+
const parts = locale.replace('_', '-').split('-');
|
|
553
|
+
const lang = parts[0].toLowerCase();
|
|
554
|
+
const region = parts[1] ? parts[1].toUpperCase() : null;
|
|
555
|
+
return region ? lang + '-' + region : lang;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
static isValid(locale) {
|
|
559
|
+
return /^[a-zA-Z]{2,3}(-[a-zA-Z]{2,3})?$/.test(locale);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
static toPOSIX(locale) {
|
|
563
|
+
return Locale.normalize(locale).replace('-', '_');
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static update(locale) {
|
|
567
|
+
HTTPClient.setHeader('Accept-Language', Locale.normalize(locale));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
module.exports = { Country, Locale, PostalAddress, GeographicCoordinates, Polygon };
|
package/package.json
CHANGED
package/tests/location.test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { Country, PostalAddress, GeographicCoordinates, Polygon } = require('../location');
|
|
1
|
+
const { Country, Locale, PostalAddress, GeographicCoordinates, Polygon } = require('../location');
|
|
2
2
|
|
|
3
3
|
describe('Country', () => {
|
|
4
4
|
describe('getCountries', () => {
|
|
@@ -19,12 +19,17 @@ describe('Country', () => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
describe('getCountryName', () => {
|
|
22
|
-
test('should return country name for valid code', () => {
|
|
22
|
+
test('should return country name for valid code (default fr-FR locale)', () => {
|
|
23
23
|
expect(Country.getCountryName('FR')).toBe('France');
|
|
24
|
-
expect(Country.getCountryName('US')).toBe(
|
|
24
|
+
expect(Country.getCountryName('US')).toBe("États-Unis d'Amérique");
|
|
25
25
|
expect(Country.getCountryName('CA')).toBe('Canada');
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
test('should return country name in specified locale', () => {
|
|
29
|
+
expect(Country.getCountryName('US', 'en')).toBe('United States of America');
|
|
30
|
+
expect(Country.getCountryName('DE', 'de')).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
|
|
28
33
|
test('should return the code itself if country not found', () => {
|
|
29
34
|
expect(Country.getCountryName('XX')).toBe('XX');
|
|
30
35
|
expect(Country.getCountryName('ZZZ')).toBe('ZZZ');
|
|
@@ -42,50 +47,35 @@ describe('Country', () => {
|
|
|
42
47
|
});
|
|
43
48
|
|
|
44
49
|
describe('getFlagPath', () => {
|
|
45
|
-
test('should return
|
|
46
|
-
|
|
47
|
-
expect(
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('should lowercase the country code', () => {
|
|
51
|
-
const path = Country.getFlagPath('US');
|
|
52
|
-
expect(path).toContain('us.png');
|
|
50
|
+
test('should return null when no flagsPath set', () => {
|
|
51
|
+
Country.flagsPath = undefined;
|
|
52
|
+
expect(Country.getFlagPath('FR')).toBeNull();
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
test('should
|
|
55
|
+
test('should return image path when flagsPath set', () => {
|
|
56
56
|
Country.setFlagsPath('/custom/flags/');
|
|
57
|
-
|
|
58
|
-
expect(
|
|
59
|
-
|
|
60
|
-
// Reset for other tests
|
|
57
|
+
expect(Country.getFlagPath('FR')).toBe('/custom/flags/fr.png');
|
|
58
|
+
expect(Country.getFlagPath('US')).toBe('/custom/flags/us.png');
|
|
61
59
|
Country.flagsPath = undefined;
|
|
62
60
|
});
|
|
61
|
+
});
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
describe('getFlagImg', () => {
|
|
64
|
+
test('should return flag-icons span when no flagsPath set', () => {
|
|
65
65
|
Country.flagsPath = undefined;
|
|
66
|
-
const
|
|
67
|
-
expect(
|
|
66
|
+
const html = Country.getFlagImg('FR');
|
|
67
|
+
expect(html).toContain('<span');
|
|
68
|
+
expect(html).toContain('fi fi-fr');
|
|
68
69
|
});
|
|
69
|
-
});
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
test('should return img tag when flagsPath set', () => {
|
|
72
|
+
Country.setFlagsPath('/flags/');
|
|
73
73
|
const html = Country.getFlagImg('FR');
|
|
74
74
|
expect(html).toContain('<img');
|
|
75
|
-
expect(html).toContain('src=');
|
|
76
75
|
expect(html).toContain('fr.png');
|
|
77
76
|
expect(html).toContain('class="flag"');
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
test('should include country name in title', () => {
|
|
81
|
-
const html = Country.getFlagImg('US');
|
|
82
|
-
expect(html).toContain('title="United States of America"');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('should wrap img in span', () => {
|
|
86
|
-
const html = Country.getFlagImg('GB');
|
|
87
|
-
expect(html).toMatch(/^<span>/);
|
|
88
|
-
expect(html).toMatch(/<\/span>$/);
|
|
77
|
+
expect(html).toContain("title=\"France\"");
|
|
78
|
+
Country.flagsPath = undefined;
|
|
89
79
|
});
|
|
90
80
|
});
|
|
91
81
|
|
|
@@ -129,6 +119,74 @@ describe('Country', () => {
|
|
|
129
119
|
});
|
|
130
120
|
});
|
|
131
121
|
|
|
122
|
+
describe('Locale', () => {
|
|
123
|
+
describe('normalize', () => {
|
|
124
|
+
test('should canonicalize to lang-REGION format', () => {
|
|
125
|
+
expect(Locale.normalize('fr-FR')).toBe('fr-FR');
|
|
126
|
+
expect(Locale.normalize('fr-fr')).toBe('fr-FR');
|
|
127
|
+
expect(Locale.normalize('FR-fr')).toBe('fr-FR');
|
|
128
|
+
expect(Locale.normalize('fr_FR')).toBe('fr-FR');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('should handle lang-only locales', () => {
|
|
132
|
+
expect(Locale.normalize('fr')).toBe('fr');
|
|
133
|
+
expect(Locale.normalize('EN')).toBe('en');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('getBaseLang', () => {
|
|
138
|
+
test('should extract base language', () => {
|
|
139
|
+
expect(Locale.getBaseLang('fr-FR')).toBe('fr');
|
|
140
|
+
expect(Locale.getBaseLang('en-US')).toBe('en');
|
|
141
|
+
expect(Locale.getBaseLang('fr_FR')).toBe('fr');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('should return lang as-is when no region', () => {
|
|
145
|
+
expect(Locale.getBaseLang('fr')).toBe('fr');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('getRegion', () => {
|
|
150
|
+
test('should extract region code', () => {
|
|
151
|
+
expect(Locale.getRegion('fr-FR')).toBe('FR');
|
|
152
|
+
expect(Locale.getRegion('en-US')).toBe('US');
|
|
153
|
+
expect(Locale.getRegion('fr_FR')).toBe('FR');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('should return null when no region', () => {
|
|
157
|
+
expect(Locale.getRegion('fr')).toBeNull();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('isValid', () => {
|
|
162
|
+
test('should accept valid locales', () => {
|
|
163
|
+
expect(Locale.isValid('fr')).toBe(true);
|
|
164
|
+
expect(Locale.isValid('fr-FR')).toBe(true);
|
|
165
|
+
expect(Locale.isValid('en-US')).toBe(true);
|
|
166
|
+
expect(Locale.isValid('zh-CN')).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('should reject invalid locales', () => {
|
|
170
|
+
expect(Locale.isValid('foobar')).toBe(false);
|
|
171
|
+
expect(Locale.isValid('fr_FR')).toBe(false);
|
|
172
|
+
expect(Locale.isValid('')).toBe(false);
|
|
173
|
+
expect(Locale.isValid('1234')).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('toPOSIX', () => {
|
|
178
|
+
test('should convert to POSIX format', () => {
|
|
179
|
+
expect(Locale.toPOSIX('fr-FR')).toBe('fr_FR');
|
|
180
|
+
expect(Locale.toPOSIX('en-US')).toBe('en_US');
|
|
181
|
+
expect(Locale.toPOSIX('fr_FR')).toBe('fr_FR');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('should handle lang-only locales', () => {
|
|
185
|
+
expect(Locale.toPOSIX('fr')).toBe('fr');
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
132
190
|
describe('GeographicCoordinates', () => {
|
|
133
191
|
describe('check', () => {
|
|
134
192
|
test('should validate correct coordinates', () => {
|