Skip to content

@comvi/next API Reference

@comvi/next extends Comvi i18n with Next.js-specific utilities: Server Component support, locale routing middleware, navigation helpers, and static generation tools. Runtime-specific APIs are split across entry points: import shared setup from @comvi/next, server helpers from @comvi/next/server, and Client Component hooks/components from @comvi/next/client.

Creates an i18n instance with Next.js-specific configuration. Extends the standard createI18n options with server-side and routing settings.

src/i18n.ts
import { createNextI18n } from '@comvi/next';
import { FetchLoader } from '@comvi/plugin-fetch-loader';
export const { i18n, routing } = createNextI18n({
locales: ['en', 'de', 'fr'],
defaultLocale: 'en',
fallbackLocale: 'en',
})
.use(FetchLoader({
cdnUrl: 'https://cdn.comvi.io/your-distribution-id',
}));
interface CreateNextI18nOptions {
// routing (required)
locales: string[];
defaultLocale: string;
localePrefix?: "always" | "as-needed" | "never";
pathnames?: RoutingConfig["pathnames"];
// i18n (optional)
apiKey?: string;
ns?: string[];
translation?: I18nOptions["translation"];
fallbackLocale?: string | string[];
defaultNs?: string;
devMode?: boolean;
basicHtmlTags?: string[];
onMissingKey?: I18nOptions["onMissingKey"];
}
interface CreateNextI18nResult {
i18n: I18n;
routing: Required<RoutingConfig>;
use(plugin, options?): this;
useClient(plugin, options?): this; // only on client (typeof window !== 'undefined')
useServer(plugin, options?): this; // only on server (NEXT_RUNTIME present)
useClientLazy(loadPlugin, options?): this;
useServerLazy(loadPlugin, options?): this;
}
import { createNextI18n } from '@comvi/next';
import { FetchLoader } from '@comvi/plugin-fetch-loader';
const nextI18n = createNextI18n({
locales: ['en', 'de'],
defaultLocale: 'en',
})
.use(FetchLoader({ cdnUrl: 'https://cdn.comvi.io/your-distribution-id' }))
.useClientLazy(
() => import('@comvi/plugin-in-context-editor').then(m => m.InContextEditorPlugin()),
{ environment: 'development', required: false },
);
export const { i18n, routing } = nextI18n;

Store locale in async context for server functions. Call at the top of layout/page Server Components.

import { setRequestLocale, getI18n } from '@comvi/next/server';
export default async function Layout({ params: { locale } }) {
setRequestLocale(locale);
const { t } = await getI18n();
return <h1>{t('title')}</h1>;
}

Access translation function in Server Components. Returns ServerI18n with t and hasTranslation. Async (may fetch for locale).

interface GetI18nOptions {
locale?: string; // defaults to request locale
ns?: string; // default namespace for t()
}
interface ServerI18n {
t: TranslationFunction;
hasTranslation(key, options?: HasTranslationOptions): boolean;
}
type TranslationFunction = (key: string, params?: TranslationParams) => string;
interface HasTranslationOptions {
locale?: string;
ns?: string;
}

Get the current request locale (set by setRequestLocale or middleware).

import { getLocale } from '@comvi/next/server';
export default async function Layout({ children }) {
const locale = await getLocale();
return <html lang={locale}>{children}</html>;
}

Preload translations on the server before rendering. Returns a serializable map keyed by "locale:namespace" that you can pass into the client <I18nProvider> for hydration. Defaults to the default namespace; pass { namespaces: [...] } for more.

interface LoadTranslationsOptions {
namespaces?: string[]; // default: [defaultNs]
}
type TranslationsResult = Record<string, Record<string, TranslationValue>>;
import { loadTranslations, setRequestLocale } from '@comvi/next/server';
export default async function Layout({ params: { locale }, children }) {
setRequestLocale(locale);
const messages = await loadTranslations(locale, {
namespaces: ['common', 'dashboard'],
});
return <>{children}</>;
}

Set the i18n instance explicitly (advanced).

Client Components use the same hooks as @comvi/react. Import from @comvi/next/client — that is the only entry point that exports React-only code marked with "use client". Importing from @comvi/next (the main entry) does not expose useI18n, T, or I18nProvider.

src/components/Counter.tsx
'use client';
import { useI18n } from '@comvi/next/client';
export function Counter() {
const { t, locale, setLocale, isLoading } = useI18n();
return <button>{t('counter.increment')}</button>;
}

@comvi/next/client re-exports useI18n, useI18nContext, T, createI18n, and UseI18nReturn/TProps types from @comvi/react, plus a Next.js-aware <I18nProvider> (handles locale syncing for hydration) with its I18nProviderProps and MessagesMap types.

