@rovela-ai/sdk 0.10.2 → 0.11.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/dist/admin/api/settings.d.ts.map +1 -1
- package/dist/admin/api/settings.js +15 -0
- package/dist/admin/api/settings.js.map +1 -1
- package/dist/admin/components/StoreSettings.d.ts.map +1 -1
- package/dist/admin/components/StoreSettings.js +28 -1
- package/dist/admin/components/StoreSettings.js.map +1 -1
- package/dist/admin/types.d.ts +2 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/cart/components/AddToCartButton.d.ts +1 -1
- package/dist/cart/components/AddToCartButton.d.ts.map +1 -1
- package/dist/cart/components/AddToCartButton.js +4 -2
- package/dist/cart/components/AddToCartButton.js.map +1 -1
- package/dist/cart/components/CartDrawer.d.ts.map +1 -1
- package/dist/cart/components/CartDrawer.js +4 -2
- package/dist/cart/components/CartDrawer.js.map +1 -1
- package/dist/cart/components/CartIcon.d.ts.map +1 -1
- package/dist/cart/components/CartIcon.js +4 -2
- package/dist/cart/components/CartIcon.js.map +1 -1
- package/dist/cart/components/CartItem.d.ts.map +1 -1
- package/dist/cart/components/CartItem.js +3 -1
- package/dist/cart/components/CartItem.js.map +1 -1
- package/dist/cart/components/CartSummary.d.ts.map +1 -1
- package/dist/cart/components/CartSummary.js +6 -4
- package/dist/cart/components/CartSummary.js.map +1 -1
- package/dist/cart/components/QuantitySelector.d.ts.map +1 -1
- package/dist/cart/components/QuantitySelector.js +4 -2
- package/dist/cart/components/QuantitySelector.js.map +1 -1
- package/dist/checkout/components/CheckoutButton.d.ts.map +1 -1
- package/dist/checkout/components/CheckoutButton.js +4 -2
- package/dist/checkout/components/CheckoutButton.js.map +1 -1
- package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
- package/dist/checkout/components/CheckoutFlow.js +42 -38
- package/dist/checkout/components/CheckoutFlow.js.map +1 -1
- package/dist/checkout/components/OrderSummary.d.ts.map +1 -1
- package/dist/checkout/components/OrderSummary.js +5 -2
- package/dist/checkout/components/OrderSummary.js.map +1 -1
- package/dist/checkout/components/ShippingForm.d.ts.map +1 -1
- package/dist/checkout/components/ShippingForm.js +28 -25
- package/dist/checkout/components/ShippingForm.js.map +1 -1
- package/dist/checkout/components/ShippingOptions.d.ts.map +1 -1
- package/dist/checkout/components/ShippingOptions.js +8 -5
- package/dist/checkout/components/ShippingOptions.js.map +1 -1
- package/dist/core/StoreSettingsProvider.d.ts +2 -0
- package/dist/core/StoreSettingsProvider.d.ts.map +1 -1
- package/dist/core/StoreSettingsProvider.js +4 -0
- package/dist/core/StoreSettingsProvider.js.map +1 -1
- package/dist/core/api/settings.d.ts +2 -0
- package/dist/core/api/settings.d.ts.map +1 -1
- package/dist/core/api/settings.js +4 -0
- package/dist/core/api/settings.js.map +1 -1
- package/dist/core/db/queries.d.ts +31 -27
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +12 -0
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +39 -1
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +8 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/i18n/LanguageSwitcher.d.ts +7 -0
- package/dist/core/i18n/LanguageSwitcher.d.ts.map +1 -0
- package/dist/core/i18n/LanguageSwitcher.js +44 -0
- package/dist/core/i18n/LanguageSwitcher.js.map +1 -0
- package/dist/core/i18n/context.d.ts +27 -0
- package/dist/core/i18n/context.d.ts.map +1 -0
- package/dist/core/i18n/context.js +47 -0
- package/dist/core/i18n/context.js.map +1 -0
- package/dist/core/i18n/index.d.ts +19 -0
- package/dist/core/i18n/index.d.ts.map +1 -0
- package/dist/core/i18n/index.js +14 -0
- package/dist/core/i18n/index.js.map +1 -0
- package/dist/core/i18n/messages/en.d.ts +9 -0
- package/dist/core/i18n/messages/en.d.ts.map +1 -0
- package/dist/core/i18n/messages/en.js +135 -0
- package/dist/core/i18n/messages/en.js.map +1 -0
- package/dist/core/i18n/messages/fr.d.ts +10 -0
- package/dist/core/i18n/messages/fr.d.ts.map +1 -0
- package/dist/core/i18n/messages/fr.js +136 -0
- package/dist/core/i18n/messages/fr.js.map +1 -0
- package/dist/core/i18n/resolve.d.ts +64 -0
- package/dist/core/i18n/resolve.d.ts.map +1 -0
- package/dist/core/i18n/resolve.js +95 -0
- package/dist/core/i18n/resolve.js.map +1 -0
- package/dist/core/i18n/translate.d.ts +26 -0
- package/dist/core/i18n/translate.d.ts.map +1 -0
- package/dist/core/i18n/translate.js +46 -0
- package/dist/core/i18n/translate.js.map +1 -0
- package/dist/core/i18n/types.d.ts +46 -0
- package/dist/core/i18n/types.d.ts.map +1 -0
- package/dist/core/i18n/types.js +50 -0
- package/dist/core/i18n/types.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* French catalog. Sourced from EasyElec's production French storefront
|
|
3
|
+
* (hand-translated by a French merchant team, live-validated) — not machine
|
|
4
|
+
* translation. Conventions: "vous" form, French e-commerce vocabulary
|
|
5
|
+
* (Panier, Livraison, TVA, Code promo), non-breaking-space-free punctuation
|
|
6
|
+
* kept simple for email-client + font portability.
|
|
7
|
+
*/
|
|
8
|
+
export const fr = {
|
|
9
|
+
// ── Common ────────────────────────────────────────────────────────────────
|
|
10
|
+
'common.back': 'Retour',
|
|
11
|
+
'common.change': 'Modifier',
|
|
12
|
+
'common.edit': 'Modifier',
|
|
13
|
+
'common.remove': 'Retirer',
|
|
14
|
+
'common.free': 'Gratuit',
|
|
15
|
+
'common.freeUpper': 'GRATUIT',
|
|
16
|
+
'common.total': 'Total',
|
|
17
|
+
'common.subtotal': 'Sous-total',
|
|
18
|
+
'common.shipping': 'Livraison',
|
|
19
|
+
'common.tax': 'TVA',
|
|
20
|
+
'common.discount': 'Remise',
|
|
21
|
+
'common.contact': 'Contact',
|
|
22
|
+
'common.continue': 'Continuer',
|
|
23
|
+
'common.saving': 'Enregistrement…',
|
|
24
|
+
'common.processing': 'Traitement…',
|
|
25
|
+
// ── Cart ──────────────────────────────────────────────────────────────────
|
|
26
|
+
'cart.title': 'Panier',
|
|
27
|
+
'cart.ariaLabel': 'Panier',
|
|
28
|
+
'cart.close': 'Fermer le panier',
|
|
29
|
+
'cart.empty': 'Votre panier est vide',
|
|
30
|
+
'cart.emptyHint': 'Ajoutez des articles pour commencer !',
|
|
31
|
+
'cart.item': 'article',
|
|
32
|
+
'cart.items': 'articles',
|
|
33
|
+
'cart.removeItem': 'Retirer {name} du panier',
|
|
34
|
+
'cart.addToCart': 'Ajouter au panier',
|
|
35
|
+
'cart.added': 'Ajouté !',
|
|
36
|
+
'cart.addFailed': "Impossible d'ajouter au panier",
|
|
37
|
+
'cart.quantity': 'Quantité',
|
|
38
|
+
'cart.estimatedTotal': 'Total estimé',
|
|
39
|
+
'cart.calculatedAtCheckout': 'Calculée au paiement',
|
|
40
|
+
'cart.checkout': 'Passer la commande',
|
|
41
|
+
// ── Checkout flow ─────────────────────────────────────────────────────────
|
|
42
|
+
'checkout.stepPickup': 'Retrait',
|
|
43
|
+
'checkout.stepAddress': 'Adresse',
|
|
44
|
+
'checkout.stepShipping': 'Livraison',
|
|
45
|
+
'checkout.stepReview': 'Vérification',
|
|
46
|
+
'checkout.closedToday': "Fermé aujourd'hui",
|
|
47
|
+
'checkout.openToday': "Ouvert aujourd'hui {open}–{close}",
|
|
48
|
+
'checkout.shipTo': 'Livrer à',
|
|
49
|
+
'checkout.billTo': 'Facturer à',
|
|
50
|
+
'checkout.sameAsShipping': "Identique à l'adresse de livraison",
|
|
51
|
+
'checkout.shippingMethod': 'Mode de livraison',
|
|
52
|
+
'checkout.signInToCheckOut': 'Connectez-vous pour commander',
|
|
53
|
+
'checkout.accountRequired': 'Cette boutique nécessite un compte pour finaliser votre commande.',
|
|
54
|
+
'checkout.signIn': 'Se connecter',
|
|
55
|
+
'checkout.createAccount': 'Créer un compte',
|
|
56
|
+
'checkout.codeCheckFailed': 'Impossible de vérifier le code. Veuillez réessayer.',
|
|
57
|
+
'checkout.codeInvalid': "Ce code n'est pas valide.",
|
|
58
|
+
'checkout.enterFirstLastName': 'Veuillez renseigner votre prénom et votre nom.',
|
|
59
|
+
'checkout.enterEmail': 'Veuillez renseigner votre e-mail.',
|
|
60
|
+
'checkout.usuallyReadyIn': 'Prête sous {time}',
|
|
61
|
+
'checkout.shippingCalcFailed': 'Impossible de calculer la livraison',
|
|
62
|
+
'checkout.shippingCalcFailedRetry': 'Impossible de calculer la livraison. Veuillez réessayer.',
|
|
63
|
+
'checkout.cartEmpty': 'Votre panier est vide.',
|
|
64
|
+
'checkout.continueShopping': 'Continuer mes achats',
|
|
65
|
+
'checkout.discountCode': 'Code promo',
|
|
66
|
+
'checkout.enterCode': 'Saisir un code',
|
|
67
|
+
'checkout.apply': 'Appliquer',
|
|
68
|
+
'checkout.promotionApplied': 'Promotion appliquée : {title}',
|
|
69
|
+
'checkout.promotionAppliedFreeShipping': 'Promotion appliquée : {title} (livraison offerte)',
|
|
70
|
+
'checkout.delivery': 'Livraison',
|
|
71
|
+
'checkout.pickupInStore': 'Retrait en magasin',
|
|
72
|
+
'checkout.shippingAddress': 'Adresse de livraison',
|
|
73
|
+
'checkout.emailPlaceholder': 'vous@exemple.fr',
|
|
74
|
+
'checkout.pickupStore': 'Magasin de retrait',
|
|
75
|
+
'checkout.chooseAnotherStore': 'Choisir un autre magasin ({count} de plus)',
|
|
76
|
+
'checkout.continueToReview': 'Vérifier la commande',
|
|
77
|
+
'checkout.chooseDeliveryAddress': 'Choisissez une adresse de livraison',
|
|
78
|
+
'checkout.deliverHere': 'Livrer ici',
|
|
79
|
+
'checkout.useNewAddress': 'Utiliser une nouvelle adresse',
|
|
80
|
+
'checkout.useSavedAddress': 'Utiliser une adresse enregistrée',
|
|
81
|
+
'checkout.shippingMethodTitle': 'Mode de livraison',
|
|
82
|
+
'checkout.reviewYourOrder': 'Vérifiez votre commande',
|
|
83
|
+
'checkout.paymentMethod': 'Moyen de paiement',
|
|
84
|
+
'checkout.card': 'Carte bancaire',
|
|
85
|
+
'checkout.secureViaStripe': 'Paiement sécurisé via Stripe',
|
|
86
|
+
'checkout.placeOrder': 'Passer la commande',
|
|
87
|
+
'checkout.proceedToPayment': 'Procéder au paiement',
|
|
88
|
+
'checkout.manualConfirmNote': 'Votre commande sera confirmée par e-mail avec les instructions de paiement.',
|
|
89
|
+
'checkout.stripeRedirectNote': 'Vous allez être redirigé vers Stripe pour régler votre commande en toute sécurité.',
|
|
90
|
+
'checkout.orderSummary': 'Récapitulatif',
|
|
91
|
+
'checkout.qty': 'Qté : {count}',
|
|
92
|
+
'checkout.redirecting': 'Redirection…',
|
|
93
|
+
'checkout.each': "{price} l'unité",
|
|
94
|
+
'checkout.businessDays': '{days} jours ouvrés',
|
|
95
|
+
'checkout.calculatingShipping': 'Calcul des options de livraison…',
|
|
96
|
+
'checkout.noShippingOptions': 'Aucune option de livraison disponible pour votre adresse.',
|
|
97
|
+
'checkout.firstName': 'Prénom',
|
|
98
|
+
'checkout.lastName': 'Nom',
|
|
99
|
+
'checkout.email': 'E-mail',
|
|
100
|
+
// Preparation-time values as stored on locations.
|
|
101
|
+
'prep.1 hour': '1 heure',
|
|
102
|
+
'prep.2 hours': '2 heures',
|
|
103
|
+
'prep.4 hours': '4 heures',
|
|
104
|
+
'prep.24 hours': '24 heures',
|
|
105
|
+
'prep.2-4 days': '2 à 4 jours',
|
|
106
|
+
// ── Shipping form ─────────────────────────────────────────────────────────
|
|
107
|
+
'form.email': 'E-mail',
|
|
108
|
+
'form.phone': 'Téléphone',
|
|
109
|
+
'form.firstName': 'Prénom',
|
|
110
|
+
'form.lastName': 'Nom',
|
|
111
|
+
'form.country': 'Pays',
|
|
112
|
+
'form.address': 'Adresse',
|
|
113
|
+
'form.address2': "Complément d'adresse (facultatif)",
|
|
114
|
+
'form.city': 'Ville',
|
|
115
|
+
'form.state': 'État',
|
|
116
|
+
'form.zipCode': 'Code postal',
|
|
117
|
+
'form.postalCode': 'Code postal',
|
|
118
|
+
'form.phonePlaceholder': '+33 6 12 34 56 78',
|
|
119
|
+
'form.emailPlaceholder': 'vous@exemple.fr',
|
|
120
|
+
'form.streetPlaceholder': 'Numéro et rue',
|
|
121
|
+
'form.address2Placeholder': 'Appartement, bâtiment…',
|
|
122
|
+
'form.billingAddress': 'Adresse de facturation',
|
|
123
|
+
'form.billingDifferent': "L'adresse de facturation est différente de l'adresse de livraison",
|
|
124
|
+
'form.emailRequired': "L'e-mail est requis",
|
|
125
|
+
'form.emailInvalid': 'Veuillez saisir une adresse e-mail valide',
|
|
126
|
+
'form.phoneRequiredDelivery': 'Le téléphone est requis pour le contact de livraison',
|
|
127
|
+
'form.phoneRequired': 'Le téléphone est requis',
|
|
128
|
+
'form.firstNameRequired': 'Le prénom est requis',
|
|
129
|
+
'form.lastNameRequired': 'Le nom est requis',
|
|
130
|
+
'form.addressRequired': "L'adresse est requise",
|
|
131
|
+
'form.cityRequired': 'La ville est requise',
|
|
132
|
+
'form.postalCodeRequired': 'Le code postal est requis',
|
|
133
|
+
'form.countryRequired': 'Le pays est requis',
|
|
134
|
+
'form.stateRequired': "L'État est requis",
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=fr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fr.js","sourceRoot":"","sources":["../../../../src/core/i18n/messages/fr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/resolve
|
|
3
|
+
*
|
|
4
|
+
* Pure locale-resolution functions shared by the template's root layout.
|
|
5
|
+
* The template proxy (edge, DB-free) only PARSES the URL and forwards
|
|
6
|
+
* detection hints as headers; the DECISIONS happen here, server-side, where
|
|
7
|
+
* store settings are available. No next/headers import — callers pass the
|
|
8
|
+
* values in, so these stay testable and browser-safe.
|
|
9
|
+
*/
|
|
10
|
+
import { type StoreLocale } from './types';
|
|
11
|
+
export interface StoreLocaleConfig {
|
|
12
|
+
defaultLocale: StoreLocale;
|
|
13
|
+
/** Always non-empty and always contains the default. */
|
|
14
|
+
enabledLocales: StoreLocale[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalize raw settings values (nullable, legacy rows) into a usable
|
|
18
|
+
* config. Pre-i18n rows (both NULL) resolve to en-only — byte-identical
|
|
19
|
+
* legacy behavior.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveStoreLocaleConfig(settings?: {
|
|
22
|
+
defaultLocale?: string | null;
|
|
23
|
+
enabledLocales?: string[] | null;
|
|
24
|
+
} | null): StoreLocaleConfig;
|
|
25
|
+
export interface RequestLocaleInput {
|
|
26
|
+
/** Locale parsed from the URL prefix by the proxy (x-rovela-locale). */
|
|
27
|
+
prefixLocale?: string | null;
|
|
28
|
+
/** Visitor preference cookie (rovela-locale). */
|
|
29
|
+
cookieLocale?: string | null;
|
|
30
|
+
/** IP-country suggestion from the proxy (x-rovela-geo-locale). */
|
|
31
|
+
geoLocale?: string | null;
|
|
32
|
+
config: StoreLocaleConfig;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The locale this request renders in. URL prefix wins (a shared /fr link
|
|
36
|
+
* must show French regardless of the visitor's cookie); otherwise the store
|
|
37
|
+
* default — bare URLs always serve the default language, and preference
|
|
38
|
+
* routing happens via redirect (below), never via content-swap on the same
|
|
39
|
+
* URL (that would serve two languages on one URL — the SEO failure mode the
|
|
40
|
+
* path-prefix architecture exists to avoid).
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveRequestLocale({ prefixLocale, config }: RequestLocaleInput): StoreLocale;
|
|
43
|
+
export interface LocaleRedirectInput extends RequestLocaleInput {
|
|
44
|
+
/** ORIGINAL request pathname, prefix included (x-rovela-pathname). */
|
|
45
|
+
pathname?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Where this request should redirect for locale correctness, or null.
|
|
49
|
+
*
|
|
50
|
+
* - Prefixed URL for a locale the store doesn't serve → strip the prefix
|
|
51
|
+
* (no /fr ghost pages on an en-only store).
|
|
52
|
+
* - Bare URL + the visitor prefers an enabled non-default locale (explicit
|
|
53
|
+
* cookie first, else IP-country hint) → the prefixed equivalent. This is
|
|
54
|
+
* the "IP detection" behavior: first visit from France lands on /fr; the
|
|
55
|
+
* cookie the provider then writes keeps it sticky, and switching back to
|
|
56
|
+
* the default writes a default-locale cookie which suppresses this.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveLocaleRedirect({ prefixLocale, cookieLocale, geoLocale, pathname, config, }: LocaleRedirectInput): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Build the URL for the CURRENT page in another locale — the language
|
|
61
|
+
* switcher's navigation target. `pathname` may carry a locale prefix.
|
|
62
|
+
*/
|
|
63
|
+
export declare function localePath(pathname: string, target: StoreLocale, defaultLocale: StoreLocale): string;
|
|
64
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/core/i18n/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,WAAW,CAAA;IAC1B,wDAAwD;IACxD,cAAc,EAAE,WAAW,EAAE,CAAA;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,CAAC,EAAE;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CACjC,GAAG,IAAI,GAAG,iBAAiB,CAU3B;AAED,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,kBAAkB,GAAG,WAAW,CAK9F;AAED,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,MAAM,GACP,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CA0BrC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,GAAG,MAAM,CAYpG"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/resolve
|
|
3
|
+
*
|
|
4
|
+
* Pure locale-resolution functions shared by the template's root layout.
|
|
5
|
+
* The template proxy (edge, DB-free) only PARSES the URL and forwards
|
|
6
|
+
* detection hints as headers; the DECISIONS happen here, server-side, where
|
|
7
|
+
* store settings are available. No next/headers import — callers pass the
|
|
8
|
+
* values in, so these stay testable and browser-safe.
|
|
9
|
+
*/
|
|
10
|
+
import { DEFAULT_LOCALE, SUPPORTED_LOCALES, isSupportedLocale, } from './types';
|
|
11
|
+
/**
|
|
12
|
+
* Normalize raw settings values (nullable, legacy rows) into a usable
|
|
13
|
+
* config. Pre-i18n rows (both NULL) resolve to en-only — byte-identical
|
|
14
|
+
* legacy behavior.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveStoreLocaleConfig(settings) {
|
|
17
|
+
const def = isSupportedLocale(settings?.defaultLocale)
|
|
18
|
+
? settings.defaultLocale
|
|
19
|
+
: DEFAULT_LOCALE;
|
|
20
|
+
const enabled = (settings?.enabledLocales ?? [])
|
|
21
|
+
.filter(isSupportedLocale)
|
|
22
|
+
// preserve declaration order, dedupe
|
|
23
|
+
.filter((l, i, arr) => arr.indexOf(l) === i);
|
|
24
|
+
if (!enabled.includes(def))
|
|
25
|
+
enabled.unshift(def);
|
|
26
|
+
return { defaultLocale: def, enabledLocales: enabled };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The locale this request renders in. URL prefix wins (a shared /fr link
|
|
30
|
+
* must show French regardless of the visitor's cookie); otherwise the store
|
|
31
|
+
* default — bare URLs always serve the default language, and preference
|
|
32
|
+
* routing happens via redirect (below), never via content-swap on the same
|
|
33
|
+
* URL (that would serve two languages on one URL — the SEO failure mode the
|
|
34
|
+
* path-prefix architecture exists to avoid).
|
|
35
|
+
*/
|
|
36
|
+
export function resolveRequestLocale({ prefixLocale, config }) {
|
|
37
|
+
if (isSupportedLocale(prefixLocale) && config.enabledLocales.includes(prefixLocale)) {
|
|
38
|
+
return prefixLocale;
|
|
39
|
+
}
|
|
40
|
+
return config.defaultLocale;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Where this request should redirect for locale correctness, or null.
|
|
44
|
+
*
|
|
45
|
+
* - Prefixed URL for a locale the store doesn't serve → strip the prefix
|
|
46
|
+
* (no /fr ghost pages on an en-only store).
|
|
47
|
+
* - Bare URL + the visitor prefers an enabled non-default locale (explicit
|
|
48
|
+
* cookie first, else IP-country hint) → the prefixed equivalent. This is
|
|
49
|
+
* the "IP detection" behavior: first visit from France lands on /fr; the
|
|
50
|
+
* cookie the provider then writes keeps it sticky, and switching back to
|
|
51
|
+
* the default writes a default-locale cookie which suppresses this.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveLocaleRedirect({ prefixLocale, cookieLocale, geoLocale, pathname, config, }) {
|
|
54
|
+
if (!pathname || !pathname.startsWith('/'))
|
|
55
|
+
return null;
|
|
56
|
+
// Prefixed URL: only "not enabled" needs correction.
|
|
57
|
+
if (isSupportedLocale(prefixLocale)) {
|
|
58
|
+
if (!config.enabledLocales.includes(prefixLocale) || prefixLocale === config.defaultLocale) {
|
|
59
|
+
const bare = pathname.replace(new RegExp(`^/${prefixLocale}(?=/|$)`), '') || '/';
|
|
60
|
+
return bare;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
// Bare URL: route an explicit or detected preference to its prefix.
|
|
65
|
+
const preferred = isSupportedLocale(cookieLocale)
|
|
66
|
+
? cookieLocale
|
|
67
|
+
: isSupportedLocale(geoLocale)
|
|
68
|
+
? geoLocale
|
|
69
|
+
: null;
|
|
70
|
+
if (preferred &&
|
|
71
|
+
preferred !== config.defaultLocale &&
|
|
72
|
+
config.enabledLocales.includes(preferred)) {
|
|
73
|
+
return `/${preferred}${pathname === '/' ? '' : pathname}`;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the URL for the CURRENT page in another locale — the language
|
|
79
|
+
* switcher's navigation target. `pathname` may carry a locale prefix.
|
|
80
|
+
*/
|
|
81
|
+
export function localePath(pathname, target, defaultLocale) {
|
|
82
|
+
// Strip any existing supported-locale prefix.
|
|
83
|
+
let bare = pathname;
|
|
84
|
+
for (const l of SUPPORTED_LOCALES) {
|
|
85
|
+
const re = new RegExp(`^/${l}(?=/|$)`);
|
|
86
|
+
if (re.test(bare)) {
|
|
87
|
+
bare = bare.replace(re, '') || '/';
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (target === defaultLocale)
|
|
92
|
+
return bare;
|
|
93
|
+
return `/${target}${bare === '/' ? '' : bare}`;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/i18n/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/translate
|
|
3
|
+
*
|
|
4
|
+
* The pure translation function — server-safe (no React). Client components
|
|
5
|
+
* reach it through `useT()` (context.tsx); server components and emails call
|
|
6
|
+
* `getT(locale)` directly with an explicit locale.
|
|
7
|
+
*
|
|
8
|
+
* Lookup contract (load-bearing): locale catalog → English catalog → the key
|
|
9
|
+
* itself. A missing key can never crash or blank a surface — worst case the
|
|
10
|
+
* visitor sees English, and a raw key in the UI is a loud, greppable bug.
|
|
11
|
+
*/
|
|
12
|
+
import { type StoreLocale } from './types';
|
|
13
|
+
export type TranslateVars = Record<string, string | number>;
|
|
14
|
+
export type Translator = (key: string, vars?: TranslateVars) => string;
|
|
15
|
+
/** Build a translator bound to a locale. */
|
|
16
|
+
export declare function getT(locale: StoreLocale): Translator;
|
|
17
|
+
/** Direct one-shot translation (emails, server helpers). */
|
|
18
|
+
export declare function translate(locale: StoreLocale, key: string, vars?: TranslateVars): string;
|
|
19
|
+
/**
|
|
20
|
+
* Translate a DYNAMIC value through a key prefix, falling back to the raw
|
|
21
|
+
* value (not the key) when no catalog entry exists. For merchant-stored
|
|
22
|
+
* enum-ish strings like preparation times: `translateDynamic(t, 'prep', '2
|
|
23
|
+
* hours')` → '2 heures' in fr, '2 hours' when unmapped.
|
|
24
|
+
*/
|
|
25
|
+
export declare function translateDynamic(t: Translator, prefix: string, value: string): string;
|
|
26
|
+
//# sourceMappingURL=translate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/core/i18n/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,SAAS,CAAA;AAI/E,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAU3D,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,KAAK,MAAM,CAAA;AAEtE,4CAA4C;AAC5C,wBAAgB,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CAOpD;AAED,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAExF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/translate
|
|
3
|
+
*
|
|
4
|
+
* The pure translation function — server-safe (no React). Client components
|
|
5
|
+
* reach it through `useT()` (context.tsx); server components and emails call
|
|
6
|
+
* `getT(locale)` directly with an explicit locale.
|
|
7
|
+
*
|
|
8
|
+
* Lookup contract (load-bearing): locale catalog → English catalog → the key
|
|
9
|
+
* itself. A missing key can never crash or blank a surface — worst case the
|
|
10
|
+
* visitor sees English, and a raw key in the UI is a loud, greppable bug.
|
|
11
|
+
*/
|
|
12
|
+
import { en } from './messages/en';
|
|
13
|
+
import { fr } from './messages/fr';
|
|
14
|
+
import { DEFAULT_LOCALE } from './types';
|
|
15
|
+
const CATALOGS = { en, fr };
|
|
16
|
+
/** `{name}` interpolation. Unknown slots are left verbatim (greppable). */
|
|
17
|
+
function interpolate(template, vars) {
|
|
18
|
+
if (!vars)
|
|
19
|
+
return template;
|
|
20
|
+
return template.replace(/\{(\w+)\}/g, (match, name) => name in vars ? String(vars[name]) : match);
|
|
21
|
+
}
|
|
22
|
+
/** Build a translator bound to a locale. */
|
|
23
|
+
export function getT(locale) {
|
|
24
|
+
const catalog = CATALOGS[locale] ?? CATALOGS[DEFAULT_LOCALE];
|
|
25
|
+
const fallback = CATALOGS[DEFAULT_LOCALE];
|
|
26
|
+
return (key, vars) => {
|
|
27
|
+
const template = catalog[key] ?? fallback[key] ?? key;
|
|
28
|
+
return interpolate(template, vars);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Direct one-shot translation (emails, server helpers). */
|
|
32
|
+
export function translate(locale, key, vars) {
|
|
33
|
+
return getT(locale)(key, vars);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Translate a DYNAMIC value through a key prefix, falling back to the raw
|
|
37
|
+
* value (not the key) when no catalog entry exists. For merchant-stored
|
|
38
|
+
* enum-ish strings like preparation times: `translateDynamic(t, 'prep', '2
|
|
39
|
+
* hours')` → '2 heures' in fr, '2 hours' when unmapped.
|
|
40
|
+
*/
|
|
41
|
+
export function translateDynamic(t, prefix, value) {
|
|
42
|
+
const key = `${prefix}.${value}`;
|
|
43
|
+
const out = t(key);
|
|
44
|
+
return out === key ? value : out;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=translate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../../../src/core/i18n/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAA;AAClC,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAA;AAClC,OAAO,EAAE,cAAc,EAAyC,MAAM,SAAS,CAAA;AAE/E,MAAM,QAAQ,GAAwC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;AAIhE,2EAA2E;AAC3E,SAAS,WAAW,CAAC,QAAgB,EAAE,IAAoB;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAA;IAC1B,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE,CAC5D,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAC1C,CAAA;AACH,CAAC;AAID,4CAA4C;AAC5C,MAAM,UAAU,IAAI,CAAC,MAAmB;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAA;IAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;IACzC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAA;QACrD,OAAO,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACpC,CAAC,CAAA;AACH,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,SAAS,CAAC,MAAmB,EAAE,GAAW,EAAE,IAAoB;IAC9E,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;AAChC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAa,EAAE,MAAc,EAAE,KAAa;IAC3E,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,KAAK,EAAE,CAAA;IAChC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAA;AAClC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/types
|
|
3
|
+
*
|
|
4
|
+
* Locale types for the storefront i18n core. The SDK ships its own message
|
|
5
|
+
* catalogs (en + fr) so its components translate themselves — no external
|
|
6
|
+
* i18n library, no peer-dependency dance. Store-authored content (product
|
|
7
|
+
* names, custom sections) is a SEPARATE layer (catalog translations, jsonb).
|
|
8
|
+
*/
|
|
9
|
+
/** Locales the SDK ships catalogs for. Extending = add a catalog + append here. */
|
|
10
|
+
export declare const SUPPORTED_LOCALES: readonly ["en", "fr"];
|
|
11
|
+
export type StoreLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
12
|
+
/** The default when nothing is configured — matches pre-i18n behavior. */
|
|
13
|
+
export declare const DEFAULT_LOCALE: StoreLocale;
|
|
14
|
+
/** Runtime guard for values coming from cookies / headers / settings. */
|
|
15
|
+
export declare function isSupportedLocale(value: unknown): value is StoreLocale;
|
|
16
|
+
/**
|
|
17
|
+
* Flat message catalog: `namespace.key` → string. Interpolation slots use
|
|
18
|
+
* `{name}` syntax, substituted by `t()`.
|
|
19
|
+
*/
|
|
20
|
+
export type MessageCatalog = Record<string, string>;
|
|
21
|
+
/** BCP-47 tag used for Intl formatting per locale. */
|
|
22
|
+
export declare const LOCALE_INTL: Record<StoreLocale, string>;
|
|
23
|
+
/**
|
|
24
|
+
* The cookie that persists an explicit visitor choice (language switcher) or
|
|
25
|
+
* a first-visit geo detection. Read by the template proxy for bare-path
|
|
26
|
+
* redirects; written client-side by the LocaleProvider / switcher.
|
|
27
|
+
*/
|
|
28
|
+
export declare const LOCALE_COOKIE = "rovela-locale";
|
|
29
|
+
/**
|
|
30
|
+
* Request headers set by the template proxy (see template/proxy.ts):
|
|
31
|
+
* - LOCALE_HEADER: the locale parsed from a URL prefix (`/fr/...`), when present.
|
|
32
|
+
* - GEO_LOCALE_HEADER: the locale suggested by the visitor's IP country
|
|
33
|
+
* (`x-vercel-ip-country`), detection hint only.
|
|
34
|
+
* - PATHNAME_HEADER: the ORIGINAL request pathname (prefix included) so
|
|
35
|
+
* server components can build locale-switch + redirect URLs.
|
|
36
|
+
*/
|
|
37
|
+
export declare const LOCALE_HEADER = "x-rovela-locale";
|
|
38
|
+
export declare const GEO_LOCALE_HEADER = "x-rovela-geo-locale";
|
|
39
|
+
export declare const PATHNAME_HEADER = "x-rovela-pathname";
|
|
40
|
+
/**
|
|
41
|
+
* IP country → locale suggestion. Deliberately minimal: only countries whose
|
|
42
|
+
* dominant language we ship a catalog for. Everything else falls through to
|
|
43
|
+
* the store default.
|
|
44
|
+
*/
|
|
45
|
+
export declare const COUNTRY_TO_LOCALE: Record<string, StoreLocale>;
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/i18n/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,uBAAwB,CAAA;AAEtD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,cAAc,EAAE,WAAkB,CAAA;AAE/C,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAEtE;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEnD,sDAAsD;AACtD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAGnD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,oBAAoB,CAAA;AAC9C,eAAO,MAAM,iBAAiB,wBAAwB,CAAA;AACtD,eAAO,MAAM,eAAe,sBAAsB,CAAA;AAElD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAKzD,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/core/i18n/types
|
|
3
|
+
*
|
|
4
|
+
* Locale types for the storefront i18n core. The SDK ships its own message
|
|
5
|
+
* catalogs (en + fr) so its components translate themselves — no external
|
|
6
|
+
* i18n library, no peer-dependency dance. Store-authored content (product
|
|
7
|
+
* names, custom sections) is a SEPARATE layer (catalog translations, jsonb).
|
|
8
|
+
*/
|
|
9
|
+
/** Locales the SDK ships catalogs for. Extending = add a catalog + append here. */
|
|
10
|
+
export const SUPPORTED_LOCALES = ['en', 'fr'];
|
|
11
|
+
/** The default when nothing is configured — matches pre-i18n behavior. */
|
|
12
|
+
export const DEFAULT_LOCALE = 'en';
|
|
13
|
+
/** Runtime guard for values coming from cookies / headers / settings. */
|
|
14
|
+
export function isSupportedLocale(value) {
|
|
15
|
+
return typeof value === 'string' && SUPPORTED_LOCALES.includes(value);
|
|
16
|
+
}
|
|
17
|
+
/** BCP-47 tag used for Intl formatting per locale. */
|
|
18
|
+
export const LOCALE_INTL = {
|
|
19
|
+
en: 'en-US',
|
|
20
|
+
fr: 'fr-FR',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The cookie that persists an explicit visitor choice (language switcher) or
|
|
24
|
+
* a first-visit geo detection. Read by the template proxy for bare-path
|
|
25
|
+
* redirects; written client-side by the LocaleProvider / switcher.
|
|
26
|
+
*/
|
|
27
|
+
export const LOCALE_COOKIE = 'rovela-locale';
|
|
28
|
+
/**
|
|
29
|
+
* Request headers set by the template proxy (see template/proxy.ts):
|
|
30
|
+
* - LOCALE_HEADER: the locale parsed from a URL prefix (`/fr/...`), when present.
|
|
31
|
+
* - GEO_LOCALE_HEADER: the locale suggested by the visitor's IP country
|
|
32
|
+
* (`x-vercel-ip-country`), detection hint only.
|
|
33
|
+
* - PATHNAME_HEADER: the ORIGINAL request pathname (prefix included) so
|
|
34
|
+
* server components can build locale-switch + redirect URLs.
|
|
35
|
+
*/
|
|
36
|
+
export const LOCALE_HEADER = 'x-rovela-locale';
|
|
37
|
+
export const GEO_LOCALE_HEADER = 'x-rovela-geo-locale';
|
|
38
|
+
export const PATHNAME_HEADER = 'x-rovela-pathname';
|
|
39
|
+
/**
|
|
40
|
+
* IP country → locale suggestion. Deliberately minimal: only countries whose
|
|
41
|
+
* dominant language we ship a catalog for. Everything else falls through to
|
|
42
|
+
* the store default.
|
|
43
|
+
*/
|
|
44
|
+
export const COUNTRY_TO_LOCALE = {
|
|
45
|
+
FR: 'fr',
|
|
46
|
+
BE: 'fr',
|
|
47
|
+
LU: 'fr',
|
|
48
|
+
MC: 'fr',
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/i18n/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,mFAAmF;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAA;AAItD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAgB,IAAI,CAAA;AAE/C,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC9F,CAAC;AAQD,sDAAsD;AACtD,MAAM,CAAC,MAAM,WAAW,GAAgC;IACtD,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;CACZ,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAE5C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAA;AAC9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAA;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAA;AAElD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAgC;IAC5D,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;CACT,CAAA"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
export * from './types';
|
|
18
|
+
export * from './i18n';
|
|
18
19
|
export { StoreSettingsProvider, useStoreSettings, useStoreSettingsOptional, } from './StoreSettingsProvider';
|
|
19
20
|
export type { StoreSettings, StoreSettingsContextValue, StoreSettingsProviderProps, } from './StoreSettingsProvider';
|
|
20
21
|
export { cn, formatPrice, parsePrice, getCurrencySymbol, generateSlug, generateSKU, formatDate, formatRelativeTime, truncate, capitalize, titleCase, clamp, percentage, isValidEmail, isValidPhone, compact, pick, omit, sleep, retry, } from './utils';
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,cAAc,SAAS,CAAA;AAGvB,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EACV,aAAa,EACb,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAEL,EAAE,EAEF,WAAW,EACX,UAAU,EACV,iBAAiB,EAEjB,YAAY,EAEZ,WAAW,EAEX,UAAU,EACV,kBAAkB,EAElB,QAAQ,EACR,UAAU,EACV,SAAS,EAET,KAAK,EACL,UAAU,EAEV,YAAY,EACZ,YAAY,EAEZ,OAAO,EACP,IAAI,EACJ,IAAI,EAEJ,KAAK,EACL,KAAK,GACN,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAGjD,OAAO,EACL,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,OAAO,CAAA;AACd,YAAY,EACV,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,OAAO,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,cAAc,SAAS,CAAA;AAGvB,cAAc,QAAQ,CAAA;AAGtB,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EACV,aAAa,EACb,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAEL,EAAE,EAEF,WAAW,EACX,UAAU,EACV,iBAAiB,EAEjB,YAAY,EAEZ,WAAW,EAEX,UAAU,EACV,kBAAkB,EAElB,QAAQ,EACR,UAAU,EACV,SAAS,EAET,KAAK,EACL,UAAU,EAEV,YAAY,EACZ,YAAY,EAEZ,OAAO,EACP,IAAI,EACJ,IAAI,EAEJ,KAAK,EACL,KAAK,GACN,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAGjD,OAAO,EACL,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,OAAO,CAAA;AACd,YAAY,EACV,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,OAAO,CAAA"}
|
package/dist/core/index.js
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
// Types - all shared domain types (browser-safe)
|
|
18
18
|
export * from './types';
|
|
19
|
+
// i18n core (browser-safe: provider + hooks + server-safe translators)
|
|
20
|
+
export * from './i18n';
|
|
19
21
|
// Store Settings Provider and Hook (browser-safe)
|
|
20
22
|
export { StoreSettingsProvider, useStoreSettings, useStoreSettingsOptional, } from './StoreSettingsProvider';
|
|
21
23
|
// Utilities - browser-safe functions
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iDAAiD;AACjD,cAAc,SAAS,CAAA;AAEvB,kDAAkD;AAClD,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAQhC,qCAAqC;AACrC,OAAO;AACL,cAAc;AACd,EAAE;AACF,mBAAmB;AACnB,WAAW,EACX,UAAU,EACV,iBAAiB;AACjB,kBAAkB;AAClB,YAAY;AACZ,iBAAiB;AACjB,WAAW;AACX,kBAAkB;AAClB,UAAU,EACV,kBAAkB;AAClB,mBAAmB;AACnB,QAAQ,EACR,UAAU,EACV,SAAS;AACT,mBAAmB;AACnB,KAAK,EACL,UAAU;AACV,aAAa;AACb,YAAY,EACZ,YAAY;AACZ,mBAAmB;AACnB,OAAO,EACP,IAAI,EACJ,IAAI;AACJ,kBAAkB;AAClB,KAAK,EACL,KAAK,GACN,MAAM,SAAS,CAAA;AAIhB,yDAAyD;AACzD,OAAO,EACL,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,OAAO,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iDAAiD;AACjD,cAAc,SAAS,CAAA;AAEvB,uEAAuE;AACvE,cAAc,QAAQ,CAAA;AAEtB,kDAAkD;AAClD,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAQhC,qCAAqC;AACrC,OAAO;AACL,cAAc;AACd,EAAE;AACF,mBAAmB;AACnB,WAAW,EACX,UAAU,EACV,iBAAiB;AACjB,kBAAkB;AAClB,YAAY;AACZ,iBAAiB;AACjB,WAAW;AACX,kBAAkB;AAClB,UAAU,EACV,kBAAkB;AAClB,mBAAmB;AACnB,QAAQ,EACR,UAAU,EACV,SAAS;AACT,mBAAmB;AACnB,KAAK,EACL,UAAU;AACV,aAAa;AACb,YAAY,EACZ,YAAY;AACZ,mBAAmB;AACnB,OAAO,EACP,IAAI,EACJ,IAAI;AACJ,kBAAkB;AAClB,KAAK,EACL,KAAK,GACN,MAAM,SAAS,CAAA;AAIhB,yDAAyD;AACzD,OAAO,EACL,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,OAAO,CAAA"}
|