@salesforce/storefront-next-runtime 0.3.1-alpha.1 → 0.4.0-alpha.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 +82 -0
- package/dist/DesignComponent.js +37 -12
- package/dist/DesignComponent.js.map +1 -1
- package/dist/DesignContext.js +47 -2
- package/dist/DesignContext.js.map +1 -1
- package/dist/DesignFrame.js +1 -1
- package/dist/DesignRegion.js +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/custom-global-preferences.d.ts +20 -0
- package/dist/custom-global-preferences.d.ts.map +1 -0
- package/dist/custom-global-preferences.js +28 -0
- package/dist/custom-global-preferences.js.map +1 -0
- package/dist/custom-site-preferences.d.ts +20 -0
- package/dist/custom-site-preferences.d.ts.map +1 -0
- package/dist/custom-site-preferences.js +28 -0
- package/dist/custom-site-preferences.js.map +1 -0
- package/dist/data-store-custom-global-preferences.d.ts +2 -0
- package/dist/data-store-custom-global-preferences.js +6 -0
- package/dist/data-store-custom-site-preferences.d.ts +2 -0
- package/dist/data-store-custom-site-preferences.js +6 -0
- package/dist/data-store-gcp-preferences.d.ts +2 -0
- package/dist/data-store-gcp-preferences.js +6 -0
- package/dist/data-store.d.ts +97 -0
- package/dist/data-store.d.ts.map +1 -0
- package/dist/data-store.js +42 -0
- package/dist/data-store.js.map +1 -0
- package/dist/design-data.d.ts +82 -88
- package/dist/design-data.d.ts.map +1 -1
- package/dist/design-data.js +95 -57
- package/dist/design-data.js.map +1 -1
- package/dist/design-messaging.d.ts +2 -2
- package/dist/events.d.ts +34 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +6 -6
- package/dist/events.js.map +1 -1
- package/dist/gcp-preferences.d.ts +52 -0
- package/dist/gcp-preferences.d.ts.map +1 -0
- package/dist/gcp-preferences.js +61 -0
- package/dist/gcp-preferences.js.map +1 -0
- package/dist/i18n-client.d.ts +38 -0
- package/dist/i18n-client.d.ts.map +1 -0
- package/dist/i18n-client.js +72 -0
- package/dist/i18n-client.js.map +1 -0
- package/dist/i18n.d.ts +63 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +98 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +60 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/messaging-api.js +3 -1
- package/dist/messaging-api.js.map +1 -1
- package/dist/scapi.d.ts +247 -2
- package/dist/scapi.d.ts.map +1 -1
- package/dist/scapi.js +1 -1
- package/dist/scapi.js.map +1 -1
- package/dist/site-context.d.ts +94 -18
- package/dist/site-context.d.ts.map +1 -1
- package/dist/site-context.js +2 -417
- package/dist/site-context2.js +513 -0
- package/dist/site-context2.js.map +1 -0
- package/dist/types2.d.ts +210 -0
- package/dist/types2.d.ts.map +1 -1
- package/dist/utils.js +179 -0
- package/dist/utils.js.map +1 -0
- package/package.json +63 -4
- package/dist/site-context.js.map +0 -1
package/dist/events.d.ts
CHANGED
|
@@ -114,6 +114,11 @@ interface ClickSearchSuggestionEvent extends BaseEvent {
|
|
|
114
114
|
searchInputText: string;
|
|
115
115
|
suggestion: string;
|
|
116
116
|
}
|
|
117
|
+
/** Shopper opened agentic commerce (e.g. header or search assistant entry point). */
|
|
118
|
+
interface CommerceAgentEngagementEvent extends BaseEvent {
|
|
119
|
+
eventType: 'commerce_agent_engagement';
|
|
120
|
+
surface: 'header' | 'search';
|
|
121
|
+
}
|
|
117
122
|
/**
|
|
118
123
|
* Interface for custom analytics events.
|
|
119
124
|
* Extend this interface via module augmentation.
|
|
@@ -133,7 +138,7 @@ interface AnalyticsEventExtensions {}
|
|
|
133
138
|
*
|
|
134
139
|
* Custom types can be added by extending the AnalyticsEventExtensions interface.
|
|
135
140
|
*/
|
|
136
|
-
type AnalyticsEvent = ViewPageEvent | ViewProductEvent | ViewSearchEvent | ViewCategoryEvent | ViewRecommenderEvent | ClickProductInCategoryEvent | ClickProductInSearchEvent | ClickProductInRecommenderEvent | CartItemAddEvent | CheckoutStartEvent | CheckoutStepEvent | ViewSearchSuggestionEvent | ClickSearchSuggestionEvent | AnalyticsEventExtensions[keyof AnalyticsEventExtensions];
|
|
141
|
+
type AnalyticsEvent = ViewPageEvent | ViewProductEvent | ViewSearchEvent | ViewCategoryEvent | ViewRecommenderEvent | ClickProductInCategoryEvent | ClickProductInSearchEvent | ClickProductInRecommenderEvent | CartItemAddEvent | CheckoutStartEvent | CheckoutStepEvent | ViewSearchSuggestionEvent | ClickSearchSuggestionEvent | CommerceAgentEngagementEvent | AnalyticsEventExtensions[keyof AnalyticsEventExtensions];
|
|
137
142
|
/**
|
|
138
143
|
* Helper type for mapping event_type to the corresponding event type.
|
|
139
144
|
*/
|
|
@@ -149,20 +154,43 @@ type EventSiteInfo = {
|
|
|
149
154
|
siteId: string;
|
|
150
155
|
localeId: string;
|
|
151
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* Consent categories for granular tracking control.
|
|
159
|
+
*
|
|
160
|
+
* Adapters declare which consent category they require via configuration.
|
|
161
|
+
* The event system passes the shopper's granted categories (consentPreferences) to each adapter,
|
|
162
|
+
* allowing per-adapter consent decisions.
|
|
163
|
+
*
|
|
164
|
+
* This is typed as `string` so projects can define categories that match their
|
|
165
|
+
* consent management platform. Common conventions:
|
|
166
|
+
*
|
|
167
|
+
* - `'necessary'` — Essential cookies/tracking required for site functionality
|
|
168
|
+
* - `'analytics'` — Usage analytics and performance measurement
|
|
169
|
+
* - `'marketing'` — Marketing, advertising, and retargeting
|
|
170
|
+
* - `'personalization'` — Product recommendations and personalized experiences
|
|
171
|
+
*/
|
|
172
|
+
type ConsentCategory = string;
|
|
173
|
+
/**
|
|
174
|
+
* The set of consent categories a shopper has granted.
|
|
175
|
+
*
|
|
176
|
+
* Each adapter checks whether its required `consentCategory` is included
|
|
177
|
+
* in the preferences before sending events.
|
|
178
|
+
*/
|
|
179
|
+
type ConsentPreferences = ConsentCategory[];
|
|
152
180
|
/**
|
|
153
181
|
* Minimal interface for engagement adapters that can send analytics events.
|
|
154
|
-
*
|
|
182
|
+
* Engagement Adapters must implement this interface to work with the event mediator.
|
|
155
183
|
*/
|
|
156
184
|
interface EventAdapter {
|
|
157
185
|
name: string;
|
|
158
|
-
sendEvent?: (event: AnalyticsEvent, siteInfo?: EventSiteInfo) => Promise<unknown>;
|
|
186
|
+
sendEvent?: (event: AnalyticsEvent, siteInfo?: EventSiteInfo, consentPreferences?: ConsentPreferences) => Promise<unknown>;
|
|
159
187
|
}
|
|
160
188
|
/**
|
|
161
189
|
* Generic event mediator interface for tracking events.
|
|
162
190
|
* This can be used for analytics, telemetry, or any other event tracking system.
|
|
163
191
|
*/
|
|
164
192
|
type EventMediator = {
|
|
165
|
-
track: (event: AnalyticsEvent, siteInfo?: EventSiteInfo) => void;
|
|
193
|
+
track: (event: AnalyticsEvent, siteInfo?: EventSiteInfo, consentPreferences?: ConsentPreferences) => void;
|
|
166
194
|
};
|
|
167
195
|
//#endregion
|
|
168
196
|
//#region src/events/events.d.ts
|
|
@@ -190,7 +218,7 @@ declare function createEvent<T extends AnalyticsEvent['eventType']>(eventType: T
|
|
|
190
218
|
* @param event - The view page event to send
|
|
191
219
|
* @param eventMediator - The event mediator to send the event to
|
|
192
220
|
*/
|
|
193
|
-
declare function sendViewPageEvent(event: ViewPageEvent, eventMediator: EventMediator, siteInfo?: EventSiteInfo): void;
|
|
221
|
+
declare function sendViewPageEvent(event: ViewPageEvent, eventMediator: EventMediator, siteInfo?: EventSiteInfo, consentPreferences?: ConsentPreferences): void;
|
|
194
222
|
//#endregion
|
|
195
223
|
//#region src/events/mediator.d.ts
|
|
196
224
|
/**
|
|
@@ -209,5 +237,5 @@ declare function getEventMediator(getAdapters: () => EventAdapter[]): EventMedia
|
|
|
209
237
|
*/
|
|
210
238
|
declare function resetEventMediator(): void;
|
|
211
239
|
//#endregion
|
|
212
|
-
export { AnalyticsEvent, AnalyticsEventExtensions, AnalyticsPayload, AnalyticsUser, BaseEvent, CartItemAddEvent, CheckoutStartEvent, CheckoutStepEvent, ClickProductInCategoryEvent, ClickProductInRecommenderEvent, ClickProductInSearchEvent, ClickSearchSuggestionEvent, EventAdapter, EventMediator, EventPayload, EventSiteInfo, EventTypeMap, PayloadTbd, ViewCategoryEvent, ViewPageEvent, ViewProductEvent, ViewRecommenderEvent, ViewSearchEvent, ViewSearchSuggestionEvent, createEvent, getEventMediator, resetEventMediator, sendViewPageEvent };
|
|
240
|
+
export { AnalyticsEvent, AnalyticsEventExtensions, AnalyticsPayload, AnalyticsUser, BaseEvent, CartItemAddEvent, CheckoutStartEvent, CheckoutStepEvent, ClickProductInCategoryEvent, ClickProductInRecommenderEvent, ClickProductInSearchEvent, ClickSearchSuggestionEvent, CommerceAgentEngagementEvent, ConsentCategory, ConsentPreferences, EventAdapter, EventMediator, EventPayload, EventSiteInfo, EventTypeMap, PayloadTbd, ViewCategoryEvent, ViewPageEvent, ViewProductEvent, ViewRecommenderEvent, ViewSearchEvent, ViewSearchSuggestionEvent, createEvent, getEventMediator, resetEventMediator, sendViewPageEvent };
|
|
213
241
|
//# sourceMappingURL=events.d.ts.map
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","names":[],"sources":["../src/events/types.ts","../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":[],"mappings":";;;;;KAmBK,iBAAA,GAAoB,gBAAA,CAAiB,OAqEQ,CAAA,aAAA,CAAA,GArEiB,gBAAA,CAAiB,OAqElC,CAAA,aAAA,CAAA;AAQlD,KA5EK,MAAA,GAAS,gBAAA,CAAiB,OA4EI,CAAA,QAAA,CAAA,GA5EgB,gBAAA,CAAiB,OA4EjC,CAAA,QAAA,CAAA;;;;;;AAQnC;AAOA;;;;;AAMA;AAMA;AAOA;;AAEe,UA3FE,aAAA,CA2FF;EAF2B,QAAA,EAAA,YAAA,GAAA,OAAA;EAAS,IAAA,CAAA,EAAA,MAAA;EAKlC,GAAA,CAAA,EAAA,MAAA;EAKA,SAAA,CAAA,EAAA,MAAA;EAOA,UAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"events.d.ts","names":[],"sources":["../src/events/types.ts","../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/events.js
CHANGED
|
@@ -28,8 +28,8 @@ function createEvent(eventType, data) {
|
|
|
28
28
|
* @param event - The view page event to send
|
|
29
29
|
* @param eventMediator - The event mediator to send the event to
|
|
30
30
|
*/
|
|
31
|
-
function sendViewPageEvent(event, eventMediator, siteInfo) {
|
|
32
|
-
eventMediator.track(event, siteInfo);
|
|
31
|
+
function sendViewPageEvent(event, eventMediator, siteInfo, consentPreferences) {
|
|
32
|
+
eventMediator.track(event, siteInfo, consentPreferences);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
//#endregion
|
|
@@ -48,8 +48,8 @@ let mediatorInstance;
|
|
|
48
48
|
* @returns EventMediator instance
|
|
49
49
|
*/
|
|
50
50
|
function createEventMediator(getAdapters) {
|
|
51
|
-
return { track: (event, siteInfo) => {
|
|
52
|
-
processEventWithAdapters(event, getAdapters, siteInfo).catch((error) => {
|
|
51
|
+
return { track: (event, siteInfo, consentPreferences) => {
|
|
52
|
+
processEventWithAdapters(event, getAdapters, siteInfo, consentPreferences).catch((error) => {
|
|
53
53
|
console.error("Analytics tracking failed:", error);
|
|
54
54
|
});
|
|
55
55
|
} };
|
|
@@ -82,7 +82,7 @@ function resetEventMediator() {
|
|
|
82
82
|
* @param event - The analytics event to process
|
|
83
83
|
* @param getAdapters - Function that returns the current array of event adapters
|
|
84
84
|
*/
|
|
85
|
-
async function processEventWithAdapters(event, getAdapters, siteInfo) {
|
|
85
|
+
async function processEventWithAdapters(event, getAdapters, siteInfo, consentPreferences) {
|
|
86
86
|
const eventAdapters = getAdapters();
|
|
87
87
|
if (eventAdapters.length === 0) {
|
|
88
88
|
console.warn(`There are no active adapters to send the event to`);
|
|
@@ -90,7 +90,7 @@ async function processEventWithAdapters(event, getAdapters, siteInfo) {
|
|
|
90
90
|
}
|
|
91
91
|
const promises = eventAdapters.map(async (adapter) => {
|
|
92
92
|
try {
|
|
93
|
-
if (typeof adapter.sendEvent === "function") await adapter.sendEvent(event, siteInfo);
|
|
93
|
+
if (typeof adapter.sendEvent === "function") await adapter.sendEvent(event, siteInfo, consentPreferences);
|
|
94
94
|
else console.warn(`Adapter ${adapter.name} does not implement sendEvent`);
|
|
95
95
|
} catch (error) {
|
|
96
96
|
console.error(`Failed to send event to ${adapter.name}:`, error);
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":["mediatorInstance: EventMediator | undefined"],"sources":["../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {
|
|
1
|
+
{"version":3,"file":"events.js","names":["mediatorInstance: EventMediator | undefined"],"sources":["../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalyticsEvent,\n ConsentPreferences,\n EventMediator,\n EventPayload,\n EventSiteInfo,\n EventTypeMap,\n ViewPageEvent,\n} from './types';\n\n/**\n * Type-safe event creation function\n *\n * This generic function allows creating any event type under AnalyticsEvent\n * with full type safety. The event type is inferred from the string literal\n * passed as the first parameter, and TypeScript will enforce the correct\n * data properties for that specific event type.\n *\n * @example\n * ```typescript\n * const viewPageEvent = createEvent('view_page', { path: '/products', payload });\n * const viewProductEvent = createEvent('view_product', { product, payload });\n * ```\n */\nexport function createEvent<T extends AnalyticsEvent['eventType']>(\n eventType: T,\n data: EventPayload<T>\n): EventTypeMap[T] {\n return {\n eventType,\n ...data,\n } as EventTypeMap[T];\n}\n\n/**\n * Send a view page event to the event mediator\n *\n * This wrapper function is used in the automated page view event tracking client middleware.\n * This function exists to support build-time checks and type safety.\n *\n * @param event - The view page event to send\n * @param eventMediator - The event mediator to send the event to\n */\nexport function sendViewPageEvent(\n event: ViewPageEvent,\n eventMediator: EventMediator,\n siteInfo?: EventSiteInfo,\n consentPreferences?: ConsentPreferences\n): void {\n eventMediator.track(event, siteInfo, consentPreferences);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { EventMediator, AnalyticsEvent, EventAdapter, EventSiteInfo, ConsentPreferences } from './types';\n\n// Module-level storage for the event mediator singleton\n// This ensures a single mediator instance across all usages\nlet mediatorInstance: EventMediator | undefined;\n\n/**\n * Create an event mediator instance\n *\n * Creates a new EventMediator that processes events through the provided adapters.\n * The mediator uses the getAdapters function on each track() invocation to ensure\n * it always uses the latest adapters from the adapter registry.\n *\n * @param getAdapters - Function that returns the current array of engagement adapters.\n * This function is called on each track() invocation to ensure\n * the mediator always uses the latest adapters from the adapter registry.\n * @returns EventMediator instance\n */\nfunction createEventMediator(getAdapters: () => EventAdapter[]): EventMediator {\n return {\n track: (event: AnalyticsEvent, siteInfo?: EventSiteInfo, consentPreferences?: ConsentPreferences) => {\n processEventWithAdapters(event, getAdapters, siteInfo, consentPreferences).catch((error) => {\n // eslint-disable-next-line no-console\n console.error('Analytics tracking failed:', error);\n });\n },\n };\n}\n\n/**\n * Get the event mediator singleton instance\n *\n * Returns the singleton EventMediator instance, creating it if it doesn't exist.\n *\n * @param getAdapters - Function that returns the current array of engagement adapters.\n * @returns EventMediator instance (singleton) or undefined if not on client side\n */\nexport function getEventMediator(getAdapters: () => EventAdapter[]): EventMediator | undefined {\n // If mediator already exists, return it\n if (mediatorInstance) {\n return mediatorInstance;\n }\n\n // Only create on client side\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n // Create the event mediator singleton\n mediatorInstance = createEventMediator(getAdapters);\n return mediatorInstance;\n}\n\n/**\n * Reset the event mediator singleton (for testing only)\n *\n * This function clears the singleton instance, allowing tests to create a fresh mediator.\n */\nexport function resetEventMediator(): void {\n mediatorInstance = undefined;\n}\n\n/**\n * Process an event with all registered adapters\n *\n * @param event - The analytics event to process\n * @param getAdapters - Function that returns the current array of event adapters\n */\nasync function processEventWithAdapters(\n event: AnalyticsEvent,\n getAdapters: () => EventAdapter[],\n siteInfo?: EventSiteInfo,\n consentPreferences?: ConsentPreferences\n): Promise<void> {\n // Get the current array of event adapters\n const eventAdapters = getAdapters();\n if (eventAdapters.length === 0) {\n // eslint-disable-next-line no-console\n console.warn(`There are no active adapters to send the event to`);\n return;\n }\n\n // Send event to all registered adapters that implement sendEvent in parallel\n const promises = eventAdapters.map(async (adapter) => {\n try {\n if (typeof adapter.sendEvent === 'function') {\n await adapter.sendEvent(event, siteInfo, consentPreferences);\n } else {\n // eslint-disable-next-line no-console\n console.warn(`Adapter ${adapter.name} does not implement sendEvent`);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(`Failed to send event to ${adapter.name}:`, error);\n }\n });\n\n await Promise.allSettled(promises);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,SAAgB,YACZ,WACA,MACe;AACf,QAAO;EACH;EACA,GAAG;EACN;;;;;;;;;;;AAYL,SAAgB,kBACZ,OACA,eACA,UACA,oBACI;AACJ,eAAc,MAAM,OAAO,UAAU,mBAAmB;;;;;AC7C5D,IAAIA;;;;;;;;;;;;;AAcJ,SAAS,oBAAoB,aAAkD;AAC3E,QAAO,EACH,QAAQ,OAAuB,UAA0B,uBAA4C;AACjG,2BAAyB,OAAO,aAAa,UAAU,mBAAmB,CAAC,OAAO,UAAU;AAExF,WAAQ,MAAM,8BAA8B,MAAM;IACpD;IAET;;;;;;;;;;AAWL,SAAgB,iBAAiB,aAA8D;AAE3F,KAAI,iBACA,QAAO;AAIX,KAAI,OAAO,WAAW,YAClB;AAIJ,oBAAmB,oBAAoB,YAAY;AACnD,QAAO;;;;;;;AAQX,SAAgB,qBAA2B;AACvC,oBAAmB;;;;;;;;AASvB,eAAe,yBACX,OACA,aACA,UACA,oBACa;CAEb,MAAM,gBAAgB,aAAa;AACnC,KAAI,cAAc,WAAW,GAAG;AAE5B,UAAQ,KAAK,oDAAoD;AACjE;;CAIJ,MAAM,WAAW,cAAc,IAAI,OAAO,YAAY;AAClD,MAAI;AACA,OAAI,OAAO,QAAQ,cAAc,WAC7B,OAAM,QAAQ,UAAU,OAAO,UAAU,mBAAmB;OAG5D,SAAQ,KAAK,WAAW,QAAQ,KAAK,+BAA+B;WAEnE,OAAO;AAEZ,WAAQ,MAAM,2BAA2B,QAAQ,KAAK,IAAI,MAAM;;GAEtE;AAEF,OAAM,QAAQ,WAAW,SAAS"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as react_router1 from "react-router";
|
|
2
|
+
import { RouterContextProvider } from "react-router";
|
|
3
|
+
|
|
4
|
+
//#region src/data-store/middleware/gcp-preferences.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* OOTB Google Cloud Platform preferences sourced from the MRT data store.
|
|
8
|
+
*
|
|
9
|
+
* Additional fields (e.g. `projectId`, `region`) may be added here as the
|
|
10
|
+
* ECOM MRT sync job expands the `gcp` entry. Consumers should read the
|
|
11
|
+
* object as a whole via `getGcpPreferences`, or use a specific convenience
|
|
12
|
+
* getter like `getGcpApiKey` for a single field.
|
|
13
|
+
*/
|
|
14
|
+
type GcpPreferences = {
|
|
15
|
+
apiKey: string;
|
|
16
|
+
};
|
|
17
|
+
declare const DEFAULT_GCP_PREFERENCES_KEY = "gcp";
|
|
18
|
+
declare const gcpPreferencesContext: react_router1.RouterContext<GcpPreferences | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Read the GCP (Google Cloud Platform) preferences object from router context.
|
|
21
|
+
*
|
|
22
|
+
* The preferences are sourced from the MRT data store entry `gcp`, which is
|
|
23
|
+
* populated only for storefronts connecting to production ECOM instances.
|
|
24
|
+
* In non-production environments, or when the entry is missing, returns an
|
|
25
|
+
* object whose fields are all empty/default.
|
|
26
|
+
*
|
|
27
|
+
* @param context - Router context provider
|
|
28
|
+
* @returns GCP preferences object; fields are empty/default when the entry is unavailable
|
|
29
|
+
*/
|
|
30
|
+
declare function getGcpPreferences(context: Readonly<RouterContextProvider>): GcpPreferences;
|
|
31
|
+
/**
|
|
32
|
+
* Convenience getter for the Google Cloud API key alone.
|
|
33
|
+
*
|
|
34
|
+
* Equivalent to `getGcpPreferences(context).apiKey`.
|
|
35
|
+
*
|
|
36
|
+
* @param context - Router context provider
|
|
37
|
+
* @returns The GCP API key, or an empty string when unavailable
|
|
38
|
+
*/
|
|
39
|
+
declare function getGcpApiKey(context: Readonly<RouterContextProvider>): string;
|
|
40
|
+
/**
|
|
41
|
+
* Middleware that reads the OOTB GCP preferences from the MRT data store and
|
|
42
|
+
* stores them in the router context. The entry shape is `{ "api-key": string, ... }`
|
|
43
|
+
* under data store key `gcp`. Missing/invalid fields coerce to empty/default values.
|
|
44
|
+
*
|
|
45
|
+
* Only available for storefronts connecting to production ECOM instances.
|
|
46
|
+
* Must run before any loader/middleware that reads `getGcpPreferences(context)`
|
|
47
|
+
* or `getGcpApiKey(context)`.
|
|
48
|
+
*/
|
|
49
|
+
declare const gcpPreferencesMiddleware: react_router1.MiddlewareFunction<Response>;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { getGcpApiKey as a, gcpPreferencesMiddleware as i, GcpPreferences as n, getGcpPreferences as o, gcpPreferencesContext as r, DEFAULT_GCP_PREFERENCES_KEY as t };
|
|
52
|
+
//# sourceMappingURL=gcp-preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-preferences.d.ts","names":[],"sources":["../src/data-store/middleware/gcp-preferences.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;KA2BY,cAAA;;;cAIC,2BAAA;cAQA,uBAAqB,aAAA,CAAA,cAAA;;;;;;;;;;;;iBAalB,iBAAA,UAA2B,SAAS,yBAAyB;;;;;;;;;iBAoB7D,YAAA,UAAsB,SAAS;;;;;;;;;;cAalC,0BAAwB,aAAA,CAAA,mBAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { n as createDataStoreMiddleware, t as createDataStoreContext } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/data-store/middleware/gcp-preferences.ts
|
|
4
|
+
const DEFAULT_GCP_PREFERENCES_KEY = "gcp";
|
|
5
|
+
/**
|
|
6
|
+
* Map keys inside the `gcp` data store entry. The ECOM MRT sync job writes
|
|
7
|
+
* to these exact keys; keep in sync with the sync job contract.
|
|
8
|
+
*/
|
|
9
|
+
const API_KEY_MAP_KEY = "api-key";
|
|
10
|
+
const gcpPreferencesContext = createDataStoreContext();
|
|
11
|
+
/**
|
|
12
|
+
* Read the GCP (Google Cloud Platform) preferences object from router context.
|
|
13
|
+
*
|
|
14
|
+
* The preferences are sourced from the MRT data store entry `gcp`, which is
|
|
15
|
+
* populated only for storefronts connecting to production ECOM instances.
|
|
16
|
+
* In non-production environments, or when the entry is missing, returns an
|
|
17
|
+
* object whose fields are all empty/default.
|
|
18
|
+
*
|
|
19
|
+
* @param context - Router context provider
|
|
20
|
+
* @returns GCP preferences object; fields are empty/default when the entry is unavailable
|
|
21
|
+
*/
|
|
22
|
+
function getGcpPreferences(context) {
|
|
23
|
+
const data = context.get(gcpPreferencesContext);
|
|
24
|
+
if (data === null) {
|
|
25
|
+
console.warn("GCP preferences context not found. Ensure gcpPreferencesMiddleware runs before loaders, or expect empty values in environments without the MRT data store entry.");
|
|
26
|
+
return { apiKey: "" };
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Convenience getter for the Google Cloud API key alone.
|
|
32
|
+
*
|
|
33
|
+
* Equivalent to `getGcpPreferences(context).apiKey`.
|
|
34
|
+
*
|
|
35
|
+
* @param context - Router context provider
|
|
36
|
+
* @returns The GCP API key, or an empty string when unavailable
|
|
37
|
+
*/
|
|
38
|
+
function getGcpApiKey(context) {
|
|
39
|
+
return getGcpPreferences(context).apiKey;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Middleware that reads the OOTB GCP preferences from the MRT data store and
|
|
43
|
+
* stores them in the router context. The entry shape is `{ "api-key": string, ... }`
|
|
44
|
+
* under data store key `gcp`. Missing/invalid fields coerce to empty/default values.
|
|
45
|
+
*
|
|
46
|
+
* Only available for storefronts connecting to production ECOM instances.
|
|
47
|
+
* Must run before any loader/middleware that reads `getGcpPreferences(context)`
|
|
48
|
+
* or `getGcpApiKey(context)`.
|
|
49
|
+
*/
|
|
50
|
+
const gcpPreferencesMiddleware = createDataStoreMiddleware({
|
|
51
|
+
entryKey: DEFAULT_GCP_PREFERENCES_KEY,
|
|
52
|
+
context: gcpPreferencesContext,
|
|
53
|
+
transform: (value) => {
|
|
54
|
+
const rawKey = value[API_KEY_MAP_KEY];
|
|
55
|
+
return { apiKey: typeof rawKey === "string" ? rawKey : "" };
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { getGcpPreferences as a, getGcpApiKey as i, gcpPreferencesContext as n, gcpPreferencesMiddleware as r, DEFAULT_GCP_PREFERENCES_KEY as t };
|
|
61
|
+
//# sourceMappingURL=gcp-preferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-preferences.js","names":[],"sources":["../src/data-store/middleware/gcp-preferences.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { RouterContextProvider } from 'react-router';\nimport { createDataStoreContext, createDataStoreMiddleware } from '../utils';\n\n/**\n * OOTB Google Cloud Platform preferences sourced from the MRT data store.\n *\n * Additional fields (e.g. `projectId`, `region`) may be added here as the\n * ECOM MRT sync job expands the `gcp` entry. Consumers should read the\n * object as a whole via `getGcpPreferences`, or use a specific convenience\n * getter like `getGcpApiKey` for a single field.\n */\nexport type GcpPreferences = {\n apiKey: string;\n};\n\nexport const DEFAULT_GCP_PREFERENCES_KEY = 'gcp';\n\n/**\n * Map keys inside the `gcp` data store entry. The ECOM MRT sync job writes\n * to these exact keys; keep in sync with the sync job contract.\n */\nconst API_KEY_MAP_KEY = 'api-key';\n\nexport const gcpPreferencesContext = createDataStoreContext<GcpPreferences>();\n\n/**\n * Read the GCP (Google Cloud Platform) preferences object from router context.\n *\n * The preferences are sourced from the MRT data store entry `gcp`, which is\n * populated only for storefronts connecting to production ECOM instances.\n * In non-production environments, or when the entry is missing, returns an\n * object whose fields are all empty/default.\n *\n * @param context - Router context provider\n * @returns GCP preferences object; fields are empty/default when the entry is unavailable\n */\nexport function getGcpPreferences(context: Readonly<RouterContextProvider>): GcpPreferences {\n const data = context.get(gcpPreferencesContext);\n if (data === null) {\n // eslint-disable-next-line no-console\n console.warn(\n 'GCP preferences context not found. Ensure gcpPreferencesMiddleware runs before loaders, or expect empty values in environments without the MRT data store entry.'\n );\n return { apiKey: '' };\n }\n return data;\n}\n\n/**\n * Convenience getter for the Google Cloud API key alone.\n *\n * Equivalent to `getGcpPreferences(context).apiKey`.\n *\n * @param context - Router context provider\n * @returns The GCP API key, or an empty string when unavailable\n */\nexport function getGcpApiKey(context: Readonly<RouterContextProvider>): string {\n return getGcpPreferences(context).apiKey;\n}\n\n/**\n * Middleware that reads the OOTB GCP preferences from the MRT data store and\n * stores them in the router context. The entry shape is `{ \"api-key\": string, ... }`\n * under data store key `gcp`. Missing/invalid fields coerce to empty/default values.\n *\n * Only available for storefronts connecting to production ECOM instances.\n * Must run before any loader/middleware that reads `getGcpPreferences(context)`\n * or `getGcpApiKey(context)`.\n */\nexport const gcpPreferencesMiddleware = createDataStoreMiddleware<GcpPreferences>({\n entryKey: DEFAULT_GCP_PREFERENCES_KEY,\n context: gcpPreferencesContext,\n transform: (value) => {\n const rawKey = value[API_KEY_MAP_KEY];\n return { apiKey: typeof rawKey === 'string' ? rawKey : '' };\n },\n});\n"],"mappings":";;;AA+BA,MAAa,8BAA8B;;;;;AAM3C,MAAM,kBAAkB;AAExB,MAAa,wBAAwB,wBAAwC;;;;;;;;;;;;AAa7E,SAAgB,kBAAkB,SAA0D;CACxF,MAAM,OAAO,QAAQ,IAAI,sBAAsB;AAC/C,KAAI,SAAS,MAAM;AAEf,UAAQ,KACJ,mKACH;AACD,SAAO,EAAE,QAAQ,IAAI;;AAEzB,QAAO;;;;;;;;;;AAWX,SAAgB,aAAa,SAAkD;AAC3E,QAAO,kBAAkB,QAAQ,CAAC;;;;;;;;;;;AAYtC,MAAa,2BAA2B,0BAA0C;CAC9E,UAAU;CACV,SAAS;CACT,YAAY,UAAU;EAClB,MAAM,SAAS,MAAM;AACrB,SAAO,EAAE,QAAQ,OAAO,WAAW,WAAW,SAAS,IAAI;;CAElE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ResourceLanguage, i18n } from "i18next";
|
|
2
|
+
|
|
3
|
+
//#region src/i18n/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Callback that dynamically imports all translations for a given language.
|
|
7
|
+
* Must be defined in template code so Vite can resolve the `import()` path at build time
|
|
8
|
+
* and split translations into per-language chunks.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const loadLocale: LocaleLoader = (language) => import(`@/locales/${language}/index.ts`);
|
|
12
|
+
*/
|
|
13
|
+
type LocaleLoader = (language: string) => Promise<{
|
|
14
|
+
default: ResourceLanguage;
|
|
15
|
+
}>;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/i18n/client.d.ts
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initialize i18next on the client side.
|
|
21
|
+
* Pass a `loadLocale` callback containing the dynamic import so Vite can resolve it
|
|
22
|
+
* at build time relative to the template's source tree.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // In root.tsx — Vite resolves the import() relative to this file
|
|
26
|
+
* initI18next({
|
|
27
|
+
* language: document.documentElement.lang || undefined,
|
|
28
|
+
* loadLocale: (language) => import(`@/locales/${language}/index.ts`),
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
declare function initI18next(options?: {
|
|
32
|
+
language?: string;
|
|
33
|
+
instance?: i18n;
|
|
34
|
+
loadLocale?: LocaleLoader;
|
|
35
|
+
}): i18n;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { initI18next };
|
|
38
|
+
//# sourceMappingURL=i18n-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-client.d.ts","names":[],"sources":["../src/i18n/types.ts","../src/i18n/client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;KAoCY,YAAA,yBAAqC;WAAmB;;;;;;;;;;;;;;;;;iBCwBpD,WAAA;;aAAsD;eAAmB;IAAiB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import i18next from "i18next";
|
|
2
|
+
import { initReactI18next } from "react-i18next";
|
|
3
|
+
import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
|
|
4
|
+
|
|
5
|
+
//#region src/i18n/defaults.ts
|
|
6
|
+
/** Shared i18next interpolation config. Disables HTML escaping (React handles that) and adds `{{ value, number }}` formatting via `toLocaleString`. */
|
|
7
|
+
const defaultInterpolation = {
|
|
8
|
+
escapeValue: false,
|
|
9
|
+
format: (value, format) => {
|
|
10
|
+
if (format === "number" && typeof value === "number") return value.toLocaleString();
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/i18n/client.ts
|
|
17
|
+
/**
|
|
18
|
+
* Custom i18next backend that calls the provided `loadLocale` callback to dynamically
|
|
19
|
+
* import translations. Keeping the import() call in the template lets Vite resolve the
|
|
20
|
+
* dynamic path at build time and split translations into per-language chunks.
|
|
21
|
+
*/
|
|
22
|
+
function createDynamicImportBackend(instance, loadLocale) {
|
|
23
|
+
return {
|
|
24
|
+
type: "backend",
|
|
25
|
+
init() {},
|
|
26
|
+
read(language, namespace, callback) {
|
|
27
|
+
loadLocale(language).then((module) => {
|
|
28
|
+
const translations = module.default;
|
|
29
|
+
Object.entries(translations).forEach(([ns, nsTranslations]) => {
|
|
30
|
+
instance.addResourceBundle(language, ns, nsTranslations, true, true);
|
|
31
|
+
});
|
|
32
|
+
callback(null, translations[namespace] ?? {});
|
|
33
|
+
}).catch((error) => {
|
|
34
|
+
callback(error, false);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialize i18next on the client side.
|
|
41
|
+
* Pass a `loadLocale` callback containing the dynamic import so Vite can resolve it
|
|
42
|
+
* at build time relative to the template's source tree.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // In root.tsx — Vite resolves the import() relative to this file
|
|
46
|
+
* initI18next({
|
|
47
|
+
* language: document.documentElement.lang || undefined,
|
|
48
|
+
* loadLocale: (language) => import(`@/locales/${language}/index.ts`),
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
function initI18next(options) {
|
|
52
|
+
const language = options?.language;
|
|
53
|
+
const instance = options?.instance ?? i18next;
|
|
54
|
+
const loadLocale = options?.loadLocale;
|
|
55
|
+
if (language) instance.language = language;
|
|
56
|
+
const i18nextInstance = instance.use(initReactI18next);
|
|
57
|
+
if (loadLocale) i18nextInstance.use(createDynamicImportBackend(instance, loadLocale));
|
|
58
|
+
if (!language) i18nextInstance.use(I18nextBrowserLanguageDetector);
|
|
59
|
+
i18nextInstance.init({
|
|
60
|
+
ns: [],
|
|
61
|
+
...language ? { lng: language } : { detection: {
|
|
62
|
+
order: ["htmlTag"],
|
|
63
|
+
caches: []
|
|
64
|
+
} },
|
|
65
|
+
interpolation: defaultInterpolation
|
|
66
|
+
});
|
|
67
|
+
return instance;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { initI18next };
|
|
72
|
+
//# sourceMappingURL=i18n-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-client.js","names":["defaultInterpolation: InterpolationOptions"],"sources":["../src/i18n/defaults.ts","../src/i18n/client.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { InterpolationOptions } from 'i18next';\n\n/** Shared i18next interpolation config. Disables HTML escaping (React handles that) and adds `{{ value, number }}` formatting via `toLocaleString`. */\nexport const defaultInterpolation: InterpolationOptions = {\n escapeValue: false,\n format: (value, format) => {\n if (format === 'number' && typeof value === 'number') {\n return value.toLocaleString();\n }\n return value;\n },\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport i18next, { type i18n, type BackendModule, type ReadCallback } from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector';\nimport { defaultInterpolation } from './defaults.js';\nimport type { LocaleLoader } from './types.js';\n\n/**\n * Custom i18next backend that calls the provided `loadLocale` callback to dynamically\n * import translations. Keeping the import() call in the template lets Vite resolve the\n * dynamic path at build time and split translations into per-language chunks.\n */\nfunction createDynamicImportBackend(instance: i18n, loadLocale: LocaleLoader): BackendModule {\n return {\n type: 'backend',\n init() {\n // No initialization needed\n },\n read(language: string, namespace: string, callback: ReadCallback) {\n loadLocale(language)\n .then((module) => {\n const translations = module.default;\n Object.entries(translations).forEach(([ns, nsTranslations]) => {\n instance.addResourceBundle(language, ns, nsTranslations, true, true);\n });\n callback(null, translations[namespace] ?? {});\n })\n .catch((error: Error) => {\n callback(error, false);\n });\n },\n };\n}\n\n/**\n * Initialize i18next on the client side.\n * Pass a `loadLocale` callback containing the dynamic import so Vite can resolve it\n * at build time relative to the template's source tree.\n *\n * @example\n * // In root.tsx — Vite resolves the import() relative to this file\n * initI18next({\n * language: document.documentElement.lang || undefined,\n * loadLocale: (language) => import(`@/locales/${language}/index.ts`),\n * });\n */\nexport function initI18next(options?: { language?: string; instance?: i18n; loadLocale?: LocaleLoader }): i18n {\n // NOTE: For any changes to this function, verify that Vite HMR still works with translations\n\n const language = options?.language;\n const instance = options?.instance ?? i18next;\n const loadLocale = options?.loadLocale;\n\n if (language) {\n instance.language = language;\n }\n\n const i18nextInstance = instance.use(initReactI18next);\n\n if (loadLocale) {\n i18nextInstance.use(createDynamicImportBackend(instance, loadLocale));\n }\n\n if (!language) {\n i18nextInstance.use(I18nextBrowserLanguageDetector);\n }\n\n void i18nextInstance.init({\n ns: [],\n ...(language\n ? { lng: language }\n : {\n detection: { order: ['htmlTag'], caches: [] },\n }),\n interpolation: defaultInterpolation,\n });\n\n return instance;\n}\n"],"mappings":";;;;;;AAkBA,MAAaA,uBAA6C;CACtD,aAAa;CACb,SAAS,OAAO,WAAW;AACvB,MAAI,WAAW,YAAY,OAAO,UAAU,SACxC,QAAO,MAAM,gBAAgB;AAEjC,SAAO;;CAEd;;;;;;;;;ACAD,SAAS,2BAA2B,UAAgB,YAAyC;AACzF,QAAO;EACH,MAAM;EACN,OAAO;EAGP,KAAK,UAAkB,WAAmB,UAAwB;AAC9D,cAAW,SAAS,CACf,MAAM,WAAW;IACd,MAAM,eAAe,OAAO;AAC5B,WAAO,QAAQ,aAAa,CAAC,SAAS,CAAC,IAAI,oBAAoB;AAC3D,cAAS,kBAAkB,UAAU,IAAI,gBAAgB,MAAM,KAAK;MACtE;AACF,aAAS,MAAM,aAAa,cAAc,EAAE,CAAC;KAC/C,CACD,OAAO,UAAiB;AACrB,aAAS,OAAO,MAAM;KACxB;;EAEb;;;;;;;;;;;;;;AAeL,SAAgB,YAAY,SAAmF;CAG3G,MAAM,WAAW,SAAS;CAC1B,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,aAAa,SAAS;AAE5B,KAAI,SACA,UAAS,WAAW;CAGxB,MAAM,kBAAkB,SAAS,IAAI,iBAAiB;AAEtD,KAAI,WACA,iBAAgB,IAAI,2BAA2B,UAAU,WAAW,CAAC;AAGzE,KAAI,CAAC,SACD,iBAAgB,IAAI,+BAA+B;AAGvD,CAAK,gBAAgB,KAAK;EACtB,IAAI,EAAE;EACN,GAAI,WACE,EAAE,KAAK,UAAU,GACjB,EACI,WAAW;GAAE,OAAO,CAAC,UAAU;GAAE,QAAQ,EAAE;GAAE,EAChD;EACP,eAAe;EAClB,CAAC;AAEF,QAAO"}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { MiddlewareFunction, RouterContextProvider } from "react-router";
|
|
2
|
+
import * as i18next0 from "i18next";
|
|
3
|
+
import { InterpolationOptions, Resource, ResourceLanguage, ThirdPartyModule, i18n } from "i18next";
|
|
4
|
+
|
|
5
|
+
//#region src/i18n/context.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gets the i18next instance and translation function for non-component code.
|
|
9
|
+
* Use `useTranslation` hook for React components. Mirrors the `getConfig`/`useConfig` pattern.
|
|
10
|
+
*/
|
|
11
|
+
declare function getTranslation(context?: Readonly<RouterContextProvider>): {
|
|
12
|
+
i18next: i18n;
|
|
13
|
+
t: i18next0.TFunction<["translation", ...string[]], undefined>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Gets the active locale string from server context.
|
|
17
|
+
* Returns undefined on the client (locale is on the document element or URL).
|
|
18
|
+
*/
|
|
19
|
+
declare function getLocale(context: Readonly<RouterContextProvider>): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Sets up a mock i18n context on a RouterContextProvider for use in tests.
|
|
22
|
+
* Replaces the need to import the internal i18nextContext key directly.
|
|
23
|
+
*/
|
|
24
|
+
declare function mockI18nContext(contextProvider: RouterContextProvider, options?: {
|
|
25
|
+
locale?: string;
|
|
26
|
+
instance?: i18n;
|
|
27
|
+
}): void;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/i18n/types.d.ts
|
|
30
|
+
|
|
31
|
+
/** Config passed to `createI18nMiddleware`. All values come from the template — the SDK never reads config values directly. */
|
|
32
|
+
interface I18nMiddlewareConfig {
|
|
33
|
+
resources: Resource;
|
|
34
|
+
supportedLanguages: string[];
|
|
35
|
+
fallbackLanguage: string;
|
|
36
|
+
interpolation?: InterpolationOptions;
|
|
37
|
+
plugins?: ThirdPartyModule[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Callback that dynamically imports all translations for a given language.
|
|
41
|
+
* Must be defined in template code so Vite can resolve the `import()` path at build time
|
|
42
|
+
* and split translations into per-language chunks.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const loadLocale: LocaleLoader = (language) => import(`@/locales/${language}/index.ts`);
|
|
46
|
+
*/
|
|
47
|
+
type LocaleLoader = (language: string) => Promise<{
|
|
48
|
+
default: ResourceLanguage;
|
|
49
|
+
}>;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/i18n/middleware.d.ts
|
|
52
|
+
/**
|
|
53
|
+
* Creates a server-side i18next middleware from the provided config.
|
|
54
|
+
* Lazy-initializes on first request so supported languages can come from runtime config.
|
|
55
|
+
*/
|
|
56
|
+
declare function createI18nMiddleware(config: I18nMiddlewareConfig): MiddlewareFunction<Response>;
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/i18n/defaults.d.ts
|
|
59
|
+
/** Shared i18next interpolation config. Disables HTML escaping (React handles that) and adds `{{ value, number }}` formatting via `toLocaleString`. */
|
|
60
|
+
declare const defaultInterpolation: InterpolationOptions;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { type I18nMiddlewareConfig, type LocaleLoader, type Resource, type ResourceLanguage, createI18nMiddleware, defaultInterpolation, getLocale, getTranslation, mockI18nContext };
|
|
63
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","names":[],"sources":["../src/i18n/context.ts","../src/i18n/types.ts","../src/i18n/middleware.ts","../src/i18n/defaults.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AE2BA;AAA6C,iBFI7B,cAAA,CEJ6B,OAAA,CAAA,EFIJ,QEJI,CFIK,qBEJL,CAAA,CAAA,EAAA;EAA0C,OAAA,MAAA;EAAnB,CAAA,oBAAA,CAAA,CAAA,aAAA,EAAA,GAAA,MAAA,EAAA,CAAA,EAAA,SAAA,CAAA;CAAkB;;;;ACTtF;iBHqCgB,SAAA,UAAmB,SAAS;;;;;iBAQ5B,eAAA,kBACK;;aACsB;;;;;;ACzCvB,UAJH,oBAAA,CAIG;EACN,SAAA,EAJC,QAID;EAAgB,kBAAA,EAAA,MAAA,EAAA;EAWlB,gBAAY,EAAA,MAAA;kBAZJ;YACN;;ACEd;;;;;;;;ACTa,KFkBD,YAAA,GEVX,CAAA,QAAA,EAAA,MARkC,EAAA,GFkBc,OElBd,CAAA;WFkBiC;;;;;;;ADLpE;AAAkD,iBEJlC,oBAAA,CFIkC,MAAA,EEJL,oBFIK,CAAA,EEJkB,kBFIlB,CEJqC,QFIrC,CAAA;;;ACXlD;AACe,cEHF,oBFGE,EEHoB,oBFGpB"}
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { a as requestToLocaleMap } from "./site-context2.js";
|
|
2
|
+
import "./apply-url-config.js";
|
|
3
|
+
import { createContext } from "react-router";
|
|
4
|
+
import i18next from "i18next";
|
|
5
|
+
import { initReactI18next } from "react-i18next";
|
|
6
|
+
import { createI18nextMiddleware } from "remix-i18next/middleware";
|
|
7
|
+
|
|
8
|
+
//#region src/i18n/context.ts
|
|
9
|
+
const i18nextContext = createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* Gets the i18next instance and translation function for non-component code.
|
|
12
|
+
* Use `useTranslation` hook for React components. Mirrors the `getConfig`/`useConfig` pattern.
|
|
13
|
+
*/
|
|
14
|
+
function getTranslation(context) {
|
|
15
|
+
if (context && typeof window === "undefined") {
|
|
16
|
+
const i18nextData = context.get(i18nextContext);
|
|
17
|
+
if (!i18nextData) throw new Error("i18next data not found in context. Ensure i18next middleware runs before loaders.");
|
|
18
|
+
const i18nextInstance = i18nextData.getI18nextInstance();
|
|
19
|
+
return {
|
|
20
|
+
i18next: i18nextInstance,
|
|
21
|
+
t: i18nextInstance.t
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
i18next,
|
|
26
|
+
t: i18next.t
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Gets the active locale string from server context.
|
|
31
|
+
* Returns undefined on the client (locale is on the document element or URL).
|
|
32
|
+
*/
|
|
33
|
+
function getLocale(context) {
|
|
34
|
+
return context.get(i18nextContext)?.getLocale();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Sets up a mock i18n context on a RouterContextProvider for use in tests.
|
|
38
|
+
* Replaces the need to import the internal i18nextContext key directly.
|
|
39
|
+
*/
|
|
40
|
+
function mockI18nContext(contextProvider, options = {}) {
|
|
41
|
+
const { locale = "en-GB", instance = i18next } = options;
|
|
42
|
+
contextProvider.set(i18nextContext, {
|
|
43
|
+
getLocale: () => locale,
|
|
44
|
+
getI18nextInstance: () => instance
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/i18n/defaults.ts
|
|
50
|
+
/** Shared i18next interpolation config. Disables HTML escaping (React handles that) and adds `{{ value, number }}` formatting via `toLocaleString`. */
|
|
51
|
+
const defaultInterpolation = {
|
|
52
|
+
escapeValue: false,
|
|
53
|
+
format: (value, format) => {
|
|
54
|
+
if (format === "number" && typeof value === "number") return value.toLocaleString();
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/i18n/middleware.ts
|
|
61
|
+
/**
|
|
62
|
+
* Creates a server-side i18next middleware from the provided config.
|
|
63
|
+
* Lazy-initializes on first request so supported languages can come from runtime config.
|
|
64
|
+
*/
|
|
65
|
+
function createI18nMiddleware(config) {
|
|
66
|
+
const { resources, supportedLanguages, fallbackLanguage, interpolation, plugins = [] } = config;
|
|
67
|
+
let cached = null;
|
|
68
|
+
return async (args, next) => {
|
|
69
|
+
if (!cached) cached = createI18nextMiddleware({
|
|
70
|
+
detection: {
|
|
71
|
+
order: ["custom"],
|
|
72
|
+
findLocale: async (request) => {
|
|
73
|
+
return requestToLocaleMap.get(request) ?? null;
|
|
74
|
+
},
|
|
75
|
+
fallbackLanguage,
|
|
76
|
+
supportedLanguages
|
|
77
|
+
},
|
|
78
|
+
i18next: {
|
|
79
|
+
resources,
|
|
80
|
+
interpolation: {
|
|
81
|
+
...defaultInterpolation,
|
|
82
|
+
...interpolation
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
plugins: [initReactI18next, ...plugins]
|
|
86
|
+
});
|
|
87
|
+
const [originalMiddleware, getLocale$1, getInstance] = cached;
|
|
88
|
+
args.context.set(i18nextContext, {
|
|
89
|
+
getLocale: () => getLocale$1(args.context),
|
|
90
|
+
getI18nextInstance: () => getInstance(args.context)
|
|
91
|
+
});
|
|
92
|
+
return originalMiddleware(args, next);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { createI18nMiddleware, defaultInterpolation, getLocale, getTranslation, mockI18nContext };
|
|
98
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","names":["defaultInterpolation: InterpolationOptions","cached: ReturnType<typeof createI18nextMiddleware> | null","getLocale"],"sources":["../src/i18n/context.ts","../src/i18n/defaults.ts","../src/i18n/middleware.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport i18next, { type i18n } from 'i18next';\nimport { createContext, type RouterContextProvider } from 'react-router';\n\ntype I18nContextValue = {\n getLocale: () => string;\n getI18nextInstance: () => i18n;\n};\n\n// Internal context key — not exported. Use getTranslation() / getLocale() to read,\n// and mockI18nContext() in tests to write.\nexport const i18nextContext = createContext<I18nContextValue | null>(null);\n\n/**\n * Gets the i18next instance and translation function for non-component code.\n * Use `useTranslation` hook for React components. Mirrors the `getConfig`/`useConfig` pattern.\n */\nexport function getTranslation(context?: Readonly<RouterContextProvider>) {\n if (context && typeof window === 'undefined') {\n const i18nextData = context.get(i18nextContext);\n if (!i18nextData) {\n throw new Error('i18next data not found in context. Ensure i18next middleware runs before loaders.');\n }\n\n const i18nextInstance = i18nextData.getI18nextInstance();\n return {\n i18next: i18nextInstance,\n t: i18nextInstance.t,\n };\n }\n\n return {\n i18next,\n t: i18next.t,\n };\n}\n\n/**\n * Gets the active locale string from server context.\n * Returns undefined on the client (locale is on the document element or URL).\n */\nexport function getLocale(context: Readonly<RouterContextProvider>): string | undefined {\n return context.get(i18nextContext)?.getLocale();\n}\n\n/**\n * Sets up a mock i18n context on a RouterContextProvider for use in tests.\n * Replaces the need to import the internal i18nextContext key directly.\n */\nexport function mockI18nContext(\n contextProvider: RouterContextProvider,\n options: { locale?: string; instance?: i18n } = {}\n): void {\n const { locale = 'en-GB', instance = i18next } = options;\n contextProvider.set(i18nextContext, {\n getLocale: () => locale,\n getI18nextInstance: () => instance,\n });\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { InterpolationOptions } from 'i18next';\n\n/** Shared i18next interpolation config. Disables HTML escaping (React handles that) and adds `{{ value, number }}` formatting via `toLocaleString`. */\nexport const defaultInterpolation: InterpolationOptions = {\n escapeValue: false,\n format: (value, format) => {\n if (format === 'number' && typeof value === 'number') {\n return value.toLocaleString();\n }\n return value;\n },\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { initReactI18next } from 'react-i18next';\nimport { createI18nextMiddleware } from 'remix-i18next/middleware';\nimport { type MiddlewareFunction } from 'react-router';\nimport { requestToLocaleMap } from '../site-context/index.js';\nimport { defaultInterpolation } from './defaults.js';\nimport { i18nextContext } from './context.js';\nimport type { I18nMiddlewareConfig } from './types.js';\n\n/**\n * Creates a server-side i18next middleware from the provided config.\n * Lazy-initializes on first request so supported languages can come from runtime config.\n */\nexport function createI18nMiddleware(config: I18nMiddlewareConfig): MiddlewareFunction<Response> {\n const { resources, supportedLanguages, fallbackLanguage, interpolation, plugins = [] } = config;\n\n let cached: ReturnType<typeof createI18nextMiddleware> | null = null;\n\n return async (args, next) => {\n if (!cached) {\n cached = createI18nextMiddleware({\n detection: {\n order: ['custom'],\n // eslint-disable-next-line @typescript-eslint/require-await\n findLocale: async (request: Request) => {\n const localeId = requestToLocaleMap.get(request);\n return localeId ?? null;\n },\n fallbackLanguage,\n supportedLanguages,\n },\n i18next: {\n resources,\n interpolation: { ...defaultInterpolation, ...interpolation },\n },\n plugins: [initReactI18next, ...plugins],\n });\n }\n\n const [originalMiddleware, getLocale, getInstance] = cached;\n\n args.context.set(i18nextContext, {\n getLocale: () => getLocale(args.context),\n getI18nextInstance: () => getInstance(args.context),\n });\n\n return originalMiddleware(args, next);\n };\n}\n"],"mappings":";;;;;;;;AAyBA,MAAa,iBAAiB,cAAuC,KAAK;;;;;AAM1E,SAAgB,eAAe,SAA2C;AACtE,KAAI,WAAW,OAAO,WAAW,aAAa;EAC1C,MAAM,cAAc,QAAQ,IAAI,eAAe;AAC/C,MAAI,CAAC,YACD,OAAM,IAAI,MAAM,oFAAoF;EAGxG,MAAM,kBAAkB,YAAY,oBAAoB;AACxD,SAAO;GACH,SAAS;GACT,GAAG,gBAAgB;GACtB;;AAGL,QAAO;EACH;EACA,GAAG,QAAQ;EACd;;;;;;AAOL,SAAgB,UAAU,SAA8D;AACpF,QAAO,QAAQ,IAAI,eAAe,EAAE,WAAW;;;;;;AAOnD,SAAgB,gBACZ,iBACA,UAAgD,EAAE,EAC9C;CACJ,MAAM,EAAE,SAAS,SAAS,WAAW,YAAY;AACjD,iBAAgB,IAAI,gBAAgB;EAChC,iBAAiB;EACjB,0BAA0B;EAC7B,CAAC;;;;;;ACrDN,MAAaA,uBAA6C;CACtD,aAAa;CACb,SAAS,OAAO,WAAW;AACvB,MAAI,WAAW,YAAY,OAAO,UAAU,SACxC,QAAO,MAAM,gBAAgB;AAEjC,SAAO;;CAEd;;;;;;;;ACCD,SAAgB,qBAAqB,QAA4D;CAC7F,MAAM,EAAE,WAAW,oBAAoB,kBAAkB,eAAe,UAAU,EAAE,KAAK;CAEzF,IAAIC,SAA4D;AAEhE,QAAO,OAAO,MAAM,SAAS;AACzB,MAAI,CAAC,OACD,UAAS,wBAAwB;GAC7B,WAAW;IACP,OAAO,CAAC,SAAS;IAEjB,YAAY,OAAO,YAAqB;AAEpC,YADiB,mBAAmB,IAAI,QAAQ,IAC7B;;IAEvB;IACA;IACH;GACD,SAAS;IACL;IACA,eAAe;KAAE,GAAG;KAAsB,GAAG;KAAe;IAC/D;GACD,SAAS,CAAC,kBAAkB,GAAG,QAAQ;GAC1C,CAAC;EAGN,MAAM,CAAC,oBAAoBC,aAAW,eAAe;AAErD,OAAK,QAAQ,IAAI,gBAAgB;GAC7B,iBAAiBA,YAAU,KAAK,QAAQ;GACxC,0BAA0B,YAAY,KAAK,QAAQ;GACtD,CAAC;AAEF,SAAO,mBAAmB,MAAM,KAAK"}
|