I’m running into what feels like a fundamental inconsistency between Shopify’s i18n system with Translate app and how product identification works across storefront and email contexts.
When enabling multiple languages, Shopify forces a different handle
per language (e.g., /products/red-shoes
→ /products/chaussures-rouges
).
That makes sense for SEO and UX—but the problem is that the handle
is also the identifier used everywhere in Liquid (all_products[handle]
, URLs, etc.).
This means that the same product effectively becomes a different product in each language from a template or automation point of view.
Here’s what that breaks:
-
Email templates and automations:
-
In notifications, we get product and variant IDs (
gid://shopify/Product/...
), which are stable across languages. -
But Liquid has no way to access a product by ID (
product_by_id
doesn’t exist). -
The only option is
all_products[handle]
, which requires a handle—and that handle changes with language.
-
-
Cross-language consistency:
-
If a customer checks out on the French version of the site, I have no way in the email template to link them to the Spanish (or even the original) version of the product, because Liquid can’t resolve another locale’s handle.
-
There’s no built-in mapping from product ID → localized handles.
-
As a result:
-
It’s impossible to safely identify or link products across locales within Shopify’s own templating environment.
-
The stable identifiers (product/variant IDs) can’t be used directly.
-
The localized identifiers (handles) break when switching languages.
Expected behavior (or feature request):
-
Liquid in email templates should allow fetching products by ID (
product_by_id
or similar), or -
Shopify should provide a simple way to access a product’s handles across locales (e.g.,
product.handles['es']
).
Example use case:
I want to include product info or links in an email template using only the product ID and variant ID I have from an order or external system, without relying on a localized handle that changes per market/language.
Right now, this is not possible without custom metafields or an external resolver.
Has anyone found a clean workaround for this, or can Shopify clarify if this design is intentional?