Frequently Asked Questions

Internationalization & Localization with Next.js and Hygraph

How can I internationalize my Next.js app using Hygraph and next-intl?

You can internationalize your Next.js app by integrating the next-intl library, which supports interpolation, pluralization, and locale-based routing. Hygraph enables you to manage and retrieve localized content by localizing fields in your schema and updating content for each locale. You can then query localized content using GraphQL and display it in your Next.js app based on the user's selected language. For a step-by-step guide, see this tutorial.

How do I manage and retrieve localized content from Hygraph?

To manage localized content in Hygraph, edit your schema fields and enable the "Localize field" option. Add your desired languages in Project Settings > Locales, then update content for each locale. You can retrieve localized content using GraphQL queries with the locales parameter, ensuring your Next.js app displays the correct language version. See Hygraph's localization documentation for details.

What translation management systems does Hygraph integrate with?

Hygraph offers out-of-the-box integrations with four translation management systems (TMS): Smartling, Lokalise, EasyTranslate, and Crowdin. Each integration comes with a setup guide for seamless connection to your localization workflow.

Features & Capabilities

What are the key features of Hygraph?

Hygraph is a GraphQL-native Headless CMS with features including Smart Edge Cache for fast content delivery, Content Federation to integrate data from multiple sources, advanced Rich Text management, custom roles for granular access control, project backups, and robust APIs. It supports seamless integration with eCommerce, localization, and other systems, and is SOC 2 Type 2, ISO 27001, and GDPR compliant. Learn more about Hygraph features.

Does Hygraph support integration with other platforms?

Yes, Hygraph supports integrations with digital asset management systems (Aprimo, AWS S3, Bynder, Cloudinary, Mux, Scaleflex Filerobot), hosting platforms (Netlify, Vercel), eCommerce solutions (BigCommerce, commercetools, Shopify), localization tools (Lokalise, Crowdin, EasyTranslate, Smartling), personalization and AB testing (Ninetailed), AI tools (AltText.ai), and more. See the full list in the Hygraph Integrations Documentation.

Does Hygraph provide APIs for content management?

Yes, Hygraph provides GraphQL Content API for querying and managing content, GraphQL Management API for schema changes, and REST APIs for connecting with external systems. Developers can access and manage content programmatically, with options for public exposure and selective permissions. Explore the Hygraph Documentation for API details.

Use Cases & Benefits

Who can benefit from using Hygraph?

Hygraph is designed for developers, IT decision-makers, content creators, project managers, agencies, and technology partners. It is valuable for modern software companies, enterprises seeking to modernize, brands scaling across geographies, and organizations re-platforming from legacy solutions. Hygraph is ideal for managing content across multiple channels and delivering exceptional digital experiences. See use cases.

What business impact can customers expect from using Hygraph?

Customers report significant business impacts, including up to 3X faster time-to-market (Komax), 20% increase in website monetization (AutoWeb), 15% higher customer engagement (Samsung), 7X higher content velocity, 125% traffic growth, and scalability across 40+ global markets. These outcomes are supported by real case studies: Hygraph Case Studies.

What industries are represented in Hygraph's customer case studies?

Hygraph's case studies span industries including eCommerce, automotive, healthcare, consumer electronics, media and publishing, food and beverage, travel and hospitality, engineering, government, and SaaS. Explore detailed stories on the Hygraph Case Studies Page.

Can you share specific customer success stories using Hygraph?

Yes. For example, Komax achieved 3X faster time-to-market and managed 20,000+ product variations across 40+ markets. Samsung saw a 15% increase in customer engagement. Sennheiser migrated to a MACH-compliant headless commerce solution, resulting in a 136.7% increase in e-commerce conversions within 4 months. Stobag improved online revenue share from 15% to 70%. See more at Hygraph Case Studies.

Technical Requirements & Implementation

How easy is it to implement Hygraph and get started?

Hygraph is recognized as the #1 easiest to implement headless CMS. For example, Top Villas launched a new project in just 2 months. The platform is intuitive for both developers and non-technical users, with a logical UI and free API playground. Structured onboarding includes introduction calls, account provisioning, and kickoff sessions. Start for free with a developer account or request an enterprise demo. See onboarding details.

