diff --git a/.changeset/great-spoons-relax.md b/.changeset/great-spoons-relax.md new file mode 100644 index 000000000..d318bb238 --- /dev/null +++ b/.changeset/great-spoons-relax.md @@ -0,0 +1,5 @@ +--- +"vue-demo-store": patch +--- + +Added `sw-language-id` header property in `SwContactForm.vue` and `App.vue` components diff --git a/.changeset/healthy-goats-buy.md b/.changeset/healthy-goats-buy.md new file mode 100644 index 000000000..faa8a6f52 --- /dev/null +++ b/.changeset/healthy-goats-buy.md @@ -0,0 +1,5 @@ +--- +"@shopware/composables": patch +--- + +Added `sw-language-id` header property for API calls in `useCart`, `useCategorySearch`, `useCheckout`, `useCustomerOrders`, `useInternationalization`, and `useLandingSearch` composables. diff --git a/examples/commercial-quick-order/src/App.vue b/examples/commercial-quick-order/src/App.vue index ecf2f82f1..7dea190f0 100644 --- a/examples/commercial-quick-order/src/App.vue +++ b/examples/commercial-quick-order/src/App.vue @@ -10,7 +10,8 @@ import type { Schemas } from "#shopware"; const { apiClient } = useShopwareContext(); // for initialize the session and get the current currency -const { currency, refreshSessionContext } = useSessionContext(); +const { currency, refreshSessionContext, languageIdChain } = + useSessionContext(); // to log in a customer, because the Quick Order feature is enabled for specifically selected users (in admin panel) const { login } = useUser(); @@ -108,6 +109,9 @@ const onAddToCartClick = async () => { body: { items: lineItemsPayload, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); chosenItems.value = new Map(); diff --git a/packages/cms-base-layer/components/SwContactForm.vue b/packages/cms-base-layer/components/SwContactForm.vue index f17ea1b34..76c7ecd79 100644 --- a/packages/cms-base-layer/components/SwContactForm.vue +++ b/packages/cms-base-layer/components/SwContactForm.vue @@ -11,6 +11,7 @@ import { useCmsElementConfig, useNavigationContext, useSalutations, + useSessionContext, useShopwareContext, } from "#imports"; @@ -84,6 +85,7 @@ const { getSalutations } = useSalutations(); const { foreignKey } = useNavigationContext(); const { apiClient } = useShopwareContext(); const { getConfigValue } = useCmsElementConfig(props.content); +const { languageIdChain } = useSessionContext(); const getConfirmationText = computed( () => @@ -148,6 +150,9 @@ const invokeSubmit = async () => { ...state, navigationId: foreignKey.value, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); formSent.value = true; } catch (e) { diff --git a/packages/composables/src/useCart/useCart.test.ts b/packages/composables/src/useCart/useCart.test.ts index 32adac434..4721b725d 100644 --- a/packages/composables/src/useCart/useCart.test.ts +++ b/packages/composables/src/useCart/useCart.test.ts @@ -86,6 +86,11 @@ describe("useCart", () => { await vm.refreshCart(); expect(injections.apiClient.invoke).toHaveBeenCalledWith( expect.stringContaining("readCart"), + expect.objectContaining({ + headers: { + "sw-language-id": "", + }, + }), ); }); diff --git a/packages/composables/src/useCart/useCart.ts b/packages/composables/src/useCart/useCart.ts index 5d988ca6d..72d8c9fed 100644 --- a/packages/composables/src/useCart/useCart.ts +++ b/packages/composables/src/useCart/useCart.ts @@ -1,7 +1,7 @@ import { createSharedComposable } from "@vueuse/core"; import { computed } from "vue"; import type { ComputedRef } from "vue"; -import { useContext, useShopwareContext } from "#imports"; +import { useContext, useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; /** @@ -101,6 +101,7 @@ export type UseCartReturn = { */ export function useCartFunction(): UseCartReturn { const { apiClient } = useShopwareContext(); + const { languageIdChain } = useSessionContext(); const _storeCart = useContext("swCart"); const _storeCartErrors = useContext( @@ -115,7 +116,11 @@ export function useCartFunction(): UseCartReturn { return newCart; } - const { data } = await apiClient.invoke("readCart get /checkout/cart"); + const { data } = await apiClient.invoke("readCart get /checkout/cart", { + headers: { + "sw-language-id": languageIdChain.value, + }, + }); _storeCart.value = data; setCartErrors(data); return data; diff --git a/packages/composables/src/useCategorySearch/useCategorySearch.test.ts b/packages/composables/src/useCategorySearch/useCategorySearch.test.ts index 6030712cf..1a85ada4a 100644 --- a/packages/composables/src/useCategorySearch/useCategorySearch.test.ts +++ b/packages/composables/src/useCategorySearch/useCategorySearch.test.ts @@ -19,6 +19,7 @@ describe("useCategorySearch", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, }), ); @@ -41,6 +42,7 @@ describe("useCategorySearch", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, body: { associations: cmsAssociations, diff --git a/packages/composables/src/useCategorySearch/useCategorySearch.ts b/packages/composables/src/useCategorySearch/useCategorySearch.ts index dc62b6dbe..9c5eab6ee 100644 --- a/packages/composables/src/useCategorySearch/useCategorySearch.ts +++ b/packages/composables/src/useCategorySearch/useCategorySearch.ts @@ -1,4 +1,4 @@ -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; import { cmsAssociations } from "../cms/cmsAssociations"; @@ -31,6 +31,7 @@ export type UseCategorySearchReturn = { */ export function useCategorySearch(): UseCategorySearchReturn { const { apiClient } = useShopwareContext(); + const { languageIdChain } = useSessionContext(); async function search( categoryId: string, @@ -48,6 +49,7 @@ export function useCategorySearch(): UseCategorySearchReturn { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": languageIdChain.value, }, body: { associations, @@ -70,6 +72,9 @@ export function useCategorySearch(): UseCategorySearchReturn { associations, ...options?.query, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); return result.data.elements ?? []; } diff --git a/packages/composables/src/useCheckout/useCheckout.ts b/packages/composables/src/useCheckout/useCheckout.ts index d911f3e3c..32c55ae0e 100644 --- a/packages/composables/src/useCheckout/useCheckout.ts +++ b/packages/composables/src/useCheckout/useCheckout.ts @@ -80,6 +80,7 @@ export function useCheckout(): UseCheckoutReturn { selectedShippingMethod, setShippingMethod, setPaymentMethod, + languageIdChain, } = useSessionContext(); const storeShippingMethods = inject("swShippingMethods", ref()); @@ -109,6 +110,9 @@ export function useCheckout(): UseCheckoutReturn { query: { onlyAvailable: true, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); storeShippingMethods.value = @@ -125,6 +129,9 @@ export function useCheckout(): UseCheckoutReturn { "readPaymentMethod post /payment-method", { body: { onlyAvailable: true }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); storePaymentMethods.value = response.data.elements || []; @@ -136,6 +143,9 @@ export function useCheckout(): UseCheckoutReturn { ) { const order = await apiClient.invoke("createOrder post /checkout/order", { body: params, + headers: { + "sw-language-id": languageIdChain.value, + }, }); return order.data; } diff --git a/packages/composables/src/useCustomerOrders/useCustomerOrders.ts b/packages/composables/src/useCustomerOrders/useCustomerOrders.ts index 13ff25448..c74e9eca7 100644 --- a/packages/composables/src/useCustomerOrders/useCustomerOrders.ts +++ b/packages/composables/src/useCustomerOrders/useCustomerOrders.ts @@ -1,6 +1,6 @@ import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; export type UseCustomerOrdersReturn = { @@ -41,7 +41,7 @@ export type UseCustomerOrdersReturn = { */ export function useCustomerOrders(): UseCustomerOrdersReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const orders: Ref = ref([]); const currentPaginationPage = ref(1); @@ -61,6 +61,9 @@ export function useCustomerOrders(): UseCustomerOrdersReturn { currentParams.value = params; const fetchedOrders = await apiClient.invoke("readOrder post /order", { body: { ...params, "total-count-mode": "exact" }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); orders.value = fetchedOrders.data.orders.elements; totalOrderItemsCount.value = fetchedOrders.data.orders.total ?? 0; diff --git a/packages/composables/src/useInternationalization/useInternationalization.test.ts b/packages/composables/src/useInternationalization/useInternationalization.test.ts index 8240f1d99..a4164cd97 100644 --- a/packages/composables/src/useInternationalization/useInternationalization.test.ts +++ b/packages/composables/src/useInternationalization/useInternationalization.test.ts @@ -29,6 +29,11 @@ describe("useInternationalization", () => { vm.getAvailableLanguages(); expect(injections.apiClient.invoke).toHaveBeenCalledWith( expect.stringContaining("readLanguages"), + expect.objectContaining({ + headers: { + "sw-language-id": "", + }, + }), ); }); @@ -38,7 +43,9 @@ describe("useInternationalization", () => { vm.changeLanguage("test-id"); expect(injections.apiClient.invoke).toHaveBeenCalledWith( expect.stringContaining("updateContext"), - expect.objectContaining({ body: { languageId: "test-id" } }), + expect.objectContaining({ + body: { languageId: "test-id" }, + }), ); }); diff --git a/packages/composables/src/useInternationalization/useInternationalization.ts b/packages/composables/src/useInternationalization/useInternationalization.ts index a9dff92d7..ad68457ad 100644 --- a/packages/composables/src/useInternationalization/useInternationalization.ts +++ b/packages/composables/src/useInternationalization/useInternationalization.ts @@ -1,6 +1,6 @@ import { urlIsAbsolute } from "@shopware/helpers"; import type { Ref } from "vue"; -import { useContext, useShopwareContext } from "#imports"; +import { useContext, useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; export type UseInternationalizationReturn = { @@ -82,7 +82,7 @@ export function useInternationalization( ): UseInternationalizationReturn { const { devStorefrontUrl } = useShopwareContext(); const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const _storeLanguages = useContext("swLanguages"); const _storeCurrentLanguage = useContext( "swLanguagesCurrentLanguage", @@ -94,7 +94,11 @@ export function useInternationalization( } async function getAvailableLanguages() { - const { data } = await apiClient.invoke("readLanguages post /language"); + const { data } = await apiClient.invoke("readLanguages post /language", { + headers: { + "sw-language-id": languageIdChain.value, + }, + }); _storeLanguages.value = data.elements; return data; } diff --git a/packages/composables/src/useLandingSearch/useLandingSearch.ts b/packages/composables/src/useLandingSearch/useLandingSearch.ts index 6f93a9a91..7db78d4c2 100644 --- a/packages/composables/src/useLandingSearch/useLandingSearch.ts +++ b/packages/composables/src/useLandingSearch/useLandingSearch.ts @@ -1,4 +1,4 @@ -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; import { cmsAssociations } from "../cms/cmsAssociations"; @@ -29,7 +29,7 @@ export function useLandingSearch(): { ) => Promise; } { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const search = async ( navigationId: string, options?: { @@ -47,6 +47,9 @@ export function useLandingSearch(): { body: { associations, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); return result.data; diff --git a/packages/composables/src/useListing/useListing.test.ts b/packages/composables/src/useListing/useListing.test.ts index ab8e97838..67506c298 100644 --- a/packages/composables/src/useListing/useListing.test.ts +++ b/packages/composables/src/useListing/useListing.test.ts @@ -21,7 +21,12 @@ describe("useListing", () => { expect(injections.apiClient.invoke).toHaveBeenCalledWith( expect.stringContaining("search"), - expect.objectContaining({}), + expect.objectContaining({ + headers: { + "sw-include-seo-urls": true, + "sw-language-id": "", + }, + }), ); expect(vm.getCurrentPage).toBe(1); @@ -48,6 +53,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, pathParams: { categoryId: "1234", @@ -92,6 +98,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, pathParams: { categoryId: "1234", @@ -131,6 +138,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, pathParams: { categoryId: "1234", @@ -189,6 +197,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, }), ); @@ -211,6 +220,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, }), ); @@ -233,6 +243,7 @@ describe("useListing", () => { }, headers: { "sw-include-seo-urls": true, + "sw-language-id": "", }, }), ); diff --git a/packages/composables/src/useListing/useListing.ts b/packages/composables/src/useListing/useListing.ts index a07281614..01ec6978d 100644 --- a/packages/composables/src/useListing/useListing.ts +++ b/packages/composables/src/useListing/useListing.ts @@ -2,7 +2,7 @@ import { getListingFilters } from "@shopware/helpers"; import { createInjectionState, createSharedComposable } from "@vueuse/core"; import { computed, inject, provide, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useCategory, useShopwareContext } from "#imports"; +import { useCategory, useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; function isObject(item: T): boolean { @@ -186,7 +186,7 @@ export function useListing(params?: { }): UseListingReturn { const listingType = params?.listingType || "categoryListing"; let categoryId = params?.categoryId || null; - + const { languageIdChain } = useSessionContext(); // const { getDefaults } = useDefaults({ defaultsKey: contextName }); const { apiClient } = useShopwareContext(); @@ -205,6 +205,7 @@ export function useListing(params?: { const { data } = await apiClient.invoke("searchPage post /search", { headers: { "sw-include-seo-urls": true, + "sw-language-id": languageIdChain.value, }, body: searchCriteria, }); @@ -224,6 +225,7 @@ export function useListing(params?: { { headers: { "sw-include-seo-urls": true, + "sw-language-id": languageIdChain.value, }, pathParams: { categoryId: categoryId as string, // null exception in useCategory, diff --git a/packages/composables/src/useNavigation/useNavigation.ts b/packages/composables/src/useNavigation/useNavigation.ts index fb4b6bf03..b12a9a33e 100644 --- a/packages/composables/src/useNavigation/useNavigation.ts +++ b/packages/composables/src/useNavigation/useNavigation.ts @@ -1,6 +1,6 @@ import { computed, inject, provide, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; /** @@ -40,6 +40,7 @@ export function useNavigation(params?: { const type = params?.type || "main-navigation"; const { apiClient } = useShopwareContext(); + const { languageIdChain } = useSessionContext(); const sharedElements: Ref = inject( `swNavigation-${type}`, @@ -58,6 +59,7 @@ export function useNavigation(params?: { { headers: { "sw-include-seo-urls": true, + "sw-language-id": languageIdChain.value, }, pathParams: { activeId: type, diff --git a/packages/composables/src/useNavigationSearch/useNavigationSearch.test.ts b/packages/composables/src/useNavigationSearch/useNavigationSearch.test.ts index 639c44bd3..e6afb4879 100644 --- a/packages/composables/src/useNavigationSearch/useNavigationSearch.test.ts +++ b/packages/composables/src/useNavigationSearch/useNavigationSearch.test.ts @@ -8,6 +8,7 @@ const sessionContext = ref(); vi.mocked(useSessionContext).mockReturnValue({ sessionContext, + languageIdChain: ref(), } as unknown as ReturnType); const mockedResponse = { diff --git a/packages/composables/src/useNavigationSearch/useNavigationSearch.ts b/packages/composables/src/useNavigationSearch/useNavigationSearch.ts index 8ee828745..c527e7daa 100644 --- a/packages/composables/src/useNavigationSearch/useNavigationSearch.ts +++ b/packages/composables/src/useNavigationSearch/useNavigationSearch.ts @@ -16,7 +16,7 @@ export type UseNavigationSearchReturn = { */ export function useNavigationSearch(): UseNavigationSearchReturn { const { apiClient } = useShopwareContext(); - const { sessionContext } = useSessionContext(); + const { sessionContext, languageIdChain } = useSessionContext(); async function resolvePath(path: string) { if (path === "/") { @@ -49,6 +49,9 @@ export function useNavigationSearch(): UseNavigationSearchReturn { }, ], }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); return seoResult.data.elements?.[0]; diff --git a/packages/composables/src/useOrderDetails/useOrderDetails.ts b/packages/composables/src/useOrderDetails/useOrderDetails.ts index f5ee5a8d1..669fa5221 100644 --- a/packages/composables/src/useOrderDetails/useOrderDetails.ts +++ b/packages/composables/src/useOrderDetails/useOrderDetails.ts @@ -1,7 +1,11 @@ import { defu } from "defu"; import { computed, inject, provide, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useDefaultOrderAssociations, useShopwareContext } from "#imports"; +import { + useDefaultOrderAssociations, + useSessionContext, + useShopwareContext, +} from "#imports"; import type { Schemas } from "#shopware"; export type UseOrderDetailsReturn = { @@ -129,7 +133,7 @@ export function useOrderDetails( associations?: Schemas["Criteria"]["associations"], ): UseOrderDetailsReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const paymentChangeableList: Ref<{ [key: string]: boolean }> = ref({}); const _sharedOrder = inject>( "swOrderDetails", @@ -201,6 +205,9 @@ export function useOrderDetails( "readOrder post /order", { body: params, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); _sharedOrder.value = @@ -232,6 +239,9 @@ export function useOrderDetails( body: { orderId, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); await loadOrderDetails(); @@ -245,6 +255,9 @@ export function useOrderDetails( orderId: orderId, paymentMethodId: paymentMethodId, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); @@ -261,6 +274,9 @@ export function useOrderDetails( orderId, downloadId, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); @@ -275,6 +291,9 @@ export function useOrderDetails( documentId, deepLinkCode, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); @@ -297,6 +316,9 @@ export function useOrderDetails( "readPaymentMethod post /payment-method", { body: { onlyAvailable: true }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); return response.data.elements || []; diff --git a/packages/composables/src/useOrderPayment/useOrderPayment.ts b/packages/composables/src/useOrderPayment/useOrderPayment.ts index d43ccf778..54397742e 100644 --- a/packages/composables/src/useOrderPayment/useOrderPayment.ts +++ b/packages/composables/src/useOrderPayment/useOrderPayment.ts @@ -1,6 +1,6 @@ import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; export type UseOrderPaymentReturn = { @@ -56,6 +56,7 @@ export function useOrderPayment( order: ComputedRef, ): UseOrderPaymentReturn { const { apiClient } = useShopwareContext(); + const { languageIdChain } = useSessionContext(); const activeTransaction = computed(() => order.value?.transactions?.find((t) => t.paymentMethod?.active === true), ); @@ -102,6 +103,9 @@ export function useOrderPayment( orderId: order.value.id, paymentMethodId, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); return response.data; diff --git a/packages/composables/src/useProductAssociations/useProductAssociations.ts b/packages/composables/src/useProductAssociations/useProductAssociations.ts index dc84dd70c..c60717bb7 100644 --- a/packages/composables/src/useProductAssociations/useProductAssociations.ts +++ b/packages/composables/src/useProductAssociations/useProductAssociations.ts @@ -1,6 +1,6 @@ import { computed, ref } from "vue"; import type { ComputedRef } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; export type UseProductAssociationsReturn = { @@ -38,7 +38,7 @@ export function useProductAssociations( // @ts-ignore: temporary until fixed or removed const association = options.associationContext; - + const { languageIdChain } = useSessionContext(); const { apiClient } = useShopwareContext(); const isLoading = ref(false); const associations = ref([]); @@ -85,6 +85,9 @@ export function useProductAssociations( "readProductCrossSellings post /product/{productId}/cross-selling", { pathParams: { productId: product.value.id }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); diff --git a/packages/composables/src/useProductConfigurator/useProductConfigurator.ts b/packages/composables/src/useProductConfigurator/useProductConfigurator.ts index be6a76678..c7d1a1f3c 100644 --- a/packages/composables/src/useProductConfigurator/useProductConfigurator.ts +++ b/packages/composables/src/useProductConfigurator/useProductConfigurator.ts @@ -1,7 +1,7 @@ import { getTranslatedProperty } from "@shopware/helpers"; import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useProduct, useShopwareContext } from "#imports"; +import { useProduct, useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; export type UseProductConfiguratorReturn = { @@ -41,7 +41,7 @@ export type UseProductConfiguratorReturn = { */ export function useProductConfigurator(): UseProductConfiguratorReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const { configurator, product } = useProduct(); const selected = ref<{ @@ -103,6 +103,9 @@ export function useProductConfigurator(): UseProductConfiguratorReturn { seoUrls: {}, }, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); return response.data.elements?.[0]; // return first matching product } catch (e) { diff --git a/packages/composables/src/useProductReviews/useProductReviews.ts b/packages/composables/src/useProductReviews/useProductReviews.ts index 8fa164011..df76ff135 100644 --- a/packages/composables/src/useProductReviews/useProductReviews.ts +++ b/packages/composables/src/useProductReviews/useProductReviews.ts @@ -1,6 +1,6 @@ import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; export type UseProductReviewsReturn = { @@ -39,7 +39,7 @@ export function useProductReviews( product: Ref, ): UseProductReviewsReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const productReviews: Ref = ref([]); const loadProductReviews = async ( @@ -52,6 +52,9 @@ export function useProductReviews( { pathParams: { productId: product.value.id }, body: parameters, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); productReviews.value = fetchedReviews.data.elements ?? []; diff --git a/packages/composables/src/useProductSearch/useProductSearch.ts b/packages/composables/src/useProductSearch/useProductSearch.ts index 1517d4738..2426fb6de 100644 --- a/packages/composables/src/useProductSearch/useProductSearch.ts +++ b/packages/composables/src/useProductSearch/useProductSearch.ts @@ -1,5 +1,5 @@ import { defu } from "defu"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; import { cmsAssociations } from "../cms/cmsAssociations"; @@ -29,7 +29,7 @@ export type UseProductSearchReturn = { */ export function useProductSearch(): UseProductSearchReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const search = async ( productId: string, options?: UseProductSearchReturnOptions, @@ -44,6 +44,7 @@ export function useProductSearch(): UseProductSearchReturn { { headers: { "sw-include-seo-urls": true, + "sw-language-id": languageIdChain.value, }, pathParams: { productId }, body: associations, diff --git a/packages/composables/src/useSalutations/useSalutations.ts b/packages/composables/src/useSalutations/useSalutations.ts index 4258803a0..9c0cc8965 100644 --- a/packages/composables/src/useSalutations/useSalutations.ts +++ b/packages/composables/src/useSalutations/useSalutations.ts @@ -1,6 +1,6 @@ import { computed, inject, onMounted, provide, ref } from "vue"; import type { ComputedRef } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas, operations } from "#shopware"; export type UseSalutationsReturn = { @@ -23,14 +23,18 @@ export type UseSalutationsReturn = { */ export function useSalutations(): UseSalutationsReturn { const { apiClient } = useShopwareContext(); - + const { languageIdChain } = useSessionContext(); const _salutations = inject("swSalutations", ref()); provide("swSalutations", _salutations); const fetchSalutations = async (): Promise< operations["readSalutation post /salutation"]["response"] > => { - const result = await apiClient.invoke("readSalutation post /salutation"); + const result = await apiClient.invoke("readSalutation post /salutation", { + headers: { + "sw-language-id": languageIdChain.value, + }, + }); _salutations.value = result.data.elements; return result.data; }; diff --git a/packages/composables/src/useSessionContext/useSessionContext.test.ts b/packages/composables/src/useSessionContext/useSessionContext.test.ts index 3fc4ef896..f41df39a0 100644 --- a/packages/composables/src/useSessionContext/useSessionContext.test.ts +++ b/packages/composables/src/useSessionContext/useSessionContext.test.ts @@ -218,4 +218,22 @@ describe("useSessionContext", () => { city: "test", }); }); + + it("should return languageIdChain", () => { + const { vm } = useSetup(() => useSessionContext()); + vm.setContext({ + context: { + languageIdChain: ["test", "test2"], + }, + } as unknown as Schemas["SalesChannelContext"]); + + expect(vm.languageIdChain).toStrictEqual("test"); + }); + + it("should return empty languageIdChain", () => { + const { vm } = useSetup(() => useSessionContext()); + vm.setContext({} as unknown as Schemas["SalesChannelContext"]); + + expect(vm.languageIdChain).toStrictEqual(""); + }); }); diff --git a/packages/composables/src/useSyncWishlist/useSyncWishlist.ts b/packages/composables/src/useSyncWishlist/useSyncWishlist.ts index 5819bf508..2cc99979e 100644 --- a/packages/composables/src/useSyncWishlist/useSyncWishlist.ts +++ b/packages/composables/src/useSyncWishlist/useSyncWishlist.ts @@ -1,7 +1,7 @@ import { ApiClientError } from "@shopware/api-client"; import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; -import { useShopwareContext } from "#imports"; +import { useSessionContext, useShopwareContext } from "#imports"; import type { Schemas } from "#shopware"; export type UseSyncWishlistReturn = { @@ -48,6 +48,7 @@ const totalWishlistItemsCount: Ref = ref(0); */ export function useSyncWishlist(): UseSyncWishlistReturn { const { apiClient } = useShopwareContext(); + const { languageIdChain } = useSessionContext(); async function addToWishlistSync(id: string) { await apiClient.invoke( "addProductOnWishlist post /customer/wishlist/add/{productId}", @@ -76,7 +77,12 @@ export function useSyncWishlist(): UseSyncWishlistReturn { try { const response = await apiClient.invoke( "readCustomerWishlist post /customer/wishlist", - { body: { ...defaultSearchCriteria, "total-count-mode": "exact" } }, + { + body: { ...defaultSearchCriteria, "total-count-mode": "exact" }, + headers: { + "sw-language-id": languageIdChain.value, + }, + }, ); _wishlistItems.value = [ ...response.data.products.elements.map((element) => element.id), diff --git a/packages/composables/src/useUser/useUser.test.ts b/packages/composables/src/useUser/useUser.test.ts index c9db6e0bf..bdb943c0c 100644 --- a/packages/composables/src/useUser/useUser.test.ts +++ b/packages/composables/src/useUser/useUser.test.ts @@ -22,6 +22,7 @@ vi.mock("../useSessionContext/useSessionContext.ts", async () => { return { refreshSessionContext: refreshSessionContextSpy, userFromContext: ref(), + languageIdChain: ref(), }; }, }; diff --git a/packages/composables/src/useUser/useUser.ts b/packages/composables/src/useUser/useUser.ts index 05c0520ad..e73e5dcdc 100644 --- a/packages/composables/src/useUser/useUser.ts +++ b/packages/composables/src/useUser/useUser.ts @@ -128,7 +128,8 @@ export type UseUserReturn = { */ export function useUser(): UseUserReturn { const { apiClient } = useShopwareContext(); - const { userFromContext, refreshSessionContext } = useSessionContext(); + const { userFromContext, refreshSessionContext, languageIdChain } = + useSessionContext(); const _user = useContext("customer"); syncRefs(userFromContext, _user, { @@ -228,6 +229,9 @@ export function useUser(): UseUserReturn { }, ], }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); country.value = countries.data.elements?.[0] ?? null; @@ -249,6 +253,9 @@ export function useUser(): UseUserReturn { }, ], }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); salutation.value = salutations.data.elements?.[0] ?? null; diff --git a/packages/nuxt-module/plugin.ts b/packages/nuxt-module/plugin.ts index d7418e6e6..3c73b7963 100644 --- a/packages/nuxt-module/plugin.ts +++ b/packages/nuxt-module/plugin.ts @@ -1,6 +1,5 @@ import { createAPIClient } from "@shopware/api-client"; import { isMaintenanceMode } from "@shopware/helpers"; -import { defu } from "defu"; import { getCookie } from "h3"; import Cookies from "js-cookie"; import { ref } from "vue"; diff --git a/templates/vue-demo-store/components/FrontendAccountCustomerGroupRegistrationPage.vue b/templates/vue-demo-store/components/FrontendAccountCustomerGroupRegistrationPage.vue index 0e3dd1830..3d6b011bb 100644 --- a/templates/vue-demo-store/components/FrontendAccountCustomerGroupRegistrationPage.vue +++ b/templates/vue-demo-store/components/FrontendAccountCustomerGroupRegistrationPage.vue @@ -4,6 +4,7 @@ const props = defineProps<{ }>(); const { apiClient } = useShopwareContext(); +const { languageIdChain } = useSessionContext(); const { data: registrationResponse } = await useAsyncData( `cmsNavigation${props.navigationId}`, @@ -12,6 +13,9 @@ const { data: registrationResponse } = await useAsyncData( "getCustomerGroupRegistrationInfo get /customer-group-registration/config/{customerGroupId}", { pathParams: { customerGroupId: props.navigationId }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); return response.data || {}; diff --git a/templates/vue-demo-store/components/cms/element/CmsElementProductDescriptionReviews.vue b/templates/vue-demo-store/components/cms/element/CmsElementProductDescriptionReviews.vue index 60fbb9520..fd2c8d10a 100644 --- a/templates/vue-demo-store/components/cms/element/CmsElementProductDescriptionReviews.vue +++ b/templates/vue-demo-store/components/cms/element/CmsElementProductDescriptionReviews.vue @@ -34,6 +34,7 @@ translations = defu(useCmsTranslations(), translations) as Translations; const currentTab = ref(1); const { product } = useProduct(props.content.data?.product); +const { languageIdChain } = useSessionContext(); const description = computed(() => getTranslatedProperty(product.value, "description"), @@ -54,6 +55,9 @@ const fetchReviews = async () => { "readProductReviews post /product/{productId}/reviews", { pathParams: { productId: product.value.id }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); reviews.value = reviewsResponse.data.elements || []; diff --git a/templates/vue-demo-store/components/product/ProductReviewsForm.vue b/templates/vue-demo-store/components/product/ProductReviewsForm.vue index b0bb1e5f8..d9fe2e305 100644 --- a/templates/vue-demo-store/components/product/ProductReviewsForm.vue +++ b/templates/vue-demo-store/components/product/ProductReviewsForm.vue @@ -40,7 +40,7 @@ const { apiClient } = useShopwareContext(); const { resolveApiErrors } = useApiErrorsResolver(); const { pushError } = useNotifications(); const { required, minLength } = customValidators(); - +const { languageIdChain } = useSessionContext(); const $v = useVuelidate(rules, state); const emits = defineEmits<(e: "success") => void>(); @@ -66,6 +66,9 @@ const invokeSend = async () => { content: state.review, points: state.rating || 0, }, + headers: { + "sw-language-id": languageIdChain.value, + }, }, ); reviewAdded.value = true; diff --git a/templates/vue-demo-store/pages/wishlist.vue b/templates/vue-demo-store/pages/wishlist.vue index cb98ba309..119e35f47 100644 --- a/templates/vue-demo-store/pages/wishlist.vue +++ b/templates/vue-demo-store/pages/wishlist.vue @@ -32,6 +32,7 @@ const { totalPagesCount, canSyncWishlist, } = useWishlist(); +const { languageIdChain } = useSessionContext(); defineOptions({ name: "WishlistPage", }); @@ -64,6 +65,9 @@ const loadProductsByItemIds = async (itemIds: string[]): Promise => { try { const { data } = await apiClient.invoke("readProduct post /product", { body: { ids: itemIds || items.value }, + headers: { + "sw-language-id": languageIdChain.value, + }, }); if (data?.elements) {