Benutzerdefinierte Locale-Resolver
Passen Sie an, wie Locales erkannt und gespeichert werden, indem Sie benutzerdefinierte Resolver-Dateien bereitstellen.
Standardmäßig verwendet der Compiler Cookie-basierte Locale-Persistierung. Benutzerdefinierte Resolver ermöglichen es Ihnen, alternative Strategien wie localStorage, URL-Parameter, Datenbankabfragen oder Subdomain-Erkennung zu implementieren.
Funktionsweise
Erstellen Sie optionale Dateien im Verzeichnis .lingo/:
.lingo/locale-resolver.server.ts— Serverseitige Locale-Erkennung.lingo/locale-resolver.client.ts— Clientseitige Locale-Erkennung und -Persistierung
Wenn diese Dateien nicht existieren, verwendet der Compiler die standardmäßige Cookie-basierte Implementierung.
Server-Locale-Resolver
Erstellen Sie .lingo/locale-resolver.server.ts für benutzerdefinierte serverseitige Locale-Erkennung:
// .lingo/locale-resolver.server.ts
export async function getServerLocale(): Promise<string> {
// Your custom logic
return "en";
}
Beispiel: Accept-Language-Header (Next.js)
import { headers } from "next/headers";
export async function getServerLocale(): Promise<string> {
const headersList = await headers();
const acceptLanguage = headersList.get("accept-language");
// Parse accept-language: "en-US,en;q=0.9,es;q=0.8"
const locale = acceptLanguage
?.split(",")[0]
?.split("-")[0]
?.trim() || "en";
return locale;
}
Beispiel: Datenbankabfrage
import { cookies } from "next/headers";
import { db } from "@/lib/db";
export async function getServerLocale(): Promise<string> {
const cookieStore = await cookies();
const sessionToken = cookieStore.get("session")?.value;
if (!sessionToken) return "en";
// Query user preferences from database
const user = await db.user.findUnique({
where: { sessionToken },
select: { preferredLocale: true },
});
return user?.preferredLocale || "en";
}
Beispiel: Subdomain-Erkennung
import { headers } from "next/headers";
export async function getServerLocale(): Promise<string> {
const headersList = await headers();
const host = headersList.get("host") || "";
// Extract subdomain: es.example.com → es
const subdomain = host.split(".")[0];
// Map subdomain to locale
const localeMap: Record<string, string> = {
es: "es",
de: "de",
fr: "fr",
};
return localeMap[subdomain] || "en";
}
Client-Locale-Resolver
Erstellen Sie .lingo/locale-resolver.client.ts für benutzerdefinierte clientseitige Locale-Erkennung und -Persistierung:
// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
// Detect locale
return "en";
}
export function persistLocale(locale: string): void {
// Save locale preference
}
Beispiel: localStorage
export function getClientLocale(): string {
if (typeof window === "undefined") return "en";
// Check localStorage
const stored = localStorage.getItem("user-locale");
if (stored) return stored;
// Fall back to browser language
return navigator.language.split("-")[0] || "en";
}
export function persistLocale(locale: string): void {
if (typeof window === "undefined") return;
localStorage.setItem("user-locale", locale);
// Optionally reload page to apply new locale
window.location.reload();
}
Beispiel: URL-Parameter
export function getClientLocale(): string {
if (typeof window === "undefined") return "en";
// Check URL parameter: ?lang=es
const params = new URLSearchParams(window.location.search);
const urlLocale = params.get("lang");
if (urlLocale) return urlLocale;
// Fall back to localStorage
return localStorage.getItem("locale") || "en";
}
export function persistLocale(locale: string): void {
if (typeof window === "undefined") return;
// Update URL parameter
const url = new URL(window.location.href);
url.searchParams.set("lang", locale);
window.history.replaceState({}, "", url.toString());
// Also save to localStorage
localStorage.setItem("locale", locale);
// Reload to apply new locale
window.location.reload();
}
Beispiel: Kombinierte Strategie
export function getClientLocale(): string {
if (typeof window === "undefined") return "en";
// Priority 1: URL parameter
const params = new URLSearchParams(window.location.search);
const urlLocale = params.get("lang");
if (urlLocale) return urlLocale;
// Priority 2: localStorage
const stored = localStorage.getItem("locale");
if (stored) return stored;
// Priority 3: Browser language
const browserLocale = navigator.language.split("-")[0];
const supportedLocales = ["en", "es", "de", "fr"];
if (supportedLocales.includes(browserLocale)) {
return browserLocale;
}
// Priority 4: Default
return "en";
}
export function persistLocale(locale: string): void {
if (typeof window === "undefined") return;
// Save to localStorage
localStorage.setItem("locale", locale);
// Update URL
const url = new URL(window.location.href);
url.searchParams.set("lang", locale);
window.history.replaceState({}, "", url.toString());
// Reload page
window.location.reload();
}
TypeScript-Typen
Beide Resolver sind vollständig typisiert:
// Server resolver
export async function getServerLocale(): Promise<string>;
// Client resolver
export function getClientLocale(): string;
export function persistLocale(locale: string): void;
Integration mit setLocale
Die Funktion setLocale() aus useLingoContext() ruft automatisch Ihre benutzerdefinierte persistLocale() auf:
import { useLingoContext } from "@lingo.dev/compiler/react";
function MyComponent() {
const { setLocale } = useLingoContext();
// Calls your persistLocale() under the hood
setLocale("es");
}
SSR-Überlegungen
Für SSR-Frameworks (Next.js, Remix, etc.):
- Server-Resolver wird bei jeder Anfrage ausgeführt
- Client-Resolver wird im Browser nach der Hydration ausgeführt
- Stellen Sie Konsistenz zwischen Server- und Client-Erkennung sicher
Gängiges Muster: Server liest aus Cookie/Header, Client speichert in Cookie/localStorage.
Standard-Implementierung
Wenn keine benutzerdefinierten Resolver bereitgestellt werden, verwendet der Compiler diese Standardeinstellung:
// Default server resolver
export async function getServerLocale(): Promise<string> {
const cookies = await import("next/headers").then((m) => m.cookies());
return cookies().get("locale")?.value || "en";
}
// Default client resolver
export function getClientLocale(): string {
return document.cookie
.split("; ")
.find((row) => row.startsWith("locale="))
?.split("=")[1] || "en";
}
export function persistLocale(locale: string): void {
document.cookie = `locale=${locale}; path=/; max-age=31536000`;
window.location.reload();
}
Häufige Fragen
Benötige ich sowohl Server- als auch Client-Resolver? Nein. Stellen Sie nur das bereit, was Sie anpassen möchten. Fehlende Dateien verwenden das Standardverhalten.
Kann ich benutzerdefinierte Resolver mit SPA-Apps verwenden? Ja. Nur der Client-Resolver ist für SPA-Apps relevant. Der Server-Resolver ist für SSR.
Funktioniert das mit Vite? Ja. Der Client-Resolver funktioniert identisch. Der Server-Resolver ist Next.js-spezifisch (für SSR).
Wie teste ich benutzerdefinierte Resolver?
- Resolver-Dateien erstellen
- Ihre Logik implementieren
- Dev-Server starten
- Locale-Wechsel mit Ihrer benutzerdefinierten Persistierung testen
Kann ich auf Next.js-spezifische APIs zugreifen? Ja. Importieren Sie Next.js-Utilities (headers, cookies, etc.) direkt in Ihren Resolver-Dateien.
Was passiert, wenn getServerLocale eine ungültige Locale zurückgibt?
Der Compiler fällt auf sourceLocale zurück, wenn die zurückgegebene Locale nicht in targetLocales enthalten ist.
Beispiele nach Anwendungsfall
Subdomain-basiertes Routing
Server:
const host = (await headers()).get("host") || "";
const locale = host.split(".")[0]; // es.example.com → es
return supportedLocales.includes(locale) ? locale : "en";
Client:
const locale = window.location.hostname.split(".")[0];
return supportedLocales.includes(locale) ? locale : "en";
Datenbankgestützte Benutzerpräferenzen
Server:
const session = await getSession();
const user = await db.user.findUnique({
where: { id: session.userId },
});
return user.locale || "en";
Client:
// After user changes locale in UI
await fetch("/api/user/locale", {
method: "POST",
body: JSON.stringify({ locale }),
});
window.location.reload();
Pfadbasiertes Routing (/en/about, /es/about)
Server:
const pathname = (await headers()).get("x-pathname") || "/";
const locale = pathname.split("/")[1];
return supportedLocales.includes(locale) ? locale : "en";
Client:
const locale = window.location.pathname.split("/")[1];
return supportedLocales.includes(locale) ? locale : "en";
Nächste Schritte
- Locale-Umschaltung — Sprachwechsler implementieren
- Framework-Integration — Framework-spezifische Muster
- Best Practices — Empfohlene Strategien zur Locale-Erkennung