What resources do I need to get started with Hygraph?

To get started, you need a Hygraph account (free for developers), basic GraphQL knowledge (optional), and for developers, tools like a code editor, Node.js, and a hosting platform (e.g., Netlify). Hygraph provides extensive documentation, tutorials, and 24/7 support. See the Getting Started tutorial.

What technical documentation is available for Hygraph?

Hygraph offers comprehensive documentation, including API references, guides for content workflows, webhooks, and interactive API playgrounds. Visit the Hygraph Documentation Page for all technical resources.

Support & Training

What customer support and training does Hygraph offer?

Hygraph provides 24/7 support via chat, email, and phone. Enterprise customers receive SLAs with critical issue resolution in less than an hour and a dedicated Customer Success Manager. Structured onboarding, training resources (webinars, live streams), and a community Slack channel are available. Extensive documentation and Intercom chat support are also provided. See support details.

How does Hygraph handle maintenance, upgrades, and troubleshooting?

Hygraph's cloud-based infrastructure handles all maintenance, server updates, and security patches. Upgrades are automatic, and troubleshooting is supported by audit logs, monitoring, and performance reporting. Customers have access to 24/7 support, SLAs, documentation, and community resources for efficient issue resolution. Learn more.

Security & Compliance

What security and compliance certifications does Hygraph have?

Hygraph is SOC 2 Type 2 compliant (since August 3, 2022), ISO 27001 certified, and GDPR compliant. Security features include granular permissions, audit logs, encryption at rest and in transit, SSO integrations, and automatic backups. Enterprise-grade compliance is supported with dedicated hosting, custom SLAs, and security certifications. See the Hygraph Security Report for details.

Product Performance

What should I know about Hygraph's product performance?

Hygraph delivers high-performance endpoints with state-of-the-art caching and robust edge services, ensuring low latency and high read-throughput. Content delivery is optimized for rapid distribution, improving user experience and engagement. Customers have reported 7X higher content velocity, 125% traffic growth, and support for 40+ global markets. Learn more about performance.

Customer Proof

Who are some of Hygraph's customers?

Hygraph is trusted by leading brands such as Sennheiser, HolidayCheck, Ancestry, JDE, Dr. Oetker, Ashley Furniture, Lindex, Hairhouse, Komax, Shure, Stobag, Burrow, G2I, Epic Games, Bandai Namco, Gamescom, Leo Vegas, Codecentric, Voi, and Clayton Homes. See more customer stories and logos at Hygraph Case Studies.

Customer Experience & Ease of Use

What do customers say about the ease of use of Hygraph?

Customers consistently praise Hygraph for its intuitive user interface, logical CMS structure, and accessibility for non-technical users. The editor UI is described as clear and easy to use after initial setup, with streamlined workflows and customization features. Both technical and non-technical teams find Hygraph user-friendly, making it a preferred choice for efficient content management. Read more customer feedback.

Pain Points & Solutions

What problems does Hygraph solve for its customers?

Hygraph addresses operational inefficiencies (removing developer bottlenecks, improving workflows), financial challenges (reducing costs, accelerating speed-to-market), and technical issues (simplifying schema evolution, cache management, and integration with multiple GraphQL endpoints). It helps unify APIs, improve editorial autonomy, and scale content operations. Learn more about solutions.

Meet Hygraph AI Agents - Your Autonomous Teammates

How to Internationalize your Next.js app with next-intl in App Router

In this guide, we’ll walk you through how to set up internationalization into your Next.js application utilizing the next-intl library, demonstrate how to configure static localized content through and manage and retrieve localized content from Hygraph.
Joel Olawanle

Written by Joel 

Mar 08, 2024
Mobile image

#Prerequisites

To follow along with this guide and code, you should have the following:

  • Basic understanding of HTML, CSS, and JavaScript
  • At least a little experience or knowledge of Next.js
  • Node and npm or yarn installed on your local computer

#Leveraging next-intl for Next.js internationalization

