Getting Started internationalizing (i18n) with Intlayer and Next.js 15 App Router
ما هو Intlayer؟
Intlayer هو مكتبة مفتوحة المصدر مبتكرة للتدويل (i18n) مصممة لتبسيط دعم اللغات المتعددة في تطبيقات الويب الحديثة. يتكامل Intlayer بسلاسة مع أحدث إطار عمل Next.js 15، بما في ذلك App Router القوي. تم تحسينه للعمل مع Server Components لتقديم فعال وهو متوافق تمامًا مع Turbopack.
مع Intlayer، يمكنك:
- إدارة الترجمات بسهولة باستخدام القواميس التصريحية على مستوى المكونات.
- توطين البيانات الوصفية ديناميكيًا، والمسارات، والمحتوى.
- الوصول إلى الترجمات في مكونات العميل والخادم.
- ضمان دعم TypeScript مع الأنواع المولدة تلقائيًا، مما يحسن الإكمال التلقائي واكتشاف الأخطاء.
- الاستفادة من الميزات المتقدمة، مثل اكتشاف اللغة الديناميكي والتبديل.
Intlayer متوافق مع Next.js 12، 13، 14، و15. إذا كنت تستخدم Next.js Page Router، يمكنك الرجوع إلى هذا الدليل. بالنسبة لـ Next.js 12، 13، 14 مع App Router، راجع هذا الدليل.
دليل خطوة بخطوة لإعداد Intlayer في تطبيق Next.js
الخطوة 1: تثبيت التبعيات
قم بتثبيت الحزم اللازمة باستخدام npm:
npm install intlayer next-intlayer
intlayer
الحزمة الأساسية التي توفر أدوات التدويل لإدارة التكوين، والترجمة، وإعلان المحتوى، والترجمة، وأوامر CLI.
next-intlayer
الحزمة التي تدمج Intlayer مع Next.js. توفر موفري السياق وخطافات لتدويل Next.js. بالإضافة إلى ذلك، تتضمن مكون إضافي لـ Next.js لدمج Intlayer مع Webpack أو Turbopack، بالإضافة إلى البرامج الوسيطة لاكتشاف اللغة المفضلة للمستخدم، وإدارة ملفات تعريف الارتباط، ومعالجة إعادة توجيه URL.
الخطوة 2: تكوين مشروعك
قم بإنشاء ملف تكوين لتحديد لغات تطبيقك:
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // لغاتك الأخرى ], defaultLocale: Locales.ENGLISH, },};export default config;
من خلال ملف التكوين هذا، يمكنك إعداد عناوين URL المحلية، وإعادة توجيه البرامج الوسيطة، وأسماء ملفات تعريف الارتباط، وموقع وامتداد إعلانات المحتوى الخاصة بك، وتعطيل سجلات Intlayer في وحدة التحكم، والمزيد. للحصول على قائمة كاملة بالمعلمات المتاحة، راجع وثائق التكوين.
الخطوة 3: دمج Intlayer في تكوين Next.js الخاص بك
قم بتكوين إعداد Next.js الخاص بك لاستخدام Intlayer:
import type { NextConfig } from "next";import { withIntlayer } from "next-intlayer/server";const nextConfig: NextConfig = { /* خيارات التكوين هنا */};export default withIntlayer(nextConfig);
يتم استخدام مكون Next.js الإضافي withIntlayer() لدمج Intlayer مع Next.js. يضمن بناء ملفات إعلان المحتوى ومراقبتها في وضع التطوير. يحدد متغيرات بيئة Intlayer داخل بيئات Webpack أو Turbopack. بالإضافة إلى ذلك، يوفر أسماء مستعارة لتحسين الأداء ويضمن التوافق مع مكونات الخادم.
الخطوة 4: تحديد مسارات اللغة الديناميكية
قم بإزالة كل شيء من RootLayout واستبدله بالكود التالي:
import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;
إبقاء مكون RootLayout فارغًا يسمح بتعيين سمات lang و dir إلى علامة <html>.
لتنفيذ التوجيه الديناميكي، قم بتوفير المسار للغة عن طريق إضافة تخطيط جديد في دليل [locale] الخاص بك:
import type { NextLayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { const { locale } = await params; return ( <html lang={locale} dir={getHTMLTextDir(locale)}> <body className={inter.className}>{children}</body> </html> );};export default LocaleLayout;
يتم استخدام جزء المسار [locale] لتحديد اللغة. مثال: /en-US/about سيشير إلى en-US و /fr/about إلى fr.
ثم قم بتنفيذ وظيفة generateStaticParams في تخطيط تطبيقك.
export { generateStaticParams } from "next-intlayer"; // السطر المراد إدراجهconst LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { /*... باقي الكود*/};export default LocaleLayout;
يضمن generateStaticParams أن يقوم تطبيقك ببناء الصفحات الضرورية مسبقًا لجميع اللغات، مما يقلل من حساب وقت التشغيل ويحسن تجربة المستخدم. لمزيد من التفاصيل، راجع وثائق Next.js حول generateStaticParams.
الخطوة 5: إعلان المحتوى الخاص بك
قم بإنشاء وإدارة إعلانات المحتوى الخاصة بك لتخزين الترجمات:
import { t, type Dictionary } from "intlayer";const pageContent = { key: "page", content: { getStarted: { main: t({ en: "Get started by editing", fr: "Commencez par éditer", es: "Comience por editar", ar: "ابدأ بالتعديل", }), pageLink: "src/app/page.tsx", }, },} satisfies Dictionary;export default pageContent;
يمكن تعريف إعلانات المحتوى الخاصة بك في أي مكان في تطبيقك طالما تم تضمينها في دليل contentDir (افتراضيًا، ./src). وتطابق امتداد ملف إعلان المحتوى (افتراضيًا، .content.{ts,tsx,js,jsx,mjs,cjs}). لمزيد من التفاصيل، راجع وثائق إعلان المحتوى.
الخطوة 6: استخدام المحتوى في الكود الخاص بك
الوصول إلى قواميس المحتوى الخاصة بك في جميع أنحاء التطبيق الخاص بك:
import type { FC } from "react";import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type NextPageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const PageContent: FC = () => { const { title, content } = useIntlayer("page"); return ( <> <p>{content.getStarted.main}</p> <code>{content.getStarted.pageLink}</code> </> );};const Page: NextPageIntlayer = async ({ params }) => { const { locale } = await params; return ( <IntlayerServerProvider locale={locale}> <PageContent /> <ServerComponentExample /> <IntlayerClientProvider locale={locale}> <ClientComponentExample /> </IntlayerClientProvider> </IntlayerServerProvider> );};export default Page;
- IntlayerClientProvider تُستخدم لتوفير اللغة للمكونات على جانب العميل. يمكن وضعها في أي مكون رئيسي، بما في ذلك التخطيط. ومع ذلك، يُوصى بوضعها في التخطيط لأن Next.js يشارك كود التخطيط عبر الصفحات، مما يجعله أكثر كفاءة. باستخدام IntlayerClientProvider في التخطيط، تتجنب إعادة تهيئتها لكل صفحة، مما يحسن الأداء ويحافظ على سياق توطين متسق في جميع أنحاء تطبيقك.
IntlayerServerProvider تُستخدم لتوفير اللغة للأطفال على الخادم. لا يمكن تعيينها في التخطيط.
لا يمكن للتخطيط والصفحة مشاركة سياق خادم مشترك لأن نظام سياق الخادم يعتمد على متجر بيانات لكل طلب (عبر آلية ذاكرة التخزين المؤقت لـ React)، مما يتسبب في إعادة إنشاء كل "سياق" لشرائح مختلفة من التطبيق. سيؤدي وضع الموفر في تخطيط مشترك إلى كسر هذا العزل، مما يمنع الانتشار الصحيح لقيم سياق الخادم إلى مكونات الخادم الخاصة بك.
"use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";export const ClientComponentExample: FC = () => { const content = useIntlayer("client-component-example"); // قم بإنشاء إعلان محتوى ذي صلة return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";export const ServerComponentExample: FC = () => { const content = useIntlayer("server-component-example"); // قم بإنشاء إعلان محتوى ذي صلة return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
إذا كنت تريد استخدام المحتوى الخاص بك في سمة string، مثل alt، title، href، aria-label، إلخ، يجب عليك استدعاء قيمة الوظيفة، مثل:
jsx<img src={content.image.src.value} alt={content.image.value} />
لمعرفة المزيد عن خطاف useIntlayer، راجع الوثائق.
(اختياري) الخطوة 7: تكوين البرامج الوسيطة لاكتشاف اللغة
قم بإعداد البرامج الوسيطة لاكتشاف اللغة المفضلة للمستخدم:
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\..*|_next).*)",};
يتم استخدام intlayerMiddleware لاكتشاف اللغة المفضلة للمستخدم وإعادة توجيههم إلى عنوان URL المناسب كما هو محدد في التكوين. بالإضافة إلى ذلك، فإنه يمكّن من حفظ اللغة المفضلة للمستخدم في ملف تعريف ارتباط.
(اختياري) الخطوة 8: تدويل البيانات الوصفية الخاصة بك
في حالة رغبتك في تدويل البيانات الوصفية الخاصة بك، مثل عنوان صفحتك، يمكنك استخدام وظيفة generateMetadata التي يوفرها Next.js. داخل الوظيفة، استخدم وظيفة getTranslation لترجمة البيانات الوصفية الخاصة بك.
import { type IConfigLocales, getTranslation, getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalPromiseParams } from "next-intlayer";export const generateMetadata = async ({ params,}: LocalPromiseParams): Promise<Metadata> => { const { locale } = await params; const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale); /** * يولد كائنًا يحتوي على جميع عناوين URL لكل لغة. * * مثال: * ```ts * getMultilingualUrls('/about'); * * // يعيد * // { * // en: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); return { title: t<string>({ en: "My title", fr: "Mon titre", es: "Mi título", ar: "عنواني", }), description: t({ en: "My description", fr: "Ma description", es: "Mi descripción", ar: "وصف صفحتي", }), alternates: { canonical: "/", languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: multilingualUrls[locale], }, };};// ... باقي الكود
تعرف على المزيد حول تحسين البيانات الوصفية في وثائق Next.js الرسمية.
(اختياري) الخطوة 9: تدويل ملف sitemap.xml و robots.txt
لتدويل ملف sitemap.xml و robots.txt، يمكنك استخدام وظيفة getMultilingualUrls التي يوفرها Intlayer. تتيح لك هذه الوظيفة إنشاء عناوين URL متعددة اللغات لخريطة الموقع الخاصة بك.
import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [ { url: "https://example.com", alternates: { languages: { ...getMultilingualUrls("https://example.com") }, }, }, { url: "https://example.com/login", alternates: { languages: { ...getMultilingualUrls("https://example.com/login") }, }, }, { url: "https://example.com/register", alternates: { languages: { ...getMultilingualUrls("https://example.com/register") }, }, },];export default sitemap;
import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) => urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({ rules: { userAgent: "*", allow: ["/"], disallow: getAllMultilingualUrls(["/login", "/register"]), }, host: "https://example.com", sitemap: `https://example.com/sitemap.xml`,});export default robots;
تعرف على المزيد حول تحسين خريطة الموقع في وثائق Next.js الرسمية. تعرف على المزيد حول تحسين robots.txt في وثائق Next.js الرسمية.
(اختياري) الخطوة 10: تغيير لغة المحتوى الخاص بك
لتغيير لغة المحتوى الخاص بك، يمكنك استخدام وظيفة setLocale التي يوفرها خطاف useLocale. تتيح لك هذه الوظيفة تعيين لغة التطبيق وتحديث المحتوى وفقًا لذلك.
"use client";import type { FC } from "react";import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import Link from "next/link";export const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <div> <button popoverTarget="localePopover">{getLocaleName(locale)}</button> <div id="localePopover" popover="auto"> {availableLocales.map((localeItem) => ( <Link href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} key={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* اللغة - مثال: FR */} {localeItem} </span> <span> {/* اللغة في لغتها الخاصة - مثال: Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* اللغة في اللغة الحالية - مثال: Francés مع اللغة الحالية المعينة إلى Locales.SPANISH */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* اللغة بالإنجليزية - مثال: French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> </Link> ))} </div> </div> );};
مراجع الوثائق:
(اختياري) الخطوة 11: إنشاء مكون رابط محلي
لضمان أن التنقل في تطبيقك يحترم اللغة الحالية، يمكنك إنشاء مكون Link مخصص. يقوم هذا المكون تلقائيًا بإضافة بادئة لعناوين URL الداخلية باللغة الحالية، بحيث يتم توجيه المستخدمين إلى الصفحات المناسبة بلغتهم.
"use client";import { getLocalizedUrl } from "intlayer";import NextLink, { type LinkProps as NextLinkProps } from "next/link";import { useLocale } from "next-intlayer";import type { PropsWithChildren, FC } from "react";/** * وظيفة مساعدة للتحقق مما إذا كان عنوان URL خارجيًا. * إذا كان عنوان URL يبدأ بـ http:// أو https://، فإنه يعتبر خارجيًا. */export const checkIsExternalLink = (href?: string): boolean => /^https?:///.test(href ?? "");/** * مكون رابط مخصص يتكيف مع سمة href بناءً على اللغة الحالية. * بالنسبة للروابط الداخلية، يستخدم `getLocalizedUrl` لإضافة بادئة للعنوان باللغة (مثل /fr/about). * يضمن ذلك أن يظل التنقل داخل نفس سياق اللغة. */export const Link: FC<PropsWithChildren<NextLinkProps>> = ({ href, children, ...props}) => { const { locale } = useLocale(); const isExternalLink = checkIsExternalLink(href.toString()); // إذا كان الرابط داخليًا وتم توفير href صالح، احصل على عنوان URL المحلي. const hrefI18n: NextLinkProps["href"] = href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href; return ( <NextLink href={hrefI18n} {...props}> {children} </NextLink> );};
كيف يعمل
اكتشاف الروابط الخارجية:
تحدد وظيفة المساعدة checkIsExternalLink ما إذا كان عنوان URL خارجيًا. يتم ترك الروابط الخارجية دون تغيير لأنها لا تحتاج إلى توطين.استرجاع اللغة الحالية:
يوفر خطاف useLocale اللغة الحالية (مثل fr للفرنسية).توطين عنوان URL:
بالنسبة للروابط الداخلية (أي غير الخارجية)، يتم استخدام getLocalizedUrl لإضافة بادئة تلقائيًا للعنوان باللغة الحالية. هذا يعني أنه إذا كان المستخدم باللغة الفرنسية، فإن تمرير /about كـ href سيحولها إلى /fr/about.إرجاع الرابط:
يعيد المكون عنصر <a> بعنوان URL المحلي، مما يضمن أن التنقل يتسق مع اللغة.
من خلال دمج مكون Link هذا عبر تطبيقك، تحافظ على تجربة مستخدم متماسكة وواعية باللغة مع الاستفادة أيضًا من تحسين SEO وسهولة الاستخدام.
تكوين TypeScript
يستخدم Intlayer توسيع الوحدة للحصول على فوائد TypeScript وجعل قاعدة التعليمات البرمجية الخاصة بك أقوى.
تأكد من أن تكوين TypeScript الخاص بك يتضمن الأنواع المولدة تلقائيًا.
{ // ... تكوينات TypeScript الحالية الخاصة بك "include": [ // ... تكوينات TypeScript الحالية الخاصة بك ".intlayer/**/*.ts", // تضمين الأنواع المولدة تلقائيًا ],}
تكوين Git
يوصى بتجاهل الملفات التي يتم إنشاؤها بواسطة Intlayer. يتيح لك ذلك تجنب الالتزام بها في مستودع Git الخاص بك.
للقيام بذلك، يمكنك إضافة التعليمات التالية إلى ملف .gitignore الخاص بك:
# تجاهل الملفات التي يتم إنشاؤها بواسطة Intlayer.intlayer
الذهاب أبعد
للمضي قدمًا، يمكنك تنفيذ المحرر المرئي أو نقل المحتوى الخاص بك باستخدام CMS.
إذا كان لديك فكرة لتحسين هذه الوثيقة، فلا تتردد في المساهمة من خلال تقديم طلب سحب على GitHub.
رابط GitHub للتوثيق