i18n Package
Internationalization. Routing, middleware, translations, and 10 supported languages.
Wraps next-intl into a shared module consumed by both apps. Defines supported locales, provides locale-aware navigation helpers, exports message files, and exposes the middleware and plugin for Next.js.
Directory Structure
Supported Languages
| Code | Language | Native Name |
|---|---|---|
en | English | English |
tr | Turkish | Türkçe |
es | Spanish | Español |
fr | French | Français |
de | German | Deutsch |
pt | Portuguese | Português |
it | Italian | Italiano |
ru | Russian | Русский |
ja | Japanese | 日本語 |
zh | Chinese | 中文 |
Package Exports
Each file in this package maps to a specific export path in package.json:
| Export | File | Used by |
|---|---|---|
@workspace/i18n | index.ts | Both apps (messages, types, re-exports) |
@workspace/i18n/routing | routing.ts | Both apps (locale config, routing) |
@workspace/i18n/navigation | navigation.ts | Both apps (Link, useRouter, usePathname) |
@workspace/i18n/middleware | middleware.ts | Web app (proxy.ts) |
@workspace/i18n/plugin | plugin.ts | Both apps (next.config.ts) |
@workspace/i18n/server | server.ts | Web app (server components) |
@workspace/i18n/messages/* | messages/*.json | Direct JSON access |
Source Files
import { defineRouting } from "next-intl/routing";
export const localeConfig = {
en: { flag: "🇬🇧", label: "English", nativeName: "English" },
tr: { flag: "🇹🇷", label: "Turkish", nativeName: "Türkçe" },
// ... 8 more (see Supported Languages table above)
} as const;
export const locales = Object.keys(localeConfig) as Array<
keyof typeof localeConfig
>;
export const routing = defineRouting({
locales: locales,
defaultLocale: "en",
});Each locale entry provides flag emoji, English label, and native name for the language toggle UI.
import { routing, localeConfig } from "@workspace/i18n/routing";
export type Locale = (typeof routing.locales)[number];
export * from "next-intl";
export { localeConfig };
// Static imports for all 10 language files
import enMessages from "./messages/en.json" with { type: "json" };
import trMessages from "./messages/tr.json" with { type: "json" };
// ... 8 more
export const messages = {
en: enMessages, tr: trMessages, /* ... all 10 */
} as const;All message files are imported statically so they work with both SSR (web) and static export (native). Re-exports everything from next-intl so consumers only need one import source.
import type { Locale } from "@workspace/i18n";
import messages from "@workspace/i18n/messages/en.json";
type Messages = typeof messages;
declare module "next-intl" {
interface AppConfig {
Locale: Locale;
Messages: Messages;
}
}Module augmentation that uses en.json as the type source. TypeScript will autocomplete and validate all namespace names and translation keys across the codebase.
The remaining files (plugin.ts, middleware.ts, server.ts) are one-line re-exports from next-intl:
// plugin.ts → export { default } from "next-intl/plugin";
// middleware.ts → export { default } from "next-intl/middleware";
// server.ts → export { getLocale, getRequestConfig, getTranslations } from "next-intl/server";Message Structure
Messages are organized by component namespace. Each top-level key maps to a component:
{
"HomePage": { "title": "You are on the Home Page." },
"DashboardPage": { "title": "You are on the Dashboard Page." },
"OverviewPage": { "title": "You are on the Overview Page." },
"AnalyticsPage": { "title": "You are on the Analytics Page." },
"SettingsPage": { "title": "Settings", "description": "..." },
"Greet": { "placeholder": "Enter a name...", "button": "Greet", "error": "..." },
"LanguageCard": { "title": "Language", "description": "..." },
"ModeCard": { "title": "Modes", "light": "Light", "dark": "Dark", "system": "System" },
"SidebarVariantCard": { "title": "Sidebar Variant", "sidebar": "...", "floating": "...", "inset": "..." },
"ThemesList": { "title": "Themes", "searchPlaceholder": "...", "sortBy": "...", ... },
"Navigation": { "home": "Home", "dashboard": "Dashboard", "settings": "Settings", ... }
}All 10 language files follow this exact structure. Missing keys fall back to the default locale (English).
For step-by-step instructions on adding new translation keys or new languages, see the Managing Translations guide.
Usage
// Client component with translations
import { useTranslations } from "@workspace/i18n";
function HomePage() {
const t = useTranslations("HomePage");
return <h1>{t("title")}</h1>;
}// Locale-aware navigation (not next/link)
import { Link } from "@workspace/i18n/navigation";
<Link href="/settings">Settings</Link>
// Renders: /en/settings, /tr/settings, etc.Always import Link, useRouter, and usePathname from @workspace/i18n/navigation, not from next/link or next/navigation. Using the Next.js defaults bypasses locale prefixing.