Next.js usage

The Next adapter is split into:

  • one local 18ways.config.ts file
  • build-time Next integration in next.config.js
  • server helpers from @18ways/next/server
  • client helpers in @18ways/next/client

Shared config

Create 18ways.config.ts in your app root.

ts
// 18ways.config.ts
import type { WaysConfig } from '@18ways/next/config';
 
export default {
  apiKey: process.env.NEXT_PUBLIC_18WAYS_PUBLIC_API_KEY,
  baseLocale: 'en-GB',
  router: 'app', // 'app', 'path', or 'none' depending on if you use app router, path router, or if you don't want the router to sync with locale at all
} satisfies WaysConfig;

Then, in your next.config.js:

ts
// next.config.js
const { withWays } = require('@18ways/next/config');
 
module.exports = withWays({
  // your normal next config here
});

App Router path routing

For App Router, locale routing is defined by the route tree itself:

  • public localized routes live under app/[lang]/...
  • unlocalized routes stay outside [lang]

Path Router path routing

If you want path-based locale routing, set router: 'path' and provide acceptedLocales. withWays() then configures native Next i18n path routing for you, with Next’s automatic locale detection disabled so 18ways stays in charge of locale resolution.

ts
// 18ways.config.ts
import type { WaysConfig } from '@18ways/next/config';
 
export default {
  apiKey: process.env.NEXT_PUBLIC_18WAYS_PUBLIC_API_KEY,
  baseLocale: 'en-GB',
  router: 'path', // 'app', 'path', or 'none' depending on if you use app router, path router, or if you don't want the router to sync with locale at all
  acceptedLocales: ['en-GB', 'fr-FR'], // keep this in sync with the languages enabled in your 18ways dashboard
} satisfies WaysConfig;

Use router: 'none' when some existing routing layer already owns locale-aware URLs and you only want 18ways to manage locale state.

Root layout

Import from @18ways/next/server.

tsx
import { WaysRoot, htmlAttrs } from '@18ways/next/server';
 
export default async function RootLayout({ children, params }) {
  const attrs = await htmlAttrs({ params });
 
  return (
    <html {...attrs}>
      <body>
        <WaysRoot params={params}>{children}</WaysRoot>
      </body>
    </html>
  );
}

Proxy

In App Router, use proxy.ts to handle the root locale redirect and any domain canonicalization:

ts
export { default, config } from '@18ways/next/proxy';

If your app already has its own proxy.ts or middleware.ts, compose getWaysProxyResponse() and return it before the rest of your app-specific logic:

ts
import type { NextFetchEvent, NextRequest } from 'next/server';
import { getWaysProxyResponse } from '@18ways/next/proxy';
 
export default async function middleware(request: NextRequest, event: NextFetchEvent) {
  const waysResponse = await getWaysProxyResponse(request);
  if (waysResponse) {
    return waysResponse;
  }
 
  // your existing middleware logic
}

Client-side locale changes

Use useLocale() from @18ways/next/client.

tsx
'use client';
 
import { LanguageSwitcher } from '@18ways/react';
import { useLocale } from '@18ways/next/client';
 
export function LocaleControls() {
  const { locale, setLocale } = useLocale();
 
  return <LanguageSwitcher currentLocale={locale} onLocaleChange={setLocale} />;
}

When the current route is localized, setLocale() preserves the route and updates the locale segment. When the current route is unlocalized, it keeps the route unlocalized and updates locale state.

Import from @18ways/next/client:

tsx
import { Link, useRouter, useUnlocalizedPathname } from '@18ways/next/client';
  • Link localizes internal hrefs automatically
  • useRouter() applies the same rules to push() and replace()
  • useUnlocalizedPathname() lets you compare route state without the locale prefix

Use the locale override only when you need to force a choice:

  • locale="fr-FR" forces a localized target
  • locale={false} forces an unlocalized target

Translated metadata

generateWaysMetadata() can translate string metadata fields for you.

tsx
export async function generateMetadata({ params }) {
  return generateWaysMetadata(
    (t) => ({
      title: t('Pricing'),
      description: t('Simple pricing for runtime translation'),
    }),
    { params, pathname: '/pricing' }
  );
}
भाषा बदली जा रही है
Next.js उपयोग