@smileid/web-components 11.0.3 → 11.2.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/README.md +61 -0
- package/dist/components/smart-camera-web/src/README.md +0 -1
- package/dist/esm/{DocumentCaptureScreens-C5BhNB-0.js → DocumentCaptureScreens-BbtA-WkX.js} +199 -193
- package/dist/esm/DocumentCaptureScreens-BbtA-WkX.js.map +1 -0
- package/dist/esm/{EndUserConsent-D4fd1ovG.js → EndUserConsent-HVufMamg.js} +65 -63
- package/dist/esm/EndUserConsent-HVufMamg.js.map +1 -0
- package/dist/esm/{Navigation-CTjK6tLU.js → Navigation-B-dqPkZj.js} +17 -9
- package/dist/esm/Navigation-B-dqPkZj.js.map +1 -0
- package/dist/esm/{SelfieCaptureScreens-KoQpCxtc.js → SelfieCaptureScreens-ChAMfKi3.js} +3274 -3329
- package/dist/esm/SelfieCaptureScreens-ChAMfKi3.js.map +1 -0
- package/dist/esm/{TotpConsent-CQU5jQi4.js → TotpConsent-XxR8TNxy.js} +13 -9
- package/dist/esm/TotpConsent-XxR8TNxy.js.map +1 -0
- package/dist/esm/combobox.js +20 -19
- package/dist/esm/combobox.js.map +1 -1
- package/dist/esm/document.js +1 -1
- package/dist/esm/end-user-consent.js +1 -1
- package/dist/esm/index-B_ozpejI.js +1360 -0
- package/dist/esm/index-B_ozpejI.js.map +1 -0
- package/dist/esm/localisation.js +21 -0
- package/dist/esm/localisation.js.map +1 -0
- package/dist/esm/main.js +34 -17
- package/dist/esm/main.js.map +1 -1
- package/dist/esm/navigation.js +1 -1
- package/dist/esm/{package-B-UwEdv7.js → package-u3FEJ3Fm.js} +25 -40
- package/dist/esm/package-u3FEJ3Fm.js.map +1 -0
- package/dist/esm/selfie.js +1 -1
- package/dist/esm/smart-camera-web.js +32 -23
- package/dist/esm/smart-camera-web.js.map +1 -1
- package/dist/esm/totp-consent.js +1 -1
- package/dist/package.json +1 -1
- package/dist/smart-camera-web.js +144 -160
- package/dist/smart-camera-web.js.map +1 -1
- package/dist/src/components/combobox/src/index.js +424 -1
- package/dist/src/components/document/src/index.js +1422 -1
- package/dist/src/components/end-user-consent/src/index.js +1573 -1
- package/dist/src/components/selfie/src/index.js +1220 -1
- package/dist/src/components/signature-pad/src/index.js +787 -1
- package/dist/src/components/smart-camera-web/src/SmartCameraWeb.js +2753 -1
- package/dist/src/components/totp-consent/src/index.js +1292 -1
- package/dist/types/combobox.d.ts +2 -2
- package/dist/types/document.d.ts +2 -2
- package/dist/types/end-user-consent.d.ts +2 -2
- package/dist/types/locale.d.ts +19 -0
- package/dist/types/localisation.d.ts +21 -0
- package/dist/types/main.d.ts +35 -26
- package/dist/types/navigation.d.ts +2 -2
- package/dist/types/selfie.d.ts +2 -2
- package/dist/types/signature-pad.d.ts +2 -2
- package/dist/types/smart-camera-web.d.ts +2 -2
- package/dist/types/totp-consent.d.ts +2 -2
- package/lib/components/camera-permission/CameraPermission.js +9 -4
- package/lib/components/combobox/src/Combobox.js +4 -2
- package/lib/components/document/src/DocumentCaptureScreens.js +4 -3
- package/lib/components/document/src/DocumentCaptureScreens.stories.js +37 -13
- package/lib/components/document/src/document-capture/DocumentCapture.js +23 -17
- package/lib/components/document/src/document-capture/DocumentCapture.stories.js +11 -2
- package/lib/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +19 -14
- package/lib/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +14 -5
- package/lib/components/document/src/document-capture-review/DocumentCaptureReview.js +14 -10
- package/lib/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +14 -5
- package/lib/components/end-user-consent/src/EndUserConsent.js +30 -29
- package/lib/components/end-user-consent/src/EndUserConsent.stories.js +12 -2
- package/lib/components/navigation/src/Navigation.js +15 -2
- package/lib/components/navigation/src/Navigation.stories.js +20 -4
- package/lib/components/selfie/src/SelfieCaptureScreens.js +12 -8
- package/lib/components/selfie/src/SelfieCaptureScreens.stories.js +16 -4
- package/lib/components/selfie/src/selfie-capture/SelfieCapture.js +25 -18
- package/lib/components/selfie/src/selfie-capture/SelfieCapture.stories.js +19 -7
- package/lib/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +19 -14
- package/lib/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +14 -5
- package/lib/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +13 -8
- package/lib/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +14 -5
- package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +98 -47
- package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +2 -2
- package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +5 -2
- package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +4 -4
- package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +6 -5
- package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +11 -9
- package/lib/components/selfie/src/smartselfie-capture/utils/imageCapture.ts +3 -1
- package/lib/components/signature-pad/package.json +1 -1
- package/lib/components/smart-camera-web/src/SmartCameraWeb.js +9 -1
- package/lib/components/totp-consent/src/TotpConsent.js +8 -3
- package/lib/domain/camera/src/SmartCamera.js +7 -22
- package/lib/domain/constants/src/Constants.js +28 -0
- package/lib/domain/file-upload/src/SmartFileUpload.js +9 -10
- package/lib/domain/localisation/index.js +456 -0
- package/package.json +13 -7
- package/dist/esm/DocumentCaptureScreens-C5BhNB-0.js.map +0 -1
- package/dist/esm/EndUserConsent-D4fd1ovG.js.map +0 -1
- package/dist/esm/Navigation-CTjK6tLU.js.map +0 -1
- package/dist/esm/SelfieCaptureScreens-KoQpCxtc.js.map +0 -1
- package/dist/esm/TotpConsent-CQU5jQi4.js.map +0 -1
- package/dist/esm/package-B-UwEdv7.js.map +0 -1
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal runtime i18n module for SmileID web components.
|
|
3
|
+
* Provides simple locale registration, loading, and translation lookup.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import merge from 'lodash/merge';
|
|
7
|
+
|
|
8
|
+
// Bundle supported locales for offline/instant switching
|
|
9
|
+
import arLocale from '../../../locales/ar-EG.json';
|
|
10
|
+
import enLocale from '../../../locales/en-GB.json';
|
|
11
|
+
import frLocale from '../../../locales/fr-FR.json';
|
|
12
|
+
|
|
13
|
+
// Locale alias mapping for short codes
|
|
14
|
+
const LOCALE_ALIASES = {
|
|
15
|
+
ar: 'ar-EG',
|
|
16
|
+
en: 'en-GB',
|
|
17
|
+
fr: 'fr-FR',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Resolve locale alias to full locale code.
|
|
22
|
+
* @param {string} lang - Language code (e.g., 'en', 'ar', 'en-GB')
|
|
23
|
+
* @returns {string} Resolved locale code
|
|
24
|
+
*/
|
|
25
|
+
function resolveLocale(lang) {
|
|
26
|
+
return LOCALE_ALIASES[lang] || lang;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DEFAULT_LOCALE = 'en-GB';
|
|
30
|
+
const FETCH_TIMEOUT_MS = 5000;
|
|
31
|
+
|
|
32
|
+
let currentLocale = DEFAULT_LOCALE;
|
|
33
|
+
const locales = {
|
|
34
|
+
'ar-EG': arLocale,
|
|
35
|
+
'en-GB': enLocale,
|
|
36
|
+
'fr-FR': frLocale,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Register a locale object (in-memory).
|
|
41
|
+
* @param {string} lang - Language code (e.g., 'en-GB', 'ar-EG')
|
|
42
|
+
* @param {object} data - Locale translation object
|
|
43
|
+
*/
|
|
44
|
+
export function registerLocale(lang, data) {
|
|
45
|
+
locales[lang] = data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Deep merge source object into target object.
|
|
50
|
+
* Recursively merges nested objects while preserving non-overridden values.
|
|
51
|
+
* Uses lodash merge under the hood but returns a new object (does not mutate inputs).
|
|
52
|
+
* @param {object} target - Base object to merge into
|
|
53
|
+
* @param {object} source - Object with values to merge/override
|
|
54
|
+
* @returns {object} New merged object (does not mutate inputs)
|
|
55
|
+
*/
|
|
56
|
+
export function deepMerge(target, source) {
|
|
57
|
+
if (!source || typeof source !== 'object') {
|
|
58
|
+
return target;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!target || typeof target !== 'object') {
|
|
62
|
+
return source;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Use lodash merge with empty object as first arg to avoid mutating target
|
|
66
|
+
return merge({}, target, source);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Required translation keys for a complete locale.
|
|
71
|
+
* These are the minimum keys needed for the SDK to function properly.
|
|
72
|
+
*/
|
|
73
|
+
const REQUIRED_LOCALE_KEYS = [
|
|
74
|
+
'direction',
|
|
75
|
+
'common.back',
|
|
76
|
+
'common.close',
|
|
77
|
+
'common.continue',
|
|
78
|
+
'common.cancel',
|
|
79
|
+
'camera.permission.description',
|
|
80
|
+
'camera.permission.requestButton',
|
|
81
|
+
'camera.error.notAllowed',
|
|
82
|
+
'selfie.instructions.title',
|
|
83
|
+
'selfie.capture.button.takeSelfie',
|
|
84
|
+
'selfie.review.title',
|
|
85
|
+
'selfie.review.acceptButton',
|
|
86
|
+
'selfie.review.retakeButton',
|
|
87
|
+
'document.capture.captureButton',
|
|
88
|
+
'document.review.acceptButton',
|
|
89
|
+
'document.review.retakeButton',
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Fetch with timeout wrapper.
|
|
94
|
+
* @param {string} url - URL to fetch
|
|
95
|
+
* @param {number} timeout - Timeout in milliseconds
|
|
96
|
+
* @returns {Promise<Response>} Fetch response
|
|
97
|
+
*/
|
|
98
|
+
async function fetchWithTimeout(url, timeout = FETCH_TIMEOUT_MS) {
|
|
99
|
+
const controller = new AbortController();
|
|
100
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
104
|
+
return response;
|
|
105
|
+
} finally {
|
|
106
|
+
clearTimeout(timeoutId);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Register a locale by URL (fetch and cache).
|
|
112
|
+
* @param {string} lang - Language code
|
|
113
|
+
* @param {string} url - URL to locale JSON file
|
|
114
|
+
* @returns {Promise<object>} Loaded locale data
|
|
115
|
+
*/
|
|
116
|
+
export async function registerLocaleUrl(lang, url) {
|
|
117
|
+
try {
|
|
118
|
+
const response = await fetchWithTimeout(url);
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(`Failed to load locale from ${url}: ${response.status}`);
|
|
121
|
+
}
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
registerLocale(lang, data);
|
|
124
|
+
return data;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
const errorMessage =
|
|
127
|
+
error.name === 'AbortError'
|
|
128
|
+
? `Timeout loading locale '${lang}' from ${url}`
|
|
129
|
+
: `Error loading locale '${lang}' from ${url}: ${error.message}`;
|
|
130
|
+
console.error(errorMessage);
|
|
131
|
+
|
|
132
|
+
// Fallback to default locale if available
|
|
133
|
+
if (lang !== DEFAULT_LOCALE && locales[DEFAULT_LOCALE]) {
|
|
134
|
+
console.warn(`Falling back to default locale '${DEFAULT_LOCALE}'`);
|
|
135
|
+
return locales[DEFAULT_LOCALE];
|
|
136
|
+
}
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Load a locale (supports both inline registration and URL fetch).
|
|
143
|
+
* @param {string} lang - Language code
|
|
144
|
+
* @param {string} [url] - Optional URL to fetch locale from
|
|
145
|
+
* @returns {Promise<object>} Loaded locale data
|
|
146
|
+
*/
|
|
147
|
+
export async function loadLocale(lang, url) {
|
|
148
|
+
const resolvedLang = resolveLocale(lang);
|
|
149
|
+
|
|
150
|
+
// Return cached locale if available
|
|
151
|
+
if (locales[resolvedLang]) {
|
|
152
|
+
return locales[resolvedLang];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Fetch from URL if provided
|
|
156
|
+
if (url) {
|
|
157
|
+
return registerLocaleUrl(lang, url);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// No URL provided and locale not cached - fallback to default
|
|
161
|
+
console.warn(
|
|
162
|
+
`Locale '${lang}' not found and no URL provided, using default '${DEFAULT_LOCALE}'`,
|
|
163
|
+
);
|
|
164
|
+
return locales[DEFAULT_LOCALE] || {};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Helper to get nested value from object using dot notation.
|
|
169
|
+
* @param {object} obj - Object to traverse
|
|
170
|
+
* @param {string} key - Dot-separated key path
|
|
171
|
+
* @returns {string|undefined} Value at path or undefined
|
|
172
|
+
*/
|
|
173
|
+
function getNestedValue(obj, key) {
|
|
174
|
+
if (!obj) return undefined;
|
|
175
|
+
|
|
176
|
+
const value = key.split('.').reduce((acc, k) => {
|
|
177
|
+
if (acc && typeof acc === 'object' && k in acc) {
|
|
178
|
+
return acc[k];
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
}, obj);
|
|
182
|
+
|
|
183
|
+
return typeof value === 'string' ? value : undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Validate that a locale has all required translation keys.
|
|
188
|
+
* @param {object} locale - Locale data to validate
|
|
189
|
+
* @returns {{ missingKeys: string[], valid: boolean }} Validation result
|
|
190
|
+
*/
|
|
191
|
+
export function validateLocale(locale) {
|
|
192
|
+
if (!locale || typeof locale !== 'object') {
|
|
193
|
+
return { missingKeys: REQUIRED_LOCALE_KEYS, valid: false };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const missingKeys = REQUIRED_LOCALE_KEYS.filter((key) => {
|
|
197
|
+
if (key === 'direction') {
|
|
198
|
+
return !locale.direction;
|
|
199
|
+
}
|
|
200
|
+
return !getNestedValue(locale, key);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
missingKeys,
|
|
205
|
+
valid: missingKeys.length === 0,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get translation for a key.
|
|
211
|
+
* Supports nested keys with dot notation (e.g., 'camera.permission.description').
|
|
212
|
+
* Fallback chain: current locale → default locale (English) → raw key.
|
|
213
|
+
* @param {string} key - Translation key
|
|
214
|
+
* @returns {string} Translated string or fallback
|
|
215
|
+
*/
|
|
216
|
+
export function t(key) {
|
|
217
|
+
// Try current locale first
|
|
218
|
+
const resolvedLocale = resolveLocale(currentLocale);
|
|
219
|
+
const currentLocaleData = locales[resolvedLocale];
|
|
220
|
+
const value = getNestedValue(currentLocaleData, key);
|
|
221
|
+
if (value) {
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Fallback to default locale if different from current
|
|
226
|
+
const resolvedDefault = resolveLocale(DEFAULT_LOCALE);
|
|
227
|
+
if (resolvedLocale !== resolvedDefault) {
|
|
228
|
+
const defaultValue = getNestedValue(locales[resolvedDefault], key);
|
|
229
|
+
if (defaultValue) {
|
|
230
|
+
return defaultValue;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Final fallback: return the key itself
|
|
235
|
+
console.warn(`Translation key '${key}' not found in any locale`);
|
|
236
|
+
return key;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Alias for t() function.
|
|
241
|
+
* @see t
|
|
242
|
+
*/
|
|
243
|
+
export const translate = t;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* HTML entity map for escaping special characters.
|
|
247
|
+
*/
|
|
248
|
+
const HTML_ENTITIES = {
|
|
249
|
+
'"': '"',
|
|
250
|
+
'&': '&',
|
|
251
|
+
"'": ''',
|
|
252
|
+
'<': '<',
|
|
253
|
+
'>': '>',
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Escape HTML special characters to prevent XSS.
|
|
258
|
+
* @param {string} str - String to escape
|
|
259
|
+
* @returns {string} Escaped string
|
|
260
|
+
*/
|
|
261
|
+
export function escapeHtml(str) {
|
|
262
|
+
return str.replace(/[&<>"']/g, (char) => HTML_ENTITIES[char]);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get translation with HTML interpolation for styled placeholders.
|
|
267
|
+
* Placeholders in format {{key}} will be replaced with provided values.
|
|
268
|
+
* Values can be plain strings or objects with {value, className} for styled spans.
|
|
269
|
+
* @param {string} key - Translation key
|
|
270
|
+
* @param {Object} params - Interpolation parameters
|
|
271
|
+
* @returns {string} Translated string with interpolations
|
|
272
|
+
* @example
|
|
273
|
+
* // Plain interpolation
|
|
274
|
+
* tHtml('greeting', { name: 'John' }) // "Hello, John"
|
|
275
|
+
*
|
|
276
|
+
* // Styled interpolation
|
|
277
|
+
* tHtml('consent.accessRequest', {
|
|
278
|
+
* partnerName: { value: 'Acme', className: 'theme' }
|
|
279
|
+
* }) // "<span class="theme">Acme</span> wants to access..."
|
|
280
|
+
*/
|
|
281
|
+
export function tHtml(key, params = {}) {
|
|
282
|
+
let text = t(key);
|
|
283
|
+
|
|
284
|
+
Object.keys(params).forEach((paramKey) => {
|
|
285
|
+
const paramValue = params[paramKey];
|
|
286
|
+
const placeholder = `{{${paramKey}}}`;
|
|
287
|
+
|
|
288
|
+
if (paramValue && typeof paramValue === 'object' && 'value' in paramValue) {
|
|
289
|
+
// Styled interpolation: { value: 'text', className: 'theme' }
|
|
290
|
+
const escapedValue = escapeHtml(String(paramValue.value || ''));
|
|
291
|
+
const className = escapeHtml(String(paramValue.className || ''));
|
|
292
|
+
text = text
|
|
293
|
+
.split(placeholder)
|
|
294
|
+
.join(
|
|
295
|
+
className
|
|
296
|
+
? `<span class="${className}">${escapedValue}</span>`
|
|
297
|
+
: escapedValue,
|
|
298
|
+
);
|
|
299
|
+
} else {
|
|
300
|
+
// Plain text interpolation
|
|
301
|
+
text = text.split(placeholder).join(escapeHtml(String(paramValue)));
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
return text;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Alias for tHtml() function.
|
|
310
|
+
* @see tHtml
|
|
311
|
+
*/
|
|
312
|
+
export const translateHtml = tHtml;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Set the current locale.
|
|
316
|
+
* If the locale is not registered, it will attempt to load it from the provided URL.
|
|
317
|
+
* Applies RTL direction to document element if direction is specified in locale.
|
|
318
|
+
* @param {string} lang - Language code
|
|
319
|
+
* @param {Object} [options] - Configuration options
|
|
320
|
+
* @param {string} [options.url] - URL to fetch locale from if not registered
|
|
321
|
+
* @param {Object} [options.translation] - Complete locale data object (legacy)
|
|
322
|
+
* @param {Object} [options.locales] - Locale data keyed by language code (new API)
|
|
323
|
+
* @param {boolean} [options.validate] - Whether to validate locale completeness
|
|
324
|
+
* @returns {Promise<boolean>} Whether locale was successfully set
|
|
325
|
+
*/
|
|
326
|
+
export async function setCurrentLocale(
|
|
327
|
+
lang,
|
|
328
|
+
{ url, translation, locales: customLocales, validate = false } = {},
|
|
329
|
+
) {
|
|
330
|
+
currentLocale = resolveLocale(lang);
|
|
331
|
+
// Step 1: Process custom locales (new API - keyed by language code)
|
|
332
|
+
if (customLocales && typeof customLocales === 'object') {
|
|
333
|
+
Object.entries(customLocales).forEach(([localeKey, localeData]) => {
|
|
334
|
+
if (!localeData || typeof localeData !== 'object') {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const resolvedKey = resolveLocale(localeKey);
|
|
339
|
+
|
|
340
|
+
if (locales[resolvedKey]) {
|
|
341
|
+
// Deep merge into existing bundled locale
|
|
342
|
+
locales[resolvedKey] = deepMerge(locales[resolvedKey], localeData);
|
|
343
|
+
} else {
|
|
344
|
+
// Register as new locale
|
|
345
|
+
registerLocale(resolvedKey, localeData);
|
|
346
|
+
|
|
347
|
+
// Add alias if short code provided
|
|
348
|
+
if (localeKey !== resolvedKey) {
|
|
349
|
+
LOCALE_ALIASES[localeKey] = resolvedKey;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Step 2: Handle legacy translation option (for backward compatibility)
|
|
356
|
+
if (!locales[currentLocale]) {
|
|
357
|
+
if (translation) {
|
|
358
|
+
registerLocale(currentLocale, translation);
|
|
359
|
+
} else if (url) {
|
|
360
|
+
try {
|
|
361
|
+
await loadLocale(currentLocale, url);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error(
|
|
364
|
+
`Failed to load locale '${lang}', keeping current locale '${currentLocale}'`,
|
|
365
|
+
);
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
console.warn(`Locale '${lang}' not registered and no URL provided`);
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Step 3: Validate locale completeness if requested
|
|
375
|
+
if (validate && locales[currentLocale]) {
|
|
376
|
+
const validation = validateLocale(locales[currentLocale]);
|
|
377
|
+
if (!validation.valid) {
|
|
378
|
+
console.warn(
|
|
379
|
+
`Locale '${lang}' is missing required keys:`,
|
|
380
|
+
validation.missingKeys,
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Step 4: Apply RTL/LTR direction if specified in locale data
|
|
386
|
+
const locale = locales[currentLocale];
|
|
387
|
+
if (locale && locale.direction && document?.documentElement) {
|
|
388
|
+
document.documentElement.dir = locale.direction;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Get the current locale.
|
|
396
|
+
* @returns {string} Current language code
|
|
397
|
+
*/
|
|
398
|
+
export function getCurrentLocale() {
|
|
399
|
+
return currentLocale;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get the default locale code.
|
|
404
|
+
* @returns {string} Default language code
|
|
405
|
+
*/
|
|
406
|
+
export function getDefaultLocale() {
|
|
407
|
+
return DEFAULT_LOCALE;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Check if a locale is registered.
|
|
412
|
+
* @param {string} lang - Language code
|
|
413
|
+
* @returns {boolean} Whether locale is registered
|
|
414
|
+
*/
|
|
415
|
+
export function hasLocale(lang) {
|
|
416
|
+
return lang in locales;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Set document direction based on locale direction property.
|
|
421
|
+
* @param {string} lang - Language code
|
|
422
|
+
*/
|
|
423
|
+
export function setDocumentDir(lang) {
|
|
424
|
+
const locale = locales[lang];
|
|
425
|
+
if (locale && locale.direction) {
|
|
426
|
+
document.documentElement.dir = locale.direction;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Get the text direction for the current locale.
|
|
432
|
+
* @returns {string} Direction ('ltr' or 'rtl'), defaults to 'ltr'
|
|
433
|
+
*/
|
|
434
|
+
export function getDirection() {
|
|
435
|
+
const locale = locales[currentLocale];
|
|
436
|
+
return locale?.direction || 'ltr';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export default {
|
|
440
|
+
deepMerge,
|
|
441
|
+
escapeHtml,
|
|
442
|
+
getCurrentLocale,
|
|
443
|
+
getDefaultLocale,
|
|
444
|
+
getDirection,
|
|
445
|
+
hasLocale,
|
|
446
|
+
loadLocale,
|
|
447
|
+
registerLocale,
|
|
448
|
+
registerLocaleUrl,
|
|
449
|
+
setCurrentLocale,
|
|
450
|
+
setDocumentDir,
|
|
451
|
+
t,
|
|
452
|
+
tHtml,
|
|
453
|
+
translate,
|
|
454
|
+
translateHtml,
|
|
455
|
+
validateLocale,
|
|
456
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smileid/web-components",
|
|
3
|
-
"version": "11.0
|
|
3
|
+
"version": "11.2.0",
|
|
4
4
|
"main": "dist/esm/main.js",
|
|
5
5
|
"module": "dist/esm/main.js",
|
|
6
6
|
"types": "dist/types/main.d.ts",
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"./smart-camera-web": {
|
|
41
41
|
"types": "./dist/types/smart-camera-web.d.ts",
|
|
42
42
|
"import": "./dist/esm/smart-camera-web.js"
|
|
43
|
+
},
|
|
44
|
+
"./localisation": {
|
|
45
|
+
"types": "./dist/types/localisation.d.ts",
|
|
46
|
+
"import": "./dist/esm/localisation.js"
|
|
43
47
|
}
|
|
44
48
|
},
|
|
45
49
|
"files": [
|
|
@@ -75,8 +79,8 @@
|
|
|
75
79
|
"@mediapipe/tasks-vision": "^0.10.22-rc.20250304",
|
|
76
80
|
"@preact/signals": "^2.1.1",
|
|
77
81
|
"@tabler/icons-preact": "^3.34.0",
|
|
78
|
-
"lodash": "^4.17.
|
|
79
|
-
"preact": "^10.
|
|
82
|
+
"lodash": "^4.17.23",
|
|
83
|
+
"preact": "^10.27.3",
|
|
80
84
|
"preact-custom-element": "^4.3.0",
|
|
81
85
|
"preact-router": "^4.1.2",
|
|
82
86
|
"signature_pad": "^5.0.2",
|
|
@@ -87,25 +91,27 @@
|
|
|
87
91
|
"@types/lodash": "^4.17.20",
|
|
88
92
|
"@types/node": "^20.11.24",
|
|
89
93
|
"@types/preact-custom-element": "^4.0.4",
|
|
90
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
91
|
-
"@typescript-eslint/parser": "^
|
|
94
|
+
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
|
95
|
+
"@typescript-eslint/parser": "^8.49.0",
|
|
92
96
|
"cross-env": "^7.0.3",
|
|
93
97
|
"cypress": "^13.15.0",
|
|
94
98
|
"eslint": "^8.57.0",
|
|
95
99
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
96
|
-
"eslint-config-airbnb-typescript": "^18.0.0",
|
|
97
100
|
"eslint-config-prettier": "^9.1.0",
|
|
98
101
|
"eslint-import-resolver-typescript": "^3.6.1",
|
|
99
102
|
"eslint-plugin-cypress": "^3.3.0",
|
|
100
103
|
"eslint-plugin-import": "^2.29.1",
|
|
101
104
|
"eslint-plugin-jest": "^28.8.3",
|
|
102
105
|
"eslint-plugin-prettier": "^5.2.1",
|
|
103
|
-
"glob": "^10.
|
|
106
|
+
"glob": "^10.5.0",
|
|
104
107
|
"prettier": "^3.6.2",
|
|
105
108
|
"rollup-plugin-visualizer": "^6.0.3",
|
|
106
109
|
"typescript": "^5.8.3",
|
|
107
110
|
"vite": "^7.2.2",
|
|
108
111
|
"vite-plugin-dts": "^4.5.4",
|
|
109
112
|
"vite-plugin-tsconfig-paths": "^1.4.1"
|
|
113
|
+
},
|
|
114
|
+
"optionalDependencies": {
|
|
115
|
+
"@rollup/rollup-linux-x64-gnu": "^4.53.5"
|
|
110
116
|
}
|
|
111
117
|
}
|