
الدليل الشامل لتدويل Next.js
أعدّ next-intl مع App Router، وهيّئ توجيه الإعدادات المحلية، وأتمت الترجمات بالذكاء الاصطناعي.
تثبيت next-intl
next-intl هي حزمة واحدة تتولى توجيه الإعدادات المحلية، وتحميل الرسائل، وخطافات الترجمة لـ Next.js App Router.
npm install next-intlإنشاء تهيئة طلب i18n
أنشئ ملفين: src/i18n/request.ts لتحميل الرسائل وsrc/i18n/routing.ts لتعريف الإعدادات المحلية. يحددان كيفية حل next-intl للرسائل وكيفية التوجيه.
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
locales: ['en', 'de', 'ja', 'es'],
defaultLocale: 'en',
localePrefix: 'as-needed', // /about for en, /de/about for de
});
export const { Link, redirect, usePathname, useRouter } =
createNavigation(routing);تهيئة middleware
أضف middleware.ts للتعامل مع اكتشاف الإعدادات المحلية، وإعادة كتابة URL، وعمليات إعادة التوجيه. تعترض middleware كل طلب وتضمن تطبيق الإعدادات المحلية الصحيحة.
// middleware.ts <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};إعداد بنية مجلد [locale]
انقل مسارات التطبيق داخل app/[locale]/. أضف generateStaticParams لتوليد صفحات لكل إعدادات محلية وقت البناء. يؤدي ذلك إلى بنية URL مثل /en/about، /de/about، وغيرها.
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}تحديث Root Layout
حمّل الرسائل باستخدام getMessages() ومرّرها إلى NextIntlClientProvider ضمن تخطيط الإعدادات المحلية الجذري. عيّن سمة html lang من معامل الإعدادات المحلية.
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const { locale } = await params;
if (!routing.locales.includes(locale as any)) notFound();
setRequestLocale(locale);
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}استخدام الترجمات في المكوّنات
تستخدم مكوّنات الخادم getTranslations (async، await). وتستخدم مكوّنات العميل useTranslations (hook). اختر وفقاً لمكان عرض المكوّن — فمكوّنات الخادم تُبقي الترجمات خارج حزمة JavaScript الخاصة بالعميل بالكامل.
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';
export default async function AboutPage({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
setRequestLocale(locale);
const t = await getTranslations('AboutPage');
return <h1>{t('title')}</h1>;
}
// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';
export default function SearchBar() {
const t = useTranslations('SearchBar');
return <input placeholder={t('placeholder')} />;
}إضافة SEO: Metadata وHreflang
استخدم generateMetadata لإنتاج عناوين وأوصاف صفحات خاصة بكل إعدادات محلية. أضف alternates.languages لوسوم hreflang كي تكتشف محركات البحث جميع نسخ اللغة لكل صفحة.
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';
export async function generateMetadata({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'Metadata' });
return {
title: t('title'),
description: t('description'),
alternates: {
languages: Object.fromEntries(
routing.locales.map((l) => [l, `/${l}`])
),
},
};
}التعامل مع صفحات الخطأ وصفحات غير الموجود
تتطلب error.tsx وnot-found.tsx معالجة خاصة لأنها قد تُعرَض خارج تخطيط الإعدادات المحلية المعتاد. يحتاج not-found.tsx الجذري إلى إعداد موفّر i18n خاص به لعرض رسائل خطأ مترجمة.
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';
export default function Error() {
const t = useTranslations('Error');
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</div>
);
}
// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';
export default async function GlobalNotFound() {
return (
<html lang={routing.defaultLocale}>
<body>
<h1>404 - Page Not Found</h1>
</body>
</html>
);
}أتمتة الترجمات
بعد اكتمال إعداد i18n، ترجم ملفات الرسائل باستخدام الذكاء الاصطناعي مباشرة من IDE، أو استخدم i18n Agent CLI ضمن خط CI/CD لأتمتة الترجمة مع كل عملية نشر.
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish
✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)أتمتة جودة الترجمة
أدوات مفتوحة المصدر لـ Next.js i18n
تعالج هذه الحزم مفتوحة المصدر نقاط ألم شائعة في سير عمل تدويل Next.js.
next-intl-localechain
يرجع next-intl القياسي مباشرة إلى الإعدادات المحلية الافتراضية لديك عند غياب ترجمة. عندها يرى مستخدم البرتغالية البرازيلية الإنجليزية بدلاً من ترجمات pt-PT المتوفرة. يضيف next-intl-localechain سلاسل رجوع ذكية — إذ يدمج الترجمات بدمج عميق عبر إعدادات محلية ذات صلة، بحيث يرى المستخدمون الإقليميون دائماً أقرب ترجمة متاحة.
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';
export default getRequestConfig(withLocaleChain({
loadMessages: (locale) =>
import(`../../messages/${locale}.json`).then(m => m.default),
defaultLocale: 'en'
}));@i18n-agent/cli
أداة سطر أوامر لترجمة ملفات رسائل Next.js دون مغادرة الطرفية. ترجم الملفات مباشرةً، وتحقق من حالة المهام، ونزّل النتائج. تعمل ضمن خطوط CI/CD مع المصادقة بمفتاح API لتحقيق سير عمل توطين مؤتمت بالكامل.
# Install the CLI
npm install -g @i18n-agent/cli
# Authenticate
i18nagent login
# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es
# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,esالمشكلات الشائعة
"Unable to find next-intl locale"
لم تطابق middleware الطلب. تحقّق: هل middleware.ts في جذر المشروع؟ هل يستبعد نمط matcher الملفات الثابتة بشكل صحيح؟ هل الإعدادات المحلية مضمنة في مصفوفة locales ضمن تهيئة التوجيه؟
عرض ديناميكي غير متوقع
setRequestLocale(locale) مفقودة من صفحة أو تخطيط. بدونها، يستخدم next-intl headers/cookies لاكتشاف الإعدادات المحلية، ما يفرض العرض الديناميكي ويمنع التوليد الثابت.
تعطّل Parallel Routes مع i18n
توجد حالات عدم توافق معروفة بين parallel routes (@modal) وintercepting routes ((.)photo) وبين المقطع الديناميكي [locale]. استخدم التوجيه القائم على middleware كحل بديل لهذه أنماط التوجيه المتقدمة.
تبديل اللغة يفقد المسار الحالي
عند تبديل الإعدادات المحلية، حافظ على pathname الحالي باستخدام usePathname() واستبدل مقطع الإعدادات المحلية فقط. انتبه لمعلمات المسارات الديناميكية — إذ يلزم حلّها مجدداً للإعدادات المحلية الجديدة.
بنية الملفات الموصى بها
my-nextjs-app/
├── middleware.ts # Locale routing (project root!)
├── next.config.mjs
├── messages/
│ ├── en.json # Source messages
│ ├── de.json
│ └── ja.json
├── src/
│ ├── i18n/
│ │ ├── request.ts # Message loading config
│ │ └── routing.ts # Locale definitions
│ └── app/
│ └── [locale]/
│ ├── layout.tsx # Root locale layout
│ ├── page.tsx # Home page
│ ├── error.tsx # Localized error page
│ ├── not-found.tsx # Localized 404
│ └── about/
│ └── page.tsx
└── package.jsonجرّب i18n Agent الآن
أفلت ملف الترجمة هنا
JSON, YAML, PO, XML, CSV, Markdown, Properties
أو انقر للاستعراض
اللغات المستهدفة
الرجوع إلى إعدادات محلية بديلة باستخدام next-intl-localechain
عندما يكون مفتاح الترجمة مفقوداً في إعدادات محلية إقليمية مثل pt-BR، يقفز next-intl مباشرة إلى الإعدادات المحلية الافتراضية بدلاً من التحقق أولاً من الإعدادات المحلية الأصلية pt.
npm install next-intl-localechainimport { withLocaleChain } from 'next-intl-localechain';
export default withLocaleChain({
fallbacks: {
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
},
defaultLocale: 'en',
loadMessages: (locale) => import(`./messages/${locale}.json`),
});اطّلع على دليل الرجوع إلى إعدادات محلية بديلة للاطّلاع على القائمة الكاملة للأطر المدعومة و75 سلسلة مدمجة. Learn more →