Skip to main content

How to Integrate i18next with Weaverse Hydrogen

This guide explains how to integrate i18next as the primary translation engine in your Weaverse Hydrogen project. While Weaverse provides a built-in useTranslation() hook for simple { {variable} } substitution, integrating i18next enables advanced localization features like plurals, context-based formatting, and ordinals—without breaking Weaverse’s visual translation workflow!

How It Works

Weaverse’s resolution chain allows you to inject an external translator function into the withWeaverse configuration. When provided, Weaverse evaluates translations in the following priority:
  1. External t (i18next) ← Highest priority
  2. Live design-mode overrides (unsaved edits in the Weaverse Studio editor)
  3. Published merchant overrides (translations saved in Weaverse Studio)
  4. Static theme content (schema.i18n.staticContent)
  5. Raw translation key ← Fallback
By routing translations through i18next first and gracefully falling back to Weaverse if strings aren’t matched, your components enjoy full i18next capabilities while giving non-technical merchants complete control inside the Weaverse builder.

Step 1: Install Dependencies

You only need the core i18next package. React bindings (react-i18next) are optional unless you prefer using its hook directly instead of useTranslation from @weaverse/hydrogen.

Step 2: Create the i18n Bridge

Create a bridge file (e.g., app/utils/i18n.ts) that builds a request-scoped i18next instance and the adapter function expected by Weaverse.
Do not use a module-global i18next singleton and call changeLanguage() from your root loader. Pilot server-renders every request in the same worker isolate (see app/entry.server.tsx), so concurrent requests for different locales would race on shared language state and leak one visitor’s language into another’s HTML. Create or clone an instance per request instead.
On the browser there is only one visitor, so a single client-side instance is fine — the isolation requirement is a server concern. The code above works for both: create the instance once per request on the server, and once per page load on the client.

Step 3: Configure Weaverse at the Root Level

withWeaverse receives a plain translator callback. That callback must not call React hooks. Instead, create one i18next instance for the current render tree, close the translator over that instance, and memoize the wrapped layout:
Each server render gets a separate Layout hook state, so concurrent locales never share an i18next instance. In the browser, the memoized wrapped layout remains stable until the active locale changes. A locale change intentionally creates a new wrapped layout so the translation callback cannot retain the previous locale.
Do not call useContext(), useTranslation(), or any other hook from the translator passed to withWeaverse. The SDK invokes that callback as a plain function, so hooks there violate React’s Rules of Hooks. Also never mutate a module-global i18next instance during SSR.

Step 4: Write Components

Your components don’t need any updates. Standard keys simply fall back to Weaverse, but keys mapped in your i18next bundles using advanced interpolations now resolve correctly! Theme JSON Example:
React Component Example:

Summary Checklist

  • Install i18next.
  • Create an i18n bridge that builds a new instance per request (createInstance()), never a mutated module-global singleton.
  • Return the active storefront locale from the root loader.
  • Memoize a withWeaverse wrapper whose translator closes over that render tree’s instance; never call hooks from the translator callback.
  • Enjoy full i18next pluralization combined with Weaverse’s visual translation integration!