تحميل الترجمات
استخدام موفر لإدارة الرسائل
المشكلة
إن كتابة النصوص بشكل مباشر في الكود، مثل 'Hello World'، داخل مكونات التطبيق يربط المحتوى بالكود. لعرض لغة مختلفة، يجب على المطورين تكرار المكون أو إضافة منطق if/else، مما يجعل الترجمة غير قابلة للتوسع ويتطلب تغييرًا كاملًا في الكود لكل نص جديد.
الحل
استخدم IntlProvider من مكتبة react-intl لتوفير الترجمات. قم بتحميل رسائل الترجمة على الخادم في التخطيط الرئيسي، ومررها إلى مكون المزود على جانب العميل، ثم استهلكها في مكونات العميل الأخرى باستخدام الدالة المساعدة useIntl.
الخطوات
1. تثبيت react-intl
أولاً، أضف react-intl كاعتماد إلى مشروعك.
npm install react-intl
2. إنشاء ملفات ترجمة مسطحة
قم بإنشاء مجلد dictionaries. بداخله، أضف ملف JSON لكل لغة. تعمل react-intl بشكل أفضل مع هيكل مفتاح-قيمة مسطح.
// dictionaries/en.json
{
"home.title": "Home Page",
"home.welcome": "Hello, welcome to our site!",
"about.title": "About Us"
}
// dictionaries/es.json
{
"home.title": "Página de Inicio",
"home.welcome": "¡Hola, bienvenido a nuestro sitio!",
"about.title": "Sobre Nosotros"
}
3. إنشاء دالة لتحميل القواميس
قم بإنشاء دالة مساعدة لتحميل ملف القاموس الصحيح على الخادم بناءً على معلمة lang.
// app/get-dictionary.ts
import 'server-only';
// Define the type for our flat message object
type Messages = Record<string, string>;
const dictionaries: { [key: string]: () => Promise<Messages> } = {
en: () => import('@/dictionaries/en.json').then((module) => module.default),
es: () => import('@/dictionaries/es.json').then((module) => module.default),
// fr: () => import('@/dictionaries/fr.json').then((module) => module.default),
};
export const getDictionary = async (lang: string) => {
const load = dictionaries[lang];
if (load) {
return load();
}
// Fallback to English
return dictionaries.en();
};
4. إنشاء مزود على جانب العميل
IntlProvider هو مكون عميل يستخدم سياق React. يجب علينا إنشاء غلاف له يمكنه قبول الرسائل المحملة من الخادم.
// app/components/IntlClientProvider.tsx
'use client';
import { IntlProvider } from 'react-intl';
type Props = {
children: React.ReactNode;
locale: string;
messages: Record<string, string>; // Flat messages object
};
export default function IntlClientProvider({
children,
locale,
messages,
}: Props) {
return (
<IntlProvider messages={messages} locale={locale} defaultLocale="en">
{children}
</IntlProvider>
);
}
5. تحديث التخطيط الرئيسي
قم بتعديل ملف app/[lang]/layout.tsx ليكون مكون async. سيقوم بتحميل الرسائل وتمريرها إلى IntlClientProvider.
// app/[lang]/layout.tsx
import { getDictionary } from '@/app/get-dictionary';
import IntlClientProvider from '@/app/components/IntlClientProvider';
export async function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'es' }];
}
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
// Load messages on the server
const messages = await getDictionary(params.lang);
return (
<html lang={params.lang}>
<body>
{/* Pass messages to the client provider */}
<IntlClientProvider locale={params.lang} messages={messages}>
{children}
</IntlClientProvider>
</body>
</html>
);
}
6. استخدام الترجمات في مكون العميل
يمكنك الآن استخدام خطاف useIntl في أي مكون عميل. لا يمكن لمكونات الخادم استخدام هذا الخطاف.
قم بإنشاء مكون عميل جديد لعرض النص المترجم:
// app/components/HomePageContent.tsx
'use client';
import { useIntl } from 'react-intl';
export default function HomePageContent() {
const intl = useIntl();
return (
<div>
<h1>{intl.formatMessage({ id: 'home.title' })}</h1>
<p>{intl.formatMessage({ id: 'home.welcome' })}</p>
</div>
);
}
7. أضف المكون إلى صفحتك
أخيرًا، أضف مكون العميل الجديد إلى صفحتك.
// app/[lang]/page.tsx
import HomePageContent from '@/app/components/HomePageContent';
export default function Home() {
// This page is a Server Component
return (
<div>
{/* It renders the Client Component */}
<HomePageContent />
</div>
);
}