feat(translation,core-flows): translate remaining core entities and sync shipping option <> method translations (#14358)

* Get translated shipping options step

* Apply translations on shipping options list methods.

* Pass shipping option naem when refreshing cart shipping methods, so if locale changed, we update the name

* Update translatable fields config

* Cart shipping method update translation tests

* Shipping options translations tests

* Add changeset

* Update order shipping method translations on update

* Remove unnecessary workflow and use step instead

* Translate shipping method on order edit

* Use new update shipping methods tranlsations step

* Draft order shipping method translation sync

* Translate shipping method on order exchange

* Translate returns shipping methods

* Translate claims shipping methods

* Remove unnecessary check

* Early return

* Fix import

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Nicolas Gorga
2026-01-02 07:26:06 -03:00
committed by GitHub
parent 5f807ee657
commit 11de7e3e34
25 changed files with 2831 additions and 27 deletions

View File

@@ -142,6 +142,7 @@ export const cartFieldsForPricingContext = [
"shipping_address.postal_code",
"item_total",
"total",
"locale",
"customer.id",
"email",
"customer.groups.id",
@@ -188,6 +189,7 @@ export const productVariantsFields = [
// ensure that at least these fields are present when fetching cart for caluclating shipping options prices
export const cartFieldsForCalculateShippingOptionsPrices = [
"id",
"locale",
"items.*",
"items.variant.id",
"items.variant.product.id",

View File

@@ -23,6 +23,7 @@ import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
import { calculateShippingOptionsPricesStep } from "../../fulfillment"
import { cartFieldsForCalculateShippingOptionsPrices } from "../utils/fields"
import { shippingOptionsContextResult } from "../utils/schemas"
import { getTranslatedShippingOptionsStep } from "../../common/steps/get-translated-shipping-option"
const COMMON_OPTIONS_FIELDS = [
"id",
@@ -397,7 +398,12 @@ export const listShippingOptionsForCartWithPricingWorkflow = createWorkflow(
}
)
return new WorkflowResponse(shippingOptionsWithPrice, {
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptionsWithPrice,
locale: cart.locale,
})
return new WorkflowResponse(translatedShippingOptions as any[], {
hooks: [setShippingOptionsContext] as const,
})
}

View File

@@ -24,6 +24,7 @@ import {
pricingContextResult,
shippingOptionsContextResult,
} from "../utils/schemas"
import { getTranslatedShippingOptionsStep } from "../../common/steps/get-translated-shipping-option"
export const listShippingOptionsForCartWorkflowId =
"list-shipping-options-for-cart"
@@ -359,7 +360,12 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
})
)
return new WorkflowResponse(shippingOptionsWithPrice, {
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptionsWithPrice,
locale: cart.locale,
})
return new WorkflowResponse(translatedShippingOptions as any[], {
hooks: [setPricingContext, setShippingOptionsContext] as const,
})
}

View File

