StarterApp Docs
Packages

@starterapp/i18n-next

Next.js bindings for localization providers, middleware, navigation, and SEO helpers.

@starterapp/i18n-next bridges @starterapp/i18n-core with Next.js. It wraps dictionary registration, localized route handling, runtime providers, and edge negotiation helpers.

Pro Tip

Everything in this package is safe for Server Components and middleware. The provider is the only client boundary ("use client").

createAppI18n Factory

import { createAppI18n } from "@starterapp/i18n-next/app-factory";
import { marketingDictionaries, marketingRoutes } from "~/i18n";

const marketingI18n = createAppI18n({
  dictionaries: marketingDictionaries,
  routes: marketingRoutes,
  baseNamespaces: ["common"],
  loadSharedMessages: async () =>
    (await import("../messages/shared/common.json")).default,
});

export const createMarketingLocalizedPage = marketingI18n.createLocalizedPage;

Factory options

  • dictionaries — locale → namespace loaders (lazily registered)
  • routes — shared LocalizedRouteRegistry used by middleware & server helpers
  • localizedRoutes — initial allow-list when you don’t provide a registry
  • baseNamespaces — namespaces loaded for every page
  • loadSharedMessages — merge global dictionaries (e.g., navigation)
  • wrapWithProviders — optional callback to wrap the i18n provider with app-specific providers

Runtime API

MethodDescription
resolve(options)Returns { locale, messages } for the current request.
createLocalizedPage({ namespaces, render })Wraps RSC exports with the provider and preloaded dictionaries.
loadMessages(locale, namespaces)Fetches merged dictionaries without rendering.
isLocalizedRoute(path) / registerLocalizedRoute(path)Manage the allow list used by middleware.

Provider & Client Hooks

return (
  <StarterAppI18nProvider locale={locale} messages={messages}>
    {content}
  </StarterAppI18nProvider>
);

When localization is disabled, the provider falls back to identity translations but still injects runtime context (locale + messages). Client hooks read from that context:

const t = useTranslations("localizedExample.client");
const format = useFormatter();
const locale = useLocale();

If dictionaries exist locally (single-locale mode), useTranslations builds a translator with use-intl/createTranslator so components still see localized strings without mounting next-intl.

Middleware Helpers

import {
  resolveRequestLocale,
  createI18nResponse,
  applyI18nHeaders,
} from "@starterapp/i18n-next";

const resolution = resolveRequestLocale(request);
const response = createI18nResponse(request, resolution);
if (response) {
  return applyI18nHeaders(response, resolution);
}
  • resolveRequestLocale — determines locale from pathname, cookie, Accept-Language
  • createI18nResponse — issues redirect/rewrites + locale cookie when needed
  • applyI18nHeaders — attaches Vary and x-starterapp-locale

Combine these helpers with createLocalizedRouteRegistry to ensure only opted-in routes negotiate locales.

const href = buildLocalizedPath("/pricing", "es");
const normalized = removeLocaleFromPath("/es/pricing");
const links = generateHreflangLinks({
  baseUrl: "https://example.com",
  pathname: "/pricing",
});

Helpers respect the default-locale opt-out: when only English is enabled, paths remain unprefixed and hreflang generation returns an empty array.

Testing Patterns

Reset registered dictionaries and locales between tests to avoid state leakage:

import { clearDictionaries } from "@starterapp/i18n-next/dictionary-map";
import { registerLocaleDefinition, resetEnabledLocales } from "@starterapp/i18n-core";

beforeEach(() => {
  clearDictionaries();
  resetEnabledLocales();
  registerLocaleDefinition({
    id: "es",
    label: "Español",
    dir: "ltr",
    fallback: ["es", "en"],
    enabled: true,
    coverageThreshold: 0.95,
  });
});

Integration tests in apps/marketing/__tests__/localized-example.integration.test.tsx demonstrate middleware + provider behavior for both English and Spanish.

  • @starterapp/i18n-core — locale registry, fallback chains, Accept-Language parsing
  • @starterapp/i18n-next/navigation & @starterapp/i18n-next/seo — tree-shakable submodules for client/server usage