دليل دمج next-intl مع Next.js 15 لدعم الترجمة والتدويل خطوة بخطوة
شرح خطوة بخطوة لدمج next-intl من أجل الترجمة في مشروع Next.js 15.

الترجمة (i18n) ضرورية لتطبيقات الويب الحديثة. مع Next.js 15، الطريقة الموصى بها لإضافة الترجمة هي استخدام next-intl. في هذا الدليل، ستتعلم كيفية إعداد next-intl في مشروع Next.js 15 بطريقة عملية وفعالة.
🚀 هل تبحث عن قالب Next.js مع next-intl مدمج مسبقاً؟
إذا كنت تريد تخطي الإعداد والبدء بقالب جاهز للإنتاج يتضمن بالفعل التدويل next-intl، تحقق من قالب لوحة التحكم المالية Next.js.
🎯 يتضمن هذا القالب المميز:
- ✅ next-intl مُعد مسبقاً وجاهز للاستخدام
- ✅ تبديل المظهر المظلم/الفاتح
- ✅ إدارة الحالة Redux Toolkit
- ✅ واجهة لوحة تحكم مالية حديثة
- ✅ المصادقة بالبريد الإلكتروني
- ✅ تصميم متجاوب
- ✅ دعم TypeScript
مثالي لتطبيقات التكنولوجيا المالية ولوحات التحكم المصرفية وأنظمة الإدارة المالية.
مشاهدة التجربة | الحصول على القالب
1. تثبيت next-intl
أولاً، قم بتثبيت الحزمة:
npm install next-intl
2. إعداد التوجيه (Routing)
أنشئ ملف إعداد التوجيه لتعريف اللغات المدعومة. في Aniq-UI، يتم ذلك في src/i18n/routing.ts:
// src/i18n/routing.ts
import {defineRouting} from 'next-intl/routing';
export const routing = defineRouting({
locales: ['en', 'fr', 'ar', 'es'],
defaultLocale: 'en'
});
3. إضافة أدوات التنقل
قم بإعداد أدوات التنقل في src/i18n/navigation.ts:
// src/i18n/navigation.ts
import { createNavigation } from 'next-intl/navigation';
import { routing } from './routing';
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);
4. تحميل الرسائل على الخادم
قم بإعداد تحميل الرسائل في src/i18n/request.ts:
// src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { hasLocale } from 'next-intl';
import { routing } from './routing';
export default getRequestConfig(async ({ requestLocale }) => {
const requested = await requestLocale;
const locale = hasLocale(routing.locales, requested)
? requested
: routing.defaultLocale;
const [seoMessages] = await Promise.all([
import(`../messages/seo/${locale}.json`).then(module => module.default).catch(() => ({})),
]);
return {
locale,
messages: {
seo: seoMessages,
}
};
});
5. تمرير الرسائل إلى التطبيق
قم بلف صفحاتك بـ NextIntlClientProvider. على سبيل المثال، في src/app/[locale]/about/layout.tsx:
// src/app/[locale]/about/layout.tsx
import { NextIntlClientProvider } from "next-intl";
export default async function AboutLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
const [about] = await Promise.all([
import(`@/messages/about/${locale}.json`).then((mod) => mod.default),
]);
const messages = { about };
return (
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
);
}
6. تنظيم ملفات الرسائل
احفظ ملفات الترجمة في src/messages/، مثلاً:
src/messages/about/en.json
src/messages/about/fr.json
src/messages/about/ar.json
src/messages/about/es.json
كل ملف يحتوي على ترجمات لمساحة اسم (namespace)، مثلاً:
{
"header_story": "قصتنا",
"header_title1": "نبني",
// ...
}
7. استخدام الترجمات في المكونات
استخدم هوك useTranslations من next-intl:
import { useTranslations } from "next-intl";
export default function AboutHeader() {
const t = useTranslations("about");
return <h1>{t("header_title1")}</h1>;
}
8. إضافة محول اللغة (Language Switcher)
إليك الكود الكامل لمكون LanguageSelector المستخدم في Aniq-UI:
// src/components/LanguageSelector/index.tsx
"use client";
import React, { useState, useRef, useEffect } from "react";
import { useParams, useRouter } from "next/navigation";
import { cn } from "@/lib/utils";
import { IconLanguage, IconChevronDown } from "@/lib/icons";
interface Language {
code: string;
name: string;
rtl: boolean;
}
const languages: Language[] = [
{ code: "en", name: "English", rtl: false },
{ code: "fr", name: "Français", rtl: false },
{ code: "es", name: "Español", rtl: false },
{ code: "ar", name: "العربية", rtl: true },
];
export default function LanguageSelector() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const router = useRouter();
const params = useParams();
const currentLocale = typeof params.locale === "string" ? params.locale : "en";
const currentLanguage = languages.find((lang) => lang.code === currentLocale) || languages[0];
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setIsOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
const changeLanguage = (langCode: string) => {
const currentPath = window.location.pathname;
// استبدال جزء اللغة في المسار
const pathSegments = currentPath.split('/');
pathSegments[1] = langCode;
const newPath = pathSegments.join('/');
router.push(newPath);
setIsOpen(false);
};
return (
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setIsOpen(!isOpen)}
className="flex items-center cursor-pointer px-2 py-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 text-sm"
aria-expanded={isOpen}
aria-haspopup="true"
>
<IconLanguage className="w-4 h-4 mr-1" />
<span className="font-medium text-xs mr-1">{currentLanguage.code.toUpperCase()}</span>
<IconChevronDown className={cn("w-3 h-3 transition-transform", isOpen ? "rotate-180" : "")} />
</button>
{isOpen && (
<div className="absolute z-50 mt-1 bg-white dark:bg-neutral-900 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg py-1 w-40 min-w-max right-0">
<ul className="py-1">
{languages.map((language) => (
<li key={language.code}>
<button
onClick={() => changeLanguage(language.code)}
className={cn(
"w-full text-left cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-800 flex items-center",
language.code === currentLocale && "bg-gray-100 dark:bg-gray-800"
)}
>
<span className="inline-block me-2 w-max font-medium text-xs">{language.code.toUpperCase()}</span>
{language.name}
</button>
</li>
))}
</ul>
</div>
)}
</div>
);
}
9. اختبار الإعداد
شغل الخادم المحلي وزر /en/about أو /fr/about أو غيرها. يجب أن ترى الترجمات الصحيحة ويمكنك التبديل بين اللغات.
الخلاصة
مع next-intl، يصبح التدويل في Next.js 15 سهلاً وقويًا. لمثال عملي كامل، راجع مستودع Aniq-UI.
المراجع:
هل وجدت هذا المقال مفيدًا؟
قد يعجبك أيضًا

دليل تحسين أداء تطبيقات Next.js: تقنيات عملية وتسريع المواقع
تعلم كيفية تسريع تطبيقات Next.js من خلال تحسين الصور وتقسيم الكود والتوليد الثابت وتحميل الخطوط وتقليل حجم الحزمة.

تعزيز أداء Next.js باستخدام TanStack Query (React Query)
اكتشف كيف يحسّن TanStack Query أداء Next.js عبر التخزين المؤقت، التحديث الخلفي، الطفرات، ودمج SSR/SSG.

Publino: أفضل قالب Next.js لصفحات الهبوط للشركات الناشئة الحديثة
اكتشف Publino، قالب Next.js عالي الأداء ومحسن للسيو، مصمم للـSaaS والشركات الناشئة والوكالات. أنشئ واطلق مواقع مذهلة في دقائق.