@@ -192,6 +192,7 @@ export const refreshCartShippingMethodsWorkflow = createWorkflow(
return {
id: shippingMethod.id,
shipping_option_id: shippingOption.id,
name: shippingOption.name,
amount: shippingOption.calculated_price.calculated_amount,
is_tax_inclusive:
shippingOption.calculated_price

View File

@@ -0,0 +1,24 @@
import { applyTranslations } from "@medusajs/framework/utils"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import { ShippingOptionDTO } from "@medusajs/types"
export const getTranslatedShippingOptionsStepId =
"get-translated-shipping-options"
export interface GetTranslatedShippingOptionsStepInput {
shippingOptions: ShippingOptionDTO[]
locale: string
}
export const getTranslatedShippingOptionsStep = createStep(
getTranslatedShippingOptionsStepId,
async (data: GetTranslatedShippingOptionsStepInput, { container }) => {
await applyTranslations({
localeCode: data.locale,
objects: data.shippingOptions,
container,
})
return new StepResponse(data.shippingOptions)
}
)

View File

@@ -6,6 +6,7 @@ export const draftOrderFieldsForRefreshSteps = [
"metadata",
"sales_channel_id",
"region_id",
"locale",
"region.*",
"items.*",
"items.product.id",

View File

@@ -31,6 +31,7 @@ import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-chan
import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
import { getTranslatedShippingOptionsStep } from "../../common/steps/get-translated-shipping-option"
const validateShippingOptionStep = createStep(
"validate-shipping-option",
@@ -148,12 +149,17 @@ export const addDraftOrderShippingMethodsWorkflow = createWorkflow(
},
}).config({ name: "fetch-shipping-option" })
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptions,
locale: order.locale!,
})
validateShippingOptionStep({ shippingOptions, input })
const shippingMethodInput = transform(
{
relatedEntity: { order_id: order.id },
shippingOptions,
shippingOptions: translatedShippingOptions,
customPrice: input.custom_amount as any, // Need to cast this to any otherwise the type becomes to complex.
orderChange,
input,

View File

@@ -9,6 +9,7 @@ import { Modules, OrderWorkflowEvents } from "@medusajs/framework/utils"
import {
createStep,
createWorkflow,
parallelize,
StepResponse,
transform,
when,
@@ -21,6 +22,7 @@ import {
previewOrderChangeStep,
registerOrderChangesStep,
updateOrderItemsTranslationsStep,
updateOrderShippingMethodsTranslationsStep,
} from "../../order"
import { validateDraftOrderStep } from "../steps/validate-draft-order"
@@ -179,6 +181,9 @@ export const updateDraftOrderWorkflow = createWorkflow(
"locale",
"shipping_address.*",
"billing_address.*",
"shipping_methods.id",
"shipping_methods.name",
"shipping_methods.shipping_option_id",
"metadata",
],
variables: {
@@ -340,10 +345,16 @@ export const updateDraftOrderWorkflow = createWorkflow(
when({ input, order }, ({ input, order }) => {
return !!input.locale && input.locale !== order.locale
}).then(() => {
updateOrderItemsTranslationsStep({
order_id: input.id,
locale: input.locale!,
})
parallelize(
updateOrderShippingMethodsTranslationsStep({
locale: input.locale!,
shippingMethods: order.shipping_methods,
}),
updateOrderItemsTranslationsStep({
order_id: input.id,
locale: input.locale!,
})
)
})
emitEventStep({

View File

@@ -37,5 +37,6 @@ export * from "./set-tax-lines-for-items"
export * from "./update-order-change-actions"
export * from "./update-order-changes"
export * from "./update-order-items-translations"
export * from "./update-order-shipping-methods-translations"
export * from "./update-orders"
export * from "./update-shipping-methods"

View File

@@ -0,0 +1,71 @@
import {
applyTranslations,
ContainerRegistrationKeys,
FeatureFlag,
Modules,
} from "@medusajs/framework/utils"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import { OrderShippingMethodDTO } from "@medusajs/types"
export const updateOrderShippingMethodsTranslationsStepId =
"update-order-shipping-methods-translations"
export interface UpdateOrderShippingMethodsTranslationsStepInput {
shippingMethods: OrderShippingMethodDTO[]
locale: string
}
export const updateOrderShippingMethodsTranslationsStep = createStep(
updateOrderShippingMethodsTranslationsStepId,
async (
data: UpdateOrderShippingMethodsTranslationsStepInput,
{ container }
) => {
const isTranslationEnabled = FeatureFlag.isFeatureEnabled("translation")
if (!isTranslationEnabled || !data.locale || !data.shippingMethods.length) {
return new StepResponse(data.shippingMethods)
}
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const orderModuleService = container.resolve(Modules.ORDER)
const { data: translatedShippingOptions } = await query.graph({
entity: "shipping_option",
fields: ["id", "name"],
filters: {
id: data.shippingMethods.map((sm) => sm.shipping_option_id),
},
})
await applyTranslations({
localeCode: data.locale,
objects: translatedShippingOptions,
container,
})
const shippingOptionTranslationMap = new Map<string, string>(
translatedShippingOptions.map((tos) => [tos.id, tos.name])
)
const updatedShippingMethods =
await orderModuleService.updateOrderShippingMethods(
data.shippingMethods.map((sm) => ({
...sm,
name: sm.shipping_option_id
? shippingOptionTranslationMap.get(sm.shipping_option_id)
: sm.name,
}))
)
return new StepResponse(updatedShippingMethods, data.shippingMethods)
},
async (dataBeforeUpdate, { container }) => {
if (!dataBeforeUpdate?.length) {
return
}
const orderModuleService = container.resolve(Modules.ORDER)
await orderModuleService.updateOrderShippingMethods(dataBeforeUpdate)
}
)

View File

@@ -24,6 +24,7 @@ import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { fetchShippingOptionForOrderWorkflow } from "../fetch-shipping-option"
import { getTranslatedShippingOptionsStep } from "../../../common/steps/get-translated-shipping-option"
/**
* The data to validate that a shipping method can be created for a claim.
@@ -162,7 +163,14 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "region_id", "currency_code", "canceled_at"],
fields: [
"id",
"status",
"region_id",
"currency_code",
"canceled_at",
"locale",
],
variables: { id: orderClaim.order_id },
list: false,
throw_if_key_not_found: true,
@@ -227,12 +235,17 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
return [shippingOption]
})
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptions,
locale: order.locale!,
})
createClaimShippingMethodValidationStep({ order, orderClaim, orderChange })
const shippingMethodInput = transform(
{
relatedEntity: orderClaim,
shippingOptions,
shippingOptions: translatedShippingOptions,
customPrice: input.custom_amount,
orderChange,
input,

View File

@@ -24,6 +24,7 @@ import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { fetchShippingOptionForOrderWorkflow } from "../fetch-shipping-option"
import { getTranslatedShippingOptionsStep } from "../../../common/steps/get-translated-shipping-option"
/**
* The data to validate that a shipping method can be created for an exchange.
@@ -163,7 +164,7 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "currency_code", "canceled_at"],
fields: ["id", "status", "currency_code", "canceled_at", "locale"],
variables: { id: orderExchange.order_id },
list: false,
throw_if_key_not_found: true,
@@ -228,6 +229,11 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
return [shippingOption]
})
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptions,
locale: order.locale!,
})
createExchangeShippingMethodValidationStep({
order,
orderExchange,
@@ -237,7 +243,7 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
const shippingMethodInput = transform(
{
relatedEntity: orderExchange,
shippingOptions,
shippingOptions: translatedShippingOptions,
customPrice: input.custom_amount,
orderChange,
input,

View File

@@ -25,6 +25,7 @@ import {
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { getTranslatedShippingOptionsStep } from "../../../common/steps/get-translated-shipping-option"
/**
* The data to validate that a shipping method can be created for an order edit.
@@ -163,7 +164,7 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "currency_code", "canceled_at"],
fields: ["id", "status", "currency_code", "canceled_at", "locale"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
@@ -220,10 +221,15 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
list: false,
}).config({ name: "order-change-query" })
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptions,
locale: order.locale!,
})
const shippingMethodInput = transform(
{
relatedEntity: { order_id: order.id },
shippingOptions,
shippingOptions: translatedShippingOptions,
customPrice: input.custom_amount,
orderChange,
input,

View File

@@ -23,6 +23,7 @@ import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { fetchShippingOptionForOrderWorkflow } from "../fetch-shipping-option"
import { getTranslatedShippingOptionsStep } from "../../../common/steps/get-translated-shipping-option"
/**
* The data to validate that a shipping method can be created for a return.
@@ -153,7 +154,7 @@ export const createReturnShippingMethodWorkflow = createWorkflow(
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "currency_code", "canceled_at"],
fields: ["id", "status", "currency_code", "canceled_at", "locale"],
variables: { id: orderReturn.order_id },
list: false,
throw_if_key_not_found: true,
@@ -202,6 +203,11 @@ export const createReturnShippingMethodWorkflow = createWorkflow(
return [shippingOption]
})
const translatedShippingOptions = getTranslatedShippingOptionsStep({
shippingOptions: shippingOptions,
locale: order.locale!,
})
createReturnShippingMethodValidationStep({
order,
orderReturn,
@@ -211,7 +217,7 @@ export const createReturnShippingMethodWorkflow = createWorkflow(
const shippingMethodInput = transform(
{
relatedEntity: orderReturn,
shippingOptions,
shippingOptions: translatedShippingOptions,
customPrice: input.custom_amount,
orderChange,
input,

View File

@@ -14,6 +14,7 @@ import {
WorkflowResponse,
createStep,
createWorkflow,
parallelize,
transform,
when,
} from "@medusajs/framework/workflows-sdk"
@@ -23,6 +24,7 @@ import {
previewOrderChangeStep,
registerOrderChangesStep,
updateOrderItemsTranslationsStep,
updateOrderShippingMethodsTranslationsStep,
updateOrdersStep,
} from "../steps"
import { throwIfOrderIsCancelled } from "../utils/order-validation"
@@ -134,6 +136,9 @@ export const updateOrderWorkflow = createWorkflow(
"shipping_address.*",
"billing_address.*",
"metadata",
"shipping_methods.id",
"shipping_methods.name",
"shipping_methods.shipping_option_id",
],
filters: { id: input.id },
options: { throwIfKeyNotFound: true },
@@ -261,10 +266,16 @@ export const updateOrderWorkflow = createWorkflow(
when("locale-changed", { input, order }, ({ input, order }) => {
return !!input.locale && input.locale !== order.locale
}).then(() => {
updateOrderItemsTranslationsStep({
order_id: input.id,
locale: input.locale!,
})
parallelize(
updateOrderItemsTranslationsStep({
order_id: input.id,
locale: input.locale!,
}),
updateOrderShippingMethodsTranslationsStep({
locale: input.locale!,
shippingMethods: order.shipping_methods,
})
)
})
emitEventStep({