Better Localization in Sitecore XM Cloud: Custom useTranslations Hook for Next.js

A Scalable and safe way to handle localization in enterprise Next.js , Sitecore XM Cloud projects.

June 27, 2025

By Sohrab Saboori

Better Localization in Sitecore XM Cloud: Custom useTranslations Hook for Next.js

Continuing our series on custom hooks for Sitecore XM Cloud with Next.js, this post introduces an optimized solution for handling localization: the useTranslations hook.

This centralized, modular, and resilient approach simplifies how your application manages dictionary items, ensuring consistency and fallback safety across the app.

๐Ÿ“Œ This is an improved version of the pattern first introduced in our blog:

Custom Hooks for Next.js in Sitecore XM Cloud

Why We Built useTranslations

In a large-scale Sitecore XM Cloud project, managing dictionary items can quickly become messy โ€” especially when translations are used across many components and features.

Instead of scattering useI18n() and raw keys throughout the app, this custom hook provides:

  • โœ… A centralized translation structure
  • โœ… Fallback values to prevent blank or broken UI
  • โœ… A modular file structure that scales with the app
  • โœ… Cleaner, more readable component code

Organized File Structure

To keep things scalable and developer-friendly, the useTranslations hook lives inside the /hooks folder, with all translation logic organized under a /translations subfolder.

Translations are grouped by domain (e.g., basic UI, billing, meter reads) into separate modules. Each file exports functions like getBasicTranslations or getBillingTranslations, which return a set of localized strings.

/hooks/
โ”œโ”€โ”€ useTranslations.ts
โ””โ”€โ”€ translations/
    โ”œโ”€โ”€ basicTranslations.ts
    โ”œโ”€โ”€ billingTranslations.ts
    โ”œโ”€โ”€ complexTranslations.ts
    โ””โ”€โ”€ profileTranslations.ts

This modular structure ensures better maintainability and keeps related translations together as the app scales.

Built-In Fallbacks

Each translation key in your app is accessed through a helper function that includes a default fallback value:

// Helper function to get translation with fallback
const getTranslation = (i18n: I18nInstance, key: string, fallback: string): string => {
  return i18n?.t?.(key) ? i18n.t(key) : fallback;
};

This ensures that even if the Sitecore dictionary hasn't loaded โ€” or the key is missing โ€” the app still displays meaningful text to users.

This fallback logic is used inside each translation module you saw in the Organized File Structure section.

Each file exports functions like:

// basicTranslations.ts
export const getBasicTranslations = (i18n) => ({
  save: getTranslation(i18n, 'save', 'Save'),
  cancel: getTranslation(i18n, 'cancel', 'Cancel'),
  continue: getTranslation(i18n, 'continue', 'Continue'),
});

Bringing It All Together in useTranslations.ts

Inside useTranslations.ts, we import all grouped translation functions and return a single merged object. This allows consumers to access all translations in one place:

import { useI18n } from 'next-localization';

import { getBasicTranslations } from './translations/basicTranslations';
import { getBillingTranslations } from './translations/billingTranslations';
import { getComplexTranslations } from './translations/complexTranslations';
import { getProfileTranslations } from './translations/profileTranslations';

export function useTranslations() {
  const i18n = useI18n();

  return {
    ...getBasicTranslations(i18n),
    ...getBillingTranslations(i18n),
    ...getComplexTranslations(i18n),
    ...getProfileTranslations(i18n),
  };
}

How to Use It

You can use the hook in two simple ways depending on your style preference:

Option 1: Destructure only what you need

const { save, cancel, loading } = useTranslations();

Option 2: Keep the full object

const translations = useTranslations();
<button>{translations.save}</button>

Both styles work great and are type-safe if you're using TypeScript with shared dictionary types.

Why It Matters

  • โœ… Always shows fallback values โ€” even offline
  • โœ… Keeps dictionary key access consistent
  • โœ… Eliminates typos and missing key errors
  • โœ… Keeps component logic clean and translation-agnostic

Is It Memory Safe?

Yes โ€” the useTranslations hook is fully memory-safe and well-suited for Sitecore XM Cloud projects.

The hook simply merges and returns localized strings using the current i18n context from next-localization. It contains no side effects or persistent memory references.

Hereโ€™s why itโ€™s safe:

  • โŒ No event listeners โ€” nothing is attached to global events or the DOM
  • โŒ No subscriptions โ€” it doesnโ€™t subscribe to any data streams or observers
  • โŒ No retained references โ€” translation objects are regenerated per render and not stored between pages

Specific to Sitecore XM Cloud

In Sitecore XM Cloud, dictionary items are delivered via the Layout Service and injected into the i18n context per page request. Each page loads fresh dictionary data through layoutData.sitecore.dictionary, so:

  • There's no client-side memory retention of previous translations
  • The hook always uses the most current data for each page
  • Memory usage remains lightweight and predictable

This makes useTranslations safe to use across multiple components, routes, and renders โ€” even in large-scale, enterprise-grade apps built with Sitecore XM Cloud and Next.js.

Bonus: Parsing Dictionary Markup

Sometimes, you need to support lightweight HTML markup in dictionary items โ€” such as:

  • <b> for bold text
  • <br> for line breaks
  • Placeholder tokens for dynamic values

In these cases, you can pair the useTranslations hook with our custom parser utility, which safely parses and renders HTML within localized strings.

๐Ÿ‘‰ Formatting Dictionary Items in Sitecore XM Cloud Headless with a Custom Dictionary Text Parser

This approach is ideal for rendering rich text in tooltips, modals, error messages, or descriptions that require flexible formatting.

Final Thoughts on Centralized Localization with useTranslations in Sitecore XM Cloud

The useTranslations hook is a clean, scalable, and production-ready approach to managing localization in Sitecore XM Cloud with Next.js.

By centralizing dictionary access, modularizing translation files, and adding built-in fallback support, it simplifies how translations are used throughout your app โ€” without sacrificing performance or maintainability.

  • โœ… Centralized and consistent usage of translation keys
  • โœ… Safe fallback handling to avoid blank or broken UI
  • โœ… Modular structure that scales with growing feature sets
  • โœ… Fully memory-safe and compatible with Sitecoreโ€™s page-level data model
  • โœ… Easily extendable with markup parsing when richer content is needed

If you're already using the pattern introduced in our earlier Custom Hooks for Next.js in Sitecore XM Cloud blog, this version is a solid evolution โ€” offering better structure, safety, and flexibility.

Photo of Fishtank employee Sohrab Saboori

Sohrab Saboori

Senior Full-Stack Developer

Sohrab is a Senior Front-End Developer with extensive experience in React, Next.js, JavaScript, and TypeScript. Sohrab is committed to delivering outstanding digital solutions that not only meet but exceed clients' expectations. His expertise in building scalable and efficient web applications, responsive websites, and e-commerce platforms is unparalleled. Sohrab has a keen eye for detail and a passion for creating seamless user experiences. He is a problem-solver at heart and enjoys working with clients to find innovative solutions to their digital needs. When he's not coding, you can find him lifting weights at the gym, pounding the pavement on the run, exploring the great outdoors, or trying new restaurants and cuisines. Sohrab believes in a healthy and balanced lifestyle and finds that these activities help fuel his creativity and problem-solving skills.