Product identification issues with Shopify i18n (different handles per language break product references)

Topic summary

Core Issue:
Shopify’s i18n system assigns different handle values per language (e.g., /products/red-shoes vs /products/chaussures-rouges), which breaks product identification in email templates and automations. While product/variant IDs remain stable across languages, Liquid templates cannot fetch products by ID—only by handle.

Key Problems:

  • Email notifications receive stable product IDs (gid://shopify/Product/...), but no product_by_id filter exists in Liquid
  • all_products[handle] requires a handle, which changes per language
  • No built-in mapping from product ID to localized handles
  • Cross-language product references become impossible without workarounds

Suggested Workarounds:

  1. Store localized handles in custom metafields (manual but stable)
  2. Use Storefront API/GraphQL via external service (requires custom development)
  3. Force single handle across languages (sacrifices SEO)

Feature Request:
Either add product_by_id filter to Liquid, or provide locale-aware handle access (e.g., product.handles['es'])

Status: Confirmed as a platform gap affecting multi-language stores. No native solution currently exists.

Summarized with AI on October 23. AI used: claude-sonnet-4-5-20250929.

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:

  1. 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.

  2. 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?

Great question and you’ve explained the issue very clearly

You’re absolutely right:
Shopify treats handles as both the URL slug and the internal Liquid identifier, and when each language gets its own handle, the same product behaves like multiple different products from a template logic point of view. This becomes a real limitation in emails, automations, and cross-language linking, where we only have stable product/variant IDs, but Liquid cannot fetch products by ID.

:white_check_mark: You’re not missing anything — currently, Shopify does not offer:

product_by_id

A built-in mapping of ID → localized handles

A way to access handles per locale (like product.handles[‘fr’])

So your feature request makes total sense.

Current workarounds (not ideal, but possible):

:white_check_mark: 1. Store the handle per locale in metafields
Create a metafield with each language’s handle. In email templates, read the metafield based on the desired locale.
→ Manual but stable.

:white_check_mark: 2. Use Storefront API / GraphQL in a function or external service
The API can return id and handle per language.
→ Requires custom function/app, not native to Liquid.

:white_check_mark: 3. Force a single handle across all languages
Works only if you don’t need translated URLs (not SEO-friendly).

I agree with your expectation:

:white_check_mark: Either product_by_id in Liquid
OR
:white_check_mark: An API like product.handle | t: ‘locale’ or product.handles[‘es’]

This feels like a core platform gap.

It impacts:

Email templates

Order notifications

Third-party integrations

Market/language consistency

I’d also love to hear if Shopify can confirm whether this is an intentional design or just a missing feature. Your post is a very strong case for improving i18n + Liquid.

Thanks for raising this a lot of multi-language stores face the same issue!
Appreciate your insight!

Hello @arol

You are 100% correct in your analysis. This is a known and fundamental limitation of Shopify’s architecture, and your frustration is shared by many developers.

The core problem is exactly what you described: email templates can only look up products by their handle, but Shopify Markets creates unique handles for each language. The stable product_id (which you get in the order data) cannot be used by Liquid to fetch a product in that environment.

This is an intentional design stemming from how the email and Markets systems were built separately. As you’ve correctly assumed, there is no clean, native-Liquid workaround for this.

The only solutions are the external setups you’ve already identified:

  1. Populate a JSON metafield on each product with all its localized handles.
  2. Build an external App Proxy to handle the redirects.

Your feature requests for a product_by_id function or a product.handles object in Liquid are exactly what’s needed to fix this. I would strongly encourage you to submit this as formal feedback to Shopify.

Hope this helps!