Next.js offers robust support for internationalization through its built-in i18n routing. This feature is designed to work well with i18n libraries, among which next-intl stands out as it covers a range of functionalities, including interpolation, pluralization, and handling arrays.

It is fully compatible with the Pages Router of Next.js (up to version 12) and the App Router introduced in version 13, which includes support for React server components.

Getting started with next-intl

To integrate next-intl into your Next.js project, start by installing the library with the following command:

npm install next-intl

Once installed, next-intl integrates with the App Router using a [locale] dynamic segment.

#Setting up your Next.js project for internationalization

Organize your project directory by creating a [locale] directory within the /app folder and adding all files to the folder. For example, this is a simple Next.js application structure with three pages moved into the [locale] folder:

|-- /app
|-- /[locale]
|-- /about
|-- page.js
|-- /blog
|-- /[postId]
|-- page.js
|-- page.js
|-- /components
|-- features.js
|-- hero.js
|-- navbar.js
|-- layout.js
|-- page.js

Next, proceed with the following configuration steps:

1. Localizing messages

Depending on your workflow preference, you can store messages locally or fetch them from a remote source, such as a translation management system.

At the root of your project, create a messages folder where you can create JSON files for each locale, such as messages/en.json:

{
"Home": {
"Hero": {
"Title": "Next.js Internalization Demo",
"Subtitle": "This demo uses Next.js and the next-intl package to create a multi-language website. We later also explore how it works with Hygraph.",
"CallToAction": "Read about us"
}
}
}

This file is organized with keys referencing each value, which simplifies locating, updating, and collaborating on content. For instance, all content related to the Home page is grouped under the Home object. Within this object, further categorization can be done for different sections, such as the Hero section and the Features section.

Also, create a messages/fr.json for the French version:

{
"Home": {
"Hero": {
"Title": "Démonstration de l'internationalisation avec Next.js",
"Subtitle": "Cette démo utilise Next.js et le package next-intl pour créer un site web multilingue. Nous explorons également son fonctionnement avec Hygraph.",
"CallToAction": "Lisez à propos de nous"
}
}
}

Always ensure the keys are the same across all files, as that is what will be used to render the text.

2. Configuring Next.js

Set up a plugin to alias your i18n configuration to Server Components by updating your next.config.mjs if you're utilizing ECMAScript modules:

import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default withNextIntl(nextConfig);

3. Defining locale-specific configurations

next-intl allows for a per-request configuration setup. In src/i18n.js, specify messages and other options based on the user's locale:

For this project, only English and French will be used. You can add more locales.

import { notFound } from 'next/navigation';
import { getRequestConfig } from 'next-intl/server';
// Can be imported from a shared config
const locales = ['en', 'fr'];
export default getRequestConfig(async ({ locale }) => {
// Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale)) notFound();
return {
messages: (await import(`../messages/${locale}.json`)).default,
};
});

4. Implementing middleware for locale matching

Use middleware in src/middleware.js to match the request's locale and manage redirects and rewrites:

import createMiddleware from 'next-intl/middleware';
export default createMiddleware({
// A list of all locales that are supported
locales: ['en', 'fr'],
// Used when no locale matches
defaultLocale: 'en',
});
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(fr|en)/:path*'],
};

5. Setting the document language

In app/[locale]/layout.tsx, utilize the matched locale to set the document language:

export default function RootLayout({ children, params: { locale } }) {
return (
<html lang={locale}>
<body className={inter.className}>
<div className="max-w-6xl mx-auto">
<Navbar />
{children}
</div>
</body>
</html>
);
}

With all these done, you can now incorporate translations within your page components or elsewhere in your project.

#Translating plain text

Having set up next-intl in your Next.js project, activating internationalization involves using the t() method, a function provided by next-intl for fetching translated strings. This method is accessed through the useTranslations hook, which you can import directly from the next-intl library.

To illustrate, let's integrate translation capabilities into the hero component of the sample application, typically located at components/hero.js:

