Ensuring Seamless Translations: Handling Custom Service IDs in ESHOPMAN's Headless Architecture

Understanding Translation Challenges with Custom Services in ESHOPMAN

As an e-commerce platform built on Node.js/TypeScript and deeply integrated with HubSpot, ESHOPMAN offers unparalleled flexibility for storefront management and deployment via HubSpot CMS. A key aspect of global e-commerce is robust translation capabilities. However, integrating custom services into this headless architecture can sometimes reveal nuanced challenges, particularly when it comes to how ESHOPMAN's core modules handle data from external sources.

Recently, our community identified an important interaction between ESHOPMAN's translation mechanism and custom services exposed through Remote Query aliases. This insight is crucial for developers leveraging ESHOPMAN's Admin API and extending its functionality with bespoke solutions.

The Core Issue: ID Type Mismatch During Translation

The challenge arises when ESHOPMAN's translation module attempts to apply translations to entities that include data from a custom service alias. Consider a scenario where you have a custom CMS service, perhaps managing rich content or meta descriptions, integrated into your ESHOPMAN setup. This service might be exposed via a Remote Query alias, allowing you to fetch its data alongside your core ESHOPMAN entities, like products.

Here's how such an alias might be configured:

__joinerConfig(): ModuleJoinerConfig {
    return {
        serviceName: "cmsModuleService",
        primaryKeys: ["id"],
        linkableKeys: {},
        alias: [
            {
                name: "cms",
            },
        ],
    }
}

When you query ESHOPMAN products and specifically request fields from this aliased CMS service, such as its ID or meta description:

GET /store/products?fields=id,handle,+cms.id,+cms.meta_description

The expected result would correctly combine the ESHOPMAN product ID (typically a string) with the CMS entity's ID (which might be a numeric value):

{
  "id": "prod_01KCPERVWF7A5K4E9TW4WECBJ6",
  "cms": {
    "id": 770,
    "meta_description": "..."
  }
}

The problem emerges when ESHOPMAN's internal applyTranslations logic, responsible for fetching localized content, processes this combined data. This function recursively collects every nested id property from the entire result tree. It doesn't distinguish between IDs belonging to core ESHOPMAN entities (which are typically string-based and managed by the Translation Module) and IDs returned by external alias services (which might be numeric and not intended for translation by ESHOPMAN).

Consequently, the translation query ends up attempting to match mixed ID types against the translation.reference_id column in the database:

where "reference_id" in (
  770,
  'prod_01KCPERVWF7A5K4E9TW4WECBJ6'
)

The Impact: Database Query Failures

Since the translation.reference_id column is designed to store text-based IDs, attempting to query it with a mix of numeric and string values leads to a PostgreSQL error:

operator does not exist: text = integer

This error prevents the product query from completing successfully, disrupting the display of product information on your HubSpot CMS storefront when translations are active and custom service IDs are requested.

Expected Behavior vs. Actual Behavior

  • Expected: The applyTranslations function should intelligently ignore IDs from alias services that are not part of ESHOPMAN's core translatable entities. Only IDs belonging to entities directly managed by the ESHOPMAN Translation Module should be collected and used for translation lookups. The product query should return successfully, preserving the numeric CMS ID without attempting to translate it.
  • Actual: The current implementation recursively collects all properties named id from the entire result set, leading to the type mismatch and database error.

Workaround for Developers

Until a core platform update addresses this behavior, developers can implement a temporary workaround: if you are experiencing this issue and require translations, avoid requesting the cms.id or other aliased service IDs directly in your ESHOPMAN queries when the locale parameter is active. Removing these specific fields from your requested query parameters allows the product query to execute correctly and retrieve translations without error.

For example, instead of:

GET /store/products?fields=id,handle,+cms.id,+cms.meta_description

You might need to query:

GET /store/products?fields=id,handle,+cms.meta_description

and fetch the cms.id through a separate, non-translated query if absolutely necessary, or ensure your custom CMS service provides a string-based ID if it's intended to be linked directly to ESHOPMAN's translation logic.

Conclusion

This community insight highlights the importance of understanding how different modules within ESHOPMAN interact, especially when extending its capabilities with custom services. While ESHOPMAN provides a powerful foundation for headless commerce on HubSpot, awareness of such nuances helps developers build more robust and error-free storefronts. The ESHOPMAN team is continuously working to refine these interactions, ensuring a seamless experience for all users and developers.

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools