@shoelace-style/localize 3.0.3 → 3.1.0
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 +8 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +18 -3
- package/package.json +1 -1
- package/src/index.ts +59 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.1.0
|
|
4
|
+
|
|
5
|
+
- Added `exists()` method to determine if a term and/or a fallback term exists [#17](https://github.com/shoelace-style/localize/issues/17)
|
|
6
|
+
|
|
7
|
+
## 3.0.4
|
|
8
|
+
|
|
9
|
+
- Ensure return values of translation functions are always a string
|
|
10
|
+
|
|
3
11
|
## 3.0.3
|
|
4
12
|
|
|
5
13
|
- Fixed a bug where regional locales stopped working
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export interface Translation {
|
|
|
8
8
|
export interface DefaultTranslation extends Translation {
|
|
9
9
|
[key: string]: any;
|
|
10
10
|
}
|
|
11
|
+
export interface ExistsOptions {
|
|
12
|
+
lang: string;
|
|
13
|
+
includeFallback: boolean;
|
|
14
|
+
}
|
|
11
15
|
export declare function registerTranslation(...translation: Translation[]): void;
|
|
12
16
|
export declare function update(): void;
|
|
13
17
|
export declare class LocalizeController<UserTranslation extends Translation = DefaultTranslation> implements ReactiveController {
|
|
@@ -17,7 +21,9 @@ export declare class LocalizeController<UserTranslation extends Translation = De
|
|
|
17
21
|
hostDisconnected(): void;
|
|
18
22
|
dir(): string;
|
|
19
23
|
lang(): string;
|
|
20
|
-
|
|
24
|
+
private getTranslationData;
|
|
25
|
+
exists<K extends keyof UserTranslation>(key: K, options: Partial<ExistsOptions>): boolean;
|
|
26
|
+
term<K extends keyof UserTranslation>(key: K, ...args: FunctionParams<UserTranslation[K]>): string;
|
|
21
27
|
date(dateToFormat: Date | string, options?: Intl.DateTimeFormatOptions): string;
|
|
22
28
|
number(numberToFormat: number | string, options?: Intl.NumberFormatOptions): string;
|
|
23
29
|
relativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;
|
package/dist/index.js
CHANGED
|
@@ -49,13 +49,28 @@ export class LocalizeController {
|
|
|
49
49
|
lang() {
|
|
50
50
|
return `${this.host.lang || documentLanguage}`.toLowerCase();
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
getTranslationData(lang) {
|
|
53
53
|
var _a, _b;
|
|
54
|
-
const locale = new Intl.Locale(
|
|
54
|
+
const locale = new Intl.Locale(lang);
|
|
55
55
|
const language = locale === null || locale === void 0 ? void 0 : locale.language.toLowerCase();
|
|
56
56
|
const region = (_b = (_a = locale === null || locale === void 0 ? void 0 : locale.region) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
|
|
57
57
|
const primary = translations.get(`${language}-${region}`);
|
|
58
58
|
const secondary = translations.get(language);
|
|
59
|
+
return { locale, language, region, primary, secondary };
|
|
60
|
+
}
|
|
61
|
+
exists(key, options) {
|
|
62
|
+
var _a;
|
|
63
|
+
const { primary, secondary } = this.getTranslationData((_a = options.lang) !== null && _a !== void 0 ? _a : this.lang());
|
|
64
|
+
options = Object.assign({ includeFallback: false }, options);
|
|
65
|
+
if ((primary && primary[key]) ||
|
|
66
|
+
(secondary && secondary[key]) ||
|
|
67
|
+
(options.includeFallback && fallback && fallback[key])) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
term(key, ...args) {
|
|
73
|
+
const { primary, secondary } = this.getTranslationData(this.lang());
|
|
59
74
|
let term;
|
|
60
75
|
if (primary && primary[key]) {
|
|
61
76
|
term = primary[key];
|
|
@@ -68,7 +83,7 @@ export class LocalizeController {
|
|
|
68
83
|
}
|
|
69
84
|
else {
|
|
70
85
|
console.error(`No translation found for: ${String(key)}`);
|
|
71
|
-
return key;
|
|
86
|
+
return String(key);
|
|
72
87
|
}
|
|
73
88
|
if (typeof term === 'function') {
|
|
74
89
|
return term(...args);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -12,6 +12,11 @@ export interface DefaultTranslation extends Translation {
|
|
|
12
12
|
[key: string]: any;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface ExistsOptions {
|
|
16
|
+
lang: string;
|
|
17
|
+
includeFallback: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
const connectedElements = new Set<HTMLElement>();
|
|
16
21
|
const documentElementObserver = new MutationObserver(update);
|
|
17
22
|
const translations: Map<string, Translation> = new Map();
|
|
@@ -25,9 +30,7 @@ documentElementObserver.observe(document.documentElement, {
|
|
|
25
30
|
attributeFilter: ['dir', 'lang']
|
|
26
31
|
});
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
// Registers one or more translations
|
|
30
|
-
//
|
|
33
|
+
/** Registers one or more translations */
|
|
31
34
|
export function registerTranslation(...translation: Translation[]) {
|
|
32
35
|
translation.map(t => {
|
|
33
36
|
const code = t.$code.toLowerCase();
|
|
@@ -48,9 +51,7 @@ export function registerTranslation(...translation: Translation[]) {
|
|
|
48
51
|
update();
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
// Updates all localized elements that are currently connected
|
|
53
|
-
//
|
|
54
|
+
/** Updates all localized elements that are currently connected */
|
|
54
55
|
export function update() {
|
|
55
56
|
documentDirection = document.documentElement.dir || 'ltr';
|
|
56
57
|
documentLanguage = document.documentElement.lang || navigator.language;
|
|
@@ -62,25 +63,25 @@ export function update() {
|
|
|
62
63
|
});
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Localize Reactive Controller for components built with Lit
|
|
68
|
+
*
|
|
69
|
+
* To use this controller, import the class and instantiate it in a custom element constructor:
|
|
70
|
+
*
|
|
71
|
+
* private localize = new LocalizeController(this);
|
|
72
|
+
*
|
|
73
|
+
* This will add the element to the set and make it respond to changes to <html dir|lang> automatically. To make it
|
|
74
|
+
* respond to changes to its own dir|lang properties, make it a property:
|
|
75
|
+
*
|
|
76
|
+
* @property() dir: string;
|
|
77
|
+
* @property() lang: string;
|
|
78
|
+
*
|
|
79
|
+
* To use a translation method, call it like this:
|
|
80
|
+
*
|
|
81
|
+
* ${this.localize.term('term_key_here')}
|
|
82
|
+
* ${this.localize.date('2021-12-03')}
|
|
83
|
+
* ${this.localize.number(1000000)}
|
|
84
|
+
*/
|
|
84
85
|
export class LocalizeController<UserTranslation extends Translation = DefaultTranslation>
|
|
85
86
|
implements ReactiveController
|
|
86
87
|
{
|
|
@@ -115,12 +116,39 @@ export class LocalizeController<UserTranslation extends Translation = DefaultTra
|
|
|
115
116
|
return `${this.host.lang || documentLanguage}`.toLowerCase();
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
const locale = new Intl.Locale(
|
|
119
|
+
private getTranslationData(lang: string) {
|
|
120
|
+
const locale = new Intl.Locale(lang);
|
|
120
121
|
const language = locale?.language.toLowerCase();
|
|
121
122
|
const region = locale?.region?.toLowerCase() ?? '';
|
|
122
123
|
const primary = <UserTranslation>translations.get(`${language}-${region}`);
|
|
123
124
|
const secondary = <UserTranslation>translations.get(language);
|
|
125
|
+
|
|
126
|
+
return { locale, language, region, primary, secondary };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Determines if the specified term exists, optionally checking the fallback translation. */
|
|
130
|
+
exists<K extends keyof UserTranslation>(key: K, options: Partial<ExistsOptions>): boolean {
|
|
131
|
+
const { primary, secondary } = this.getTranslationData(options.lang ?? this.lang());
|
|
132
|
+
|
|
133
|
+
options = {
|
|
134
|
+
includeFallback: false,
|
|
135
|
+
...options
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
(primary && primary[key]) ||
|
|
140
|
+
(secondary && secondary[key]) ||
|
|
141
|
+
(options.includeFallback && fallback && fallback[key as keyof Translation])
|
|
142
|
+
) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Outputs a translated term. */
|
|
150
|
+
term<K extends keyof UserTranslation>(key: K, ...args: FunctionParams<UserTranslation[K]>): string {
|
|
151
|
+
const { primary, secondary } = this.getTranslationData(this.lang());
|
|
124
152
|
let term: any;
|
|
125
153
|
|
|
126
154
|
// Look for a matching term using regionCode, code, then the fallback
|
|
@@ -132,7 +160,7 @@ export class LocalizeController<UserTranslation extends Translation = DefaultTra
|
|
|
132
160
|
term = fallback[key as keyof Translation];
|
|
133
161
|
} else {
|
|
134
162
|
console.error(`No translation found for: ${String(key)}`);
|
|
135
|
-
return key;
|
|
163
|
+
return String(key);
|
|
136
164
|
}
|
|
137
165
|
|
|
138
166
|
if (typeof term === 'function') {
|
|
@@ -143,19 +171,19 @@ export class LocalizeController<UserTranslation extends Translation = DefaultTra
|
|
|
143
171
|
}
|
|
144
172
|
|
|
145
173
|
/** Outputs a localized date in the specified format. */
|
|
146
|
-
date(dateToFormat: Date | string, options?: Intl.DateTimeFormatOptions) {
|
|
174
|
+
date(dateToFormat: Date | string, options?: Intl.DateTimeFormatOptions): string {
|
|
147
175
|
dateToFormat = new Date(dateToFormat);
|
|
148
176
|
return new Intl.DateTimeFormat(this.lang(), options).format(dateToFormat);
|
|
149
177
|
}
|
|
150
178
|
|
|
151
179
|
/** Outputs a localized number in the specified format. */
|
|
152
|
-
number(numberToFormat: number | string, options?: Intl.NumberFormatOptions) {
|
|
180
|
+
number(numberToFormat: number | string, options?: Intl.NumberFormatOptions): string {
|
|
153
181
|
numberToFormat = Number(numberToFormat);
|
|
154
182
|
return isNaN(numberToFormat) ? '' : new Intl.NumberFormat(this.lang(), options).format(numberToFormat);
|
|
155
183
|
}
|
|
156
184
|
|
|
157
185
|
/** Outputs a localized time in relative format. */
|
|
158
|
-
relativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions) {
|
|
186
|
+
relativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {
|
|
159
187
|
return new Intl.RelativeTimeFormat(this.lang(), options).format(value, unit);
|
|
160
188
|
}
|
|
161
189
|
}
|