feat(): sync cart translation synced (#14226)
ref: https://github.com/medusajs/medusa/pull/14189 **Summary** This PR extends the translation module to support automatic translation syncing for cart line items based on the cart's locale. Key changes: - Added locale field to the Cart model to store the cart's locale preference - Created new workflow steps: - getTranslatedLineItemsStep - Translates line items when adding to cart or creating a cart - updateCartItemsTranslationsStep - Re-translates all cart items when the cart's locale changes - Integrated translation logic into cart workflows: - createCartWorkflow - Applies translations to initial line items - addToCartWorkflow - Applies translations when adding new items - updateCartWorkflow - Re-translates all items when locale_code is updated - refreshCartItemsWorkflow - Maintains translations during cart refresh - Added applyTranslationsToItems utility to map variant/product/type/collection translations to line item fields (title, subtitle, description, etc.)
This commit is contained in:
committed by
GitHub
parent
356283c359
commit
e4877616c3
@@ -0,0 +1,46 @@
|
||||
import { ProductVariantDTO } from "@medusajs/framework/types"
|
||||
import { applyTranslations, FeatureFlag } from "@medusajs/framework/utils"
|
||||
import {
|
||||
createStep,
|
||||
StepFunction,
|
||||
StepResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { applyTranslationsToItems } from "../utils/apply-translations-to-items"
|
||||
|
||||
export interface GetTranslatedLineItemsStepInput<T> {
|
||||
items: T[] | undefined
|
||||
variants: Partial<ProductVariantDTO>[]
|
||||
locale: string | undefined
|
||||
}
|
||||
|
||||
export const getTranslatedLineItemsStepId = "get-translated-line-items"
|
||||
|
||||
const step = createStep(
|
||||
getTranslatedLineItemsStepId,
|
||||
async (data: GetTranslatedLineItemsStepInput<any>, { container }) => {
|
||||
const isTranslationEnabled = FeatureFlag.isFeatureEnabled("translation")
|
||||
|
||||
if (!isTranslationEnabled || !data.locale || !data.items?.length) {
|
||||
return new StepResponse(data.items ?? [])
|
||||
}
|
||||
|
||||
await applyTranslations({
|
||||
localeCode: data.locale,
|
||||
objects: data.variants,
|
||||
container,
|
||||
})
|
||||
|
||||
const translatedItems = applyTranslationsToItems(data.items, data.variants)
|
||||
|
||||
return new StepResponse(translatedItems)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* This step translates cart line items based on their associated variant and product IDs.
|
||||
* It fetches translations for the product (title, description, subtitle) and variant (title),
|
||||
* then applies them to the corresponding line item fields.
|
||||
*/
|
||||
export const getTranslatedLineItemsStep = <T>(
|
||||
data: GetTranslatedLineItemsStepInput<T>
|
||||
): ReturnType<StepFunction<any, T[]>> => step(data)
|
||||
@@ -10,6 +10,8 @@ export * from "./find-or-create-customer"
|
||||
export * from "./find-sales-channel"
|
||||
export * from "./get-actions-to-compute-from-promotions"
|
||||
export * from "./get-line-item-actions"
|
||||
export * from "./get-translated-line-items"
|
||||
export * from "./update-cart-items-translations"
|
||||
export * from "./get-promotion-codes-to-apply"
|
||||
export * from "./get-variant-price-sets"
|
||||
export * from "./get-variants"
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
import { MedusaContainer } from "@medusajs/framework"
|
||||
import {
|
||||
ICartModuleService,
|
||||
ProductVariantDTO,
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
applyTranslations,
|
||||
ContainerRegistrationKeys,
|
||||
deduplicate,
|
||||
FeatureFlag,
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
import { applyTranslationsToItems } from "../utils/apply-translations-to-items"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
|
||||
export interface UpdateCartItemsTranslationsStepInput {
|
||||
cart_id: string
|
||||
locale: string
|
||||
/**
|
||||
* Pre-loaded items to avoid re-fetching.
|
||||
*/
|
||||
items?: { id: string; variant_id?: string; [key: string]: any }[]
|
||||
}
|
||||
|
||||
const BATCH_SIZE = 100
|
||||
|
||||
const lineItemFields = [
|
||||
"id",
|
||||
"variant_id",
|
||||
"product_id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"product_title",
|
||||
"product_description",
|
||||
"product_subtitle",
|
||||
"product_type",
|
||||
"product_collection",
|
||||
"product_handle",
|
||||
"variant_title",
|
||||
]
|
||||
|
||||
export const updateCartItemsTranslationsStepId =
|
||||
"update-cart-items-translations"
|
||||
|
||||
type ItemTranslationSnapshot = {
|
||||
id: string
|
||||
title: string
|
||||
subtitle: string
|
||||
product_title: string
|
||||
product_description: string
|
||||
product_subtitle: string
|
||||
product_type: string
|
||||
product_collection: string
|
||||
product_handle: string
|
||||
variant_title: string
|
||||
}
|
||||
|
||||
async function compensation(
|
||||
originalItems,
|
||||
{ container }: { container: MedusaContainer }
|
||||
) {
|
||||
if (!originalItems?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const cartModule = container.resolve<ICartModuleService>(Modules.CART)
|
||||
|
||||
for (let i = 0; i < originalItems.length; i += BATCH_SIZE) {
|
||||
const batch = originalItems.slice(i, i + BATCH_SIZE)
|
||||
await cartModule.updateLineItems(batch)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This step re-translates all cart line items when the cart's locale changes.
|
||||
* It fetches items and their variants in batches to handle large carts gracefully.
|
||||
*/
|
||||
export const updateCartItemsTranslationsStep = createStep(
|
||||
updateCartItemsTranslationsStepId,
|
||||
async (data: UpdateCartItemsTranslationsStepInput, { container }) => {
|
||||
const originalItems: ItemTranslationSnapshot[] = []
|
||||
try {
|
||||
const isTranslationEnabled = FeatureFlag.isFeatureEnabled("translation")
|
||||
|
||||
if (!isTranslationEnabled || !data.locale) {
|
||||
return new StepResponse(void 0, [])
|
||||
}
|
||||
|
||||
const cartModule = container.resolve<ICartModuleService>(Modules.CART)
|
||||
const query = container.resolve<RemoteQueryFunction>(
|
||||
ContainerRegistrationKeys.QUERY
|
||||
)
|
||||
|
||||
const processBatch = async (
|
||||
items: { id: string; variant_id?: string; [key: string]: any }[]
|
||||
) => {
|
||||
const variantIds = deduplicate(
|
||||
items
|
||||
.map((item) => item.variant_id)
|
||||
.filter((id): id is string => !!id)
|
||||
)
|
||||
|
||||
if (variantIds.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Store original values before updating
|
||||
for (const item of items) {
|
||||
originalItems.push({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
product_title: item.product_title,
|
||||
product_description: item.product_description,
|
||||
product_subtitle: item.product_subtitle,
|
||||
product_type: item.product_type,
|
||||
product_collection: item.product_collection,
|
||||
product_handle: item.product_handle,
|
||||
variant_title: item.variant_title,
|
||||
})
|
||||
}
|
||||
|
||||
const { data: variants } = await query.graph({
|
||||
entity: "variants",
|
||||
filters: { id: variantIds },
|
||||
fields: productVariantsFields,
|
||||
})
|
||||
|
||||
await applyTranslations({
|
||||
localeCode: data.locale,
|
||||
objects: variants as Record<string, any>[],
|
||||
container,
|
||||
})
|
||||
|
||||
const translatedItems = applyTranslationsToItems(
|
||||
items as { variant_id?: string; [key: string]: any }[],
|
||||
variants as Partial<ProductVariantDTO>[]
|
||||
)
|
||||
|
||||
const itemsToUpdate = translatedItems
|
||||
.filter((item) => item.id)
|
||||
.map((item) => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
product_title: item.product_title,
|
||||
product_description: item.product_description,
|
||||
product_subtitle: item.product_subtitle,
|
||||
product_type: item.product_type,
|
||||
product_collection: item.product_collection,
|
||||
product_handle: item.product_handle,
|
||||
variant_title: item.variant_title,
|
||||
}))
|
||||
|
||||
if (itemsToUpdate.length > 0) {
|
||||
await cartModule.updateLineItems(itemsToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.items?.length) {
|
||||
await processBatch(data.items)
|
||||
return new StepResponse(void 0, originalItems)
|
||||
}
|
||||
|
||||
let offset = 0
|
||||
let hasMore = true
|
||||
|
||||
while (hasMore) {
|
||||
const { data: items } = await query.graph({
|
||||
entity: "line_items",
|
||||
filters: { cart_id: data.cart_id },
|
||||
fields: lineItemFields,
|
||||
pagination: {
|
||||
take: BATCH_SIZE,
|
||||
skip: offset,
|
||||
},
|
||||
})
|
||||
|
||||
if (items.length === 0) {
|
||||
hasMore = false
|
||||
break
|
||||
}
|
||||
|
||||
await processBatch(items as { id: string; variant_id?: string }[])
|
||||
|
||||
offset += items.length
|
||||
hasMore = items.length === BATCH_SIZE
|
||||
}
|
||||
|
||||
return new StepResponse(void 0, originalItems)
|
||||
} catch (error) {
|
||||
await compensation(originalItems, { container })
|
||||
throw error
|
||||
}
|
||||
},
|
||||
compensation
|
||||
)
|
||||
@@ -0,0 +1,69 @@
|
||||
import { ProductVariantDTO } from "@medusajs/framework/types"
|
||||
|
||||
const VARIANT_PREFIX = "variant_"
|
||||
const PRODUCT_PREFIX = "product_"
|
||||
const PRODUCT_TYPE_PREFIX = "type_"
|
||||
const PRODUCT_COLLECTION_PREFIX = "collection_"
|
||||
|
||||
const TRANSLATABLE_ITEM_PROP_PREFIXES = [
|
||||
VARIANT_PREFIX,
|
||||
PRODUCT_PREFIX,
|
||||
PRODUCT_TYPE_PREFIX,
|
||||
PRODUCT_COLLECTION_PREFIX,
|
||||
]
|
||||
|
||||
const entityGetterPerPrefix = {
|
||||
[VARIANT_PREFIX]: (variant: ProductVariantDTO) => variant,
|
||||
[PRODUCT_PREFIX]: (variant: ProductVariantDTO) => variant.product!,
|
||||
[PRODUCT_TYPE_PREFIX]: (variant: ProductVariantDTO) => variant.product?.type!,
|
||||
[PRODUCT_COLLECTION_PREFIX]: (variant: ProductVariantDTO) =>
|
||||
variant.product?.collection!,
|
||||
}
|
||||
|
||||
function applyTranslation(
|
||||
itemAny: Record<string, any>,
|
||||
translatedInput: Record<string, any>,
|
||||
key: string,
|
||||
translationKey: string
|
||||
) {
|
||||
if (typeof itemAny[key] === typeof translatedInput?.[translationKey]) {
|
||||
itemAny[key] = translatedInput?.[translationKey]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies translated variant/product fields to line items.
|
||||
*/
|
||||
export function applyTranslationsToItems<
|
||||
T extends { variant_id?: string; [key: string]: any }
|
||||
>(items: T[], variants: Partial<ProductVariantDTO>[]): T[] {
|
||||
const variantMap = new Map(variants.map((variant) => [variant.id, variant]))
|
||||
|
||||
return items.map((item) => {
|
||||
if (!item.variant_id) {
|
||||
return item
|
||||
}
|
||||
|
||||
const variant = variantMap.get(item.variant_id)
|
||||
if (!variant) {
|
||||
return item
|
||||
}
|
||||
|
||||
const itemAny = item as Record<string, any>
|
||||
|
||||
Object.entries(itemAny).forEach(([key, value]) => {
|
||||
for (const prefix of TRANSLATABLE_ITEM_PROP_PREFIXES) {
|
||||
if (key.startsWith(prefix)) {
|
||||
const translationKey = key.replace(prefix, "")
|
||||
const entity = entityGetterPerPrefix[prefix](variant)
|
||||
if (!entity) {
|
||||
break
|
||||
}
|
||||
applyTranslation(itemAny, entity, key, translationKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return item
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export const cartFieldsForRefreshSteps = [
|
||||
"quantity",
|
||||
"subtotal",
|
||||
"item_total",
|
||||
"locale",
|
||||
"total",
|
||||
"item_subtotal",
|
||||
"shipping_subtotal",
|
||||
|
||||
@@ -139,30 +139,30 @@ export function prepareLineItemData(data: PrepareLineItemDataInput) {
|
||||
|
||||
let lineItem: any = {
|
||||
quantity: item?.quantity,
|
||||
title: variant?.product?.title ?? item?.title,
|
||||
subtitle: variant?.title ?? item?.subtitle,
|
||||
title: item?.title ?? variant?.product?.title,
|
||||
subtitle: item?.subtitle ?? variant?.title,
|
||||
thumbnail:
|
||||
variant?.thumbnail ?? variant?.product?.thumbnail ?? item?.thumbnail,
|
||||
item?.thumbnail ?? variant?.thumbnail ?? variant?.product?.thumbnail,
|
||||
|
||||
product_id: variant?.product?.id ?? item?.product_id,
|
||||
product_title: variant?.product?.title ?? item?.product_title,
|
||||
product_title: item?.product_title ?? variant?.product?.title,
|
||||
product_description:
|
||||
variant?.product?.description ?? item?.product_description,
|
||||
product_subtitle: variant?.product?.subtitle ?? item?.product_subtitle,
|
||||
product_type: variant?.product?.type?.value ?? item?.product_type ?? null,
|
||||
item?.product_description ?? variant?.product?.description,
|
||||
product_subtitle: item?.product_subtitle ?? variant?.product?.subtitle,
|
||||
product_type: item?.product_type ?? variant?.product?.type?.value ?? null,
|
||||
product_type_id:
|
||||
variant?.product?.type?.id ?? item?.product_type_id ?? null,
|
||||
item?.product_type_id ?? variant?.product?.type?.id ?? null,
|
||||
product_collection:
|
||||
variant?.product?.collection?.title ?? item?.product_collection ?? null,
|
||||
product_handle: variant?.product?.handle ?? item?.product_handle,
|
||||
item?.product_collection ?? variant?.product?.collection?.title ?? null,
|
||||
product_handle: item?.product_handle ?? variant?.product?.handle,
|
||||
|
||||
variant_id: variant?.id,
|
||||
variant_sku: variant?.sku ?? item?.variant_sku,
|
||||
variant_barcode: variant?.barcode ?? item?.variant_barcode,
|
||||
variant_title: variant?.title ?? item?.variant_title,
|
||||
variant_sku: item?.variant_sku ?? variant?.sku,
|
||||
variant_barcode: item?.variant_barcode ?? variant?.barcode,
|
||||
variant_title: item?.variant_title ?? variant?.title,
|
||||
variant_option_values: item?.variant_option_values,
|
||||
|
||||
is_discountable: variant?.product?.discountable ?? item?.is_discountable,
|
||||
is_discountable: item?.is_discountable ?? variant?.product?.discountable,
|
||||
is_giftcard: variant?.product?.is_giftcard ?? false,
|
||||
requires_shipping: requiresShipping,
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { acquireLockStep, releaseLockStep } from "../../locking"
|
||||
import {
|
||||
createLineItemsStep,
|
||||
getLineItemActionsStep,
|
||||
getTranslatedLineItemsStep,
|
||||
updateLineItemsStep,
|
||||
} from "../steps"
|
||||
import { validateCartStep } from "../steps/validate-cart"
|
||||
@@ -42,7 +43,9 @@ import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
|
||||
import { getVariantsAndItemsWithPrices } from "./get-variants-and-items-with-prices"
|
||||
import { refreshCartItemsWorkflow } from "./refresh-cart-items"
|
||||
|
||||
const cartFields = ["completed_at"].concat(cartFieldsForPricingContext)
|
||||
const cartFields = ["completed_at", "locale"].concat(
|
||||
cartFieldsForPricingContext
|
||||
)
|
||||
|
||||
export const addToCartWorkflowId = "add-to-cart"
|
||||
/**
|
||||
@@ -292,10 +295,33 @@ export const addToCartWorkflow = createWorkflow(
|
||||
},
|
||||
})
|
||||
|
||||
const itemsToCreateVariants = transform(
|
||||
{ itemsToCreate, variants } as {
|
||||
itemsToCreate: CreateLineItemForCartDTO[]
|
||||
variants: PrepareVariantLineItemInput[]
|
||||
},
|
||||
(data) => {
|
||||
if (!data.itemsToCreate?.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const variantsMap = new Map(data.variants?.map((v) => [v.id, v]))
|
||||
return data.itemsToCreate
|
||||
.map((item) => item.variant_id && variantsMap.get(item.variant_id))
|
||||
.filter(Boolean) as PrepareVariantLineItemInput[]
|
||||
}
|
||||
)
|
||||
|
||||
const translatedItemsToCreate = getTranslatedLineItemsStep({
|
||||
items: itemsToCreate,
|
||||
variants: itemsToCreateVariants,
|
||||
locale: cart.locale,
|
||||
})
|
||||
|
||||
const [createdLineItems, updatedLineItems] = parallelize(
|
||||
createLineItemsStep({
|
||||
id: cart.id,
|
||||
items: itemsToCreate,
|
||||
items: translatedItemsToCreate,
|
||||
}),
|
||||
updateLineItemsStep({
|
||||
id: cart.id,
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ConfirmVariantInventoryWorkflowInputDTO,
|
||||
CreateCartDTO,
|
||||
CreateCartWorkflowInputDTO,
|
||||
CreateLineItemDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
CartWorkflowEvents,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
findOneOrAnyRegionStep,
|
||||
findOrCreateCustomerStep,
|
||||
findSalesChannelStep,
|
||||
getTranslatedLineItemsStep,
|
||||
} from "../steps"
|
||||
import { validateSalesChannelStep } from "../steps/validate-sales-channel"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
@@ -205,17 +207,31 @@ export const createCartWorkflow = createWorkflow(
|
||||
}
|
||||
}
|
||||
|
||||
return data_
|
||||
return data_ as CreateCartDTO
|
||||
}
|
||||
)
|
||||
|
||||
const cartToCreate = transform({ lineItems, cartInput }, (data) => {
|
||||
return {
|
||||
...data.cartInput,
|
||||
items: data.lineItems.map((i) => i.data),
|
||||
} as unknown as CreateCartDTO
|
||||
const itemsToCreate = transform({ lineItems }, (data) => {
|
||||
return data.lineItems.map((i) => i.data as CreateLineItemDTO)
|
||||
})
|
||||
|
||||
const translatedItems = getTranslatedLineItemsStep({
|
||||
items: itemsToCreate,
|
||||
variants,
|
||||
locale: input.locale,
|
||||
})
|
||||
|
||||
const cartToCreate = transform(
|
||||
{ cartInput, translatedItems } as unknown as {
|
||||
cartInput: CreateCartDTO
|
||||
translatedItems: CreateLineItemDTO[]
|
||||
},
|
||||
(data) => {
|
||||
data.cartInput.items = data.translatedItems
|
||||
return data.cartInput as unknown as CreateCartDTO
|
||||
}
|
||||
)
|
||||
|
||||
const validate = createHook("validate", {
|
||||
input: cartInput,
|
||||
cart: cartToCreate,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
CreateCartCreateLineItemDTO,
|
||||
CustomerDTO,
|
||||
OrderWorkflow,
|
||||
ProductVariantDTO,
|
||||
RegionDTO,
|
||||
UpdateLineItemDTO,
|
||||
UpdateLineItemWithSelectorDTO,
|
||||
@@ -54,7 +55,7 @@ interface GetVariantsAndItemsWithPricesWorkflowInput {
|
||||
|
||||
type GetVariantsAndItemsWithPricesWorkflowOutput = {
|
||||
// The variant can depend on the requested fields and therefore the caller will know better
|
||||
variants: (object & {
|
||||
variants: (Partial<ProductVariantDTO> & {
|
||||
calculated_price: {
|
||||
calculated_price: {
|
||||
price_list_type: string
|
||||
@@ -184,8 +185,11 @@ export const getVariantsAndItemsWithPrices = createWorkflow(
|
||||
}
|
||||
|
||||
const variant = variantsData.find((v) => v.id === item.variant_id)
|
||||
if ((item.variant_id && !variant) || // variant specified but doesn't exist
|
||||
(variant && (!variant?.product?.status || variant.product.status !== ProductStatus.PUBLISHED)) // variant exists but product is not published
|
||||
if (
|
||||
(item.variant_id && !variant) || // variant specified but doesn't exist
|
||||
(variant &&
|
||||
(!variant?.product?.status ||
|
||||
variant.product.status !== ProductStatus.PUBLISHED)) // variant exists but product is not published
|
||||
) {
|
||||
variantNotFoundOrPublished.push(item_.variant_id)
|
||||
}
|
||||
@@ -225,7 +229,9 @@ export const getVariantsAndItemsWithPrices = createWorkflow(
|
||||
if (variantNotFoundOrPublished.length > 0) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Variants ${variantNotFoundOrPublished.join(", ")} do not exist or belong to a product that is not published`
|
||||
`Variants ${variantNotFoundOrPublished.join(
|
||||
", "
|
||||
)} do not exist or belong to a product that is not published`
|
||||
)
|
||||
}
|
||||
if (priceNotFound.length > 0) {
|
||||
|
||||
@@ -10,7 +10,11 @@ import {
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "../../common"
|
||||
import { acquireLockStep, releaseLockStep } from "../../locking"
|
||||
import { updateLineItemsStep, validateCartStep } from "../steps"
|
||||
import {
|
||||
updateCartItemsTranslationsStep,
|
||||
updateLineItemsStep,
|
||||
validateCartStep,
|
||||
} from "../steps"
|
||||
import { cartFieldsForRefreshSteps } from "../utils/fields"
|
||||
import { pricingContextResult } from "../utils/schemas"
|
||||
import { getVariantsAndItemsWithPrices } from "./get-variants-and-items-with-prices"
|
||||
@@ -54,6 +58,12 @@ export type RefreshCartItemsWorkflowInput = {
|
||||
* on the configurations of the cart's tax region.
|
||||
*/
|
||||
force_tax_calculation?: boolean
|
||||
|
||||
/**
|
||||
* The new locale code to update cart items translations.
|
||||
* When provided, all cart items will be re-translated using this locale.
|
||||
*/
|
||||
locale?: string
|
||||
}
|
||||
|
||||
export const refreshCartItemsWorkflowId = "refresh-cart-items"
|
||||
@@ -234,6 +244,16 @@ export const refreshCartItemsWorkflow = createWorkflow(
|
||||
},
|
||||
})
|
||||
|
||||
when("should-update-item-translations", { input }, ({ input }) => {
|
||||
return !!input.locale
|
||||
}).then(() => {
|
||||
updateCartItemsTranslationsStep({
|
||||
cart_id: input.cart_id,
|
||||
locale: input.locale!,
|
||||
items: refetchedCart.items,
|
||||
})
|
||||
})
|
||||
|
||||
const beforeRefreshingPaymentCollection = createHook(
|
||||
"beforeRefreshingPaymentCollection",
|
||||
{ input }
|
||||
|
||||
@@ -99,6 +99,7 @@ export const updateCartWorkflow = createWorkflow(
|
||||
"email",
|
||||
"customer_id",
|
||||
"sales_channel_id",
|
||||
"locale",
|
||||
"shipping_address.*",
|
||||
"region.*",
|
||||
"region.countries.*",
|
||||
@@ -280,6 +281,17 @@ export const updateCartWorkflow = createWorkflow(
|
||||
}).config({ name: "emit-region-updated" })
|
||||
})
|
||||
|
||||
// Get the new locale code if it's being updated
|
||||
const newLocaleCode = transform(
|
||||
{ input, cartToUpdate },
|
||||
({ input, cartToUpdate }) => {
|
||||
if (isDefined(input.locale) && input.locale !== cartToUpdate?.locale) {
|
||||
return input.locale
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
)
|
||||
|
||||
parallelize(
|
||||
updateCartsStep([cartInput]),
|
||||
emitEventStep({
|
||||
@@ -314,6 +326,7 @@ export const updateCartWorkflow = createWorkflow(
|
||||
cart_id: cartInput.id,
|
||||
promo_codes: input.promo_codes,
|
||||
force_refresh: !!newRegion,
|
||||
locale: newLocaleCode,
|
||||
additional_data: input.additional_data,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -14,7 +14,7 @@ export const createTranslationsStepId = "create-translations"
|
||||
* {
|
||||
* reference_id: "prod_123",
|
||||
* reference: "product",
|
||||
* locale_code: "fr-FR",
|
||||
* locale: "fr-FR",
|
||||
* translations: { title: "Produit", description: "Description du produit" }
|
||||
* }
|
||||
* ])
|
||||
|
||||
@@ -36,7 +36,7 @@ export const updateTranslationsStepId = "update-translations"
|
||||
* const data = updateTranslationsStep({
|
||||
* selector: {
|
||||
* reference_id: "prod_123",
|
||||
* locale_code: "fr-FR"
|
||||
* locale: "fr-FR"
|
||||
* },
|
||||
* update: {
|
||||
* translations: { title: "Nouveau titre" }
|
||||
|
||||
@@ -24,7 +24,7 @@ export const validateTranslationsStep = createStep(
|
||||
} = await query.graph(
|
||||
{
|
||||
entity: "store",
|
||||
fields: ["supported_locales.*"],
|
||||
fields: ["id", "supported_locales.*"],
|
||||
pagination: {
|
||||
take: 1,
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ export const createTranslationsWorkflowId = "create-translations"
|
||||
* {
|
||||
* reference_id: "prod_123",
|
||||
* reference: "product",
|
||||
* locale_code: "fr-FR",
|
||||
* locale: "fr-FR",
|
||||
* translations: { title: "Produit", description: "Description du produit" }
|
||||
* }
|
||||
* ]
|
||||
|
||||
@@ -24,7 +24,7 @@ export const updateTranslationsWorkflowId = "update-translations"
|
||||
* input: {
|
||||
* selector: {
|
||||
* reference_id: "prod_123",
|
||||
* locale_code: "fr-FR"
|
||||
* locale: "fr-FR"
|
||||
* },
|
||||
* update: {
|
||||
* translations: { title: "Nouveau titre" }
|
||||
|
||||
Reference in New Issue
Block a user