import { useTranslations } from 'next-intl';
const Hero = () => {
const t = useTranslations('Home.Hero');
return (
<div className="w-3/4 mx-auto py-32 text-center">
<h1 className="text-6xl font-bold">{t('Title')}</h1>
<p className="pt-8 text-xl">{t('Subtitle')}</p>
<a
href="/about"
className="px-4 py-4 mt-6 bg-blue-500 text-white rounded inline-block"
>
{t('CallToAction')}
</a>
</div>
);
};
export default Hero;

This approach utilizes a key to retrieve the corresponding value. For example, navigating to http://localhost:3000/en displays the English version of the Hero section, while http://localhost:3000/fr shows its French counterpart.

Side-by-side comparison of a Next.js Internationalization demo showing the Hero section in English and French

#Interpolation and pluralization

Interpolation is a technique for inserting dynamic values into predefined text. It's beneficial for creating adaptable messages that may vary based on user input or other variables. A common use case is greeting users by name:

"message": "Hello {name}!"

By replacing {name} with a dynamic value, the message becomes personalized:

t('message', {name: 'Jane'});

Resulting in:

"Hello Jane!"

Cardinal pluralization

This addresses the need to format messages differently based on numerical values, especially to distinguish between singular and plural forms. A classic example involves indicating the number of followers:

"message": "You have {count, plural, =0 {no followers yet} =1 {one follower} other {# followers}}."

This setup allows for different messages based on the value of count. For instance:

  • If count is 0, the message is: "You have no followers yet."
  • If count is 1, the message is: "You have one follower."
  • For any other number, say 3580, the message is: "You have 3,580 followers."

The # symbol is used to represent the actual number, formatted appropriately.

Ordinal pluralization

Ordinal pluralization is similar to cardinal pluralization but is used for ordering rather than quantity. It helps in formatting messages that relate to ranks or positions.

"message": "It's your {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} birthday!"

This message would allow for a correct ordinal suffix to be applied based on the year value:

  • 1st, 2nd, 3rd (special cases for one, two, and few in English)
  • 4th, 5th, ... 21st, 22nd, ... (using other for all other numbers)

#Date/time translations

next-intl offers a comprehensive solution to the complex challenge of internationalizing date and time formats, accommodating the diverse preferences found across global locales. Since date formats can vary widely from region to region, adopting a flexible approach to date and time representation in international applications is crucial.

The next-intl library leverages the ICU (International Components for Unicode) syntax to simplify incorporating dates and times within localization files. This syntax allows for directly embedding dynamic date formats into your messages, utilizing placeholders for dates, thus streamlining the internationalization process.

Here's an example in an English localization file (en.json), demonstrating the use of a placeholder for the current date in a short format:

// en.json
{
"todayDate": "Today's date is {currentDate, date, short}."
}

next-intl supports predefined date formats such as short, full, long, and medium. It also allows defining custom date formats using “date skeletons". For instance, to display a date in a specific custom format, you could specify it in your localization file like so:

// en.json
{
"todayDate": "Today's date is {currentDate, date, ::yyyyMd}."
}

The :: prefix signifies the use of a custom skeleton format, granting developers precise control over how dates are presented. The next-intl documentation offers a detailed guide on the available formats and skeletons.

To integrate a date within a Next.js page or component, the t() function is utilized:

<p>{t('todayDate', { currentDate: new Date() })}</p>

By supplying the current date to this method, next-intl dynamically renders the date in the format appropriate to the user's locale. For example, an English locale might display as "Today's date is 2/25/24," whereas in a French locale, it would appear as "La date d'aujourd'hui est 25/02/24."

Furthermore, next-intl facilitates custom date formats within messages, allowing developers to define formatters based on DateTimeFormat options. These custom formatters can be named and utilized throughout your application:

<p>
{t(
'todayDate',
{ currentDate: new Date() },
{
dateTime: {
short: {
day: 'numeric',
month: 'short',
year: 'numeric',
},
},
}
)}
</p>

#Switching languages with App Router using next-intl

next-intl provides drop-in replacements for common Next.js navigation APIs that automatically handle the user locale behind the scenes. There are two strategies to achieving this, but the straightforward method is using shared pathnames.

With this strategy, the pathnames of your app are identical for all locales. This is the simplest case, because the routes you define in Next.js will map directly to the pathnames a user can request.

