تدويل Next.js مع next-intl — دليل شامل لتعدد اللغات مع App Router

بناء تطبيقات للجمهور العالمي يتطلب أكثر من مجرد ترجمة النصوص. تحتاج إلى توجيه مبني على اللغة، ودعم التخطيط من اليمين إلى اليسار (RTL)، وقواعد الجمع، وتنسيق التواريخ والأرقام، وتجربة مطور تتوسع مع نمو تطبيقك. أصبح next-intl الحل المفضل لتدويل تطبيقات Next.js مع App Router، حيث يوفر ترجمات آمنة الأنواع، ودعم مكونات الخادم، وتكامل سلس مع React Server Components.
في هذا الدليل، ستبني تطبيق Next.js متعدد اللغات بالكامل يدعم الإنجليزية والعربية (RTL) والفرنسية — من إعداد المشروع إلى أنماط النشر الإنتاجي.
المتطلبات الأساسية
قبل البدء، تأكد من توفر:
- Node.js 20+ مثبت على جهازك
- معرفة أساسية بـ Next.js App Router (التخطيطات، الصفحات، مكونات الخادم)
- إلمام بـ TypeScript
- محرر أكواد مثل VS Code مع إضافة i18n Ally (موصى به)
ما الذي ستبنيه
تطبيق Next.js متعدد اللغات يتضمن:
- توجيه مبني على اللغة (
/en/about،/ar/about،/fr/about) - اكتشاف تلقائي للغة وإعادة التوجيه
- دعم تخطيط RTL للعربية
- رسائل ترجمة آمنة الأنواع
- محتوى ديناميكي مع الاستيفاء وصيغ الجمع
- تنسيق تواريخ وأرقام حسب اللغة
- مكون تبديل اللغات
- تحسين SEO مع وسوم
hreflangالصحيحة
الخطوة 1: إنشاء مشروع Next.js جديد
ابدأ بإنشاء تطبيق Next.js جديد:
npx create-next-app@latest my-i18n-app --typescript --tailwind --eslint --app --src-dir
cd my-i18n-appثبّت next-intl:
npm install next-intlهيكل المشروع يجب أن يكون كالتالي:
my-i18n-app/
├── src/
│ ├── app/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ └── ...
├── package.json
└── tsconfig.json
الخطوة 2: تحديد إعدادات التدويل
أنشئ ملف الإعدادات الذي يحدد اللغات المدعومة واللغة الافتراضية.
أنشئ src/i18n/config.ts:
export const locales = ["en", "ar", "fr"] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = "en";
export const localeNames: Record<Locale, string> = {
en: "English",
ar: "العربية",
fr: "Français",
};
// اللغات التي تستخدم اتجاه النص من اليمين إلى اليسار
export const rtlLocales: Locale[] = ["ar"];
export function isRtlLocale(locale: Locale): boolean {
return rtlLocales.includes(locale);
}الخطوة 3: إنشاء ملفات الترجمة
أنشئ مجلد messages في جذر المشروع مع ملف JSON لكل لغة.
messages/en.json:
{
"Metadata": {
"title": "My International App",
"description": "A fully internationalized Next.js application"
},
"Navigation": {
"home": "Home",
"about": "About",
"contact": "Contact",
"blog": "Blog"
},
"HomePage": {
"title": "Welcome to Our Platform",
"subtitle": "Build global applications with ease",
"cta": "Get Started",
"features": {
"title": "Why Choose Us",
"speed": "Lightning Fast",
"speedDescription": "Optimized for performance across all regions",
"i18n": "Built for Global",
"i18nDescription": "Native support for {count, plural, =1 {# language} other {# languages}}",
"secure": "Enterprise Security",
"secureDescription": "Bank-grade encryption and compliance"
},
"stats": {
"users": "{count, number} active users",
"countries": "Available in {count, number} countries",
"uptime": "{value}% uptime"
}
},
"Common": {
"loading": "Loading...",
"error": "Something went wrong",
"retry": "Try Again",
"back": "Go Back",
"lastUpdated": "Last updated: {date, date, medium}"
}
}messages/ar.json:
{
"Metadata": {
"title": "تطبيقي الدولي",
"description": "تطبيق Next.js متعدد اللغات بالكامل"
},
"Navigation": {
"home": "الرئيسية",
"about": "من نحن",
"contact": "اتصل بنا",
"blog": "المدونة"
},
"HomePage": {
"title": "مرحباً بكم في منصتنا",
"subtitle": "بناء تطبيقات عالمية بسهولة",
"cta": "ابدأ الآن",
"features": {
"title": "لماذا تختارنا",
"speed": "سرعة فائقة",
"speedDescription": "محسّن للأداء في جميع المناطق",
"i18n": "مصمم للعالمية",
"i18nDescription": "{count, plural, =1 {لغة واحدة} two {لغتان} few {# لغات} many {# لغة} other {# لغة}}",
"secure": "أمان مؤسسي",
"secureDescription": "تشفير بمستوى البنوك والامتثال"
},
"stats": {
"users": "{count, number} مستخدم نشط",
"countries": "متاح في {count, number} دولة",
"uptime": "{value}٪ وقت التشغيل"
}
},
"Common": {
"loading": "جارٍ التحميل...",
"error": "حدث خطأ ما",
"retry": "حاول مرة أخرى",
"back": "العودة",
"lastUpdated": "آخر تحديث: {date, date, medium}"
}
}messages/fr.json:
{
"Metadata": {
"title": "Mon Application Internationale",
"description": "Une application Next.js entièrement internationalisée"
},
"Navigation": {
"home": "Accueil",
"about": "À propos",
"contact": "Contact",
"blog": "Blog"
},
"HomePage": {
"title": "Bienvenue sur Notre Plateforme",
"subtitle": "Créez des applications mondiales facilement",
"cta": "Commencer",
"features": {
"title": "Pourquoi Nous Choisir",
"speed": "Ultra Rapide",
"speedDescription": "Optimisé pour la performance dans toutes les régions",
"i18n": "Conçu pour le Monde",
"i18nDescription": "{count, plural, =1 {# langue} other {# langues}} prises en charge nativement",
"secure": "Sécurité Entreprise",
"secureDescription": "Chiffrement de niveau bancaire et conformité"
},
"stats": {
"users": "{count, number} utilisateurs actifs",
"countries": "Disponible dans {count, number} pays",
"uptime": "{value} % de disponibilité"
}
},
"Common": {
"loading": "Chargement...",
"error": "Une erreur est survenue",
"retry": "Réessayer",
"back": "Retour",
"lastUpdated": "Dernière mise à jour : {date, date, medium}"
}
}لاحظ كيف تستخدم الترجمات العربية قواعد جمع ICU مع الفئات الخاصة بالعربية (two، few، many)، والتي يعالجها next-intl تلقائياً من خلال معيار ICU MessageFormat.
الخطوة 4: إعداد تهيئة الطلبات في next-intl
أنشئ src/i18n/request.ts — هذا هو الإعداد الأساسي الذي يستخدمه next-intl لحل الرسائل لكل طلب:
import { getRequestConfig } from "next-intl/server";
import { locales, type Locale } from "./config";
export default getRequestConfig(async ({ requestLocale }) => {
// التحقق من أن اللغة المطلوبة مدعومة
let locale = await requestLocale;
if (!locale || !locales.includes(locale as Locale)) {
locale = "en";
}
return {
locale,
messages: (await import(`../../../messages/${locale}.json`)).default,
timeZone: "UTC",
now: new Date(),
};
});الخطوة 5: تهيئة Next.js مع إضافة next-intl
حدّث ملف next.config.ts ليتضمن إضافة next-intl:
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
const nextConfig = {
// إعدادات Next.js الحالية
};
export default withNextIntl(nextConfig);الخطوة 6: إعداد التوجيه المبني على اللغة
أعد هيكلة مجلد app لاستخدام مقطع ديناميكي [locale]. هذا هو أساس التوجيه المبني على اللغة.
src/app/
├── [locale]/
│ ├── layout.tsx # التخطيط الجذري مع اللغة
│ ├── page.tsx # الصفحة الرئيسية
│ ├── about/
│ │ └── page.tsx # صفحة من نحن
│ └── contact/
│ └── page.tsx # صفحة التواصل
├── layout.tsx # تخطيط جذري بسيط (بدون لغة)
└── not-found.tsx # صفحة 404 عامة
أنشئ التخطيط الجذري src/app/layout.tsx (بسيط — يمرر الأبناء فقط):
import { ReactNode } from "react";
type Props = {
children: ReactNode;
};
export default function RootLayout({ children }: Props) {
return children;
}الآن أنشئ src/app/[locale]/layout.tsx — هنا يوجد منطق التخطيط الحقيقي:
import { ReactNode } from "react";
import { notFound } from "next/navigation";
import { NextIntlClientProvider } from "next-intl";
import { getMessages, setRequestLocale } from "next-intl/server";
import { locales, type Locale, isRtlLocale } from "@/i18n/config";
import "./globals.css";
type Props = {
children: ReactNode;
params: Promise<{ locale: string }>;
};
export function generateStaticParams() {
return locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({ children, params }: Props) {
const { locale } = await params;
// التحقق من اللغة
if (!locales.includes(locale as Locale)) {
notFound();
}
// تفعيل العرض الثابت
setRequestLocale(locale);
// الحصول على جميع الرسائل للغة الحالية
const messages = await getMessages();
const dir = isRtlLocale(locale as Locale) ? "rtl" : "ltr";
return (
<html lang={locale} dir={dir}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}النقاط الرئيسية:
generateStaticParamsيفعّل التوليد الثابت لجميع اللغاتsetRequestLocaleيفعّل العرض الثابت (مطلوب للتوليد الثابت)NextIntlClientProviderيجعل الترجمات متاحة لمكونات العميل- خاصية
dirتُعيّن ديناميكياً —rtlللعربية،ltrللبقية
الخطوة 7: إنشاء الـ Middleware لاكتشاف اللغة
أنشئ src/middleware.ts في جذر المصدر:
import createMiddleware from "next-intl/middleware";
import { locales, defaultLocale } from "./i18n/config";
export default createMiddleware({
locales,
defaultLocale,
// إعادة التوجيه إلى مسارات مسبوقة باللغة
localePrefix: "always",
// اكتشاف اللغة من رأس Accept-Language
localeDetection: true,
});
export const config = {
// مطابقة جميع المسارات باستثناء API والملفات الثابتة
matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
};مع هذا الـ Middleware:
- زيارة
/تعيد التوجيه إلى/en(أو اللغة المكتشفة) - زيارة
/aboutتعيد التوجيه إلى/en/about - زيارة
/ar/aboutتعرض النسخة العربية مباشرة - يُستخدم رأس
Accept-Languageللزوار الجدد
الخطوة 8: بناء الصفحة الرئيسية مع الترجمات
أنشئ src/app/[locale]/page.tsx:
import { useTranslations } from "next-intl";
import { setRequestLocale } from "next-intl/server";
type Props = {
params: Promise<{ locale: string }>;
};
export default async function HomePage({ params }: Props) {
const { locale } = await params;
setRequestLocale(locale);
return <HomeContent />;
}
function HomeContent() {
const t = useTranslations("HomePage");
return (
<main className="min-h-screen">
{/* قسم البطل */}
<section className="flex flex-col items-center justify-center px-4 py-24 text-center">
<h1 className="mb-4 text-5xl font-bold tracking-tight">
{t("title")}
</h1>
<p className="mb-8 max-w-2xl text-xl text-gray-600">
{t("subtitle")}
</p>
<button className="rounded-lg bg-blue-600 px-8 py-3 text-lg font-semibold text-white transition hover:bg-blue-700">
{t("cta")}
</button>
</section>
{/* قسم الميزات */}
<section className="mx-auto max-w-6xl px-4 py-16">
<h2 className="mb-12 text-center text-3xl font-bold">
{t("features.title")}
</h2>
<div className="grid gap-8 md:grid-cols-3">
<FeatureCard
title={t("features.speed")}
description={t("features.speedDescription")}
/>
<FeatureCard
title={t("features.i18n")}
description={t("features.i18nDescription", { count: 3 })}
/>
<FeatureCard
title={t("features.secure")}
description={t("features.secureDescription")}
/>
</div>
</section>
{/* قسم الإحصائيات */}
<section className="bg-gray-50 px-4 py-16 dark:bg-gray-900">
<div className="mx-auto grid max-w-4xl gap-8 text-center md:grid-cols-3">
<div>
<p className="text-4xl font-bold text-blue-600">
{t("stats.users", { count: 50000 })}
</p>
</div>
<div>
<p className="text-4xl font-bold text-blue-600">
{t("stats.countries", { count: 120 })}
</p>
</div>
<div>
<p className="text-4xl font-bold text-blue-600">
{t("stats.uptime", { value: 99.9 })}
</p>
</div>
</div>
</section>
</main>
);
}
function FeatureCard({
title,
description,
}: {
title: string;
description: string;
}) {
return (
<div className="rounded-xl border p-6 transition hover:shadow-lg">
<h3 className="mb-2 text-xl font-semibold">{title}</h3>
<p className="text-gray-600">{description}</p>
</div>
);
}لاحظ كيف يعمل useTranslations في مكونات الخادم — لا حاجة لتوجيه "use client". تدعم دالة t() صيغة ICU MessageFormat لقواعد الجمع وتنسيق الأرقام تلقائياً.
الخطوة 9: بناء مكون تبديل اللغات
أنشئ src/components/LanguageSwitcher.tsx:
"use client";
import { useLocale, useTranslations } from "next-intl";
import { useRouter, usePathname } from "next/navigation";
import { locales, localeNames, type Locale } from "@/i18n/config";
import { useTransition } from "react";
export default function LanguageSwitcher() {
const locale = useLocale();
const router = useRouter();
const pathname = usePathname();
const t = useTranslations("LanguageSwitcher");
const [isPending, startTransition] = useTransition();
function handleLocaleChange(newLocale: string) {
// استبدال مقطع اللغة الحالي في المسار
const segments = pathname.split("/");
segments[1] = newLocale;
const newPathname = segments.join("/");
startTransition(() => {
router.replace(newPathname);
});
}
return (
<div className="relative">
<label htmlFor="locale-select" className="sr-only">
{t("label")}
</label>
<select
id="locale-select"
value={locale}
onChange={(e) => handleLocaleChange(e.target.value)}
disabled={isPending}
className="appearance-none rounded-lg border bg-white px-4 py-2 text-sm font-medium shadow-sm transition hover:border-blue-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:opacity-50 dark:bg-gray-800 rtl:text-right"
aria-label={t("current", { language: localeNames[locale as Locale] })}
>
{locales.map((loc) => (
<option key={loc} value={loc}>
{localeNames[loc]}
</option>
))}
</select>
{isPending && (
<span className="absolute end-2 top-1/2 -translate-y-1/2">
<span className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" />
</span>
)}
</div>
);
}هذا المكون:
- يستخدم
useTransitionلتبديل سلس بين اللغات دون حجب واجهة المستخدم - يستبدل مقطع اللغة في مسار URL
- يعرض مؤشر تحميل أثناء الانتقال
- يستخدم
rtl:text-rightلمحاذاة RTL الصحيحة - متاح بالكامل مع وسوم ARIA المناسبة
الخطوة 10: التعامل مع تخطيطات RTL باستخدام Tailwind CSS
يتضمن Tailwind CSS v3.3+ دعم RTL مدمج باستخدام المتغيرات rtl: و ltr:. بما أننا عيّنّا خاصية dir في التخطيط، تعمل هذه المتغيرات تلقائياً.
إليك الأنماط الرئيسية لتخطيطات واعية بـ RTL:
{/* استخدم الخصائص المنطقية بدل الفيزيائية */}
{/* بدل ml-4 / mr-4، استخدم ms-4 / me-4 */}
<div className="ms-4">هامش في البداية (يسار في LTR، يمين في RTL)</div>
<div className="me-4">هامش في النهاية (يمين في LTR، يسار في RTL)</div>
{/* بدل pl-4 / pr-4، استخدم ps-4 / pe-4 */}
<div className="ps-6 pe-2">حشو البداية والنهاية</div>
{/* بدل left-0 / right-0، استخدم start-0 / end-0 */}
<div className="absolute start-0">موضع في البداية</div>
{/* للأيقونات الاتجاهية التي تحتاج للقلب */}
<svg className="rtl:rotate-180">→</svg>
{/* محاذاة النص */}
<p className="text-start">محاذاة لبداية اتجاه النص</p>
{/* Flexbox و Grid - واعية تلقائياً بـ RTL */}
<div className="flex gap-4">العناصر تتدفق بشكل صحيح في كلا الاتجاهين</div>القاعدة الأهم: استخدم الخصائص المنطقية (start/end) بدل الفيزيائية (left/right). هذا التغيير الواحد يعالج 90% من مشاكل تخطيط RTL.
الخطوة 11: إضافة أمان الأنواع للترجمات
من أقوى ميزات next-intl هي الترجمات الآمنة الأنواع. أنشئ ملف تصريح أنواع للحصول على الإكمال التلقائي والتحقق في وقت الترجمة.
أنشئ src/i18n/types.ts:
import en from "../../messages/en.json";
// استخدام الرسائل الإنجليزية كمصدر حقيقة للأنواع
type Messages = typeof en;
declare global {
interface IntlMessages extends Messages {}
}الآن عند استخدام t("HomePage.features.speed")، سيقوم TypeScript بـ:
- إكمال مفاتيح الرسائل المتاحة تلقائياً
- عرض خطأ إذا أشرت إلى مفتاح غير موجود
- التحقق من معاملات الاستيفاء
الخطوة 12: تنسيق التواريخ والأرقام والأوقات النسبية
يوفر next-intl أدوات تنسيق واعية باللغة تستفيد من واجهة Intl.
import { useFormatter, useNow, useTranslations } from "next-intl";
function StatsSection() {
const format = useFormatter();
const now = useNow();
const t = useTranslations("Common");
// تنسيق الأرقام
const revenue = format.number(1234567.89, {
style: "currency",
currency: "USD",
});
// en: "$1,234,567.89" | ar: "١٬٢٣٤٬٥٦٧٫٨٩ US$" | fr: "1 234 567,89 $US"
// تنسيق التاريخ
const date = format.dateTime(new Date("2026-03-18"), {
year: "numeric",
month: "long",
day: "numeric",
});
// en: "March 18, 2026" | ar: "١٨ مارس ٢٠٢٦" | fr: "18 mars 2026"
// الوقت النسبي
const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const relative = format.relativeTime(lastWeek);
// en: "7 days ago" | ar: "قبل ٧ أيام" | fr: "il y a 7 jours"
return (
<div>
<p>{revenue}</p>
<p>{date}</p>
<p>{relative}</p>
<p>{t("lastUpdated", { date: new Date() })}</p>
</div>
);
}الخطوة 13: التعامل مع المحتوى الديناميكي والنص المنسق
يدعم next-intl تنسيق النص المنسق، مما يسمح لك بتضمين مكونات داخل نصوص مترجمة.
في ملفات الرسائل:
{
"RichText": {
"welcome": "مرحباً بكم في <bold>منصتنا</bold>. اقرأ <link>شروط الخدمة</link>.",
"highlight": "هذه الميزة <highlight>جديدة</highlight> ومتاحة لمستخدمي <badge>Pro</badge>."
}
}في المكون:
import { useTranslations } from "next-intl";
function WelcomeMessage() {
const t = useTranslations("RichText");
return (
<p>
{t.rich("welcome", {
bold: (chunks) => <strong>{chunks}</strong>,
link: (chunks) => (
<a href="/terms" className="text-blue-600 underline">
{chunks}
</a>
),
})}
</p>
);
}هذا النهج يبقي ملفات الترجمة نظيفة مع السماح للمترجمين بالتحكم في ترتيب الكلمات — وهو أمر حاسم للغات مثل العربية حيث يختلف هيكل الجملة بشكل كبير عن الإنجليزية.
الخطوة 14: إضافة SEO مع بيانات وصفية واعية باللغة
أنشئ بيانات وصفية صحيحة لكل لغة، بما في ذلك روابط hreflang البديلة.
حدّث src/app/[locale]/layout.tsx:
import { getTranslations } from "next-intl/server";
import { locales } from "@/i18n/config";
import type { Metadata } from "next";
type Props = {
params: Promise<{ locale: string }>;
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: "Metadata" });
// توليد روابط بديلة لجميع اللغات
const languages: Record<string, string> = {};
for (const loc of locales) {
languages[loc] = `https://example.com/${loc}`;
}
return {
title: {
default: t("title"),
template: `%s | ${t("title")}`,
},
description: t("description"),
alternates: {
languages,
},
openGraph: {
title: t("title"),
description: t("description"),
locale: locale,
alternateLocale: locales.filter((l) => l !== locale),
},
};
}الخطوة 15: اختبار تطبيقك المتعدد اللغات
شغّل خادم التطوير وتحقق من كل شيء:
npm run devاختبر هذه السيناريوهات:
- إعادة التوجيه الافتراضية: زر
http://localhost:3000— يجب أن تتم إعادة التوجيه إلى/en - تبديل اللغة: استخدم مبدّل اللغات للتنقل بين الإنجليزية والعربية والفرنسية
- تخطيط RTL: بدّل إلى العربية وتحقق من أن التخطيط يعكس بشكل صحيح
- الوصول المباشر: زر
http://localhost:3000/arمباشرة - استيفاء الترجمة: تحقق من أن الأرقام والتواريخ وصيغ الجمع تُعرض بشكل صحيح
- معالجة 404: زر
http://localhost:3000/de(لغة غير مدعومة)
الخطوة 16: نصائح تحسين الإنتاج
تفعيل العرض الثابت
للحصول على أفضل أداء، فعّل التوليد الثابت لجميع صفحاتك المحلية. أضف setRequestLocale في أعلى كل صفحة وتخطيط يستخدم الترجمات:
import { setRequestLocale } from "next-intl/server";
export default async function Page({ params }: Props) {
const { locale } = await params;
setRequestLocale(locale);
// ... بقية المكون
}تقسيم الرسائل
للتطبيقات الكبيرة، تجنب تحميل جميع الترجمات في كل صفحة. قسّم الرسائل حسب مساحة الاسم لتحسين حجم الحزمة من جانب العميل.
تحليل الحزمة
تحقق من أن حزم الترجمة لا تضخم JavaScript من جانب العميل:
npx @next/bundle-analyzerمكونات الخادم التي تستخدم useTranslations لا تضيف ترجمات إلى حزمة العميل — فقط المكونات التي تحمل "use client" وتستخدم NextIntlClientProvider تتضمن الترجمات في حزمة العميل.
استكشاف الأخطاء
مشكلة شائعة: "Unable to find next-intl locale"
عادة تعني أن الـ Middleware لا يطابق مساراتك. تحقق من:
- نمط
matcherفيmiddleware.tsصحيح - ملف الـ Middleware في
src/middleware.ts(ليس داخلapp/) - أعدت تشغيل خادم التطوير بعد إضافة الـ Middleware
مشكلة شائعة: عدم تطابق الهيدريشن مع RTL
إذا رأيت تحذيرات هيدريشن عند التبديل بين LTR و RTL:
- تأكد أن
dirوlangمعيّنان على عنصرhtmlفي تخطيط الخادم - أضف
suppressHydrationWarningلوسمhtmlإذا كنت تستخدم مزود سمة
الخطوات التالية
الآن بعد أن لديك أساس i18n قوي، فكّر في:
- إضافة المزيد من اللغات — فقط أنشئ ملف رسائل جديد وأضف اللغة لإعداداتك
- إعداد نظام إدارة الترجمة مثل Crowdin أو Lokalise لسير عمل الترجمة الجماعية
- تنفيذ محتوى خاص باللغة — صور أو فيديوهات أو تخطيطات مختلفة لكل لغة
- إضافة بحث واعي باللغة مع تحليل نصي مناسب لكل لغة
الخلاصة
لقد بنيت تطبيق Next.js متعدد اللغات جاهز للإنتاج مع next-intl يدعم:
- ترجمات آمنة الأنواع مع إكمال تلقائي
- توجيه مبني على اللغة مع اكتشاف تلقائي
- دعم تخطيط RTL للعربية باستخدام خصائص Tailwind CSS المنطقية
- صيغة ICU MessageFormat لقواعد الجمع والتنسيق
- بيانات وصفية محسنة لـ SEO مع وسوم hreflang
- تجربة تبديل لغات سلسة
مزيج Next.js App Router و next-intl يوفر واحدة من أفضل تجارب المطورين لبناء تطبيقات متعددة اللغات. النهج القائم على الخادم يعني أن الترجمات لا تضخم حزمة العميل، ودعم صيغة ICU MessageFormat يعالج تفاصيل اللغات المختلفة — من قواعد الجمع العربية إلى تنسيق الأرقام الفرنسية — بدون أي منطق مخصص.
سواء كنت تبني لمنطقة الشرق الأوسط وشمال أفريقيا، أو الأسواق الأوروبية، أو جمهور عالمي حقيقي، هذا الأساس يتوسع مع تطبيقك ويبقي سير عمل الترجمة قابلاً للصيانة مع نمو محتواك.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

