Next.js reference
18ways.config.*
Create 18ways.config.ts, 18ways.config.js, or 18ways.config.cjs in your app root and export
your 18ways config there.
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;withWays()
Import from @18ways/next/config and call it from next.config.js.
import { withWays } from '@18ways/next/config';When 18ways.config.* exists, withWays() loads it automatically. For router: 'path' it
returns native Next i18n config with locale detection disabled. For router: 'app' and
router: 'none', it injects the alias needed for direct imports from @18ways/next/server.
Common options:
| Option | Type | Notes |
|---|---|---|
apiKey | string | Required. |
baseLocale | string | Source locale and default locale for routing. |
router | 'app' | 'path' | 'none' | Locale-routing mode. Use none when some other router already owns locale URLs. |
acceptedLocales | string[] | Explicit locale list. Required for path, optional otherwise. Keep path mode in sync with the languages enabled in your 18ways dashboard. |
domains | Array<{domain, defaultLocale}> | Optional domain routing map. |
localeParamName | string | App Router locale segment param. Defaults to lang. |
persistLocaleCookie | boolean | ((request) => boolean) | Locale-cookie persistence policy for server and client locale changes. |
cacheTtl | number | Cache TTL for adapter requests. |
fetcher | typeof fetch | Custom fetch implementation. |
init(config)
Import from @18ways/next/server.
Use it when you want to bind a config object explicitly.
WaysRoot
Import WaysRoot directly from @18ways/next/server in your layouts after wrapping
next.config.js with withWays(...).
Use WaysRoot in your layout so the adapter can seed runtime state for the current request.
With App Router locale routing this usually means app/[lang]/layout.tsx.
getLocale()
Resolve the current locale on the server. This is the helper to use when you need locale state
outside WaysRoot, for example in server-only SEO helpers or other request-bound server code.
htmlAttrs()
htmlAttrs() resolves the current lang and dir values for the document element.
generateWaysMetadata()
Use generateWaysMetadata() inside generateMetadata() when you want translated titles,
descriptions, and locale-aware canonical or alternate URLs.
proxy.ts
For router: 'app', proxy.ts is the opinionated entrypoint for request-time locale redirects.
Re-export from @18ways/next/proxy to handle / -> /{locale} and domain canonicalization.
export { default, config } from '@18ways/next/proxy';If you already have your own project proxy.ts or middleware.ts, use
getWaysProxyResponse(request) and return it before the rest of your logic.
Client helpers
Import from @18ways/next/client.
useLocale()
Read and change the current locale. This is the hook you pair with LanguageSwitcher or your own
custom selector UI.
useRouter()
Locale-aware wrapper around Next navigation. Pass locale="fr-FR" to force a localized target or
locale={false} to force an unlocalized one.
Link
Locale-aware wrapper around next/link with the same override model as useRouter().
useUnlocalizedPathname()
Read the current pathname without the locale prefix.
useLocalizedHref()
Lower-level helper for converting an internal href into the current locale-aware href.
Path routing config
In router: 'app' mode the adapter follows your route tree:
- routes under
app/[lang]/...are localized - routes outside that segment stay unlocalized
Link, useRouter(), and setLocale() treat internal routes as localized by default. Use
locale={false} only when you need to target an unlocalized route explicitly.