To create navigation APIs for this strategy, use the createSharedPathnamesNavigation function. Create a navigation.js in your src folder and add the following:

import { createSharedPathnamesNavigation } from 'next-intl/navigation';
export const locales = ['en', 'es', 'fr'];
export const localePrefix = 'always'; // Default
export const { Link, redirect, usePathname, useRouter } =
createSharedPathnamesNavigation({ locales, localePrefix });

This setup specifies your locales and a locale prefix, which should match the configuration passed to your middleware for consistency.

Adjust your middleware file accordingly to ensure alignment with the navigation setup:

import createMiddleware from 'next-intl/middleware';
import { locales, localePrefix } from './navigation';
export default createMiddleware({
// A list of all locales that are supported
locales,
localePrefix,
// Used when no locale matches
defaultLocale: 'en',
});
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(fr|es|en)/:path*'],
};

With this configuration, you gain access to routing components and methods like Link and usePathname, enabling intuitive navigation within your Next.js project.

Next, you can incorporate language switch functionality in your Navbar or any page you wish by attaching the pathname to the href property and a locale. For example, here is a navbar.js component:

'use client';
import { Link } from '@/navigation';
import { usePathname } from '@/navigation';
const NavLinks = [
{ id: 1, name: 'Home', path: '/' },
{ id: 1, name: 'About', path: '/about' },
{ id: 2, name: 'Blog', path: '/blog' },
];
const Navbar = () => {
const pathname = usePathname();
const isActive = (path) => path === pathname;
return (
<nav className="w-full flex justify-between items-center h-32">
<div className="logo">
<Link href="/">
<p className="text-2xl font-bold">
Next<span className="text-blue-500">Intl</span>
</p>
</Link>
</div>
<ul className="flex space-x-10">
{NavLinks.map((link) => {
return (
<li key={link.id}>
<Link
href={link.path}
className={
isActive(link.path)
? 'underline decoration-blue-500 decoration-4'
: ''
}
>
{link.name}
</Link>
</li>
);
})}
</ul>
<div className="flex space-x-10">
<Link href={pathname} locale="en">
🏴󠁧󠁢󠁥󠁮󠁧󠁿 English
</Link>
<Link href={pathname} locale="fr">
🇫🇷 Français
</Link>
</div>
</nav>
);
};
export default Navbar;

Link and usePathname are imported from the naviagtion.js file in the above code. Also, you can handle switching between different languages by attaching the pathname to the href property and a locale.

#Using a CMS to manage locales

For this guide, let’s use an existing project, aiming to localize it and integrate its content with a Next.js application. Begin by duplicating a simple blog project in the Hygraph marketplace. This action will replicate the schema and all its content, a process that may take a few moments. Once completed, the next step involves localizing the fields.

Navigate to the schema editor through the schema section. This interface allows adding, editing, or deleting fields and establishing model relationships. To localize a field, hover over it, select Edit field, check the Localize field option, and update. Repeat this process for all fields you wish to localize.

Navigating to the 'Post' content model in the Hygraph Schema editor to configure fields for localization

Subsequently, add the languages of your choice by accessing Project Settings > Locales.

Adding new languages to a Hygraph project via 'Project Settings' > 'Locales' for content localization

With languages configured, proceed to Content to update existing content with the localized versions. Enable the localization fields by clicking the eye icon next to the locale.

Hygraph content editor showing a localized 'Post' with English and French fields enabled for translation

After publishing the posts, you are ready to consume them into your Next.js application.

#Integrating localized content into Next.js with GraphQL

In Next.js, you can query GraphQL content with the @apollo/client library. Install the library by running the following command in your project directory:

npm i @apollo/client

For this Next.js project, you configured internationalization routing with the next-intl library. Alternatively, you can configure internationalization without the next-intl library since Next.js has inbuilt internalization routing configurations.

With the internalization routing already set up, you have access to the locales parameter, which would be used to query the content.

Hygraph has an API playground to create and test GraphQL queries.

Hygraph API Playground showing a GraphQL query to fetch localized 'Post' content in French (fr) for the Next.js project

