一键导入
i18n-best-practices
Guide for internationalization with next-intl. Use when adding links, translations, or localized URLs. Always use Link from @i18n/routing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Guide for internationalization with next-intl. Use when adding links, translations, or localized URLs. Always use Link from @i18n/routing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Guide for adding environment variables. Use when adding new env vars to ensure all 5 locations are updated (code, env files, Coolify, workflow, GitHub secrets).
Enforce the internal API proxy layer pattern. Use when adding API endpoints, fetching data from backend, implementing HMAC signing, or working with lib/api/* or app/api/*.
Best practices for React 19 and Next.js 16 App Router. Use when creating components, hooks, or pages. Enforces server-first rendering, proper client boundaries, and modern React patterns.
MANDATORY checklist before writing ANY new code. Use this skill FIRST before implementing any feature, component, utility, type, or hook. Enforces DRY principle and existing pattern reuse.
Evaluate external PR suggestions (Gemini, CodeRabbit) against project conventions. Use when asked to review or agree with external code review comments.
Guide for CSP, security headers, and external scripts. Use fetchWithHmac for APIs, safeFetch for external services.
| name | i18n-best-practices |
| description | Guide for internationalization with next-intl. Use when adding links, translations, or localized URLs. Always use Link from @i18n/routing. |
Enforce correct i18n patterns using next-intl to prevent broken navigation and SEO issues.
For ALL internal navigation, use Link from @i18n/routing, NOT next/link.
ESLint will warn on next/link imports in components.
Using next/link directly loses the locale prefix on navigation:
/es/barcelona clicks linknext/link: Goes to /barcelona (loses Spanish locale)@i18n/routing Link: Goes to /es/barcelona (correct)// ✅ CORRECT - Always use this
import { Link } from "@i18n/routing";
export function MyComponent() {
return <Link href="/barcelona">Barcelona</Link>;
}
// ❌ WRONG - Loses locale on navigation
import Link from "next/link";
export function MyComponent() {
return <Link href="/barcelona">Barcelona</Link>;
}
<a> tag)| Aspect | Configuration |
|---|---|
| Library | next-intl ^4.6.1 |
| Locales | ca (default), es, en |
| Prefix Strategy | as-needed (no prefix for default ca) |
| Routing Config | i18n/routing.ts |
| Messages | messages/{locale}.json |
import {
Link, // Use for all internal links
redirect, // Server-side redirects
usePathname, // Get current path (client)
useRouter, // Programmatic navigation (client)
getPathname, // Build localized paths
} from "@i18n/routing";
import { getTranslations, getLocale } from "next-intl/server";
export default async function ServerComponent() {
const locale = await getLocale();
const t = await getTranslations("common");
return <h1>{t("title")}</h1>;
}
"use client";
import { useTranslations, useLocale } from "next-intl";
export function ClientComponent() {
const locale = useLocale();
const t = useTranslations("common");
return <button>{t("submit")}</button>;
}
For structured data (JSON-LD), always use toLocalizedUrl:
import { toLocalizedUrl } from "@utils/i18n-seo";
// ✅ CORRECT
const url = toLocalizedUrl("/barcelona/avui", locale);
// Returns: "https://example.com/es/barcelona/avui" for Spanish
// ❌ WRONG - Missing locale prefix
const url = `https://example.com/barcelona/avui`;
Use the tested helper function:
import { generateBreadcrumbList } from "@components/partials/seo-meta";
// ✅ CORRECT - Handles locale automatically
const breadcrumbs = generateBreadcrumbList(items, locale);
Add keys to all locale files in messages/:
messages/ca.jsonmessages/es.jsonmessages/en.jsonPrefer reusing existing keys before adding new ones
Use namespaced keys:
{
"common": {
"submit": "Enviar",
"cancel": "Cancel·lar"
},
"events": {
"title": "Esdeveniments"
}
}
Update types/i18n.ts:
export type Locale = "ca" | "es" | "en" | "fr"; // Add new locale
Create messages/fr.json with all translations
Update i18n/routing.ts:
export const routing = defineRouting({
locales: ["ca", "es", "en", "fr"],
defaultLocale: "ca",
});
Update loader map in i18n/request.ts
Link from @i18n/routing? (not next/link)toLocalizedUrl()?generateBreadcrumbList()?getTranslations?useTranslations?toLocalizedUrl