بناء تطبيق كامل يعمل بالوقت الحقيقي باستخدام Convex و Next.js 15
تعلّم كيفية بناء تطبيق كامل يعمل بالوقت الحقيقي باستخدام Convex و Next.js 15. يغطي هذا الدليل تصميم المخططات والاستعلامات والتعديلات والاشتراكات الفورية والمصادقة ورفع الملفات — مع أمان أنواع شامل.

إضافة المصادقة لتطبيق Next.js 15 باستخدام Auth.js v5: البريد الإلكتروني وOAuth والتحكم بالأدوار
تعلم كيفية إضافة نظام مصادقة جاهز للإنتاج لتطبيق Next.js 15 باستخدام Auth.js v5. يغطي هذا الدليل الشامل تسجيل الدخول عبر Google OAuth وبيانات الاعتماد بالبريد الإلكتروني وكلمة المرور والمسارات المحمية والتحكم بالوصول حسب الأدوار.

بناء روبوت دردشة ذكاء اصطناعي محلي باستخدام Ollama و Next.js: الدليل الشامل
ابنِ روبوت دردشة ذكاء اصطناعي خاص يعمل بالكامل على جهازك المحلي باستخدام Ollama و Next.js. يغطي هذا الدليل العملي التثبيت والبث المباشر واختيار النماذج وبناء واجهة دردشة جاهزة للإنتاج — كل ذلك دون إرسال بياناتك إلى السحابة.