Once your queries are working, you can use them in the Next.js project. Before you make the request, retrieve the high performance c**ontent API, which gives you access to the Hygraph content. You can get this from the Project settings > Endpoints** page.

Hygraph Project settings showing the 'High Performance Content API' endpoint required for the Next.js application

Next, implement this in the Blog page of the sample application (blog/page.js). Here is an example where the list of all posts from the Hygraph project is fetched into Next.js:

import Link from 'next/link';
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
async function getPosts(locale) {
const client = new ApolloClient({
uri: 'https://sa-east-1.cdn.hygraph.com/content/clt1kvvhp000008jt7siz2lui/master',
cache: new InMemoryCache(),
});
const data = await client.query({
query: gql`
query PostsQuery {
posts(locales: [${locale}]) {
id
title
slug
excerpt
}
}
`,
});
return data.data.posts;
}
const page = async ({ params }) => {
const { locale } = params;
const posts = await getPosts(locale);
return (
<div className="py-10 w-3/4 mx-auto">
<h2 className="text-3xl pb-10 font-bold">Blog</h2>
<div className="flex flex-col space-y-5 text-black">
{posts &&
posts.map((post) => (
<Link href={`/${locale}/blog/${post.slug}`} key={post.id}>
<div className="bg-gray-300 p-6 rounded">
<h3 className="text-xl font-bold mb-2">{post.title}</h3>
<p>{post.excerpt}</p>
</div>
</Link>
))}
</div>
</div>
);
};
export default page;

In the code above, the getPosts function is defined to fetch posts from Hygraph for a specific locale. This function utilizes the ApolloClient from @apollo/client, configured with Hygraph's API endpoint and an in-memory cache for efficient data management. The GraphQL query within this function requests posts for the specified locale, retrieving their id, title, slug, and excerpt.

The query is dynamically constructed to include the locale parameter, allowing for retrieving localized content based on the user's language preference. This is crucial for delivering a localized user experience, as content is fetched and displayed according to the user's selected language.

Fetching dynamic posts

Similarly, dynamic posts can be fetched and displayed on individual blog pages (blog/[slug]/page.js) using a comparable approach:

import Image from 'next/image';
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
async function getPost(locale, slug) {
const client = new ApolloClient({
uri: 'https://sa-east-1.cdn.hygraph.com/content/clt1kvvhp000008jt7siz2lui/master',
cache: new InMemoryCache(),
});
const { data } = await client.query({
query: gql`
query PostQuery {
post(
where: { slug: "${slug}" }
locales: [${locale}]
) {
id
slug
title
content {
html
}
coverImage {
url
}
}
}
`,
});
return data.post;
}
const page = async ({ params }) => {
const { locale, slug } = params;
const post = await getPost(locale, slug);
return (
<div className="py-10 w-3/4 mx-auto">
<h2 className="text-3xl pb-10 font-bold">{post.title}</h2>
<div>
<div className="">
<Image
src="/about.jpeg"
width={1200}
height={200}
style={{
objectFit: 'cover',
height: '300px',
width: '100%',
}}
sizes="(max-width: 768px) 100vw, 33vw"
alt="Picture of the author"
className="rounded"
/>
</div>
<div className="pt-10">
<div
dangerouslySetInnerHTML={{
__html: post.content.html,
}}
/>
</div>
</div>
</div>
);
};
export default page;

You can find the complete code on GitHub.

#[Optional] Extending Hygraph with a Translation Management System

If your company is using a translation management system, Hygraph offers out-of-the-box integrations with 4 TMSs:

#Conclusion

This guide has walked you through leveraging the next-intl library and Hygraph with Next.js for effective internationalization and localization of a web application.

Following these steps ensures your application reaches a wider audience and provides a more inclusive and user-friendly experience across diverse languages and cultures.

Blog Author

Joel Olawanle

Joel Olawanle

Joel Olawanle is a Frontend Engineer and Technical writer based in Nigeria who is interested in making the web accessible to everyone by always looking for ways to give back to the tech community. He has a love for community building and open source.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.