Skip to content

Libraries · Reference

Localization

Provider-independent locale resolution and Effect HttpApi middleware using BCP 47 language tags.

Last updated October 8, 2026

Overview

localization provides provider-independent request-scoped locale context for Effect HttpApi applications. It resolves the locale from the locale URL query parameter, the locale request header, the locale cookie, or Accept-Language, in that order, then provides that context to downstream handlers through LocaleMiddleware. All explicit locale values are validated as BCP 47 language tags with Effect Schema, and cookies are parsed with Effect's HTTP cookie utilities. The localize helper selects a record translation using the current locale and fallback settings.

Install

shell
bunx shadcn@latest add @krak-stack/localization

Included Files

  • lib/localization.ts - LocaleContext, LocaleMiddleware, LocaleMiddlewareLive, LocalizedInputType, and localize

Locale Contract

The library has no i18n-provider dependency. It validates arbitrary BCP 47 language tags, defaults to en, and can receive locale values from Paraglide, react-i18next, FormatJS, Lingui, a custom provider, or plain request headers. Accept-Language candidates are resolved by quality weight. Regional locales such as fr-CA fall back to matching base-language translations such as fr before the configured fallback locale.

API Setup

Register the live middleware layer in the application HTTP API layer:

ts
import { Layer } from "effect";
import { LocaleMiddlewareLive } from "@/lib/localization";

const apiLayer = Layer.mergeAll(/* application layers */).pipe(
  Layer.provide(LocaleMiddlewareLive),
);

Apply LocaleMiddleware to an API group and read LocaleContext in endpoint handlers:

ts
import { Effect } from "effect";
import { HttpApiGroup } from "effect/http-api";
import { LocaleContext, LocaleMiddleware } from "@/lib/localization";

const RecordsGroup = HttpApiGroup.make("records").middleware(LocaleMiddleware);

const program = Effect.gen(function* () {
  const { locale, fallbackLocale } = yield* LocaleContext;
  // Use locale and fallbackLocale to resolve localized data.
});

Translation Resolution

localize expects a record with a translations array whose items have a locale field. It returns the matching translation merged with the base record, falls back to fallbackLocale or the first translation, and respects fallbackLocale: "none" when a translation must exactly match.

ts
import { localize, type LocalizedInputType } from "@/lib/localization";

const context: LocalizedInputType = { locale: "fr", fallbackLocale: "en" };
const record = localize(context, {
  id: "welcome",
  translations: [
    { locale: "en", name: "Welcome" },
    { locale: "fr", name: "Bienvenue" },
  ],
});
Dependencies
Packages and shadcn components required by this registry item.

Dependencies