@reykjavik/webtools 0.1.14 → 0.1.16
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/CHANGELOG.md +19 -8
- package/README.md +46 -8
- package/esm/fixIcelandicLocale.js +11 -36
- package/esm/fixIcelandicLocale.privates.d.ts +45 -0
- package/esm/fixIcelandicLocale.privates.js +226 -0
- package/fixIcelandicLocale.d.ts +1 -2
- package/fixIcelandicLocale.js +12 -35
- package/fixIcelandicLocale.privates.d.ts +45 -0
- package/fixIcelandicLocale.privates.js +232 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,18 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
- ... <!-- Add new lines here. -->
|
|
6
6
|
|
|
7
|
-
## 0.1.
|
|
7
|
+
## 0.1.16
|
|
8
8
|
|
|
9
|
-
_2024-03-
|
|
9
|
+
_2024-03-09_
|
|
10
|
+
|
|
11
|
+
- `@reykjavik/webtools/fixIcelandicLocale`:
|
|
12
|
+
- fix: Add missing `DateTimeFormat.format*ToParts` methods, fix bugs
|
|
13
|
+
- refctor: Reduce code-size and simplify logic by dog-fooding `*ToParts`
|
|
14
|
+
methods internally
|
|
15
|
+
|
|
16
|
+
## 0.1.15
|
|
17
|
+
|
|
18
|
+
_2024-03-08_
|
|
10
19
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
20
|
+
- `@reykjavik/webtools/fixIcelandicLocale`:
|
|
21
|
+
- feat: Patch `Intl.Collator`
|
|
22
|
+
- feat: Patch `Intl.NumberFormat` and `Number.prototype.toLocaleString`
|
|
23
|
+
- feat: Patch `Intl.DateTimeFormat` and `Date.prototype.toLocaleDateString`
|
|
13
24
|
|
|
14
|
-
## 0.1.13
|
|
25
|
+
## 0.1.13 – 0.1.14
|
|
15
26
|
|
|
16
27
|
_2024-03-06_
|
|
17
28
|
|
|
18
|
-
- feat: Add `@reykjavik/webtools/fixIcelandicLocale`
|
|
29
|
+
- feat: Add `@reykjavik/webtools/fixIcelandicLocale` Chrome paching module
|
|
19
30
|
|
|
20
31
|
## 0.1.12
|
|
21
32
|
|
|
@@ -35,7 +46,7 @@ _2024-02-14_
|
|
|
35
46
|
|
|
36
47
|
_2024-02-14_
|
|
37
48
|
|
|
38
|
-
- `@reykjavik/webtools/http
|
|
49
|
+
- `@reykjavik/webtools/http`:
|
|
39
50
|
- feat: Add the rest of the more obscure HTTP status constants (WebDAV,
|
|
40
51
|
etc.)
|
|
41
52
|
- fix: Add `429`, `432`, `451` to `HTTP_CLIENT_ERROR_ALL` type
|
|
@@ -44,7 +55,7 @@ _2024-02-14_
|
|
|
44
55
|
|
|
45
56
|
_2023-04-27_
|
|
46
57
|
|
|
47
|
-
- `@reykjavik/webtools/http
|
|
58
|
+
- `@reykjavik/webtools/http`:
|
|
48
59
|
- feat: Add `toSec` TTL helper
|
|
49
60
|
|
|
50
61
|
## 0.1.7 – 0.1.8
|
package/README.md
CHANGED
|
@@ -32,6 +32,7 @@ bun add @reykjavik/webtools
|
|
|
32
32
|
- [`vanillaClassNested`](#vanillaclassnested)
|
|
33
33
|
- [`vanillaNest`](#vanillanest)
|
|
34
34
|
- [`@reykjavik/webtools/fixIcelandicLocale`](#reykjavikwebtoolsfixicelandiclocale)
|
|
35
|
+
- [Limitations](#limitations)
|
|
35
36
|
- [Framework Specific Tools](#framework-specific-tools)
|
|
36
37
|
- [Next.js Tools](#nextjs-tools)
|
|
37
38
|
- [Contributing](#contributing)
|
|
@@ -427,21 +428,58 @@ vanillaGlobal(`
|
|
|
427
428
|
|
|
428
429
|
## `@reykjavik/webtools/fixIcelandicLocale`
|
|
429
430
|
|
|
430
|
-
|
|
431
|
-
`
|
|
431
|
+
As of early 2004, Google Chrome still does not support the Icelandic locale
|
|
432
|
+
`is`/`is-IS` in any way. Meanwhile other browsers have supported it for over a
|
|
433
|
+
decade.
|
|
432
434
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
+
This module does attempts to patches the following methods/classes by
|
|
436
|
+
substituting the `is` locale with `da` (Danish) and apply a few post-hoc fixes
|
|
437
|
+
to their return values.
|
|
438
|
+
|
|
439
|
+
- `Intl.Collator` and `String.prototype.localeCompare`
|
|
440
|
+
- `Intl.NumberFormat` and `Number.prototype.toLocaleString`
|
|
441
|
+
- `Intl.DateTimeFormat` and `Date.prototype.toLocaleDateString`
|
|
442
|
+
|
|
443
|
+
This provides usable (but not perfect) results, with some caveats listed
|
|
444
|
+
below.
|
|
445
|
+
|
|
446
|
+
To apply these patches, simply "side-effect import" this module at the top of
|
|
447
|
+
your app's entry point:
|
|
435
448
|
|
|
436
449
|
```ts
|
|
437
450
|
import '@reykjavik/webtools/fixIcelandicLocale';
|
|
438
451
|
|
|
439
|
-
// Then continue with your day
|
|
440
|
-
//
|
|
452
|
+
// Then continue with your day and use `localeCompare` and Intl.Collator,
|
|
453
|
+
// as you normally would. (See "limitations" below.)
|
|
441
454
|
```
|
|
442
455
|
|
|
443
|
-
**NOTE** The
|
|
444
|
-
test.
|
|
456
|
+
(**NOTE** The patch is only applied in engines that fail a simple feature
|
|
457
|
+
detection test.)
|
|
458
|
+
|
|
459
|
+
### Limitations
|
|
460
|
+
|
|
461
|
+
**`Intl.Collator` and `localeCompare`:**
|
|
462
|
+
|
|
463
|
+
- When the `sensitivty` option is set to `"base"` or `"accent"`, it will
|
|
464
|
+
incorrectly treat `ð` and `d` as the same letter, and the acute-accented
|
|
465
|
+
characters `á`, `é`, `í`, `ó`, `ú` and `ý` get lumped in with their
|
|
466
|
+
non-accented counterparts.
|
|
467
|
+
|
|
468
|
+
**`Intl.NumberFormat` and `toLocaleString`:**
|
|
469
|
+
|
|
470
|
+
- The `style: "unit"` option is not supported and prints units in Danish. (Soo
|
|
471
|
+
many units and unit-variants…)
|
|
472
|
+
- The `currencyDisplay: "name"` option is not supported and prints the
|
|
473
|
+
currency's full name in Danish.
|
|
474
|
+
|
|
475
|
+
**`Intl.DateTimeFormat` and `toLocaleDateString`:**
|
|
476
|
+
|
|
477
|
+
- The `month: 'narrow'` and `weekday: 'narrow'` options are not supported, and
|
|
478
|
+
print the corresponding Danish initials.
|
|
479
|
+
- For `timeZoneName` the values `"long"`, `"shortGeneric"` and `"longGeneric"`
|
|
480
|
+
will appear in Danish.
|
|
481
|
+
- The `timeStyle: 'full'` option prints the timezone names in Danish
|
|
482
|
+
- The `dayPeriod` option is not supported and prints the day-period in Danish.
|
|
445
483
|
|
|
446
484
|
---
|
|
447
485
|
|
|
@@ -1,39 +1,14 @@
|
|
|
1
|
+
import { _PatchedCollator, _PatchedDateTimeFormat, _patchedLocaleCompare, _PatchedNumberFormat, _patchedToLocaleDateString, _patchedToLocaleString, } from './fixIcelandicLocale.privates.js';
|
|
1
2
|
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Same kind of magic as `String.prototype.localeCompare`
|
|
6
|
-
|
|
7
|
-
- `Intl.NumberFormat`
|
|
8
|
-
Only support default plain-number and percent formatting,
|
|
9
|
-
not currency or unit — UNLESS we do some string-replacement hackery,
|
|
10
|
-
and then we may need to handle the possibility of locales arrays
|
|
11
|
-
already containing Danish ahead of "is".
|
|
12
|
-
|
|
13
|
-
- `Intl.DateTimeFormat`
|
|
14
|
-
Possible with some mad-scientist string-replacement hackery and
|
|
15
|
-
the `locales` array detection magic, as mentioned above.
|
|
16
|
-
|
|
17
|
-
Mantra: Partial Icelandic suppoort is better than no Icelandic support.
|
|
3
|
+
Mantra: Partial Icelandic suppoort is better than none. Partial Icelandic
|
|
4
|
+
suppoort is better than none. Partial Icelandic suppoort is better than
|
|
5
|
+
none. Partial Icelandic suppoort is better than none. Partial Icelandic...
|
|
18
6
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return locales.map((loc) => locAliases[loc.toLowerCase()] || loc);
|
|
27
|
-
};
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
if ('ö'.localeCompare('p', 'is') < 0) {
|
|
30
|
-
const _localeCompare = String.prototype.localeCompare;
|
|
31
|
-
/**
|
|
32
|
-
* Polyfill for String.prototype.localeCompare for the 'is' locale
|
|
33
|
-
* in browsers that don't support it (\*cough* Chrome \*cough*).
|
|
34
|
-
*/
|
|
35
|
-
String.prototype.localeCompare = function (that, locales, options) {
|
|
36
|
-
return _localeCompare.call(this, that, mapLocales(locales), options);
|
|
37
|
-
};
|
|
7
|
+
if (Intl.Collator.supportedLocalesOf(['is']).length < 1) {
|
|
8
|
+
Intl.Collator = _PatchedCollator;
|
|
9
|
+
String.prototype.localeCompare = _patchedLocaleCompare;
|
|
10
|
+
Intl.NumberFormat = _PatchedNumberFormat;
|
|
11
|
+
Number.prototype.toLocaleString = _patchedToLocaleString;
|
|
12
|
+
Intl.DateTimeFormat = _PatchedDateTimeFormat;
|
|
13
|
+
Date.prototype.toLocaleDateString = _patchedToLocaleDateString;
|
|
38
14
|
}
|
|
39
|
-
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const _PatchedCollator: {
|
|
2
|
+
(locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): Intl.Collator;
|
|
3
|
+
new (locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): Intl.Collator;
|
|
4
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.CollatorOptions | undefined): string[];
|
|
5
|
+
} & {
|
|
6
|
+
$original: typeof Intl.Collator;
|
|
7
|
+
};
|
|
8
|
+
export declare const _patchedLocaleCompare: {
|
|
9
|
+
(this: string, that: string, locales?: string | Array<string>, options?: Intl.CollatorOptions): number;
|
|
10
|
+
$original: {
|
|
11
|
+
(that: string): number;
|
|
12
|
+
(that: string, locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare const _PatchedNumberFormat: {
|
|
16
|
+
(locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): Intl.NumberFormat;
|
|
17
|
+
new (locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): Intl.NumberFormat;
|
|
18
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.NumberFormatOptions | undefined): string[];
|
|
19
|
+
readonly prototype: Intl.NumberFormat;
|
|
20
|
+
} & {
|
|
21
|
+
$original: typeof Intl.NumberFormat;
|
|
22
|
+
};
|
|
23
|
+
export declare const _patchedToLocaleString: {
|
|
24
|
+
(this: number, locales?: string | Array<string>, options?: Intl.NumberFormatOptions): string;
|
|
25
|
+
$original: {
|
|
26
|
+
(locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): string;
|
|
27
|
+
(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions | undefined): string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare const _PatchedDateTimeFormat: {
|
|
31
|
+
(locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): Intl.DateTimeFormat;
|
|
32
|
+
new (locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): Intl.DateTimeFormat;
|
|
33
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.DateTimeFormatOptions | undefined): string[];
|
|
34
|
+
readonly prototype: Intl.DateTimeFormat;
|
|
35
|
+
} & {
|
|
36
|
+
$original: typeof Intl.DateTimeFormat;
|
|
37
|
+
};
|
|
38
|
+
export declare const _patchedToLocaleDateString: {
|
|
39
|
+
(this: Date, locales?: string | Array<string>, options?: Intl.DateTimeFormatOptions): string;
|
|
40
|
+
$original: {
|
|
41
|
+
(): string;
|
|
42
|
+
(locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): string;
|
|
43
|
+
(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions | undefined): string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
const _Collator = Intl.Collator;
|
|
2
|
+
const _NumberFormat = Intl.NumberFormat;
|
|
3
|
+
const _DateTimeFormat = Intl.DateTimeFormat;
|
|
4
|
+
const mapLocales = (locales) => {
|
|
5
|
+
locales = typeof locales === 'string' ? [locales] : locales || [];
|
|
6
|
+
for (let i = 0, loc; (loc = locales[i]); i++) {
|
|
7
|
+
const isIsLocale = /^isl?(?:-|$)/i.test(loc);
|
|
8
|
+
if (isIsLocale) {
|
|
9
|
+
// Danish feels like a "good enough" substitution for Icelandic.
|
|
10
|
+
// For alphabetization, it seems to just the internal order of `Ø` and `Ö`
|
|
11
|
+
// that's different, and when the `sensitivity` option is set to "base"
|
|
12
|
+
// or "accent" then `ð` is consiered a variant of `d` and the letters
|
|
13
|
+
// á, é, í, ó, ú, and ý are not treated as separate letters but simply
|
|
14
|
+
// variants of a, e, i, o, u, and y.
|
|
15
|
+
return ['da'];
|
|
16
|
+
}
|
|
17
|
+
if (_Collator.supportedLocalesOf(loc).length) {
|
|
18
|
+
return; // no mapping needed. YOLO!
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const combineParts = (parts) => parts.map(({ value }) => value).join('');
|
|
23
|
+
// ===========================================================================
|
|
24
|
+
// Collator
|
|
25
|
+
// ===========================================================================
|
|
26
|
+
const PatchedCollator = function Collator(locales, options) {
|
|
27
|
+
locales = mapLocales(locales) || locales;
|
|
28
|
+
const instance = new _Collator(locales, options);
|
|
29
|
+
Object.setPrototypeOf(instance, PatchedCollator.prototype);
|
|
30
|
+
return instance;
|
|
31
|
+
};
|
|
32
|
+
PatchedCollator.prototype = Object.create(_Collator.prototype);
|
|
33
|
+
PatchedCollator.prototype.constructor = PatchedCollator;
|
|
34
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
35
|
+
PatchedCollator.supportedLocalesOf = _Collator.supportedLocalesOf;
|
|
36
|
+
PatchedCollator.$original = _Collator;
|
|
37
|
+
export const _PatchedCollator = PatchedCollator;
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
const _localeCompare = String.prototype.localeCompare;
|
|
40
|
+
export const _patchedLocaleCompare = function localeCompare(that, locales, options) {
|
|
41
|
+
return _PatchedCollator(locales, options).compare(this, that);
|
|
42
|
+
};
|
|
43
|
+
_patchedLocaleCompare.$original = _localeCompare;
|
|
44
|
+
// ===========================================================================
|
|
45
|
+
// NumberFormat
|
|
46
|
+
// ===========================================================================
|
|
47
|
+
const reformatNumberParts = function (parts) {
|
|
48
|
+
if (!this.mapped) {
|
|
49
|
+
return parts;
|
|
50
|
+
}
|
|
51
|
+
const options = this.super.resolvedOptions();
|
|
52
|
+
if (options.style === 'currency' && options.currencyDisplay === 'symbol') {
|
|
53
|
+
const currency = options.currency;
|
|
54
|
+
if (currency === 'DKK' || currency === 'ISK') {
|
|
55
|
+
parts.forEach((part) => {
|
|
56
|
+
if (part.type === 'currency') {
|
|
57
|
+
part.value = currency === 'DKK' ? 'DKK' : 'kr.';
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return parts;
|
|
63
|
+
};
|
|
64
|
+
const PatchedNumberFormat = function NumberFormat(locales, options) {
|
|
65
|
+
if (!(this instanceof PatchedNumberFormat)) {
|
|
66
|
+
// @ts-expect-error (YOLO! Can't be arsed)
|
|
67
|
+
return new PatchedNumberFormat(locales, options);
|
|
68
|
+
}
|
|
69
|
+
const mappedLocales = mapLocales(locales);
|
|
70
|
+
this.super = _NumberFormat(mappedLocales || locales, options);
|
|
71
|
+
this.mapped = !!mappedLocales;
|
|
72
|
+
};
|
|
73
|
+
// This is all very hacky, but extending the class *AND* preseving the
|
|
74
|
+
// ability to instantiate without `new` is a bit of a pain.
|
|
75
|
+
// Eagerly interested in finding a better way to do this.
|
|
76
|
+
const numberFormatProto = {
|
|
77
|
+
constructor: PatchedNumberFormat,
|
|
78
|
+
format(value) {
|
|
79
|
+
return combineParts(this.formatToParts(value));
|
|
80
|
+
},
|
|
81
|
+
formatRange(value1, value2) {
|
|
82
|
+
return combineParts(this.formatRangeToParts(value1, value2));
|
|
83
|
+
},
|
|
84
|
+
formatToParts(value) {
|
|
85
|
+
return reformatNumberParts.call(this, this.super.formatToParts(value));
|
|
86
|
+
},
|
|
87
|
+
formatRangeToParts(value1, value2) {
|
|
88
|
+
return reformatNumberParts.call(this, this.super.formatRangeToParts(value1, value2));
|
|
89
|
+
},
|
|
90
|
+
resolvedOptions() {
|
|
91
|
+
return this.super.resolvedOptions();
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
PatchedNumberFormat.prototype = numberFormatProto;
|
|
95
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
96
|
+
PatchedNumberFormat.supportedLocalesOf = _NumberFormat.supportedLocalesOf;
|
|
97
|
+
PatchedNumberFormat.$original = _NumberFormat;
|
|
98
|
+
export const _PatchedNumberFormat = PatchedNumberFormat;
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
const _toLocaleString = Number.prototype.toLocaleString;
|
|
101
|
+
export const _patchedToLocaleString = function toLocaleString(locales, options) {
|
|
102
|
+
return _PatchedNumberFormat(locales, options).format(this);
|
|
103
|
+
};
|
|
104
|
+
_patchedToLocaleString.$original = _toLocaleString;
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
// DateTimeFormat
|
|
107
|
+
// ===========================================================================
|
|
108
|
+
const months = {
|
|
109
|
+
jan: 'janúar',
|
|
110
|
+
feb: 'febrúar',
|
|
111
|
+
mar: 'mars',
|
|
112
|
+
apr: 'apríl',
|
|
113
|
+
maj: 'maí',
|
|
114
|
+
jun: 'júní',
|
|
115
|
+
jul: 'júlí',
|
|
116
|
+
aug: 'ágúst',
|
|
117
|
+
// sep: 'september', // is the same
|
|
118
|
+
okt: 'október',
|
|
119
|
+
nov: 'nóvember',
|
|
120
|
+
dec: 'desember',
|
|
121
|
+
};
|
|
122
|
+
const weekdays = {
|
|
123
|
+
man: 'mánudagur',
|
|
124
|
+
tir: 'þriðjudagur',
|
|
125
|
+
ons: 'miðvikudagur',
|
|
126
|
+
tor: 'fimmtudagur',
|
|
127
|
+
fre: 'föstudagur',
|
|
128
|
+
lør: 'laugardagur',
|
|
129
|
+
søn: 'sunnudagur',
|
|
130
|
+
};
|
|
131
|
+
const partMappers = {
|
|
132
|
+
month: (value) => {
|
|
133
|
+
const islMonth = months[value.slice(0, 3)];
|
|
134
|
+
if (islMonth) {
|
|
135
|
+
return value.endsWith('.') ? `${islMonth.slice(0, 3)}.` : islMonth;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
weekday: (value) => {
|
|
139
|
+
const isl = weekdays[value.slice(0, 3)];
|
|
140
|
+
if (isl) {
|
|
141
|
+
return value.endsWith('.') ? `${isl.slice(0, 3)}.` : isl;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
era: (value) => {
|
|
145
|
+
if (!value.endsWith('.')) {
|
|
146
|
+
return value.length === 3
|
|
147
|
+
? `${value[0]}.k.`
|
|
148
|
+
: value[0] === 'f'
|
|
149
|
+
? 'fyrir Krist'
|
|
150
|
+
: 'eftir Krist';
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
dayPeriod: (value) => {
|
|
154
|
+
return { AM: 'f.h.', PM: 'e.h.' }[value] || value;
|
|
155
|
+
},
|
|
156
|
+
literal: (value, lastType) => {
|
|
157
|
+
if (value === ' den ') {
|
|
158
|
+
return 'inn ';
|
|
159
|
+
}
|
|
160
|
+
else if (value === '.' && (lastType === 'hour' || lastType === 'minute')) {
|
|
161
|
+
return ':';
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
const reformatDateTimeParts = function (parts) {
|
|
166
|
+
if (!this.mapped) {
|
|
167
|
+
return parts;
|
|
168
|
+
}
|
|
169
|
+
parts.forEach((part, idx) => {
|
|
170
|
+
var _a;
|
|
171
|
+
const mapper = partMappers[part.type];
|
|
172
|
+
const newValue = mapper && mapper(part.value, (_a = parts[idx - 1]) === null || _a === void 0 ? void 0 : _a.type);
|
|
173
|
+
if (newValue != null) {
|
|
174
|
+
part.value = newValue;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return parts;
|
|
178
|
+
};
|
|
179
|
+
const PatchedDateTimeFormat = function DateTimeFormat(locales, options) {
|
|
180
|
+
if (!(this instanceof PatchedDateTimeFormat)) {
|
|
181
|
+
// @ts-expect-error (YOLO! Can't be arsed)
|
|
182
|
+
return new PatchedDateTimeFormat(locales, options);
|
|
183
|
+
}
|
|
184
|
+
const mappedLocales = mapLocales(locales);
|
|
185
|
+
if (options === null || options === void 0 ? void 0 : options.hour12) {
|
|
186
|
+
options = {
|
|
187
|
+
...options,
|
|
188
|
+
hour12: undefined,
|
|
189
|
+
hourCycle: 'h11',
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
this.super = _DateTimeFormat(mappedLocales || locales, options);
|
|
193
|
+
this.mapped = !!mappedLocales;
|
|
194
|
+
};
|
|
195
|
+
// This is all very hacky, but extending the class *AND* preseving the
|
|
196
|
+
// ability to instantiate without `new` is a bit of a pain.
|
|
197
|
+
// Eagerly interested in finding a better way to do this.
|
|
198
|
+
const dateTimeFormatProto = {
|
|
199
|
+
constructor: PatchedDateTimeFormat,
|
|
200
|
+
format(value) {
|
|
201
|
+
return combineParts(this.formatToParts(value));
|
|
202
|
+
},
|
|
203
|
+
formatRange(value1, value2) {
|
|
204
|
+
return combineParts(this.formatRangeToParts(value1, value2));
|
|
205
|
+
},
|
|
206
|
+
formatToParts(value) {
|
|
207
|
+
return reformatDateTimeParts.call(this, this.super.formatToParts(value));
|
|
208
|
+
},
|
|
209
|
+
formatRangeToParts(value1, value2) {
|
|
210
|
+
return reformatDateTimeParts.call(this, this.super.formatRangeToParts(value1, value2));
|
|
211
|
+
},
|
|
212
|
+
resolvedOptions() {
|
|
213
|
+
return this.super.resolvedOptions();
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
PatchedDateTimeFormat.prototype = dateTimeFormatProto;
|
|
217
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
218
|
+
PatchedDateTimeFormat.supportedLocalesOf = _DateTimeFormat.supportedLocalesOf;
|
|
219
|
+
PatchedDateTimeFormat.$original = _DateTimeFormat;
|
|
220
|
+
export const _PatchedDateTimeFormat = PatchedDateTimeFormat;
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
const _toLocaleDateString = Date.prototype.toLocaleDateString;
|
|
223
|
+
export const _patchedToLocaleDateString = function toLocaleDateString(locales, options) {
|
|
224
|
+
return _PatchedDateTimeFormat(locales, options).format(this);
|
|
225
|
+
};
|
|
226
|
+
_patchedToLocaleDateString.$original = _toLocaleDateString;
|
package/fixIcelandicLocale.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
declare const mapLocales: (locales: string | Array<string> | undefined) => string[];
|
|
1
|
+
export {};
|
package/fixIcelandicLocale.js
CHANGED
|
@@ -1,39 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fixIcelandicLocale_privates_js_1 = require("./fixIcelandicLocale.privates.js");
|
|
2
4
|
/*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Same kind of magic as `String.prototype.localeCompare`
|
|
7
|
-
|
|
8
|
-
- `Intl.NumberFormat`
|
|
9
|
-
Only support default plain-number and percent formatting,
|
|
10
|
-
not currency or unit — UNLESS we do some string-replacement hackery,
|
|
11
|
-
and then we may need to handle the possibility of locales arrays
|
|
12
|
-
already containing Danish ahead of "is".
|
|
13
|
-
|
|
14
|
-
- `Intl.DateTimeFormat`
|
|
15
|
-
Possible with some mad-scientist string-replacement hackery and
|
|
16
|
-
the `locales` array detection magic, as mentioned above.
|
|
17
|
-
|
|
18
|
-
Mantra: Partial Icelandic suppoort is better than no Icelandic support.
|
|
5
|
+
Mantra: Partial Icelandic suppoort is better than none. Partial Icelandic
|
|
6
|
+
suppoort is better than none. Partial Icelandic suppoort is better than
|
|
7
|
+
none. Partial Icelandic suppoort is better than none. Partial Icelandic...
|
|
19
8
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return locales.map((loc) => locAliases[loc.toLowerCase()] || loc);
|
|
28
|
-
};
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
if ('ö'.localeCompare('p', 'is') < 0) {
|
|
31
|
-
const _localeCompare = String.prototype.localeCompare;
|
|
32
|
-
/**
|
|
33
|
-
* Polyfill for String.prototype.localeCompare for the 'is' locale
|
|
34
|
-
* in browsers that don't support it (\*cough* Chrome \*cough*).
|
|
35
|
-
*/
|
|
36
|
-
String.prototype.localeCompare = function (that, locales, options) {
|
|
37
|
-
return _localeCompare.call(this, that, mapLocales(locales), options);
|
|
38
|
-
};
|
|
9
|
+
if (Intl.Collator.supportedLocalesOf(['is']).length < 1) {
|
|
10
|
+
Intl.Collator = fixIcelandicLocale_privates_js_1._PatchedCollator;
|
|
11
|
+
String.prototype.localeCompare = fixIcelandicLocale_privates_js_1._patchedLocaleCompare;
|
|
12
|
+
Intl.NumberFormat = fixIcelandicLocale_privates_js_1._PatchedNumberFormat;
|
|
13
|
+
Number.prototype.toLocaleString = fixIcelandicLocale_privates_js_1._patchedToLocaleString;
|
|
14
|
+
Intl.DateTimeFormat = fixIcelandicLocale_privates_js_1._PatchedDateTimeFormat;
|
|
15
|
+
Date.prototype.toLocaleDateString = fixIcelandicLocale_privates_js_1._patchedToLocaleDateString;
|
|
39
16
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const _PatchedCollator: {
|
|
2
|
+
(locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): Intl.Collator;
|
|
3
|
+
new (locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): Intl.Collator;
|
|
4
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.CollatorOptions | undefined): string[];
|
|
5
|
+
} & {
|
|
6
|
+
$original: typeof Intl.Collator;
|
|
7
|
+
};
|
|
8
|
+
export declare const _patchedLocaleCompare: {
|
|
9
|
+
(this: string, that: string, locales?: string | Array<string>, options?: Intl.CollatorOptions): number;
|
|
10
|
+
$original: {
|
|
11
|
+
(that: string): number;
|
|
12
|
+
(that: string, locales?: string | string[] | undefined, options?: Intl.CollatorOptions | undefined): number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare const _PatchedNumberFormat: {
|
|
16
|
+
(locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): Intl.NumberFormat;
|
|
17
|
+
new (locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): Intl.NumberFormat;
|
|
18
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.NumberFormatOptions | undefined): string[];
|
|
19
|
+
readonly prototype: Intl.NumberFormat;
|
|
20
|
+
} & {
|
|
21
|
+
$original: typeof Intl.NumberFormat;
|
|
22
|
+
};
|
|
23
|
+
export declare const _patchedToLocaleString: {
|
|
24
|
+
(this: number, locales?: string | Array<string>, options?: Intl.NumberFormatOptions): string;
|
|
25
|
+
$original: {
|
|
26
|
+
(locales?: string | string[] | undefined, options?: Intl.NumberFormatOptions | undefined): string;
|
|
27
|
+
(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions | undefined): string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare const _PatchedDateTimeFormat: {
|
|
31
|
+
(locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): Intl.DateTimeFormat;
|
|
32
|
+
new (locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): Intl.DateTimeFormat;
|
|
33
|
+
supportedLocalesOf(locales: string | string[], options?: Intl.DateTimeFormatOptions | undefined): string[];
|
|
34
|
+
readonly prototype: Intl.DateTimeFormat;
|
|
35
|
+
} & {
|
|
36
|
+
$original: typeof Intl.DateTimeFormat;
|
|
37
|
+
};
|
|
38
|
+
export declare const _patchedToLocaleDateString: {
|
|
39
|
+
(this: Date, locales?: string | Array<string>, options?: Intl.DateTimeFormatOptions): string;
|
|
40
|
+
$original: {
|
|
41
|
+
(): string;
|
|
42
|
+
(locales?: string | string[] | undefined, options?: Intl.DateTimeFormatOptions | undefined): string;
|
|
43
|
+
(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions | undefined): string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._patchedToLocaleDateString = exports._PatchedDateTimeFormat = exports._patchedToLocaleString = exports._PatchedNumberFormat = exports._patchedLocaleCompare = exports._PatchedCollator = void 0;
|
|
4
|
+
const _Collator = Intl.Collator;
|
|
5
|
+
const _NumberFormat = Intl.NumberFormat;
|
|
6
|
+
const _DateTimeFormat = Intl.DateTimeFormat;
|
|
7
|
+
const mapLocales = (locales) => {
|
|
8
|
+
locales = typeof locales === 'string' ? [locales] : locales || [];
|
|
9
|
+
for (let i = 0, loc; (loc = locales[i]); i++) {
|
|
10
|
+
const isIsLocale = /^isl?(?:-|$)/i.test(loc);
|
|
11
|
+
if (isIsLocale) {
|
|
12
|
+
// Danish feels like a "good enough" substitution for Icelandic.
|
|
13
|
+
// For alphabetization, it seems to just the internal order of `Ø` and `Ö`
|
|
14
|
+
// that's different, and when the `sensitivity` option is set to "base"
|
|
15
|
+
// or "accent" then `ð` is consiered a variant of `d` and the letters
|
|
16
|
+
// á, é, í, ó, ú, and ý are not treated as separate letters but simply
|
|
17
|
+
// variants of a, e, i, o, u, and y.
|
|
18
|
+
return ['da'];
|
|
19
|
+
}
|
|
20
|
+
if (_Collator.supportedLocalesOf(loc).length) {
|
|
21
|
+
return; // no mapping needed. YOLO!
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const combineParts = (parts) => parts.map(({ value }) => value).join('');
|
|
26
|
+
// ===========================================================================
|
|
27
|
+
// Collator
|
|
28
|
+
// ===========================================================================
|
|
29
|
+
const PatchedCollator = function Collator(locales, options) {
|
|
30
|
+
locales = mapLocales(locales) || locales;
|
|
31
|
+
const instance = new _Collator(locales, options);
|
|
32
|
+
Object.setPrototypeOf(instance, PatchedCollator.prototype);
|
|
33
|
+
return instance;
|
|
34
|
+
};
|
|
35
|
+
PatchedCollator.prototype = Object.create(_Collator.prototype);
|
|
36
|
+
PatchedCollator.prototype.constructor = PatchedCollator;
|
|
37
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
38
|
+
PatchedCollator.supportedLocalesOf = _Collator.supportedLocalesOf;
|
|
39
|
+
PatchedCollator.$original = _Collator;
|
|
40
|
+
exports._PatchedCollator = PatchedCollator;
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
const _localeCompare = String.prototype.localeCompare;
|
|
43
|
+
const _patchedLocaleCompare = function localeCompare(that, locales, options) {
|
|
44
|
+
return (0, exports._PatchedCollator)(locales, options).compare(this, that);
|
|
45
|
+
};
|
|
46
|
+
exports._patchedLocaleCompare = _patchedLocaleCompare;
|
|
47
|
+
exports._patchedLocaleCompare.$original = _localeCompare;
|
|
48
|
+
// ===========================================================================
|
|
49
|
+
// NumberFormat
|
|
50
|
+
// ===========================================================================
|
|
51
|
+
const reformatNumberParts = function (parts) {
|
|
52
|
+
if (!this.mapped) {
|
|
53
|
+
return parts;
|
|
54
|
+
}
|
|
55
|
+
const options = this.super.resolvedOptions();
|
|
56
|
+
if (options.style === 'currency' && options.currencyDisplay === 'symbol') {
|
|
57
|
+
const currency = options.currency;
|
|
58
|
+
if (currency === 'DKK' || currency === 'ISK') {
|
|
59
|
+
parts.forEach((part) => {
|
|
60
|
+
if (part.type === 'currency') {
|
|
61
|
+
part.value = currency === 'DKK' ? 'DKK' : 'kr.';
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return parts;
|
|
67
|
+
};
|
|
68
|
+
const PatchedNumberFormat = function NumberFormat(locales, options) {
|
|
69
|
+
if (!(this instanceof PatchedNumberFormat)) {
|
|
70
|
+
// @ts-expect-error (YOLO! Can't be arsed)
|
|
71
|
+
return new PatchedNumberFormat(locales, options);
|
|
72
|
+
}
|
|
73
|
+
const mappedLocales = mapLocales(locales);
|
|
74
|
+
this.super = _NumberFormat(mappedLocales || locales, options);
|
|
75
|
+
this.mapped = !!mappedLocales;
|
|
76
|
+
};
|
|
77
|
+
// This is all very hacky, but extending the class *AND* preseving the
|
|
78
|
+
// ability to instantiate without `new` is a bit of a pain.
|
|
79
|
+
// Eagerly interested in finding a better way to do this.
|
|
80
|
+
const numberFormatProto = {
|
|
81
|
+
constructor: PatchedNumberFormat,
|
|
82
|
+
format(value) {
|
|
83
|
+
return combineParts(this.formatToParts(value));
|
|
84
|
+
},
|
|
85
|
+
formatRange(value1, value2) {
|
|
86
|
+
return combineParts(this.formatRangeToParts(value1, value2));
|
|
87
|
+
},
|
|
88
|
+
formatToParts(value) {
|
|
89
|
+
return reformatNumberParts.call(this, this.super.formatToParts(value));
|
|
90
|
+
},
|
|
91
|
+
formatRangeToParts(value1, value2) {
|
|
92
|
+
return reformatNumberParts.call(this, this.super.formatRangeToParts(value1, value2));
|
|
93
|
+
},
|
|
94
|
+
resolvedOptions() {
|
|
95
|
+
return this.super.resolvedOptions();
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
PatchedNumberFormat.prototype = numberFormatProto;
|
|
99
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
100
|
+
PatchedNumberFormat.supportedLocalesOf = _NumberFormat.supportedLocalesOf;
|
|
101
|
+
PatchedNumberFormat.$original = _NumberFormat;
|
|
102
|
+
exports._PatchedNumberFormat = PatchedNumberFormat;
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
const _toLocaleString = Number.prototype.toLocaleString;
|
|
105
|
+
const _patchedToLocaleString = function toLocaleString(locales, options) {
|
|
106
|
+
return (0, exports._PatchedNumberFormat)(locales, options).format(this);
|
|
107
|
+
};
|
|
108
|
+
exports._patchedToLocaleString = _patchedToLocaleString;
|
|
109
|
+
exports._patchedToLocaleString.$original = _toLocaleString;
|
|
110
|
+
// ===========================================================================
|
|
111
|
+
// DateTimeFormat
|
|
112
|
+
// ===========================================================================
|
|
113
|
+
const months = {
|
|
114
|
+
jan: 'janúar',
|
|
115
|
+
feb: 'febrúar',
|
|
116
|
+
mar: 'mars',
|
|
117
|
+
apr: 'apríl',
|
|
118
|
+
maj: 'maí',
|
|
119
|
+
jun: 'júní',
|
|
120
|
+
jul: 'júlí',
|
|
121
|
+
aug: 'ágúst',
|
|
122
|
+
// sep: 'september', // is the same
|
|
123
|
+
okt: 'október',
|
|
124
|
+
nov: 'nóvember',
|
|
125
|
+
dec: 'desember',
|
|
126
|
+
};
|
|
127
|
+
const weekdays = {
|
|
128
|
+
man: 'mánudagur',
|
|
129
|
+
tir: 'þriðjudagur',
|
|
130
|
+
ons: 'miðvikudagur',
|
|
131
|
+
tor: 'fimmtudagur',
|
|
132
|
+
fre: 'föstudagur',
|
|
133
|
+
lør: 'laugardagur',
|
|
134
|
+
søn: 'sunnudagur',
|
|
135
|
+
};
|
|
136
|
+
const partMappers = {
|
|
137
|
+
month: (value) => {
|
|
138
|
+
const islMonth = months[value.slice(0, 3)];
|
|
139
|
+
if (islMonth) {
|
|
140
|
+
return value.endsWith('.') ? `${islMonth.slice(0, 3)}.` : islMonth;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
weekday: (value) => {
|
|
144
|
+
const isl = weekdays[value.slice(0, 3)];
|
|
145
|
+
if (isl) {
|
|
146
|
+
return value.endsWith('.') ? `${isl.slice(0, 3)}.` : isl;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
era: (value) => {
|
|
150
|
+
if (!value.endsWith('.')) {
|
|
151
|
+
return value.length === 3
|
|
152
|
+
? `${value[0]}.k.`
|
|
153
|
+
: value[0] === 'f'
|
|
154
|
+
? 'fyrir Krist'
|
|
155
|
+
: 'eftir Krist';
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
dayPeriod: (value) => {
|
|
159
|
+
return { AM: 'f.h.', PM: 'e.h.' }[value] || value;
|
|
160
|
+
},
|
|
161
|
+
literal: (value, lastType) => {
|
|
162
|
+
if (value === ' den ') {
|
|
163
|
+
return 'inn ';
|
|
164
|
+
}
|
|
165
|
+
else if (value === '.' && (lastType === 'hour' || lastType === 'minute')) {
|
|
166
|
+
return ':';
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
const reformatDateTimeParts = function (parts) {
|
|
171
|
+
if (!this.mapped) {
|
|
172
|
+
return parts;
|
|
173
|
+
}
|
|
174
|
+
parts.forEach((part, idx) => {
|
|
175
|
+
var _a;
|
|
176
|
+
const mapper = partMappers[part.type];
|
|
177
|
+
const newValue = mapper && mapper(part.value, (_a = parts[idx - 1]) === null || _a === void 0 ? void 0 : _a.type);
|
|
178
|
+
if (newValue != null) {
|
|
179
|
+
part.value = newValue;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return parts;
|
|
183
|
+
};
|
|
184
|
+
const PatchedDateTimeFormat = function DateTimeFormat(locales, options) {
|
|
185
|
+
if (!(this instanceof PatchedDateTimeFormat)) {
|
|
186
|
+
// @ts-expect-error (YOLO! Can't be arsed)
|
|
187
|
+
return new PatchedDateTimeFormat(locales, options);
|
|
188
|
+
}
|
|
189
|
+
const mappedLocales = mapLocales(locales);
|
|
190
|
+
if (options === null || options === void 0 ? void 0 : options.hour12) {
|
|
191
|
+
options = {
|
|
192
|
+
...options,
|
|
193
|
+
hour12: undefined,
|
|
194
|
+
hourCycle: 'h11',
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
this.super = _DateTimeFormat(mappedLocales || locales, options);
|
|
198
|
+
this.mapped = !!mappedLocales;
|
|
199
|
+
};
|
|
200
|
+
// This is all very hacky, but extending the class *AND* preseving the
|
|
201
|
+
// ability to instantiate without `new` is a bit of a pain.
|
|
202
|
+
// Eagerly interested in finding a better way to do this.
|
|
203
|
+
const dateTimeFormatProto = {
|
|
204
|
+
constructor: PatchedDateTimeFormat,
|
|
205
|
+
format(value) {
|
|
206
|
+
return combineParts(this.formatToParts(value));
|
|
207
|
+
},
|
|
208
|
+
formatRange(value1, value2) {
|
|
209
|
+
return combineParts(this.formatRangeToParts(value1, value2));
|
|
210
|
+
},
|
|
211
|
+
formatToParts(value) {
|
|
212
|
+
return reformatDateTimeParts.call(this, this.super.formatToParts(value));
|
|
213
|
+
},
|
|
214
|
+
formatRangeToParts(value1, value2) {
|
|
215
|
+
return reformatDateTimeParts.call(this, this.super.formatRangeToParts(value1, value2));
|
|
216
|
+
},
|
|
217
|
+
resolvedOptions() {
|
|
218
|
+
return this.super.resolvedOptions();
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
PatchedDateTimeFormat.prototype = dateTimeFormatProto;
|
|
222
|
+
// Static methods (not patched since "is" is not ACTUALLY supported.)
|
|
223
|
+
PatchedDateTimeFormat.supportedLocalesOf = _DateTimeFormat.supportedLocalesOf;
|
|
224
|
+
PatchedDateTimeFormat.$original = _DateTimeFormat;
|
|
225
|
+
exports._PatchedDateTimeFormat = PatchedDateTimeFormat;
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
const _toLocaleDateString = Date.prototype.toLocaleDateString;
|
|
228
|
+
const _patchedToLocaleDateString = function toLocaleDateString(locales, options) {
|
|
229
|
+
return (0, exports._PatchedDateTimeFormat)(locales, options).format(this);
|
|
230
|
+
};
|
|
231
|
+
exports._patchedToLocaleDateString = _patchedToLocaleDateString;
|
|
232
|
+
exports._patchedToLocaleDateString.$original = _toLocaleDateString;
|
package/package.json
CHANGED