البدء في التدويل (i18n) باستخدام Intlayer و Next.js باستخدام Page Router
ما هو Intlayer؟
Intlayer هو مكتبة مفتوحة المصدر للتدويل (i18n) مصممة لتبسيط دعم اللغات المتعددة في تطبيقات الويب الحديثة. يتكامل Intlayer بسلاسة مع أحدث إطار عمل Next.js، بما في ذلك Page Router التقليدي.
مع Intlayer، يمكنك:
- إدارة الترجمات بسهولة باستخدام قواميس إعلانية على مستوى المكونات.
- تغيير البيانات الوصفية والمسارات والمحتوى محليًا بشكل ديناميكي.
- ضمان دعم TypeScript مع توليد الأنواع تلقائيًا، مما يحسن من الإكمال التلقائي واكتشاف الأخطاء.
- الاستفادة من الميزات المتقدمة، مثل اكتشاف وتبديل اللغة ديناميكيًا.
ملاحظة: Intlayer متوافق مع Next.js 12 و13 و14 و15. إذا كنت تستخدم Next.js App Router، يرجى الرجوع إلى دليل App Router. بالنسبة لـ Next.js 15، اتبع هذا الدليل.
دليل خطوة بخطوة لإعداد Intlayer في تطبيق Next.js باستخدام Page Router
الخطوة 1: تثبيت التبعيات
قم بتثبيت الحزم اللازمة باستخدام مدير الحزم المفضل لديك:
npm install intlayer next-intlayer
yarn add intlayer next-intlayer
pnpm add intlayer next-intlayer
الخطوة 2: تكوين مشروعك
قم بإنشاء ملف تكوين لتحديد اللغات المدعومة من قبل تطبيقك:
// intlayer.config.ts
import { Locales, type IntlayerConfig } from "intlayer";
const config: IntlayerConfig = {
internationalization: {
locales: [
Locales.ENGLISH,
Locales.FRENCH,
Locales.SPANISH,
// أضف اللغات الأخرى هنا
],
defaultLocale: Locales.ENGLISH,
},
};
export default config;
للحصول على قائمة كاملة من خيارات التكوين المتاحة، يرجى الرجوع إلى وثائق التكوين.
الخطوة 3: دمج Intlayer مع تكوين Next.js
قم بتعديل تكوين Next.js الخاص بك لدمج Intlayer:
// next.config.mjs
import { withIntlayer } from "next-intlayer/server";
/** @type {import('next').NextConfig} */
const nextConfig = {
// تكوين Next.js الحالي الخاص بك
};
export default withIntlayer(nextConfig);
الخطوة 4: تكوين Middleware لاكتشاف اللغة
قم بإعداد Middleware لاكتشاف ومعالجة اللغة المفضلة للمستخدم تلقائيًا:
// src/middleware.ts
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";
export const config = {
matcher: "/((?!api|static|.*\\..*|_next).*)",
};
الخطوة 5: تحديد مسارات اللغة الديناميكية
قم بتنفيذ التوجيه الديناميكي لتقديم محتوى محلي بناءً على لغة المستخدم.
إنشاء صفحات مخصصة للغة:
أعد تسمية ملف الصفحة الرئيسي ليشمل الجزء الديناميكي [locale].
bashmv src/pages/index.tsx src/pages/[locale]/index.tsx
تحديث _app.tsx لمعالجة التدويل:
قم بتعديل _app.tsx الخاص بك لتضمين مزودي Intlayer.
tsx// src/pages/_app.tsx import { AppProps } from "next/app"; import { IntlayerClientProvider } from "next-intlayer"; import { IntlayerServerProvider } from "next-intlayer/server"; import intlayerConfig from "../../intlayer.config"; function MyApp({ Component, pageProps }: AppProps) { const { locale } = pageProps; return ( <IntlayerClientProvider locale={locale}> <Component {...pageProps} /> </IntlayerClientProvider> ); } export default MyApp;
إعداد getStaticPaths و getStaticProps:
في [locale]/index.tsx الخاص بك، قم بتعريف المسارات والخصائص لمعالجة اللغات المختلفة.
tsx// src/pages/[locale]/index.tsx import { GetStaticPaths, GetStaticProps } from "next"; import { useIntlayer } from "next-intlayer"; import { Locales } from "intlayer"; const HomePage = () => { return <div>{/* المحتوى الخاص بك هنا */}</div>; }; export const getStaticPaths: GetStaticPaths = async () => { const locales = [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH]; // أضف اللغات الخاصة بك هنا const paths = locales.map((locale) => ({ params: { locale }, })); return { paths, fallback: false }; }; export const getStaticProps: GetStaticProps = async ({ params }) => { const locale = params?.locale as string; return { props: { locale, }, }; }; export default HomePage;
الخطوة 6: إعلان المحتوى الخاص بك
قم بإنشاء وإدارة قواميس المحتوى الخاصة بك لتخزين الترجمات.
// src/pages/[locale]/home.content.ts
import { t, type DeclarationContent } from "intlayer";
const homeContent = {
key: "home",
content: {
title: t({
en: "Welcome to My Website",
fr: "Bienvenue sur mon site Web",
es: "Bienvenido a mi sitio web",
}),
description: t({
en: "Get started by editing this page.",
fr: "Commencez par éditer cette page.",
es: "Comience por editar esta página.",
}),
},
} satisfies DeclarationContent;
export default homeContent;
للحصول على مزيد من المعلومات حول إعلان المحتوى، يرجى الرجوع إلى دليل إعلان المحتوى.
الخطوة 7: استخدام المحتوى في كودك
الوصول إلى قواميس المحتوى الخاصة بك في جميع أنحاء تطبيقك لعرض المحتوى المترجم.
// src/pages/[locale]/index.tsx
import { GetStaticPaths, GetStaticProps } from "next";
import { useIntlayer } from "next-intlayer";
import { Locales } from "intlayer";
import { ComponentExample } from "@component/ComponentExample";
const HomePage = () => {
const content = useIntlayer("home");
return (
<div>
<h1>{content.title}</h1>
<p>{content.description}</p>
<ComponentExample />
{/* مكونات إضافية */}
</div>
);
};
// ... بقية الكود، بما في ذلك getStaticPaths و getStaticProps
export default HomePage;
// src/components/ComponentExample.tsx
import { useIntlayer } from "next-intlayer";
export const ComponentExample = () => {
const content = useIntlayer("client-component-example"); // تأكد من أن لديك إعلان المحتوى المقابل
return (
<div>
<h2>{content.title}</h2>
<p>{content.content}</p>
</div>
);
};
ملاحظة: عند استخدام الترجمات في سمات string (مثل alt و title و href و aria-label)، قم باستدعاء قيمة الدالة كما يلي:
<img src={content.image.src.value} alt={content.image.value} />
(اختياري) الخطوة 8: تدويل بيانات التعريف الخاصة بك
لتدويل البيانات الوصفية مثل عناوين الصفحات والوصف، استخدم دالة getStaticProps مع دالة getTranslationContent الخاصة بـ Intlayer.
// src/pages/[locale]/index.tsx
import { GetStaticPaths, GetStaticProps } from "next";
import { type IConfigLocales, getTranslationContent, Locales } from "intlayer";
import { useIntlayer } from "next-intlayer";
interface HomePageProps {
locale: string;
metadata: Metadata;
}
const HomePage = ({ metadata }: HomePageProps) => {
// يمكن استخدام بيانات التعريف في الرأس أو مكونات أخرى حسب الحاجة
return (
<div>
<Head>
<title>{metadata.title}</title>
<meta name="description" content={metadata.description} />
</Head>
{/* محتوى إضافي */}
</div>
);
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const locale = params?.locale as string;
const t = <T,>(content: IConfigLocales<T>) =>
getTranslationContent(content, locale);
const metadata = {
title: t({
en: "My Website",
fr: "Mon Site Web",
es: "Mi Sitio Web",
}),
description: t({
en: "Welcome to my website.",
fr: "Bienvenue sur mon site Web.",
es: "Bienvenido a mi sitio web.",
}),
};
return {
props: {
locale,
metadata,
},
};
};
export default HomePage;
// ... بقية الكود بما في ذلك getStaticPaths
(اختياري) الخطوة 9: تغيير لغة محتواك
للسماح للمستخدمين بتبديل اللغات ديناميكيًا، استخدم دالة setLocale المقدمة من useLocale hook.
// src/components/LanguageSwitcher.tsx
import { Locales } from "intlayer";
import { useLocalePageRouter } from "next-intlayer";
const LanguageSwitcher = () => {
const { setLocale } = useLocalePageRouter();
return (
<div>
<button onClick={() => setLocale(Locales.ENGLISH)}>English</button>
<button onClick={() => setLocale(Locales.FRENCH)}>Français</button>
<button onClick={() => setLocale(Locales.SPANISH)}>Español</button>
{/* أضف المزيد من الأزرار للغات إضافية */}
</div>
);
};
export default LanguageSwitcher;
تكوين TypeScript
يستخدم Intlayer تعزيز الوحدة لتحسين قدرات TypeScript، مما يوفر المزيد من أمان النوع وإكمالًا تلقائيًا أفضل.
تأكد من أن TypeScript تشمل الأنواع التي تم إنشاؤها تلقائيًا:
قم بتحديث tsconfig.json الخاص بك ليتضمن الأنواع المتولدة تلقائيًا.
json// tsconfig.json { "compilerOptions": { // تكوينات TypeScript الحالية الخاصة بك }, "include": [ "src", "types" // تضمين الأنواع المولدة تلقائيًا ] }
مثال على فوائد TypeScript:
تكوين Git
للحفاظ على نظافة مستودعك وتجنب الالتزام بالملفات الناتجة، يُوصى بتجاهل الملفات التي أنشأها Intlayer.
تحديث .gitignore:
أضف السطور التالية إلى ملف .gitignore الخاص بك:
gitignore# تجاهل الملفات التي تم إنشاؤها بواسطة Intlayer .intlayer
موارد إضافية
- وثائق Intlayer: مستودع GitHub
- دليل إعلان المحتوى: إعلان المحتوى
- وثائق التكوين: دليل التكوين
باتباع هذا الدليل، يمكنك دمج Intlayer بفعالية في تطبيق Next.js الخاص بك باستخدام Page Router، مما يتيح دعم التدويل القوي والقابل للتوسع لمشاريع الويب الخاصة بك.
إذا كان لديك فكرة لتحسين هذه الوثيقة، فلا تتردد في المساهمة من خلال تقديم طلب سحب على GitHub.
رابط GitHub للتوثيق