See the @comvi/react API Reference for the full useI18n() return type.

Same API as the React <T> component. Import from @comvi/next/client (re-exported from @comvi/react):

'use client';
import { T } from '@comvi/next/client';
PropTypeDefaultDescription
i18nKeystringTranslation key to resolve (required)
paramsRecord<string, unknown>{}Interpolation parameters
nsstringNamespace to look up the key in
localestringSpecific locale to use
fallbackstringFallback text if the key is missing
rawbooleanForward raw: true to post-processors that support it, such as the in-context editor marker injector
componentsRecord<string, ComponentHandler>Map of tag names to React elements or functions for rich-text interpolation
childrenReactNodeFallback content if translation is missing

The middleware handles locale detection, URL rewriting, and redirects for locale-prefixed routes. Use createMiddleware with your routing config:

src/middleware.ts
import { createMiddleware } from '@comvi/next/middleware';
import { routing } from './i18n';
export default createMiddleware(routing);
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};
  1. Reads the locale from the URL path (/de/about extracts de)
  2. Falls back to cookie, then Accept-Language header, then the default locale
  3. Handles URL prefix mode (always, as-needed, never)
  4. Sets the x-comvi-locale header for Server Components to read
  5. Persists the detected locale in a cookie

If you need to combine Comvi’s middleware with your own logic, call the returned function:

src/middleware.ts
import { createMiddleware } from '@comvi/next/middleware';
import { routing } from './i18n';
import type { NextRequest } from 'next/server';
const comviMiddleware = createMiddleware(routing);
export default function middleware(request: NextRequest) {
// Your custom logic here
// ...
return comviMiddleware(request);
}
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};

Import from @comvi/next/navigation:

import { Link, usePathname, useLocalizedRouter } from '@comvi/next/navigation';

A locale-aware replacement for Next.js’s <Link> that automatically prefixes the href with the current locale:

import { Link } from '@comvi/next/navigation';
function Nav() {
return (
<nav>
<Link href="/about">About</Link>
{/* When locale is "de", navigates to /de/about */}
<Link href="/contact" locale="fr">Contact (FR)</Link>
{/* Always navigates to /fr/contact */}
</nav>
);
}

Extends all Next.js <Link> props with an optional locale prop to override the current locale.

Returns the current pathname without the locale prefix:

'use client';
import { usePathname } from '@comvi/next/navigation';
function Breadcrumb() {
const pathname = usePathname();
// When URL is /de/about, pathname is "/about"
return <span>{pathname}</span>;
}

Returns a router object that automatically prefixes paths with the current locale. Same API as Next.js’s useRouter() but locale-aware:

'use client';
import { useLocalizedRouter } from '@comvi/next/navigation';
function Nav() {
const router = useLocalizedRouter();
return (
<button onClick={() => router.push('/about')}>
{/* When locale is "de", navigates to /de/about */}
Go to About
</button>
);
}

LocalizedRouter methods:

MethodTypeDescription
push(href: string, locale?: string) => voidNavigate to a locale-prefixed path
replace(href: string, locale?: string) => voidReplace current URL with locale-prefixed path
back() => voidNavigate back in history
forward() => voidNavigate forward in history
refresh() => voidRefresh the current route
prefetch(href: string, locale?: string) => voidPrefetch a locale-prefixed path
## Static Generation
Generate static pages for all supported locales:
```tsx title="src/app/[locale]/page.tsx"
import { routing } from '@/i18n';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}

Imports are split by runtime to keep "use client" boundaries clean:

Entry pointUse fromWhat it exports
@comvi/nextAnywhere (shared/server config)createNextI18n, createI18n, I18n, all @comvi/core types, plus RoutingConfig, LocalePrefixMode, MiddlewareConfig, GetI18nOptions, I18nProviderProps
@comvi/next/serverServer Components and route handlerssetRequestLocale, getI18n, getLocale, loadTranslations, setI18n; types: ServerI18n, TranslationFunction, LoadTranslationsOptions, TranslationsResult
@comvi/next/clientClient Components ('use client')useI18n, useI18nContext, T, createI18n (from @comvi/react), Next-aware I18nProvider; types: UseI18nReturn, TProps, I18nProviderProps, MessagesMap
@comvi/next/middlewaremiddleware.tscreateMiddleware
@comvi/next/navigationClient ComponentsLink, usePathname, useLocalizedRouter; types: LocalizedLinkProps, LocalizedRouter
@comvi/next/routingAnywheredefineRouting and routing helpers

See the @comvi/react API Reference and @comvi/core API Reference for the underlying APIs.