@jotul/jotul-widgets 1.0.1 → 1.0.3
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/dist/JotulWidget.d.ts +2 -2
- package/dist/JotulWidget.js +20 -11
- package/dist/api.js +17 -9
- package/dist/i18n/widgetStrings.d.ts +6 -2
- package/dist/i18n/widgetStrings.js +315 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/utils.js +6 -1
- package/package.json +1 -1
package/dist/JotulWidget.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import './JotulWidget.css';
|
|
2
2
|
import { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode } from './api';
|
|
3
3
|
import type { JotulWidgetProps } from './types';
|
|
4
|
-
export { normalizeWidgetLocale } from './i18n/widgetStrings';
|
|
4
|
+
export { DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, } from './i18n/widgetStrings';
|
|
5
5
|
export type { JotulWidgetLocale } from './i18n/widgetStrings';
|
|
6
6
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
7
7
|
export type { CheckWidgetAuthorizationOptions, DealerSearchResponse, JotulWidgetButtonStyling, JotulWidgetProps, JotulWidgetStyling, JotulWidgetType, WidgetAuthClientResponse, } from './types';
|
|
8
|
-
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, brands, styling, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, market: marketProp, brands, styling, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/JotulWidget.js
CHANGED
|
@@ -5,11 +5,11 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
5
5
|
import { FinderSearchRowSkeleton } from './components/FinderSearchRowSkeleton';
|
|
6
6
|
import { ProductPageWidget } from './widgets/ProductPageWidget';
|
|
7
7
|
import { ButtonSpinner } from './icons/ButtonSpinner';
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_WIDGET_LOCALE_TAG, resolveWidgetUiLocale, WIDGET_STRINGS, } from './i18n/widgetStrings';
|
|
9
9
|
import { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, } from './api';
|
|
10
10
|
import { createInquiryFormValues, getSafeWidgetErrorMessage, isValidEmail, isWidgetType, renderReadyState, } from './utils';
|
|
11
11
|
import { getWidgetPrimaryButtonPresentation } from './utils/widgetPrimaryButtonPresentation';
|
|
12
|
-
export { normalizeWidgetLocale } from './i18n/widgetStrings';
|
|
12
|
+
export { DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, } from './i18n/widgetStrings';
|
|
13
13
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
14
14
|
const GEO_PERMISSION_DENIED = 1;
|
|
15
15
|
const GEO_POSITION_UNAVAILABLE = 2;
|
|
@@ -19,9 +19,17 @@ const GEOLOCATION_OPTIONS = {
|
|
|
19
19
|
timeout: 15000,
|
|
20
20
|
maximumAge: 300000,
|
|
21
21
|
};
|
|
22
|
-
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, brands, styling, }) {
|
|
23
|
-
const
|
|
24
|
-
const t = WIDGET_STRINGS[
|
|
22
|
+
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, market: marketProp, brands, styling, }) {
|
|
23
|
+
const resolvedUiLocale = useMemo(() => resolveWidgetUiLocale(localeProp, marketProp), [localeProp, marketProp]);
|
|
24
|
+
const t = WIDGET_STRINGS[resolvedUiLocale];
|
|
25
|
+
const apiLocaleTag = useMemo(() => (localeProp?.trim() ? localeProp.trim() : DEFAULT_WIDGET_LOCALE_TAG), [localeProp]);
|
|
26
|
+
const apiMarket = useMemo(() => {
|
|
27
|
+
const m = marketProp?.trim();
|
|
28
|
+
if (!m)
|
|
29
|
+
return undefined;
|
|
30
|
+
const upper = m.toUpperCase();
|
|
31
|
+
return /^[A-Z]{2}$/.test(upper) ? upper : undefined;
|
|
32
|
+
}, [marketProp]);
|
|
25
33
|
const heroPrimaryButton = useMemo(() => getWidgetPrimaryButtonPresentation(styling?.button, 'hero', {
|
|
26
34
|
disabledWait: true,
|
|
27
35
|
}), [styling?.button]);
|
|
@@ -44,9 +52,10 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
44
52
|
const autocompleteCacheRef = useRef(new Map());
|
|
45
53
|
const dealerSearchOptions = useMemo(() => ({
|
|
46
54
|
endpoint,
|
|
47
|
-
locale:
|
|
55
|
+
locale: apiLocaleTag,
|
|
56
|
+
market: apiMarket,
|
|
48
57
|
brands,
|
|
49
|
-
}), [brands, endpoint
|
|
58
|
+
}), [apiLocaleTag, apiMarket, brands, endpoint]);
|
|
50
59
|
const runDealerSearchByCoordinates = useCallback(async (latitude, longitude) => {
|
|
51
60
|
setLocationError(null);
|
|
52
61
|
setSearchResult(null);
|
|
@@ -60,7 +69,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
60
69
|
}
|
|
61
70
|
}, [dealerSearchOptions]);
|
|
62
71
|
const runLocationSearch = useCallback(() => {
|
|
63
|
-
const messages = WIDGET_STRINGS[
|
|
72
|
+
const messages = WIDGET_STRINGS[resolvedUiLocale];
|
|
64
73
|
setShouldAutoLocateAfterAuth(false);
|
|
65
74
|
setLocationError(null);
|
|
66
75
|
setSearchResult(null);
|
|
@@ -92,7 +101,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
92
101
|
setLocationError(messages.locationGenericFailure);
|
|
93
102
|
}
|
|
94
103
|
}, GEOLOCATION_OPTIONS);
|
|
95
|
-
}, [
|
|
104
|
+
}, [resolvedUiLocale, runDealerSearchByCoordinates]);
|
|
96
105
|
useEffect(() => {
|
|
97
106
|
const query = locationQuery.trim();
|
|
98
107
|
if (query.length < 3) {
|
|
@@ -100,7 +109,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
100
109
|
setLocationSuggestions([]);
|
|
101
110
|
return;
|
|
102
111
|
}
|
|
103
|
-
const cacheKey = query.toLowerCase()
|
|
112
|
+
const cacheKey = `${apiLocaleTag}|${apiMarket ?? ''}|${query.toLowerCase()}`;
|
|
104
113
|
const cached = autocompleteCacheRef.current.get(cacheKey);
|
|
105
114
|
if (cached != null) {
|
|
106
115
|
setLocationSuggestions(cached);
|
|
@@ -121,7 +130,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
121
130
|
cancelled = true;
|
|
122
131
|
clearTimeout(timer);
|
|
123
132
|
};
|
|
124
|
-
}, [dealerSearchOptions, locationQuery]);
|
|
133
|
+
}, [apiLocaleTag, apiMarket, dealerSearchOptions, locationQuery]);
|
|
125
134
|
useEffect(() => {
|
|
126
135
|
if (type === 'productPage' && !isOpen)
|
|
127
136
|
return;
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
import { DEFAULT_WIDGET_LOCALE_TAG } from './i18n/widgetStrings';
|
|
1
2
|
/** Client-side default when JSON parse fails (English; localized in UI). */
|
|
2
3
|
export const GENERIC_WIDGET_ERROR = 'Dealer finder is currently unavailable. Please try again later.';
|
|
4
|
+
function appendLocaleAndMarket(params, options) {
|
|
5
|
+
const locale = options?.locale != null && options.locale.trim() !== ''
|
|
6
|
+
? options.locale.trim()
|
|
7
|
+
: DEFAULT_WIDGET_LOCALE_TAG;
|
|
8
|
+
params.set('locale', locale);
|
|
9
|
+
const market = options?.market?.trim();
|
|
10
|
+
if (market) {
|
|
11
|
+
const upper = market.toUpperCase();
|
|
12
|
+
if (/^[A-Z]{2}$/.test(upper)) {
|
|
13
|
+
params.set('market', upper);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
3
17
|
export async function checkWidgetAuthorization(options) {
|
|
4
18
|
const endpoint = options?.endpoint ?? '/api/jotul/widget';
|
|
5
19
|
const fetcher = options?.fetcher ?? fetch;
|
|
@@ -25,9 +39,7 @@ export async function searchDealersByPostalCode(postalCode, options) {
|
|
|
25
39
|
const endpoint = options?.endpoint ?? '/api/jotul/widget';
|
|
26
40
|
const fetcher = options?.fetcher ?? fetch;
|
|
27
41
|
const params = new URLSearchParams({ postalCode: postalCode.trim() });
|
|
28
|
-
|
|
29
|
-
params.set('locale', options.locale.trim());
|
|
30
|
-
}
|
|
42
|
+
appendLocaleAndMarket(params, options);
|
|
31
43
|
if (Array.isArray(options?.brands)) {
|
|
32
44
|
for (const brand of options.brands) {
|
|
33
45
|
const value = brand.trim();
|
|
@@ -60,9 +72,7 @@ export async function searchDealersByCoordinates(latitude, longitude, options) {
|
|
|
60
72
|
latitude: String(latitude),
|
|
61
73
|
longitude: String(longitude),
|
|
62
74
|
});
|
|
63
|
-
|
|
64
|
-
params.set('locale', options.locale.trim());
|
|
65
|
-
}
|
|
75
|
+
appendLocaleAndMarket(params, options);
|
|
66
76
|
if (Array.isArray(options?.brands)) {
|
|
67
77
|
for (const brand of options.brands) {
|
|
68
78
|
const value = brand.trim();
|
|
@@ -95,9 +105,7 @@ export async function searchLocationSuggestions(query, options) {
|
|
|
95
105
|
type: 'autocomplete',
|
|
96
106
|
q: query.trim(),
|
|
97
107
|
});
|
|
98
|
-
|
|
99
|
-
params.set('locale', options.locale.trim());
|
|
100
|
-
}
|
|
108
|
+
appendLocaleAndMarket(params, options);
|
|
101
109
|
let response;
|
|
102
110
|
try {
|
|
103
111
|
response = await fetcher(`${endpoint}?${params.toString()}`, {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export type JotulWidgetLocale = 'no' | 'se';
|
|
1
|
+
export type JotulWidgetLocale = 'no' | 'se' | 'en' | 'fr' | 'de' | 'fi' | 'nl' | 'pl' | 'cz';
|
|
2
|
+
/** Default BCP 47 tag used for API `locale` when the prop is omitted. */
|
|
3
|
+
export declare const DEFAULT_WIDGET_LOCALE_TAG = "nb-NO";
|
|
2
4
|
export type WidgetStrings = {
|
|
3
5
|
genericWidgetError: string;
|
|
4
6
|
invalidPostcodeError: string;
|
|
@@ -36,4 +38,6 @@ export type WidgetStrings = {
|
|
|
36
38
|
readyWarrantyForm: string;
|
|
37
39
|
};
|
|
38
40
|
export declare const WIDGET_STRINGS: Record<JotulWidgetLocale, WidgetStrings>;
|
|
39
|
-
export declare function
|
|
41
|
+
export declare function resolveWidgetUiLocale(raw: string | undefined, market?: string): JotulWidgetLocale;
|
|
42
|
+
/** @deprecated Use `resolveWidgetUiLocale`. */
|
|
43
|
+
export declare const normalizeWidgetLocale: typeof resolveWidgetUiLocale;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Default BCP 47 tag used for API `locale` when the prop is omitted. */
|
|
2
|
+
export const DEFAULT_WIDGET_LOCALE_TAG = 'nb-NO';
|
|
1
3
|
export const WIDGET_STRINGS = {
|
|
2
4
|
no: {
|
|
3
5
|
genericWidgetError: 'Forhandlerkartet er ikke tilgjengelig akkurat nå. Prøv igjen senere.',
|
|
@@ -71,17 +73,324 @@ export const WIDGET_STRINGS = {
|
|
|
71
73
|
readyDealerFinder: 'JotulWidget klar: dealerFinder',
|
|
72
74
|
readyWarrantyForm: 'JotulWidget klar: warrantyForm',
|
|
73
75
|
},
|
|
76
|
+
en: {
|
|
77
|
+
genericWidgetError: 'The dealer finder is unavailable right now. Please try again later.',
|
|
78
|
+
invalidPostcodeError: 'Enter a valid postcode.',
|
|
79
|
+
invalidWidgetTypeError: 'This widget is not available right now.',
|
|
80
|
+
locationSearchFailed: 'Location search could not be completed. Try again.',
|
|
81
|
+
locationUnavailableBrowser: 'Location is not available in this browser. Try another browser or device.',
|
|
82
|
+
locationPermissionDenied: 'Location access was denied. Allow location for this site to find nearby dealers.',
|
|
83
|
+
locationPositionUnavailable: 'Your position could not be determined. Try again in a moment.',
|
|
84
|
+
locationTimeout: 'Finding your location took too long. Try again.',
|
|
85
|
+
locationGenericFailure: 'Could not read your location. Try again.',
|
|
86
|
+
locationTypeMore: 'Type at least 3 characters to search for an address.',
|
|
87
|
+
locationNoResults: 'No addresses found. Try a different search.',
|
|
88
|
+
locationManualHint: 'Enter your address to find dealers nearby',
|
|
89
|
+
findDealer: 'Find a dealer',
|
|
90
|
+
loading: 'Loading …',
|
|
91
|
+
useLocationHint: 'Use your location to find dealers nearby',
|
|
92
|
+
find: 'Locate',
|
|
93
|
+
finding: 'Searching …',
|
|
94
|
+
inquirySentSuccess: 'Your request has been sent.',
|
|
95
|
+
goBack: 'Back',
|
|
96
|
+
sendInquiryTitle: 'Request',
|
|
97
|
+
sendInquiryTitleWithProduct: 'Request regarding {product}',
|
|
98
|
+
dealerWillContact: '{dealer} will contact you as soon as possible.',
|
|
99
|
+
fieldName: 'Name',
|
|
100
|
+
fieldEmail: 'Email',
|
|
101
|
+
fieldPhone: 'Phone',
|
|
102
|
+
fieldComment: 'Comment',
|
|
103
|
+
formValidationRequired: 'Enter name, email, and phone.',
|
|
104
|
+
formValidationEmail: 'Enter a valid email address.',
|
|
105
|
+
dealersNearYou: '{count} dealers nearby',
|
|
106
|
+
unknownDealer: 'Unknown dealer',
|
|
107
|
+
sendInquiryCta: 'Send request',
|
|
108
|
+
sendInquiryEditing: 'Editing request',
|
|
109
|
+
readyDealerFinder: 'JotulWidget ready: dealerFinder',
|
|
110
|
+
readyWarrantyForm: 'JotulWidget ready: warrantyForm',
|
|
111
|
+
},
|
|
112
|
+
fr: {
|
|
113
|
+
genericWidgetError: "Le recherche de revendeurs n'est pas disponible pour le moment. Réessayez plus tard.",
|
|
114
|
+
invalidPostcodeError: 'Saisissez un code postal valide.',
|
|
115
|
+
invalidWidgetTypeError: "Ce widget n'est pas disponible pour le moment.",
|
|
116
|
+
locationSearchFailed: 'La recherche de lieu a échoué. Réessayez.',
|
|
117
|
+
locationUnavailableBrowser: "La position n'est pas disponible dans ce navigateur. Essayez un autre navigateur ou appareil.",
|
|
118
|
+
locationPermissionDenied: "L'accès à la position a été refusé. Autorisez la position pour ce site afin de trouver les revendeurs proches.",
|
|
119
|
+
locationPositionUnavailable: "Votre position n'a pas pu être déterminée. Réessayez dans un instant.",
|
|
120
|
+
locationTimeout: 'La recherche de votre position a pris trop de temps. Réessayez.',
|
|
121
|
+
locationGenericFailure: 'Impossible de lire votre position. Réessayez.',
|
|
122
|
+
locationTypeMore: 'Saisissez au moins 3 caractères pour chercher une adresse.',
|
|
123
|
+
locationNoResults: 'Aucune adresse trouvée. Essayez une autre recherche.',
|
|
124
|
+
locationManualHint: 'Saisissez votre adresse pour trouver des revendeurs à proximité',
|
|
125
|
+
findDealer: 'Trouver un revendeur',
|
|
126
|
+
loading: 'Chargement …',
|
|
127
|
+
useLocationHint: 'Utilisez votre position pour trouver des revendeurs à proximité',
|
|
128
|
+
find: 'Localiser',
|
|
129
|
+
finding: 'Recherche …',
|
|
130
|
+
inquirySentSuccess: 'Votre demande a été envoyée.',
|
|
131
|
+
goBack: 'Retour',
|
|
132
|
+
sendInquiryTitle: 'Demande',
|
|
133
|
+
sendInquiryTitleWithProduct: 'Demande concernant {product}',
|
|
134
|
+
dealerWillContact: '{dealer} vous contactera dès que possible.',
|
|
135
|
+
fieldName: 'Nom',
|
|
136
|
+
fieldEmail: 'E-mail',
|
|
137
|
+
fieldPhone: 'Téléphone',
|
|
138
|
+
fieldComment: 'Commentaire',
|
|
139
|
+
formValidationRequired: 'Renseignez le nom, l’e-mail et le téléphone.',
|
|
140
|
+
formValidationEmail: 'Saisissez une adresse e-mail valide.',
|
|
141
|
+
dealersNearYou: '{count} revendeurs à proximité',
|
|
142
|
+
unknownDealer: 'Revendeur inconnu',
|
|
143
|
+
sendInquiryCta: 'Envoyer la demande',
|
|
144
|
+
sendInquiryEditing: 'Modification de la demande',
|
|
145
|
+
readyDealerFinder: 'JotulWidget prêt : dealerFinder',
|
|
146
|
+
readyWarrantyForm: 'JotulWidget prêt : warrantyForm',
|
|
147
|
+
},
|
|
148
|
+
de: {
|
|
149
|
+
genericWidgetError: 'Die Händlersuche ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut.',
|
|
150
|
+
invalidPostcodeError: 'Geben Sie eine gültige Postleitzahl ein.',
|
|
151
|
+
invalidWidgetTypeError: 'Dieses Widget ist derzeit nicht verfügbar.',
|
|
152
|
+
locationSearchFailed: 'Die Ortssuche konnte nicht abgeschlossen werden. Versuchen Sie es erneut.',
|
|
153
|
+
locationUnavailableBrowser: 'Standort ist in diesem Browser nicht verfügbar. Versuchen Sie einen anderen Browser oder ein anderes Gerät.',
|
|
154
|
+
locationPermissionDenied: 'Der Standortzugriff wurde verweigert. Erlauben Sie den Standortzugriff für diese Seite, um Händler in der Nähe zu finden.',
|
|
155
|
+
locationPositionUnavailable: 'Ihre Position konnte nicht bestimmt werden. Versuchen Sie es gleich noch einmal.',
|
|
156
|
+
locationTimeout: 'Die Standortermittlung hat zu lange gedauert. Versuchen Sie es erneut.',
|
|
157
|
+
locationGenericFailure: 'Ihr Standort konnte nicht gelesen werden. Versuchen Sie es erneut.',
|
|
158
|
+
locationTypeMore: 'Geben Sie mindestens 3 Zeichen ein, um nach einer Adresse zu suchen.',
|
|
159
|
+
locationNoResults: 'Keine Adressen gefunden. Versuchen Sie eine andere Suche.',
|
|
160
|
+
locationManualHint: 'Geben Sie Ihre Adresse ein, um Händler in Ihrer Nähe zu finden.',
|
|
161
|
+
findDealer: 'Händler finden',
|
|
162
|
+
loading: 'Laden …',
|
|
163
|
+
useLocationHint: 'Nutzen Sie Ihren Standort, um Händler in der Nähe zu finden.',
|
|
164
|
+
find: 'Suchen',
|
|
165
|
+
finding: 'Suche …',
|
|
166
|
+
inquirySentSuccess: 'Ihre Anfrage wurde gesendet.',
|
|
167
|
+
goBack: 'Zurück',
|
|
168
|
+
sendInquiryTitle: 'Anfrage',
|
|
169
|
+
sendInquiryTitleWithProduct: 'Anfrage zu {product}',
|
|
170
|
+
dealerWillContact: '{dealer} wird Sie so schnell wie möglich kontaktieren.',
|
|
171
|
+
fieldName: 'Name',
|
|
172
|
+
fieldEmail: 'E-Mail',
|
|
173
|
+
fieldPhone: 'Telefon',
|
|
174
|
+
fieldComment: 'Kommentar',
|
|
175
|
+
formValidationRequired: 'Bitte Name, E-Mail und Telefon eingeben.',
|
|
176
|
+
formValidationEmail: 'Bitte geben Sie eine gültige E-Mail-Adresse ein.',
|
|
177
|
+
dealersNearYou: '{count} Händler in Ihrer Nähe',
|
|
178
|
+
unknownDealer: 'Unbekannter Händler',
|
|
179
|
+
sendInquiryCta: 'Anfrage senden',
|
|
180
|
+
sendInquiryEditing: 'Anfrage bearbeiten',
|
|
181
|
+
readyDealerFinder: 'JotulWidget bereit: dealerFinder',
|
|
182
|
+
readyWarrantyForm: 'JotulWidget bereit: warrantyForm',
|
|
183
|
+
},
|
|
184
|
+
fi: {
|
|
185
|
+
genericWidgetError: 'Jälleenmyyjähaku ei ole juuri nyt käytettävissä. Yritä myöhemmin uudelleen.',
|
|
186
|
+
invalidPostcodeError: 'Anna kelvollinen postinumero.',
|
|
187
|
+
invalidWidgetTypeError: 'Tämä widget ei ole tällä hetkellä käytettävissä.',
|
|
188
|
+
locationSearchFailed: 'Sijainnin haku ei onnistunut. Yritä uudelleen.',
|
|
189
|
+
locationUnavailableBrowser: 'Sijainti ei ole saatavilla tässä selaimessa. Kokeile toista selainta tai laitetta.',
|
|
190
|
+
locationPermissionDenied: 'Sijainnin käyttö estettiin. Salli sijainti tälle sivustolle löytääksesi lähimmät jälleenmyyjät.',
|
|
191
|
+
locationPositionUnavailable: 'Sijaintiasi ei voitu määrittää. Yritä hetken kuluttua uudelleen.',
|
|
192
|
+
locationTimeout: 'Sijainnin haku kesti liian kauan. Yritä uudelleen.',
|
|
193
|
+
locationGenericFailure: 'Sijaintiasi ei voitu lukea. Yritä uudelleen.',
|
|
194
|
+
locationTypeMore: 'Kirjoita vähintään 3 merkkiä hakeaksesi osoitetta.',
|
|
195
|
+
locationNoResults: 'Osoitteita ei löytynyt. Kokeile toista hakua.',
|
|
196
|
+
locationManualHint: 'Anna osoitteesi löytääksesi lähimmät jälleenmyyjät.',
|
|
197
|
+
findDealer: 'Etsi jälleenmyyjä',
|
|
198
|
+
loading: 'Ladataan …',
|
|
199
|
+
useLocationHint: 'Käytä sijaintiasi löytääksesi lähimmät jälleenmyyjät.',
|
|
200
|
+
find: 'Etsi',
|
|
201
|
+
finding: 'Haetaan …',
|
|
202
|
+
inquirySentSuccess: 'Pyyntösi on lähetetty.',
|
|
203
|
+
goBack: 'Takaisin',
|
|
204
|
+
sendInquiryTitle: 'Pyyntö',
|
|
205
|
+
sendInquiryTitleWithProduct: 'Pyyntö tuotteesta {product}',
|
|
206
|
+
dealerWillContact: '{dealer} ottaa sinuun yhteyttä mahdollisimman pian.',
|
|
207
|
+
fieldName: 'Nimi',
|
|
208
|
+
fieldEmail: 'Sähköposti',
|
|
209
|
+
fieldPhone: 'Puhelin',
|
|
210
|
+
fieldComment: 'Kommentti',
|
|
211
|
+
formValidationRequired: 'Täytä nimi, sähköposti ja puhelin.',
|
|
212
|
+
formValidationEmail: 'Anna kelvollinen sähköpostiosoite.',
|
|
213
|
+
dealersNearYou: '{count} jälleenmyyjää lähelläsi',
|
|
214
|
+
unknownDealer: 'Tuntematon jälleenmyyjä',
|
|
215
|
+
sendInquiryCta: 'Lähetä pyyntö',
|
|
216
|
+
sendInquiryEditing: 'Muokataan pyyntöä',
|
|
217
|
+
readyDealerFinder: 'JotulWidget valmis: dealerFinder',
|
|
218
|
+
readyWarrantyForm: 'JotulWidget valmis: warrantyForm',
|
|
219
|
+
},
|
|
220
|
+
nl: {
|
|
221
|
+
genericWidgetError: 'De dealerzoeker is momenteel niet beschikbaar. Probeer het later opnieuw.',
|
|
222
|
+
invalidPostcodeError: 'Voer een geldige postcode in.',
|
|
223
|
+
invalidWidgetTypeError: 'Deze widget is momenteel niet beschikbaar.',
|
|
224
|
+
locationSearchFailed: 'Locatie zoeken kon niet worden voltooid. Probeer opnieuw.',
|
|
225
|
+
locationUnavailableBrowser: 'Locatie is niet beschikbaar in deze browser. Probeer een andere browser of apparaat.',
|
|
226
|
+
locationPermissionDenied: 'Locatietoegang is geweigerd. Sta locatie toe voor deze site om dealers in de buurt te vinden.',
|
|
227
|
+
locationPositionUnavailable: 'Uw locatie kon niet worden bepaald. Probeer het zo opnieuw.',
|
|
228
|
+
locationTimeout: 'Het bepalen van uw locatie duurde te lang. Probeer opnieuw.',
|
|
229
|
+
locationGenericFailure: 'Kon uw locatie niet lezen. Probeer opnieuw.',
|
|
230
|
+
locationTypeMore: 'Typ minimaal 3 tekens om een adres te zoeken.',
|
|
231
|
+
locationNoResults: 'Geen adressen gevonden. Probeer een andere zoekopdracht.',
|
|
232
|
+
locationManualHint: 'Voer uw adres in om dealers in de buurt te vinden',
|
|
233
|
+
findDealer: 'Dealer zoeken',
|
|
234
|
+
loading: 'Laden …',
|
|
235
|
+
useLocationHint: 'Gebruik uw locatie om dealers in de buurt te vinden',
|
|
236
|
+
find: 'Zoeken',
|
|
237
|
+
finding: 'Zoeken …',
|
|
238
|
+
inquirySentSuccess: 'Uw aanvraag is verzonden.',
|
|
239
|
+
goBack: 'Terug',
|
|
240
|
+
sendInquiryTitle: 'Aanvraag',
|
|
241
|
+
sendInquiryTitleWithProduct: 'Aanvraag over {product}',
|
|
242
|
+
dealerWillContact: '{dealer} neemt zo snel mogelijk contact met u op.',
|
|
243
|
+
fieldName: 'Naam',
|
|
244
|
+
fieldEmail: 'E-mail',
|
|
245
|
+
fieldPhone: 'Telefoon',
|
|
246
|
+
fieldComment: 'Opmerking',
|
|
247
|
+
formValidationRequired: 'Vul naam, e-mail en telefoon in.',
|
|
248
|
+
formValidationEmail: 'Voer een geldig e-mailadres in.',
|
|
249
|
+
dealersNearYou: '{count} dealers in de buurt',
|
|
250
|
+
unknownDealer: 'Onbekende dealer',
|
|
251
|
+
sendInquiryCta: 'Aanvraag verzenden',
|
|
252
|
+
sendInquiryEditing: 'Aanvraag bewerken',
|
|
253
|
+
readyDealerFinder: 'JotulWidget klaar: dealerFinder',
|
|
254
|
+
readyWarrantyForm: 'JotulWidget klaar: warrantyForm',
|
|
255
|
+
},
|
|
256
|
+
pl: {
|
|
257
|
+
genericWidgetError: 'Wyszukiwarka dealerów jest obecnie niedostępna. Spróbuj ponownie później.',
|
|
258
|
+
invalidPostcodeError: 'Wpisz prawidłowy kod pocztowy.',
|
|
259
|
+
invalidWidgetTypeError: 'Ten widget jest obecnie niedostępny.',
|
|
260
|
+
locationSearchFailed: 'Nie udało się zakończyć wyszukiwania lokalizacji. Spróbuj ponownie.',
|
|
261
|
+
locationUnavailableBrowser: 'Lokalizacja nie jest dostępna w tej przeglądarce. Spróbuj innej przeglądarki lub urządzenia.',
|
|
262
|
+
locationPermissionDenied: 'Odmówiono dostępu do lokalizacji. Zezwól na lokalizację dla tej strony, aby znaleźć dealerów w pobliżu.',
|
|
263
|
+
locationPositionUnavailable: 'Nie udało się określić Twojej lokalizacji. Spróbuj ponownie za chwilę.',
|
|
264
|
+
locationTimeout: 'Wyszukiwanie Twojej lokalizacji trwało zbyt długo. Spróbuj ponownie.',
|
|
265
|
+
locationGenericFailure: 'Nie udało się odczytać Twojej lokalizacji. Spróbuj ponownie.',
|
|
266
|
+
locationTypeMore: 'Wpisz co najmniej 3 znaki, aby wyszukać adres.',
|
|
267
|
+
locationNoResults: 'Nie znaleziono adresów. Spróbuj innego wyszukiwania.',
|
|
268
|
+
locationManualHint: 'Wpisz swój adres, aby znaleźć dealerów w pobliżu',
|
|
269
|
+
findDealer: 'Znajdź dealera',
|
|
270
|
+
loading: 'Ładowanie …',
|
|
271
|
+
useLocationHint: 'Użyj swojej lokalizacji, aby znaleźć dealerów w pobliżu',
|
|
272
|
+
find: 'Szukaj',
|
|
273
|
+
finding: 'Wyszukiwanie …',
|
|
274
|
+
inquirySentSuccess: 'Twoje zapytanie zostało wysłane.',
|
|
275
|
+
goBack: 'Wstecz',
|
|
276
|
+
sendInquiryTitle: 'Zapytanie',
|
|
277
|
+
sendInquiryTitleWithProduct: 'Zapytanie dotyczące {product}',
|
|
278
|
+
dealerWillContact: '{dealer} skontaktuje się z Tobą tak szybko, jak to możliwe.',
|
|
279
|
+
fieldName: 'Imię i nazwisko',
|
|
280
|
+
fieldEmail: 'E-mail',
|
|
281
|
+
fieldPhone: 'Telefon',
|
|
282
|
+
fieldComment: 'Komentarz',
|
|
283
|
+
formValidationRequired: 'Wpisz imię, e-mail i telefon.',
|
|
284
|
+
formValidationEmail: 'Wpisz prawidłowy adres e-mail.',
|
|
285
|
+
dealersNearYou: '{count} dealerów w pobliżu',
|
|
286
|
+
unknownDealer: 'Nieznany dealer',
|
|
287
|
+
sendInquiryCta: 'Wyślij zapytanie',
|
|
288
|
+
sendInquiryEditing: 'Edycja zapytania',
|
|
289
|
+
readyDealerFinder: 'JotulWidget gotowy: dealerFinder',
|
|
290
|
+
readyWarrantyForm: 'JotulWidget gotowy: warrantyForm',
|
|
291
|
+
},
|
|
292
|
+
cz: {
|
|
293
|
+
genericWidgetError: 'Vyhledávač prodejců je momentálně nedostupný. Zkuste to prosím později.',
|
|
294
|
+
invalidPostcodeError: 'Zadejte platné PSČ.',
|
|
295
|
+
invalidWidgetTypeError: 'Tento widget není momentálně dostupný.',
|
|
296
|
+
locationSearchFailed: 'Vyhledání polohy se nepodařilo dokončit. Zkuste to znovu.',
|
|
297
|
+
locationUnavailableBrowser: 'Poloha není v tomto prohlížeči dostupná. Zkuste jiný prohlížeč nebo zařízení.',
|
|
298
|
+
locationPermissionDenied: 'Přístup k poloze byl zamítnut. Povolte polohu pro tento web, abyste našli prodejce v okolí.',
|
|
299
|
+
locationPositionUnavailable: 'Vaši polohu se nepodařilo zjistit. Zkuste to za chvíli znovu.',
|
|
300
|
+
locationTimeout: 'Vyhledání vaší polohy trvalo příliš dlouho. Zkuste to znovu.',
|
|
301
|
+
locationGenericFailure: 'Nepodařilo se načíst vaši polohu. Zkuste to znovu.',
|
|
302
|
+
locationTypeMore: 'Zadejte alespoň 3 znaky pro hledání adresy.',
|
|
303
|
+
locationNoResults: 'Nebyly nalezeny žádné adresy. Zkuste jiné hledání.',
|
|
304
|
+
locationManualHint: 'Zadejte svou adresu a najděte prodejce ve svém okolí',
|
|
305
|
+
findDealer: 'Najít prodejce',
|
|
306
|
+
loading: 'Načítání …',
|
|
307
|
+
useLocationHint: 'Použijte svou polohu pro nalezení prodejců v okolí',
|
|
308
|
+
find: 'Najít',
|
|
309
|
+
finding: 'Vyhledávání …',
|
|
310
|
+
inquirySentSuccess: 'Váš požadavek byl odeslán.',
|
|
311
|
+
goBack: 'Zpět',
|
|
312
|
+
sendInquiryTitle: 'Poptávka',
|
|
313
|
+
sendInquiryTitleWithProduct: 'Poptávka na {product}',
|
|
314
|
+
dealerWillContact: '{dealer} vás bude co nejdříve kontaktovat.',
|
|
315
|
+
fieldName: 'Jméno',
|
|
316
|
+
fieldEmail: 'E-mail',
|
|
317
|
+
fieldPhone: 'Telefon',
|
|
318
|
+
fieldComment: 'Komentář',
|
|
319
|
+
formValidationRequired: 'Vyplňte jméno, e-mail a telefon.',
|
|
320
|
+
formValidationEmail: 'Zadejte platnou e-mailovou adresu.',
|
|
321
|
+
dealersNearYou: '{count} prodejců v okolí',
|
|
322
|
+
unknownDealer: 'Neznámý prodejce',
|
|
323
|
+
sendInquiryCta: 'Odeslat poptávku',
|
|
324
|
+
sendInquiryEditing: 'Úprava poptávky',
|
|
325
|
+
readyDealerFinder: 'JotulWidget připraven: dealerFinder',
|
|
326
|
+
readyWarrantyForm: 'JotulWidget připraven: warrantyForm',
|
|
327
|
+
},
|
|
74
328
|
};
|
|
75
|
-
|
|
76
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Maps `locale` prop: BCP 47 (e.g. `nb-NO`, `en-US`, `fr-FR`) or legacy shorthands (`no`, `sv`).
|
|
331
|
+
*/
|
|
332
|
+
function localeFromMarket(rawMarket) {
|
|
333
|
+
const m = rawMarket?.trim().toUpperCase();
|
|
334
|
+
if (!m)
|
|
335
|
+
return null;
|
|
336
|
+
if (m === 'NO')
|
|
77
337
|
return 'no';
|
|
338
|
+
if (m === 'SE')
|
|
339
|
+
return 'se';
|
|
340
|
+
if (m === 'FR')
|
|
341
|
+
return 'fr';
|
|
342
|
+
if (m === 'DE')
|
|
343
|
+
return 'de';
|
|
344
|
+
if (m === 'FI')
|
|
345
|
+
return 'fi';
|
|
346
|
+
if (m === 'NL')
|
|
347
|
+
return 'nl';
|
|
348
|
+
if (m === 'PL')
|
|
349
|
+
return 'pl';
|
|
350
|
+
if (m === 'CZ')
|
|
351
|
+
return 'cz';
|
|
352
|
+
if (m === 'GB' || m === 'EN' || m === 'US' || m === 'AU' || m === 'CA')
|
|
353
|
+
return 'en';
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
export function resolveWidgetUiLocale(raw, market) {
|
|
357
|
+
if (raw == null || raw.trim() === '') {
|
|
358
|
+
return localeFromMarket(market) ?? 'no';
|
|
78
359
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
360
|
+
const s = raw.trim();
|
|
361
|
+
const lower = s.toLowerCase();
|
|
362
|
+
if (lower === 'no' || lower === 'nb' || lower === 'nn') {
|
|
81
363
|
return 'no';
|
|
82
364
|
}
|
|
83
|
-
if (
|
|
365
|
+
if (lower === 'se' || lower === 'sv') {
|
|
84
366
|
return 'se';
|
|
85
367
|
}
|
|
86
|
-
|
|
368
|
+
try {
|
|
369
|
+
const loc = new Intl.Locale(s.replace(/_/g, '-'));
|
|
370
|
+
const lang = (loc.language ?? '').toLowerCase();
|
|
371
|
+
if (lang === 'nb' || lang === 'nn' || lang === 'no')
|
|
372
|
+
return 'no';
|
|
373
|
+
if (lang === 'sv')
|
|
374
|
+
return 'se';
|
|
375
|
+
if (lang === 'en')
|
|
376
|
+
return 'en';
|
|
377
|
+
if (lang === 'fr')
|
|
378
|
+
return 'fr';
|
|
379
|
+
if (lang === 'de')
|
|
380
|
+
return 'de';
|
|
381
|
+
if (lang === 'fi')
|
|
382
|
+
return 'fi';
|
|
383
|
+
if (lang === 'nl')
|
|
384
|
+
return 'nl';
|
|
385
|
+
if (lang === 'pl')
|
|
386
|
+
return 'pl';
|
|
387
|
+
if (lang === 'cs')
|
|
388
|
+
return 'cz';
|
|
389
|
+
return 'no';
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return localeFromMarket(market) ?? 'no';
|
|
393
|
+
}
|
|
87
394
|
}
|
|
395
|
+
/** @deprecated Use `resolveWidgetUiLocale`. */
|
|
396
|
+
export const normalizeWidgetLocale = resolveWidgetUiLocale;
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { checkWidgetAuthorization, normalizeWidgetLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, type CheckWidgetAuthorizationOptions, type DealerSearchResponse, type JotulWidgetButtonStyling, type JotulWidgetLocale, type JotulWidgetProps, type JotulWidgetStyling, type JotulWidgetType, type WidgetAuthClientResponse, } from './JotulWidget';
|
|
1
|
+
export { checkWidgetAuthorization, DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, type CheckWidgetAuthorizationOptions, type DealerSearchResponse, type JotulWidgetButtonStyling, type JotulWidgetLocale, type JotulWidgetProps, type JotulWidgetStyling, type JotulWidgetType, type WidgetAuthClientResponse, } from './JotulWidget';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { checkWidgetAuthorization, normalizeWidgetLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, } from './JotulWidget';
|
|
2
|
+
export { checkWidgetAuthorization, DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, searchDealersByCoordinates, searchDealersByPostalCode, JotulWidget, } from './JotulWidget';
|
package/dist/types.d.ts
CHANGED
|
@@ -37,7 +37,10 @@ export type LocationAutocompleteResponse = {
|
|
|
37
37
|
export type CheckWidgetAuthorizationOptions = {
|
|
38
38
|
endpoint?: string;
|
|
39
39
|
fetcher?: typeof fetch;
|
|
40
|
+
/** BCP 47 language tag (e.g. `nb-NO`, `en-US`) sent to the API as `locale`. */
|
|
40
41
|
locale?: string;
|
|
42
|
+
/** ISO 3166-1 alpha-2 market/country (e.g. `NO`, `SE`) sent to the API as `market`. */
|
|
43
|
+
market?: string;
|
|
41
44
|
brands?: string[];
|
|
42
45
|
};
|
|
43
46
|
/** CSS values for primary CTA buttons (find dealer, send inquiry, etc.). */
|
|
@@ -54,7 +57,10 @@ export type JotulWidgetProps = {
|
|
|
54
57
|
endpoint?: string;
|
|
55
58
|
className?: string;
|
|
56
59
|
productName?: string;
|
|
60
|
+
/** BCP 47 tag for widget UI strings and API `locale` (default `nb-NO` when omitted). */
|
|
57
61
|
locale?: string;
|
|
62
|
+
/** ISO 3166-1 alpha-2 market filter for dealers and geocoder country bias (`NO`, `SE`, …). */
|
|
63
|
+
market?: string;
|
|
58
64
|
brands?: string[];
|
|
59
65
|
styling?: JotulWidgetStyling;
|
|
60
66
|
};
|
package/dist/utils.js
CHANGED
|
@@ -32,7 +32,12 @@ export function getDealerName(dealer, unknownLabel) {
|
|
|
32
32
|
export function getDealerAddressLines(dealer) {
|
|
33
33
|
const address = asText(dealer.address);
|
|
34
34
|
const postalCode = asText(dealer.postalCode);
|
|
35
|
-
|
|
35
|
+
const city = asText(dealer.city);
|
|
36
|
+
const county = asText(dealer.county);
|
|
37
|
+
const locationLine = [postalCode, city, county]
|
|
38
|
+
.filter((value) => !!value)
|
|
39
|
+
.join(', ');
|
|
40
|
+
return [address, locationLine || null].filter((value) => Boolean(value));
|
|
36
41
|
}
|
|
37
42
|
export function createInquiryFormValues(productName, dealerName) {
|
|
38
43
|
return {
|