Add Internationalization to Next.js Without Rebuilding Routes
Published on SiteLocaleAI Blog
Internationalization (i18n) is a must‑have for any site that wants to reach a global audience, but rebuilding your routing structure can be a nightmare—especially in a Next.js app that already has dynamic routes, API endpoints, and static generation. SiteLocaleAI solves this problem with a drop‑in JavaScript library that works on any framework, is self‑hosted, and lets you keep your existing routes intact.
In this tutorial we’ll:
1. Install the SiteLocaleAI library.
2. Configure it to use your own LLM API key (Claude, GPT‑4o‑mini, etc.).
3. Hook the library into Next.js’s getStaticProps/getServerSideProps for SEO‑friendly pre‑rendering.
4. Localize prices with psychological rounding.
5. Add a simple language selector that works without touching the router.
Why SiteLocaleAI?
* Framework‑agnostic – works with React, Vue, WordPress, Shopify, and plain HTML.
* Self‑hosted – you keep your LLM API keys, no third‑party data leakage.
* SEO‑ready – a CLI can pre‑render translated pages for search‑engine indexing.
* Price rounding – automatically applies locale‑specific psychological pricing (e.g., €9.99 → €9.95).
1. Install the Library
First, add the npm package to your Next.js project:
npm install @sitelocaleai/js
# or with Yarn
yarn add @sitelocaleai/js
The package is just a thin wrapper around a fetch‑based client, so it adds virtually no bundle size.
2. Set Up Your LLM API Key
Create a .env.local file (or use your existing secret manager) and add your LLM key:
NEXT_PUBLIC_LOCALEAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_LOCALEAI_PROVIDER=claude-3-sonnet-20240229 # or gpt-4o-mini
SiteLocaleAI reads these variables at runtime, so you never have to hard‑code credentials.
3. Wrap Your Pages with the Translator
SiteLocaleAI provides a translatePage helper that can be used inside getStaticProps or getServerSideProps. Below is a minimal example for a product page that already uses dynamic routing (pages/products/[id].js).
// pages/products/[id].js
import { translatePage } from '@sitelocaleai/js';
import { getProductById } from '../../lib/api';
export async function getStaticProps({ params, locale }) {
const product = await getProductById(params.id);
// The `locale` param is optional – if omitted, SiteLocaleAI will detect the visitor's language.
const translated = await translatePage({
content: {
title: product.title,
description: product.description,
price: product.price,
},
targetLocale: locale || 'en', // fallback to English
priceLocale: locale, // enables psychological rounding
apiKey: process.env.NEXT_PUBLIC_LOCALEAI_API_KEY,
provider: process.env.NEXT_PUBLIC_LOCALEAI_PROVIDER,
});
return {
props: {
product: {
...product,
title: translated.title,
description: translated.description,
price: translated.price,
},
},
revalidate: 86400, // refresh once a day
};
}
export async function getStaticPaths() {
const ids = await getAllProductIds();
return {
paths: ids.map(id => ({ params: { id } })),
fallback: 'blocking',
};
}
export default function ProductPage({ product }) {
return (
<article>
<h1>{product.title}</h1>
<p>{product.description}</p>
<p className="price">{product.price}</p>
</article>
);
}
What’s happening?
- translatePage sends the original strings to your chosen LLM.
- The LLM returns a translated version and a price that’s been rounded according to the target currency’s psychological norms (e.g., $9.99 → $9.95).
- Because the translation occurs during static generation, the final HTML is fully localized, which is perfect for crawlers.
4. Language Selector Without Changing Routes
Instead of creating separate /en, /fr, etc., routes, you can store the user’s language choice in a cookie and let SiteLocaleAI read it on the next request.
// components/LanguageSwitcher.tsx
import { useRouter } from 'next/router';
import Cookies from 'js-cookie';
const LANGUAGES = [
{ code: 'en', label: 'English' },
{ code: 'fr', label: 'Français' },
{ code: 'de', label: 'Deutsch' },
];
export default function LanguageSwitcher() {
const router = useRouter();
const changeLang = (code: string) => {
Cookies.set('locale', code, { expires: 365, sameSite: 'strict' });
// Force a reload so getStaticProps runs again with the new locale
router.reload();
};
return (
<div className="language-switcher">
{LANGUAGES.map(l => (
<button key={l.code} onClick={() => changeLang(l.code)}>
{l.label}
</button>
))}
</div>
);
}
Add the component to your layout, and every page will be rendered in the selected language on the next request—no need to adjust the URL or the router.
5. SEO‑Friendly Pre‑Rendering with the CLI
SiteLocaleAI ships a CLI tool that can pre‑render every locale to a static folder. This is useful for static‑site hosts (Vercel, Netlify) that want search engines to see the translated HTML.
nnn eslint –-cli generate --locales en,fr,de,es --output ./out
The command walks through your pages directory, runs translatePage for each locale, and writes the HTML files to ./out. You can then point your CDN to that folder.
For more details, see the official docs: https://sitelocaleai.com/docs/cli.
6. WordPress & Shopify Integration (Quick Mention)
If you also run a WordPress blog or a Shopify store, SiteLocaleAI offers a no‑Node.js plugin that injects the same translation logic via a tiny script tag. The same LLM API key is used, so you keep a unified translation pipeline across all platforms.
7. Testing & Deployment
- Local testing – run
npm run devand switch languages with the selector. Verify that prices are rounded correctly (e.g., €19.99 → €19.95). - Staging – Deploy to a preview environment and run the CLI to generate static HTML for each locale.
- Production – Deploy the generated
outfolder or keep the dynamic version; both are SEO‑friendly because the HTML is fully rendered before it reaches the browser.
8. Wrap‑Up
By using SiteLocaleAI’s drop‑in JS library you can:
- Keep your existing Next.js routing untouched.
- Provide accurate, psychologically rounded prices per currency.
- Serve fully translated HTML to search engines without extra runtime overhead.
- Manage translations centrally with your own LLM API keys, preserving data privacy.
Ready to make your Next.js site truly global? Try SiteLocaleAI today and see how easy internationalization can be.
For deeper integration patterns, check out the full documentation at https://sitelocaleai.com/docs.