diff --git a/apps/docs/content/ar/docs/01-app/01-getting-started/02-project-structure.mdx b/apps/docs/content/ar/docs/01-app/01-getting-started/02-project-structure.mdx index 7728ad22..fc5bec04 100644 --- a/apps/docs/content/ar/docs/01-app/01-getting-started/02-project-structure.mdx +++ b/apps/docs/content/ar/docs/01-app/01-getting-started/02-project-structure.mdx @@ -1,7 +1,7 @@ --- -source-updated-at: 2025-06-01T01:32:20.000Z -translation-updated-at: 2025-06-02T20:05:50.792Z -title: هيكل وتنظيم المشروع +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:16:10.703Z +title: هيكل المشروع وتنظيمه nav_title: هيكل المشروع description: نظرة عامة على اصطلاحات المجلدات والملفات في Next.js، وكيفية تنظيم مشروعك. --- @@ -10,9 +10,9 @@ description: نظرة عامة على اصطلاحات المجلدات والم ## اصطلاحات المجلدات والملفات -### المجلدات الرئيسية +### مجلدات المستوى الأعلى -تُستخدم المجلدات الرئيسية لتنظيم كود التطبيق والأصول الثابتة. +تُستخدم مجلدات المستوى الأعلى لتنظيم كود التطبيق والأصول الثابتة. Route segments to path segments @@ -138,32 +138,32 @@ description: نظرة عامة على اصطلاحات المجلدات والم | ----------------------------------------------------------------------------------------------------------- | ------------------- | ----------------- | | [`_app`](/docs/pages/building-your-application/routing/custom-app) | `.js` `.jsx` `.tsx` | تطبيق مخصص | | [`_document`](/docs/pages/building-your-application/routing/custom-document) | `.js` `.jsx` `.tsx` | مستند مخصص | -| [`_error`](/docs/pages/building-your-application/routing/custom-error#more-advanced-error-page-customizing) | `.js` `.jsx` `.tsx` | صفحة خطأ مخصصة | -| [`404`](/docs/pages/building-your-application/routing/custom-error#404-page) | `.js` `.jsx` `.tsx` | صفحة خطأ 404 | -| [`500`](/docs/pages/building-your-application/routing/custom-error#500-page) | `.js` `.jsx` `.tsx` | صفحة خطأ 500 | +| [`_error`](/docs/pages/building-your-application/routing/custom-error#more-advanced-error-page-customizing) | `.js` `.jsx` `.tsx` | صفحة خطأ مخصصة | +| [`404`](/docs/pages/building-your-application/routing/custom-error#404-page) | `.js` `.jsx` `.tsx` | صفحة خطأ 404 | +| [`500`](/docs/pages/building-your-application/routing/custom-error#500-page) | `.js` `.jsx` `.tsx` | صفحة خطأ 500 | ### الطرق (Routes) | | | | | ---------------------------------------------------------------------------------------------- | ------------------- | ----------- | | **اصطلاح المجلد** | | | -| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | الصفحة الرئيسية | +| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | الصفحة الرئيسية | | [`folder/index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | صفحة متداخلة | | **اصطلاح الملف** | | | -| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | الصفحة الرئيسية | +| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | الصفحة الرئيسية | | [`file`](/docs/pages/building-your-application/routing/pages-and-layouts) | `.js` `.jsx` `.tsx` | صفحة متداخلة | -### الطرق الديناميكية (Dynamic routes) +### الطرق الديناميكية | | | | | ----------------------------------------------------------------------------------------------------------------- | ------------------- | -------------------------------- | | **اصطلاح المجلد** | | | | [`[folder]/index`](/docs/pages/building-your-application/routing/dynamic-routes) | `.js` `.jsx` `.tsx` | مقطع طريق ديناميكي | -| [`[...folder]/index`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل | +| [`[...folder]/index`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل (Catch-all) | | [`[[...folder]]/index`](/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل اختياري | | **اصطلاح الملف** | | | | [`[file]`](/docs/pages/building-your-application/routing/dynamic-routes) | `.js` `.jsx` `.tsx` | مقطع طريق ديناميكي | -| [`[...file]`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل | +| [`[...file]`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل (Catch-all) | | [`[[...file]]`](/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) | `.js` `.jsx` `.tsx` | مقطع طريق شامل اختياري | @@ -176,7 +176,7 @@ Next.js **غير متحيز** بشأن كيفية تنظيم وترتيب ملف ### تسلسل المكونات (Component hierarchy) -يتم عرض المكونات المحددة في الملفات الخاصة بتسلسل معين: +يتم عرض المكونات المحددة في الملفات الخاصة بتسلسل محدد: - `layout.js` - `template.js` @@ -203,7 +203,7 @@ Next.js **غير متحيز** بشأن كيفية تنظيم وترتيب ملف height="863" /> -### التنسيق المشترك (Colocation) +### التنسيق المكاني (Colocation) في دليل `app`، تحدد المجلدات المتداخلة بنية المسار (route). كل مجلد يمثل جزءًا من المسار (route segment) يتم تعيينه إلى جزء مقابل في مسار URL. @@ -217,7 +217,7 @@ Next.js **غير متحيز** بشأن كيفية تنظيم وترتيب ملف height="444" /> -وحتى عندما يصبح المسار متاحًا للجمهور، يتم إرسال **المحتوى المُعاد** بواسطة `page.js` أو `route.js` فقط إلى العميل. +وحتى عندما يصبح المسار متاحًا للجمهور، فإن **المحتوى المُعاد** فقط من خلال `page.js` أو `route.js` هو الذي يتم إرساله إلى العميل. مخطط يوضح كيف أن ملفات page.js و route.js تجعل المسارات متاحة للجمهور. -هذا يعني أنه يمكن **تنسيق ملفات المشروع بشكل آمن** داخل أجزاء المسار في دليل `app` دون أن تصبح قابلة للتوجيه بالخطأ. +هذا يعني أنه يمكن **تنسيق ملفات المشروع** بأمان داخل أجزاء المسار في دليل `app` دون أن تصبح قابلة للتوجيه بالخطأ. مخطط يوضح أن ملفات المشروع المنسقة معًا ليست قابلة للتوجيه حتى عندما يحتوي الجزء على ملف page.js أو route.js. -بما أن الملفات في دليل `app` يمكن [تنسيقها بشكل آمن افتراضيًا](#colocation)، فإن المجلدات الخاصة ليست مطلوبة للتنسيق المشترك. ومع ذلك، يمكن أن تكون مفيدة لـ: +بما أن الملفات في دليل `app` يمكن [تنسيقها بأمان افتراضيًا](#colocation)، فإن المجلدات الخاصة ليست مطلوبة للتنسيق المكاني. ومع ذلك، يمكن أن تكون مفيدة لـ: - فصل منطق واجهة المستخدم عن منطق التوجيه. - تنظيم الملفات الداخلية بشكل متسق عبر المشروع وبيئة Next.js. - فرز وتجميع الملفات في محررات الأكواد. -- تجنب التعارض المحتمل في الأسماء مع اصطلاحات ملفات Next.js المستقبلية. +- تجنب التعارضات المحتملة في التسمية مع اصطلاحات ملفات Next.js المستقبلية. > **معلومة مفيدة**: > - على الرغم من أنها ليست اصطلاحًا في الإطار، يمكنك أيضًا التفكير في تمييز الملفات خارج المجلدات الخاصة كـ "خاصة" باستخدام نفس نمط الشرطة السفلية. > - يمكنك إنشاء أجزاء URL تبدأ بشرطة سفلية عن طريق إضافة `%5F` (الشكل المشفر لـ URL للشرطة السفلية) كبادئة لاسم المجلد: `%5FfolderName`. -> - إذا كنت لا تستخدم المجلدات الخاصة، سيكون من المفيد معرفة [اصطلاحات الملفات الخاصة](/docs/app/getting-started/project-structure#routing-files) في Next.js لتجنب التعارض غير المتوقع في الأسماء. +> - إذا كنت لا تستخدم المجلدات الخاصة، سيكون من المفهم معرفة [اصطلاحات الملفات الخاصة بـ Next.js](/docs/app/getting-started/project-structure#routing-files) لتجنب تعارضات التسمية غير المتوقعة. ### مجموعات المسارات (Route Groups) -يمكن إنشاء مجموعات المسارات عن طريق وضع مجلد بين قوسين: `(folderName)` +يمكن إنشاء مجموعات المسارات عن طريق لف مجلد بين قوسين: `(folderName)` هذا يشير إلى أن المجلد هو لأغراض تنظيمية ويجب **ألا يُدرج** في مسار URL. @@ -288,7 +288,7 @@ Next.js **غير متحيز** بشأن كيفية تنظيم وترتيب ملف ### مجلد `src` -يدعم Next.js تخزين كود التطبيق (بما في ذلك `app`) داخل مجلد [`src` اختياري](/docs/app/api-reference/file-conventions/src-folder). هذا يفصل كود التطبيق عن ملفات تكوين المشروع التي توجد غالبًا في جذر المشروع. +يدعم Next.js تخزين كود التطبيق (بما في ذلك `app`) داخل مجلد [`src` اختياري](/docs/app/api-reference/file-conventions/src-folder). هذا يفصل كود التطبيق عن ملفات تكوين المشروع التي تعيش غالبًا في جذر المشروع. مثال على هيكل مجلدات مع مجلد `src` **معلومة مفيدة**: في الأمثلة أدناه، نستخدم مجلدات `components` و `lib` كعناصر نائبة عامة، أسماؤها لا تحمل أي دلالة خاصة في الإطار وقد يستخدم مشروعك مجلدات أخرى مثل `ui`، `utils`، `hooks`، `styles`، إلخ. +> **معلومة مفيدة**: في الأمثلة أدناه، نستخدم مجلدات `components` و `lib` كعناصر نائبة عامة، تسمياتها ليس لها أهمية خاصة في الإطار وقد تستخدم مشاريعك مجلدات أخرى مثل `ui`، `utils`، `hooks`، `styles`، إلخ. ### تخزين ملفات المشروع خارج `app` -تخزن هذه الاستراتيجية جميع أكواد التطبيق في مجلدات مشتركة في **جذر مشروعك** وتحافظ على دليل `app` لأغراض التوجيه فقط. +هذه الاستراتيجية تخزن جميع أكواد التطبيق في مجلدات مشتركة في **جذر مشروعك** وتحافظ على دليل `app` لأغراض التوجيه فقط. مثال على هيكل مجلدات مع ملفات المشروع خارج app -### تخزين ملفات المشروع في مجلدات رئيسية داخل `app` +### تخزين ملفات المشروع في مجلدات عليا داخل `app` -تخزن هذه الاستراتيجية جميع أكواد التطبيق في مجلدات مشتركة في **جذر دليل `app`**. +هذه الاستراتيجية تخزن جميع أكواد التطبيق في مجلدات مشتركة في **جذر دليل `app`**. مثال على هيكل مجلدات مع ملفات المشروع داخل app -### اختيار أجزاء محددة لتطبيق تخطيط عليها +### اختيار أجزاء محددة لتخطيط معين -لاختيار مسارات محددة لتطبيق تخطيط عليها، أنشئ مجموعة مسارات جديدة (مثل `(shop)`) وانقل المسارات التي تشترك في نفس التخطيط إلى المجموعة (مثل `account` و `cart`). المسارات خارج المجموعة لن تشترك في التخطيط (مثل `checkout`). +لاختيار مسارات معينة لتخطيط معين، أنشئ مجموعة مسار جديدة (مثل `(shop)`) وانقل المسارات التي تشترك في نفس التخطيط إلى المجموعة (مثل `account` و `cart`). المسارات خارج المجموعة لن تشترك في التخطيط (مثل `checkout`). مجموعات المسارات مع تخطيطات اختيارية -### اختيار هياكل التحميل (Loading Skeletons) لمسار محدد +### اختيار هيكل تحميل (loading skeleton) لمسار معين -لتطبيق [هيكل تحميل](/docs/app/building-your-application/routing/loading-ui-and-streaming) عبر ملف `loading.js` على مسار محدد، أنشئ مجموعة مسارات جديدة (مثل `/(overview)`) ثم انقل ملف `loading.tsx` داخل مجموعة المسارات هذه. +لتطبيق [هيكل تحميل](/docs/app/api-reference/file-conventions/loading) عبر ملف `loading.js` على مسار معين، أنشئ مجموعة مسار جديدة (مثل `/(overview)`) ثم انقل ملف `loading.tsx` داخل مجموعة المسار هذه. هيكل مجلدات يوضح ملف loading.tsx و page.tsx داخل مجموعة المسارات` و `` إلى كل تخطيط جذر. +لإنشاء عدة [تخطيطات جذر](/docs/app/api-reference/file-conventions/layout#root-layout)، احذف ملف `layout.js` الأعلى مستوى، وأضف ملف `layout.js` داخل كل مجموعة مسار. هذا مفيد لتقسيم التطبيق إلى أقسام لها واجهة مستخدم أو تجربة مختلفة تمامًا. يجب إضافة العلامات `` و `` إلى كل تخطيط جذر. مجموعات المسارات مع تخطيطات جذر متعددة -في المثال أعلاه، لكل من `(marketing)` و `(shop)` تخطيط جذر خاص به. +في المثال أعلاه، كل من `(marketing)` و `(shop)` لهما تخطيط جذر خاص به. diff --git a/apps/docs/content/ar/docs/01-app/01-getting-started/03-layouts-and-pages.mdx b/apps/docs/content/ar/docs/01-app/01-getting-started/03-layouts-and-pages.mdx index 0a80bca8..82fb47f6 100644 --- a/apps/docs/content/ar/docs/01-app/01-getting-started/03-layouts-and-pages.mdx +++ b/apps/docs/content/ar/docs/01-app/01-getting-started/03-layouts-and-pages.mdx @@ -1,6 +1,6 @@ --- -source-updated-at: 2025-06-01T01:32:20.000Z -translation-updated-at: 2025-06-02T20:03:36.299Z +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:13:50.198Z title: كيفية إنشاء التخطيطات والصفحات nav_title: التخطيطات والصفحات description: إنشاء أول صفحاتك وتخطيطاتك، والربط بينها. @@ -8,17 +8,18 @@ related: title: مرجع API description: تعلم المزيد عن الميزات المذكورة في هذه الصفحة من خلال قراءة مرجع API. links: + - app/getting-started/linking-and-navigating - app/api-reference/file-conventions/layout - app/api-reference/file-conventions/page - app/api-reference/components/link - app/api-reference/file-conventions/dynamic-routes --- -يستخدم Next.js **التوجيه القائم على نظام الملفات**، مما يعني أنه يمكنك استخدام المجلدات والملفات لتحديد المسارات. سترشدك هذه الصفحة حول كيفية إنشاء التخطيطات والصفحات، والربط بينها. +يستخدم Next.js **التوجيه القائم على نظام الملفات**، مما يعني أنه يمكنك استخدام المجلدات والملفات لتحديد المسارات. سيرشدك هذه الصفحة حول كيفية إنشاء التخطيطات والصفحات، والربط بينها. ## إنشاء صفحة -**الصفحة** هي واجهة مستخدم يتم عرضها على مسار معين. لإنشاء صفحة، أضف ملف [`page`](/docs/app/api-reference/file-conventions/page) داخل مجلد `app` وقم بتصدير مكون React افتراضيًا. على سبيل المثال، لإنشاء صفحة رئيسية (`/`): +**الصفحة** هي واجهة مستخدم يتم عرضها على مسار معين. لإنشاء صفحة، أضف ملف [`page`](/docs/app/api-reference/file-conventions/page) داخل دليل `app` وقم بتصدير مكون React افتراضيًا. على سبيل المثال، لإنشاء صفحة رئيسية (`/`): ملف page.js الخاص`](/docs/app/api-reference/components/link) للتنقل بين المسارات. `` هو مكون مضمن في Next.js يمتد علامة HTML `` لتوفير [الجلب المسبق](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching) و[التنقل من جانب العميل](/docs/app/building-your-application/routing/linking-and-navigating#5-soft-navigation). +يمكنك استخدام مكون [``](/docs/app/api-reference/components/link) للتنقل بين المسارات. `` هو مكون مضمن في Next.js يمتد علامة HTML `` لتوفير [الجلب المسبق](/docs/app/getting-started/linking-and-navigating#prefetching) و[التنقل من جانب العميل](/docs/app/getting-started/linking-and-navigating#client-side-transitions). على سبيل المثال، لإنشاء قائمة بمنشورات المدونة، استورد `` من `next/link` ومرر خاصية `href` إلى المكون: @@ -291,4 +292,4 @@ export default async function Post({ post }) { } ``` -`` هو الطريقة الأساسية والمفضلة للتنقل بين المسارات في تطبيق Next.js الخاص بك. ومع ذلك، يمكنك أيضًا استخدام [خطاف `useRouter`](/docs/app/api-reference/functions/use-router) للتنقل المتقدم. \ No newline at end of file +> **جيد أن تعرف**: `` هو الطريقة الأساسية للتنقل بين المسارات في Next.js. يمكنك أيضًا استخدام [خطاف `useRouter`](/docs/app/api-reference/functions/use-router) للتنقل المتقدم. \ No newline at end of file diff --git a/apps/docs/content/ar/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/apps/docs/content/ar/docs/01-app/01-getting-started/04-linking-and-navigating.mdx new file mode 100644 index 00000000..565171d5 --- /dev/null +++ b/apps/docs/content/ar/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -0,0 +1,466 @@ +--- +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:14:36.122Z +title: الربط والتنقل +description: تعرف على كيفية عمل الجلب المسبق (Prefetching)، التصيير المسبق (Prerendering)، والتنقل من جانب العميل في Next.js، وكيفية استخدام مكون Link. +related: + links: + - app/api-reference/components/link + - app/api-reference/file-conventions/loading +--- + +في Next.js، يتم تصيير المسارات (routes) على الخادم افتراضيًا. هذا يعني غالبًا أن العميل يجب أن ينتظر ردًا من الخادم قبل أن يتم عرض المسار الجديد. يأتي Next.js مزودًا مدمجًا بـ[الجلب المسبق (Prefetching)](#prefetching)، [البث (Streaming)](#streaming)، و[الانتقالات من جانب العميل (Client-side transitions)](#client-side-transitions) مما يضمن بقاء التنقل سريعًا وسريع الاستجابة. + +يشرح هذا الدليل كيفية عمل التنقل في Next.js وكيف يمكنك تحسينه لـ[المسارات الديناميكية (dynamic routes)](#dynamic-routes-without-loadingtsx) و[الشبكات البطيئة (slow networks)](#slow-networks). + +## كيف يعمل التنقل + +لفهم كيفية عمل التنقل في Next.js، من المفيد أن تكون على دراية بالمفاهيم التالية: + +- [التصيير من جانب الخادم (Server Rendering)](#server-rendering) +- [الجلب المسبق (Prefetching)](#prefetching) +- [البث (Streaming)](#streaming) +- [الانتقالات من جانب العميل (Client-side transitions)](#client-side-transitions) + +### التصيير من جانب الخادم + +في Next.js، [التخطيطات والصفحات (Layouts and Pages)](/docs/app/getting-started/layouts-and-pages) هي [مكونات خادم React (React Server Components)](https://react.dev/reference/rsc/server-components) افتراضيًا. عند التنقل الأولي واللاحق، يتم إنشاء [حمل مكون الخادم (Server Component Payload)](/docs/app/getting-started/server-and-client-components#how-do-server-and-client-components-work-in-nextjs) على الخادم قبل إرساله إلى العميل. + +هناك نوعان من التصيير من جانب الخادم، بناءً على وقت حدوثه: + +- **التصيير الثابت (Static Rendering أو Prerendering)**: يحدث وقت البناء أو أثناء [إعادة التحقق (revalidation)](/docs/app/getting-started/caching-and-revalidating) ويتم تخزين النتيجة مؤقتًا. +- **التصيير الديناميكي (Dynamic Rendering)**: يحدث وقت الطلب استجابةً لطلب العميل. + +مقايضة التصيير من جانب الخادم هي أن العميل يجب أن ينتظر رد الخادم قبل أن يتم عرض المسار الجديد. يتعامل Next.js مع هذا التأخير عن طريق [الجلب المسبق (Prefetching)](#prefetching) للمسارات التي من المحتمل أن يزورها المستخدم وإجراء [انتقالات من جانب العميل (Client-side transitions)](#client-side-transitions). + +> **معلومة مفيدة**: يتم أيضًا إنشاء HTML للزيارة الأولية. + +### الجلب المسبق (Prefetching) + +الجلب المسبق هو عملية تحميل مسار في الخلفية قبل أن ينتقل إليه المستخدم. هذا يجعل التنقل بين المسارات في تطبيقك يبدو فوريًا، لأنه بحلول الوقت الذي ينقر فيه المستخدم على رابط، تكون بيانات تصيير المسار التالي متاحة بالفعل على جانب العميل. + +يقوم Next.js تلقائيًا بجلب المسارات المرتبطة بمكون [``](/docs/app/api-reference/components/link) مسبقًا عندما تدخل في نطاق رؤية المستخدم. + +```tsx filename="app/layout.tsx" switcher +import Link from 'next/link' + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + {children} + + + ) +} +``` + +```jsx filename="app/blog/page.js" switcher +import Link from 'next/link' + +export default function Layout() { + return ( + + + + {children} + + + ) +} +``` + +تعتمد كمية المسار التي يتم جلبها مسبقًا على ما إذا كان ثابتًا أو ديناميكيًا: + +- **المسار الثابت**: يتم جلب المسار بالكامل مسبقًا. +- **المسار الديناميكي**: يتم تخطي الجلب المسبق، أو يتم جلب جزء من المسار مسبقًا إذا كان [`loading.tsx`](/docs/app/api-reference/file-conventions/loading) موجودًا. + +عن طريق تخطي أو جلب المسارات الديناميكية جزئيًا مسبقًا، يتجنب Next.js عملًا غير ضروري على الخادم للمسارات التي قد لا يزورها المستخدمون أبدًا. ومع ذلك، قد يعطي انتظار رد الخادم قبل التنقل انطباعًا للمستخدمين بأن التطبيق لا يستجيب. + +Server Rendering without Streaming + +لتحسين تجربة التنقل إلى المسارات الديناميكية، يمكنك استخدام [البث (Streaming)](#streaming). + +### البث (Streaming) + +يسمح البث للخادم بإرسال أجزاء من مسار ديناميكي إلى العميل بمجرد أن تصبح جاهزة، بدلاً من انتظار تصيير المسار بالكامل. هذا يعني أن المستخدمين يرون شيئًا ما عاجلاً، حتى إذا كانت أجزاء من الصفحة لا تزال قيد التحميل. + +بالنسبة للمسارات الديناميكية، يعني هذا أنه يمكن **جلبها مسبقًا جزئيًا**. أي أنه يمكن طلب التخطيطات المشتركة وهياكل التحميل مسبقًا. + +How Server Rendering with Streaming Works + +لاستخدام البث، قم بإنشاء `loading.tsx` في مجلد المسار الخاص بك: + +loading.js special file + +```tsx filename="app/dashboard/loading.tsx" switcher +export default function Loading() { + // أضف واجهة مستخدم احتياطية سيتم عرضها أثناء تحميل المسار. + return +} +``` + +```jsx filename="app/dashboard/loading.js" switcher +export default function Loading() { + // أضف واجهة مستخدم احتياطية سيتم عرضها أثناء تحميل المسار. + return +} +``` + +خلف الكواليس، سيقوم Next.js تلقائيًا بلف محتويات `page.tsx` في حدود ``. سيتم عرض واجهة المستخدم الاحتياطية التي تم جلبها مسبقًا أثناء تحميل المسار، واستبدالها بالمحتوى الفعلي بمجرد أن يصبح جاهزًا. + +> **معلومة مفيدة**: يمكنك أيضًا استخدام [``](https://react.dev/reference/react/Suspense) لإنشاء واجهة مستخدم تحميل للمكونات المتداخلة. + +فوائد `loading.tsx`: + +- تنقل فوري وردود فعل مرئية للمستخدم. +- تبقى التخطيطات المشتركة قابلة للتفاعل والتنقل قابلًا للإيقاف. +- تحسين مؤشرات Core Web Vitals: [TTFB](https://web.dev/articles/ttfb)، [FCP](https://web.dev/articles/fcp)، و[TTI](https://web.dev/articles/tti). + +لمزيد من تحسين تجربة التنقل، يقوم Next.js بإجراء [انتقال من جانب العميل (Client-side transition)](#client-side-transitions) باستخدام مكون ``. + +### الانتقالات من جانب العميل (Client-side transitions) + +تقليديًا، يؤدي التنقل إلى صفحة مخصصة من الخادم إلى تحميل كامل للصفحة. هذا يمسح الحالة، يعيد تعيين موضع التمرير، ويمنع التفاعل. + +يتجنب Next.js ذلك باستخدام الانتقالات من جانب العميل عبر مكون ``. بدلاً من إعادة تحميل الصفحة، يقوم بتحديث المحتوى ديناميكيًا عن طريق: + +- الحفاظ على أي تخطيطات مشتركة وواجهة مستخدم. +- استبدال الصفحة الحالية بحالة التحميل التي تم جلبها مسبقًا أو صفحة جديدة إذا كانت متاحة. + +الانتقالات من جانب العميل هي ما يجعل التطبيقات المخصصة من الخادم تشعر وكأنها تطبيقات مخصصة من العميل. وعند اقترانها بـ[الجلب المسبق (Prefetching)](#prefetching) و[البث (Streaming)](#streaming)، فإنها تمكن من انتقالات سريعة، حتى للمسارات الديناميكية. + +## ما الذي يمكن أن يجعل الانتقالات بطيئة؟ + +هذه التحسينات في Next.js تجعل التنقل سريعًا وسريع الاستجابة. ومع ذلك، في ظل ظروف معينة، قد لا تزال الانتقالات تشعر بأنها بطيئة. فيما يلي بعض الأسباب الشائعة وكيفية تحسين تجربة المستخدم: + +### المسارات الديناميكية بدون `loading.tsx` + +عند التنقل إلى مسار ديناميكي، يجب أن ينتظر العميل رد الخادم قبل عرض النتيجة. هذا قد يعطي المستخدمين انطباعًا بأن التطبيق لا يستجيب. + +نوصي بإضافة `loading.tsx` إلى المسارات الديناميكية لتمكين الجلب المسبق الجزئي، تشغيل التنقل الفوري، وعرض واجهة مستخدم تحميل أثناء تصيير المسار. + +```tsx filename="app/blog/[slug]/loading.tsx" switcher +export default function Loading() { + return +} +``` + +```jsx filename="app/blog/[slug]/loading.js" switcher +export default function Loading() { + return +} +``` + +> **معلومة مفيدة**: في وضع التطوير، يمكنك استخدام أدوات تطوير Next.js لتحديد ما إذا كان المسار ثابتًا أو ديناميكيًا. راجع [`devIndicators`](/docs/app/api-reference/config/next-config-js/devIndicators) لمزيد من المعلومات. + +### الأجزاء الديناميكية بدون `generateStaticParams` + +إذا كان [الجزء الديناميكي (dynamic segment)](/docs/app/api-reference/file-conventions/dynamic-routes) يمكن تصييره مسبقًا ولكن لم يتم ذلك لأنه يفتقد [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)، فسيعود المسار إلى التصيير الديناميكي وقت الطلب. + +تأكد من أن المسار يتم إنشاؤه ثابتًا وقت البناء عن طريق إضافة `generateStaticParams`: + +```tsx filename="app/blog/[slug]/page.tsx" switcher +export async function generateStaticParams() { + const posts = await fetch('https://.../posts').then((res) => res.json()) + + return posts.map((post) => ({ + slug: post.slug, + })) +} + +export default async function Page({ + params, +}: { + params: Promise<{ slug: string }> +}) { + const { slug } = await params + // ... +} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +export async function generateStaticParams() { + const posts = await fetch('https://.../posts').then((res) => res.json()) + + return posts.map((post) => ({ + slug: post.slug, + })) + +export default async function Page({ params }) { + const { slug } = await params + // ... +} +``` + +### الشبكات البطيئة + +على الشبكات البطيئة أو غير المستقرة، قد لا يكتمل الجلب المسبق قبل أن ينقر المستخدم على رابط. هذا يمكن أن يؤثر على كل من المسارات الثابتة والديناميكية. في هذه الحالات، قد لا تظهر واجهة `loading.js` الاحتياطية على الفور لأنها لم يتم جلبها مسبقًا بعد. + +لتحسين الأداء الملحوظ، يمكنك استخدام [خطاف `useLinkStatus`](/docs/app/api-reference/functions/use-link-status) لعرض ردود فعل مرئية مضمنة للمستخدم (مثل المؤشرات الدوارة أو توهج النص على الرابط) أثناء وجود انتقال قيد التقدم. + +```tsx +'use client' + +import { useLinkStatus } from 'next/link' + +export default function LoadingIndicator() { + const { pending } = useLinkStatus() + return pending ? ( +
+ ) : null +} +``` + +```tsx +'use client' + +import { useLinkStatus } from 'next/link' + +export default function LoadingIndicator() { + const { pending } = useLinkStatus() + return pending ? ( +
+ ) : null +} +``` + +يمكنك "إزالة الارتعاش" لمؤشر التحميل عن طريق إضافة تأخير أولي للرسوم المتحركة (مثل 100 مللي ثانية) وبدء الرسوم المتحركة كغير مرئية (مثل `opacity: 0`). هذا يعني أن مؤشر التحميل سيظهر فقط إذا استغرق التنقل وقتًا أطول من التأخير المحدد. + +```css +.spinner { + /* ... */ + opacity: 0; + animation: + fadeIn 500ms 100ms forwards, + rotate 1s linear infinite; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes rotate { + to { + transform: rotate(360deg); + } +} +``` + +> **معلومة مفيدة**: يمكنك استخدام أنماط أخرى من ردود الفعل المرئية مثل شريط التقدم. عرض مثال [هنا](https://github.com/vercel/react-transition-progress). + +### تعطيل الجلب المسبق + +يمكنك إلغاء تفعيل الجلب المسبق عن طريق تعيين خاصية `prefetch` إلى `false` في مكون ``. هذا مفيد لتجنب استخدام موارد غير ضرورية عند تصيير قوائم كبيرة من الروابط (مثل جدول تمرير لا نهائي). + +```tsx + + Blog + +``` + +ومع ذلك، فإن تعطيل الجلب المسبق يأتي مع مقايضات: + +- **المسارات الثابتة**: سيتم جلبها فقط عندما ينقر المستخدم على الرابط. +- **المسارات الديناميكية**: يجب تصييرها على الخادم أولاً قبل أن يتمكن العميل من التنقل إليها. + +لتقليل استخدام الموارد دون تعطيل الجلب المسبق بالكامل، يمكنك جلب المسارات مسبقًا عند التحويم فقط. هذا يحد من الجلب المسبق للمسارات التي من المرجح أن يزورها المستخدم، بدلاً من جميع الروابط في نطاق الرؤية. + +```tsx filename="app/ui/hover-prefetch-link.tsx" switcher +'use client' + +import Link from 'next/link' +import { useState } from 'react' + +function HoverPrefetchLink({ + href, + children, +}: { + href: string + children: React.ReactNode +}) { + const [active, setActive] = useState(false) + + return ( + setActive(true)} + > + {children} + + ) +} +``` + +```jsx filename="app/ui/hover-prefetch-link.js" switcher +'use client' + +import Link from 'next/link' +import { useState } from 'react' + +function HoverPrefetchLink({ href, children }) { + const [active, setActive] = useState(false) + + return ( + setActive(true)} + > + {children} + + ) +} +``` + +### عدم اكتمال الترطيب (Hydration) + +`` هو مكون عميل ويجب ترطيبه قبل أن يتمكن من جلب المسارات مسبقًا. في الزيارة الأولية، يمكن أن تؤخر الحزم الكبيرة من JavaScript الترطيب، مما يمنع بدء الجلب المسبق على الفور. + +يتعامل React مع هذا مع الترطيب الانتقائي ويمكنك تحسينه أكثر عن طريق: + +- استخدام مكون [`@next/bundle-analyzer`](/docs/app/guides/package-bundling#analyzing-javascript-bundles) لتحديد وتقليل حجم الحزمة عن طريق إزالة التبعيات الكبيرة. +- نقل المنطق من العميل إلى الخادم حيثما أمكن. راجع وثائق [مكونات الخادم والعميل (Server and Client Components)](/docs/app/getting-started/server-and-client-components) للحصول على إرشادات. + +## أمثلة + +### واجهة برمجة التاريخ الأصلية (Native History API) + +يسمح لك Next.js باستخدام الطرق الأصلية [`window.history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) و[`window.history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState) لتحديد سجل المتصفح دون إعادة تحميل الصفحة. + +تتكامل مكالمات `pushState` و`replaceState` مع موجه Next.js، مما يسمح لك بالمزامنة مع [`usePathname`](/docs/app/api-reference/functions/use-pathname) و[`useSearchParams`](/docs/app/api-reference/functions/use-search-params). + +#### `window.history.pushState` + +استخدمه لإضافة إدخال جديد إلى سجل المتصفح. يمكن للمستخدم التنقل للخلف إلى الحالة السابقة. على سبيل المثال، لفرز قائمة من المنتجات: + +```tsx fileName="app/ui/sort-products.tsx" switcher +'use client' + +import { useSearchParams } from 'next/navigation' + +export default function SortProducts() { + const searchParams = useSearchParams() + + function updateSorting(sortOrder: string) { + const params = new URLSearchParams(searchParams.toString()) + params.set('sort', sortOrder) + window.history.pushState(null, '', `?${params.toString()}`) + } + + return ( + <> + + + + ) +} +``` + +```jsx fileName="app/ui/sort-products.js" switcher +'use client' + +import { useSearchParams } from 'next/navigation' + +export default function SortProducts() { + const searchParams = useSearchParams() + + function updateSorting(sortOrder) { + const params = new URLSearchParams(searchParams.toString()) + params.set('sort', sortOrder) + window.history.pushState(null, '', `?${params.toString()}`) + } + + return ( + <> + + + + ) +} +``` + +#### `window.history.replaceState` + +استخدم هذه الدالة لاستبدال الإدخال الحالي في سجل التصفح (history stack) للمتصفح. لن يتمكن المستخدم من العودة إلى الحالة السابقة. على سبيل المثال، لتبديل لغة التطبيق: + +```tsx fileName="app/ui/locale-switcher.tsx" switcher +'use client' + +import { usePathname } from 'next/navigation' + +export function LocaleSwitcher() { + const pathname = usePathname() + + function switchLocale(locale: string) { + // مثال: '/en/about' أو '/fr/contact' + const newPath = `/${locale}${pathname}` + window.history.replaceState(null, '', newPath) + } + + return ( + <> + + + + ) +} +``` + +```jsx fileName="app/ui/locale-switcher.js" switcher +'use client' + +import { usePathname } from 'next/navigation' + +export function LocaleSwitcher() { + const pathname = usePathname() + + function switchLocale(locale) { + // مثال: '/en/about' أو '/fr/contact' + const newPath = `/${locale}${pathname}` + window.history.replaceState(null, '', newPath) + } + + return ( + <> + + + + ) +} +``` diff --git a/apps/docs/content/ar/docs/01-app/01-getting-started/09-fetching-data.mdx b/apps/docs/content/ar/docs/01-app/01-getting-started/09-fetching-data.mdx index 3550312f..23d200b3 100644 --- a/apps/docs/content/ar/docs/01-app/01-getting-started/09-fetching-data.mdx +++ b/apps/docs/content/ar/docs/01-app/01-getting-started/09-fetching-data.mdx @@ -1,6 +1,6 @@ --- -source-updated-at: 2025-06-01T01:32:20.000Z -translation-updated-at: 2025-06-02T20:05:12.523Z +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:13:40.243Z title: كيفية جلب البيانات والتدفق nav_title: جلب البيانات description: ابدأ بجلب البيانات وتدفق المحتوى في تطبيقك. @@ -14,7 +14,7 @@ related: - app/api-reference/config/next-config-js/taint --- -سترشدك هذه الصفحة حول كيفية جلب البيانات في [مكونات الخادم والعميل](/docs/app/getting-started/server-and-client-components)، وكيفية [تدفق](#streaming) المكونات التي تعتمد على البيانات. +سترشدك هذه الصفحة حول كيفية جلب البيانات في [مكونات الخادم والعميل (Server and Client Components)](/docs/app/getting-started/server-and-client-components)، وكيفية [تدفق](#streaming) المكونات التي تعتمد على البيانات. ## جلب البيانات @@ -25,9 +25,9 @@ related: 1. [واجهة `fetch` API](#with-the-fetch-api) 2. [ORM أو قاعدة بيانات](#with-an-orm-or-database) -#### باستخدام `fetch` API +#### مع `fetch` API -لجلب البيانات باستخدام `fetch` API، حول مكونك إلى دالة غير متزامنة، واستخدم await مع استدعاء `fetch`. على سبيل المثال: +لجلب البيانات باستخدام `fetch` API، حول مكونك إلى دالة غير متزامنة (async)، واستخدم await مع استدعاء `fetch`. على سبيل المثال: ```tsx filename="app/blog/page.tsx" switcher export default async function Page() { @@ -59,12 +59,12 @@ export default async function Page() { > **جيد أن تعرف:** > -> - استجابات `fetch` لا يتم تخزينها مؤقتًا افتراضيًا. ومع ذلك، سيقوم Next.js [بالتقديم المسبق](/docs/app/getting-started/partial-prerendering#static-rendering) للمسار وسيتم تخزين الناتج لتحسين الأداء. إذا كنت ترغب في اختيار [التقديم الديناميكي](/docs/app/getting-started/partial-prerendering#dynamic-rendering)، استخدم الخيار `{ cache: 'no-store' }`. راجع [مرجع `fetch` API](/docs/app/api-reference/functions/fetch). -> - أثناء التطوير، يمكنك تسجيل استدعاءات `fetch` لتحسين الرؤية والتdebugging. راجع [مرجع `logging` API](/docs/app/api-reference/config/next-config-js/logging). +> - استجابات `fetch` لا يتم تخزينها مؤقتًا افتراضيًا. ومع ذلك، سيقوم Next.js [بالتقديم المسبق (prerender)](/docs/app/getting-started/partial-prerendering#static-rendering) للمسار وسيتم تخزين الناتج لتحسين الأداء. إذا كنت ترغب في تفعيل [التقديم الديناميكي (dynamic rendering)](/docs/app/getting-started/partial-prerendering#dynamic-rendering)، استخدم الخيار `{ cache: 'no-store' }`. راجع [مرجع `fetch` API](/docs/app/api-reference/functions/fetch). +> - أثناء التطوير، يمكنك تسجيل استدعاءات `fetch` لتحسين الرؤية وتصحيح الأخطاء. راجع [مرجع `logging` API](/docs/app/api-reference/config/next-config-js/logging). -#### باستخدام ORM أو قاعدة بيانات +#### مع ORM أو قاعدة بيانات -بما أن مكونات الخادم يتم تقديمها على الخادم، يمكنك بأمان إجراء استعلامات قاعدة بيانات باستخدام ORM أو عميل قاعدة بيانات. حول مكونك إلى دالة غير متزامنة، واستخدم await مع الاستدعاء: +بما أن مكونات الخادم يتم تقديمها على الخادم، يمكنك بأمان إجراء استعلامات قاعدة بيانات باستخدام ORM أو عميل قاعدة بيانات. حول مكونك إلى دالة غير متزامنة واستخدم await مع الاستدعاء: ```tsx filename="app/blog/page.tsx" switcher import { db, posts } from '@/lib/db' @@ -100,12 +100,12 @@ export default async function Page() { هناك طريقتان لجلب البيانات في مكونات العميل، باستخدام: -1. [خطاف `use` من React](https://react.dev/reference/react/use) +1. خطاف [`use` في React](https://react.dev/reference/react/use) 2. مكتبة مجتمعية مثل [SWR](https://swr.vercel.app/) أو [React Query](https://tanstack.com/query/latest) -#### تدفق البيانات باستخدام خطاف `use` +#### تدفق البيانات مع خطاف `use` -يمكنك استخدام [خطاف `use` من React](https://react.dev/reference/react/use) ل[تدفق](#streaming) البيانات من الخادم إلى العميل. ابدأ بجلب البيانات في مكون الخادم الخاص بك، ومرر الوعد إلى مكون العميل كخاصية: +يمكنك استخدام خطاف [`use` في React](https://react.dev/reference/react/use) [لتدفق](#streaming) البيانات من الخادم إلى العميل. ابدأ بجلب البيانات في مكون الخادم الخاص بك، ومرر الوعد (promise) إلى مكون العميل كخاصية (prop): ```tsx filename="app/blog/page.tsx" switcher import Posts from '@/app/ui/posts @@ -179,7 +179,7 @@ export default function Posts({ posts }) { } ``` -في المثال أعلاه، تم تغليف مكون `` داخل حدود [``](https://react.dev/reference/react/Suspense). هذا يعني أنه سيتم عرض الحالة الاحتياطية أثناء حل الوعد. تعلم المزيد عن [التدفق](#streaming). +في المثال أعلاه، تم تغليف مكون `` داخل حدود [``](https://react.dev/reference/react/Suspense). هذا يعني أنه سيتم عرض الحالة الاحتياطية (fallback) أثناء حل الوعد. تعلم المزيد عن [التدفق](#streaming). #### المكتبات المجتمعية @@ -236,13 +236,13 @@ export default function BlogPage() { } ``` -## منع الطلبات المكررة باستخدام `React.cache` +## إزالة تكرار الطلبات مع `React.cache` -منع التكرار هو عملية _منع الطلبات المكررة_ لنفس المورد أثناء تمرير التقديم. يسمح لك بجلب نفس البيانات في مكونات مختلفة مع منع طلبات متعددة إلى مصدر البيانات الخاص بك. +إزالة التكرار هي عملية _منع الطلبات المكررة_ لنفس المورد أثناء تمرير التقديم. تتيح لك جلب نفس البيانات في مكونات مختلفة مع منع طلبات متعددة إلى مصدر البيانات الخاص بك. -إذا كنت تستخدم `fetch`، يمكن منع تكرار الطلبات عن طريق إضافة `cache: 'force-cache'`. هذا يعني أنه يمكنك بأمان استدعاء نفس URL بنفس الخيارات، وسيتم إجراء طلب واحد فقط. +إذا كنت تستخدم `fetch`، يمكن إزالة تكرار الطلبات بإضافة `cache: 'force-cache'`. هذا يعني أنه يمكنك استدعاء نفس الرابط بنفس الخيارات بأمان، وسيتم إجراء طلب واحد فقط. -إذا كنت _لا_ تستخدم `fetch`، وبدلاً من ذلك تستخدم ORM أو قاعدة بيانات مباشرة، يمكنك تغليف جلب البيانات الخاص بك باستخدام دالة [React `cache`](https://react.dev/reference/react/cache). +إذا كنت _لا_ تستخدم `fetch`، وتستخدم بدلاً من ذلك ORM أو قاعدة بيانات مباشرة، يمكنك تغليف جلب البيانات الخاصة بك باستخدام دالة [React `cache`](https://react.dev/reference/react/cache). ```tsx filename="app/lib/data.ts" switcher import { cache } from 'react' @@ -269,11 +269,11 @@ export const getPost = cache(async (id) => { ## التدفق -> **تحذير:** المحتوى أدناه يفترض أن خيار التكوين [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) مفعل في تطبيقك. تم تقديم هذه العلامة في Next.js 15 canary. +> **تحذير:** المحتوى أدناه يفترض تمكين خيار التكوين [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) في تطبيقك. تم تقديم هذه العلامة في Next.js 15 canary. -عند استخدام `async/await` في مكونات الخادم، سيقوم Next.js باختيار [التقديم الديناميكي](/docs/app/getting-started/partial-prerendering#dynamic-rendering). هذا يعني أنه سيتم جلب البيانات وتقديمها على الخادم لكل طلب مستخدم. إذا كانت هناك أي طلبات بيانات بطيئة، فسيتم حظر المسار بأكمله من التقديم. +عند استخدام `async/await` في مكونات الخادم، سيقوم Next.js بالانتقال إلى [التقديم الديناميكي (dynamic rendering)](/docs/app/getting-started/partial-prerendering#dynamic-rendering). هذا يعني أن البيانات سيتم جلبها وتقديمها على الخادم لكل طلب مستخدم. إذا كانت هناك أي طلبات بيانات بطيئة، فسيتم حظر المسار بالكامل من التقديم. -لتحسين وقت التحميل الأولي وتجربة المستخدم، يمكنك استخدام التدفق لتقسيم HTML الصفحة إلى أجزاء أصغر وإرسال هذه الأجزاء تدريجياً من الخادم إلى العميل. +لتحسين وقت التحميل الأولي وتجربة المستخدم، يمكنك استخدام التدفق لتقسيم HTML للصفحة إلى أجزاء أصغر وإرسال هذه الأجزاء تدريجياً من الخادم إلى العميل. كيف يعمل التقديم من الخادم مع التدفق { هناك طريقتان يمكنك من خلالهما تنفيذ التدفق في تطبيقك: 1. تغليف صفحة بملف [`loading.js`](#with-loadingjs) -2. تغليف مكون بـ [``](#with-suspense) +2. تغليف مكون ب [``](#with-suspense) -### باستخدام `loading.js` +### مع `loading.js` يمكنك إنشاء ملف `loading.js` في نفس مجلد صفحتك لتدفق **الصفحة بأكملها** أثناء جلب البيانات. على سبيل المثال، لتدفق `app/blog/page.js`، أضف الملف داخل مجلد `app/blog`. @@ -302,14 +302,14 @@ export const getPost = cache(async (id) => { ```tsx filename="app/blog/loading.tsx" switcher export default function Loading() { - // حدد واجهة المستخدم للتحميل هنا + // حدد واجهة التحميل هنا return
Loading...
} ``` ```jsx filename="app/blog/loading.js" switcher export default function Loading() { - // حدد واجهة المستخدم للتحميل هنا + // حدد واجهة التحميل هنا return
Loading...
} ``` @@ -317,14 +317,14 @@ export default function Loading() { عند التنقل، سيرى المستخدم على الفور التخطيط وحالة [التحميل](#creating-meaningful-loading-states) أثناء تقديم الصفحة. سيتم بعد ذلك تبديل المحتوى الجديد تلقائيًا بمجرد اكتمال التقديم. واجهة المستخدم للتحميل -خلف الكواليس، سيتم تداخل `loading.js` داخل `layout.js`، وسيتم تغليف ملف `page.js` وأي أطفال أدناه تلقائيًا داخل حدود ``. +خلف الكواليس، سيتم تداخل `loading.js` داخل `layout.js`، وسيتم تغليف `page.js` وأي أطفال أدناه تلقائيًا داخل حدود ``. نظرة عامة على loading.js`. -### باستخدام `` +### مع `` -يسمح لك `` بأن تكون أكثر دقة بشأن الأجزاء التي تريد تدفقها في الصفحة. على سبيل المثال، يمكنك عرض أي محتوى صفحة يقع خارج حدود `` على الفور، وتدفق قائمة منشورات المدونة داخل الحدود. +يسمح لك `` بأن تكون أكثر دقة بشأن الأجزاء التي تريد تدفقها من الصفحة. على سبيل المثال، يمكنك عرض أي محتوى صفحة يقع خارج حدود `` على الفور، وتدفق قائمة مشاركات المدونة داخل الحدود. ```tsx filename="app/blog/page.tsx" switcher import { Suspense } from 'react' @@ -350,8 +350,8 @@ export default function BlogPage() {
{/* سيتم إرسال هذا المحتوى إلى العميل على الفور */}
-

مرحبًا بكم في المدونة

-

اقرأ أحدث المنشورات أدناه.

+

Welcome to the Blog

+

Read the latest posts below.

{/* أي محتوى مغلف داخل حدود سيتم تدفقه */} @@ -374,8 +374,8 @@ export default function BlogPage() {
{/* سيتم إرسال هذا المحتوى إلى العميل على الفور */}
-

مرحبًا بكم في المدونة

-

اقرأ أحدث المنشورات أدناه.

+

Welcome to the Blog

+

Read the latest posts below.

{/* أي محتوى مغلف داخل حدود سيتم تدفقه */} @@ -390,18 +390,18 @@ export default function BlogPage() { ### إنشاء حالات تحميل ذات معنى -حالة التحميل الفورية هي واجهة المستخدم الاحتياطية التي يتم عرضها للمستخدم فورًا بعد التنقل. للحصول على أفضل تجربة مستخدم، نوصي بتصميم حالات التحميل التي تكون ذات معنى وتساعد المستخدمين على فهم أن التطبيق يستجيب. على سبيل المثال، يمكنك استخدام الهياكل العظمية والمؤشرات الدوارة، أو جزء صغير ولكن ذو معنى من الشاشات المستقبلية مثل صورة الغلاف والعنوان وما إلى ذلك. +حالة التحميل الفورية هي واجهة مستخدم احتياطية يتم عرضها للمستخدم فورًا بعد التنقل. للحصول على أفضل تجربة مستخدم، نوصي بتصميم حالات تحميل ذات معنى وتساعد المستخدمين على فهم أن التطبيق يستجيب. على سبيل المثال، يمكنك استخدام هياكل عظمية (skeletons) ودوائر تحميل، أو جزء صغير ولكن ذو معنى من الشاشات المستقبلية مثل صورة الغلاف والعنوان وما إلى ذلك. -في التطوير، يمكنك معاينة وفحص حالة التحميل لمكوناتك باستخدام [أدوات مطوري React](https://react.dev/learn/react-developer-tools). +في التطوير، يمكنك معاينة وفحص حالة التحميل لمكوناتك باستخدام [React Devtools](https://react.dev/learn/react-developer-tools). ## أمثلة -### جلب البيانات المتسلسل +### جلب البيانات التسلسلي -يحدث جلب البيانات المتسلسل عندما تقوم المكونات المتداخلة في شجرة كل منها بجلب بياناتها الخاصة ولا يتم [منع تكرارها](/docs/app/deep-dive/caching#request-memoization)، مما يؤدي إلى أوقات استجابة أطول. +يحدث جلب البيانات التسلسلي عندما تقوم المكونات المتداخلة في شجرة كل منها بجلب بياناتها الخاصة ولا يتم [إزالة تكرار](/docs/app/deep-dive/caching#request-memoization) الطلبات، مما يؤدي إلى أوقات استجابة أطول. جلب البيانات المتسلسل والمتوازي` في جلب البيانات إلا بعد أن ينتهي مكون `` من جلب البيانات لأن `` يعتمد على خاصية `artistID`: +على سبيل المثال، سيبدأ مكون `` بجلب البيانات فقط بعد انتهاء مكون `` من جلب البيانات لأن `` يعتمد على خاصية `artistID`: ```tsx filename="app/artist/[username]/page.tsx" switcher export default async function Page({ @@ -425,7 +425,7 @@ export default async function Page({ return ( <>

{artist.name}

- {/* عرض واجهة المستخدم الاحتياطية أثناء تحميل مكون Playlists */} + {/* عرض واجهة احتياطية أثناء تحميل مكون Playlists */} Loading...
}> {/* تمرير معرف الفنان إلى مكون Playlists */} @@ -457,7 +457,7 @@ export default async function Page({ params }) { return ( <>

{artist.name}

- {/* عرض واجهة المستخدم الاحتياطية أثناء تحميل مكون Playlists */} + {/* عرض واجهة احتياطية أثناء تحميل مكون Playlists */} Loading...
}> {/* تمرير معرف الفنان إلى مكون Playlists */} @@ -480,15 +480,15 @@ async function Playlists({ artistID }) { } ``` -لتحسين تجربة المستخدم، يجب عليك استخدام [React ``](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) لعرض `fallback` أثناء جلب البيانات. سيؤدي هذا إلى تمكين [التدفق](#streaming) ومنع حظر المسار بأكمله بواسطة طلبات البيانات المتسلسلة. +لتحسين تجربة المستخدم، يجب عليك استخدام [React ``](/docs/app/getting-started/linking-and-navigating#streaming) لعرض `fallback` أثناء جلب البيانات. سيؤدي هذا إلى تمكين [التدفق](#streaming) ومنع حظر المسار بالكامل بواسطة طلبات البيانات التسلسلية. -### جلب البيانات المتوازي +### جلب البيانات المتوازي (Parallel data fetching) -يحدث جلب البيانات المتوازي عندما يتم بدء طلبات البيانات في المسار (route) بحماس وتبدأ في نفس الوقت. +يحدث جلب البيانات المتوازي عندما يتم بدء طلبات البيانات في المسار (route) بشكل متحمس (eagerly) وتنفيذها في نفس الوقت. -بشكل افتراضي، يتم عرض [التخطيطات والصفحات](/docs/app/getting-started/layouts-and-pages) بشكل متوازي. لذا يبدأ كل جزء (segment) في جلب البيانات بأسرع وقت ممكن. +بشكل افتراضي، يتم عرض [التخطيطات والصفحات](/docs/app/getting-started/layouts-and-pages) بالتوازي. لذا يبدأ كل مقطع (segment) بجلب البيانات في أسرع وقت ممكن. -ومع ذلك، داخل _أي_ مكون، يمكن أن تظل طلبات `async`/`await` متعددة متسلسلة إذا تم وضعها بعد بعضها البعض. على سبيل المثال، سيتم حظر `getAlbums` حتى يتم حل `getArtist`: +ومع ذلك، داخل _أي_ مكون (component)، يمكن أن تظل طلبات `async`/`await` المتعددة متتابعة (sequential) إذا تم وضعها بعد بعضها البعض. على سبيل المثال، سيتم حظر `getAlbums` حتى يتم حل `getArtist`: ```tsx filename="app/artist/[username]/page.tsx" switcher import { getArtist, getAlbums } from '@/app/lib/data' @@ -502,7 +502,7 @@ export default async function Page({ params }) { } ``` -يمكنك بدء الطلبات بشكل متوازي عن طريق تعريفها خارج المكونات التي تستخدم البيانات، وحلها معًا، على سبيل المثال، باستخدام [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all): +يمكنك بدء الطلبات بالتوازي عن طريق تعريفها خارج المكونات التي تستخدم البيانات، وحلها معًا، على سبيل المثال باستخدام [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all): ```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher import Albums from './albums' @@ -568,13 +568,13 @@ export default async function Page({ params }) { } ``` -> **جيد أن تعرف:** إذا فشل أحد الطلبات عند استخدام `Promise.all`، فستفشل العملية بأكملها. للتعامل مع هذا، يمكنك استخدام طريقة [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) بدلاً من ذلك. +> **معلومة مفيدة:** إذا فشل أحد الطلبات عند استخدام `Promise.all`، فستفشل العملية بأكملها. للتعامل مع هذا، يمكنك استخدام طريقة [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) بدلاً من ذلك. -### جلب البيانات المسبق +### جلب البيانات المسبق (Preloading data) -يمكنك جلب البيانات مسبقًا عن طريق إنشاء دالة مساعدة تستدعيها بحماس قبل الطلبات الحاجزة (blocking requests). يقوم `` بعرض مشروط بناءً على دالة `checkIsAvailable()`. +يمكنك جلب البيانات مسبقًا عن طريق إنشاء دالة مساعدة (utility function) تقوم باستدعائها بشكل متحمس قبل الطلبات الحاجزة (blocking requests). يقوم `` بعرض مشروط بناءً على دالة `checkIsAvailable()`. -يمكنك استدعاء `preload()` قبل `checkIsAvailable()` لبدء تبعيات بيانات `` بحماس. بحلول وقت عرض ``، تكون بياناته قد تم جلبها بالفعل. +يمكنك استدعاء `preload()` قبل `checkIsAvailable()` لبدء تبعيات بيانات `` بشكل متحمس. بحلول وقت عرض ``، تكون بياناته قد تم جلبها بالفعل. ```tsx filename="app/item/[id]/page.tsx" switcher import { getItem } from '@/lib/data' @@ -627,7 +627,7 @@ export async function Item({ id }) { // ... ``` -بالإضافة إلى ذلك، يمكنك استخدام دالة [`cache`](https://react.dev/reference/react/cache) من React وحزمة [`server-only`](https://www.npmjs.com/package/server-only) لإنشاء دالة مساعدة قابلة لإعادة الاستخدام. تتيح لك هذه الطريقة تخزين دالة جلب البيانات مؤقتًا وضمان تنفيذها على الخادم فقط. +بالإضافة إلى ذلك، يمكنك استخدام دالة [`cache`](https://react.dev/reference/react/cache) من React وحزمة [`server-only`](https://www.npmjs.com/package/server-only) لإنشاء دالة مساعدة قابلة لإعادة الاستخدام. تتيح لك هذه الطريقة تخزين دالة جلب البيانات مؤقتًا (cache) وضمان تنفيذها فقط على الخادم. ```ts filename="utils/get-item.ts" switcher import { cache } from 'react' diff --git a/apps/docs/content/ar/docs/01-app/02-guides/authentication.mdx b/apps/docs/content/ar/docs/01-app/02-guides/authentication.mdx index 054d3473..193bec1d 100644 --- a/apps/docs/content/ar/docs/01-app/02-guides/authentication.mdx +++ b/apps/docs/content/ar/docs/01-app/02-guides/authentication.mdx @@ -1,6 +1,6 @@ --- -source-updated-at: 2025-06-01T01:32:20.000Z -translation-updated-at: 2025-06-02T20:10:24.280Z +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:19:26.550Z title: كيفية تنفيذ المصادقة في Next.js nav_title: المصادقة description: تعلم كيفية تنفيذ المصادقة في تطبيق Next.js الخاص بك. @@ -10,21 +10,21 @@ description: تعلم كيفية تنفيذ المصادقة في تطبيق Nex قبل البدء، من المفيد تقسيم العملية إلى ثلاثة مفاهيم: -1. **[المصادقة (Authentication)](#authentication)**: التحقق مما إذا كان المستخدم هو من يدعي أنه هو. يتطلب من المستخدم إثبات هويته بشيء يمتلكه، مثل اسم المستخدم وكلمة المرور. -2. **[إدارة الجلسة (Session Management)](#session-management)**: تتبع حالة مصادقة المستخدم عبر الطلبات. -3. **[الترخيص (Authorization)](#authorization)**: تحديد المسارات والبيانات التي يمكن للمستخدم الوصول إليها. +1. **[المصادقة](#authentication)**: التحقق مما إذا كان المستخدم هو من يدعي أنه هو. يتطلب من المستخدم إثبات هويته بشيء يمتلكه، مثل اسم المستخدم وكلمة المرور. +2. **[إدارة الجلسة](#session-management)**: تتبع حالة مصادقة المستخدم عبر الطلبات. +3. **[الترخيص](#authorization)**: تحديد المسارات والبيانات التي يمكن للمستخدم الوصول إليها. -يُظهر هذا الرسم البياني تدفق المصادقة باستخدام ميزات React وNext.js: +يظهر هذا الرسم التخطيطي تدفق المصادقة باستخدام ميزات React وNext.js: رسم بياني يوضح تدفق المصادقة باستخدام ميزات React وNext.js -تقدم الأمثلة في هذه الصفحة شرحًا للمصادقة الأساسية باستخدام اسم المستخدم وكلمة المرور لأغراض تعليمية. بينما يمكنك تنفيذ حل مصادقة مخصص، إلا أنه لزيادة الأمان والبساطة، نوصي باستخدام مكتبة مصادقة. توفر هذه المكتبات حلولًا مدمجة للمصادقة وإدارة الجلسات والترخيص، بالإضافة إلى ميزات إضافية مثل تسجيلات الدخول الاجتماعية والمصادقة متعددة العوامل والتحكم في الوصول بناءً على الأدوار. يمكنك العثور على قائمة في قسم [مكتبات المصادقة (Auth Libraries)](#auth-libraries). +تقدم الأمثلة في هذه الصفحة شرحًا أساسيًا لمصادقة اسم المستخدم وكلمة المرور لأغراض تعليمية. بينما يمكنك تنفيذ حل مصادقة مخصص، نوصي باستخدام مكتبة مصادقة لزيادة الأمان والبساطة. توفر هذه المكتبات حلولًا مدمجة للمصادقة وإدارة الجلسات والترخيص، بالإضافة إلى ميزات إضافية مثل تسجيلات الدخول الاجتماعية والمصادقة متعددة العوامل والتحكم في الوصول القائم على الأدوار. يمكنك العثور على قائمة في قسم [مكتبات المصادقة](#auth-libraries). ## المصادقة @@ -32,11 +32,11 @@ description: تعلم كيفية تنفيذ المصادقة في تطبيق Nex ### وظائف التسجيل وتسجيل الدخول -يمكنك استخدام عنصر [`
`](https://react.dev/reference/react-dom/components/form) مع [إجراءات الخادم (Server Actions)](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) في React و`useActionState` لالتقاط بيانات اعتماد المستخدم، والتحقق من صحة حقول النموذج، واستدعاء API أو قاعدة بيانات موفر المصادقة الخاص بك. +يمكنك استخدام عنصر [``](https://react.dev/reference/react-dom/components/form) مع [إجراءات الخادم](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) في React و`useActionState` لالتقاط بيانات اعتماد المستخدم والتحقق من صحة حقول النموذج واستدعاء واجهة برمجة التطبيقات أو قاعدة البيانات الخاصة بمزود المصادقة. -نظرًا لأن إجراءات الخادم تعمل دائمًا على الخادم، فإنها توفر بيئة آمنة للتعامل مع منطق المصادقة. +نظرًا لأن إجراءات الخادم تنفذ دائمًا على الخادم، فإنها توفر بيئة آمنة للتعامل مع منطق المصادقة. -فيما يلي الخطوات لتنفيذ وظائف التسجيل/تسجيل الدخول: +إليك الخطوات لتنفيذ وظائف التسجيل/تسجيل الدخول: #### 1. التقاط بيانات اعتماد المستخدم @@ -100,9 +100,9 @@ export async function signup(formData) {} #### 2. التحقق من صحة حقول النموذج على الخادم -استخدم إجراء الخادم للتحقق من صحة حقول النموذج على الخادم. إذا لم يوفر موفر المصادقة الخاص بك التحقق من صحة النموذج، يمكنك استخدام مكتبة تحقق من المخطط مثل [Zod](https://zod.dev/) أو [Yup](https://github.com/jquense/yup). +استخدم إجراء الخادم للتحقق من صحة حقول النموذج على الخادم. إذا كان مزود المصادقة لا يوفر التحقق من صحة النموذج، يمكنك استخدام مكتبة تحقق من المخطط مثل [Zod](https://zod.dev/) أو [Yup](https://github.com/jquense/yup). -باستخدام Zod كمثال، يمكنك تعريف مخطط نموذج مع رسائل خطأ مناسبة: +باستخدام Zod كمثال، يمكنك تحديد مخطط نموذج مع رسائل خطأ مناسبة: ```ts filename="app/lib/definitions.ts" switcher import { z } from 'zod' @@ -157,7 +157,7 @@ export const SignupFormSchema = z.object({ }) ``` -لمنع استدعاءات غير ضرورية لـ API أو قاعدة بيانات موفر المصادقة الخاص بك، يمكنك `إرجاع` مبكرًا في إجراء الخادم إذا كانت أي حقول نموذج لا تتطابق مع المخطط المحدد. +لمنع استدعاءات غير ضرورية لواجهة برمجة التطبيقات أو قاعدة البيانات الخاصة بمزود المصادقة، يمكنك `إرجاع` مبكرًا في إجراء الخادم إذا كانت أي حقول نموذج لا تتطابق مع المخطط المحدد. ```ts filename="app/actions/auth.ts" switcher import { SignupFormSchema, FormState } from '@/app/lib/definitions' @@ -203,7 +203,7 @@ export async function signup(state, formData) { } ``` -بالعودة إلى `` الخاص بك، يمكنك استخدام خطاف React `useActionState` لعرض أخطاء التحقق أثناء إرسال النموذج: +في نموذج `` الخاص بك، يمكنك استخدام خطاف `useActionState` في React لعرض أخطاء التحقق أثناء إرسال النموذج: ```tsx filename="app/ui/signup-form.tsx" switcher highlight={7,15,21,27-36} 'use client' @@ -297,23 +297,23 @@ export default function SignupForm() { > **جيد أن تعرف:** > -> - في React 19، يتضمن `useFormStatus` مفاتيح إضافية على الكائن المعاد، مثل data وmethod وaction. إذا كنت لا تستخدم React 19، فإن مفتاح `pending` فقط هو المتاح. -> - قبل تعديل البيانات، يجب عليك دائمًا التأكد من أن المستخدم مخول أيضًا لتنفيذ الإجراء. راجع [المصادقة والترخيص (Authentication and Authorization)](#authorization). +> - في React 19، يتضمن `useFormStatus` مفاتيح إضافية على الكائن المعاد، مثل data وmethod وaction. إذا كنت لا تستخدم React 19، فإن المفتاح `pending` فقط متاح. +> - قبل تعديل البيانات، يجب عليك دائمًا التأكد من أن المستخدم مصرح له أيضًا بتنفيذ الإجراء. راجع [المصادقة والترخيص](#authorization). -#### 3. إنشاء مستخدم أو التحقق من بيانات الاعتماد +#### ٣. إنشاء مستخدم أو التحقق من بيانات الاعتماد -بعد التحقق من صحة حقول النموذج، يمكنك إنشاء حساب مستخدم جديد أو التحقق من وجود المستخدم عن طريق استدعاء واجهة برمجة التطبيقات (API) أو قاعدة البيانات الخاصة بمزود المصادقة. +بعد التحقق من حقول النموذج، يمكنك إنشاء حساب مستخدم جديد أو التحقق من وجود المستخدم عن طريق استدعاء واجهة برمجة التطبيقات (API) أو قاعدة البيانات الخاصة بمزود المصادقة. -استكمالًا للمثال السابق: +متابعة من المثال السابق: ```tsx filename="app/actions/auth.tsx" switcher export async function signup(state: FormState, formData: FormData) { - // 1. التحقق من صحة حقول النموذج + // 1. التحقق من حقول النموذج // ... // 2. تحضير البيانات للإدراج في قاعدة البيانات const { name, email, password } = validatedFields.data - // على سبيل المثال: تشفير كلمة مرور المستخدم قبل تخزينها + // مثلاً: تشفير كلمة مرور المستخدم قبل تخزينها const hashedPassword = await bcrypt.hash(password, 10) // 3. إدراج المستخدم في قاعدة البيانات أو استدعاء واجهة برمجة التطبيقات لمكتبة المصادقة @@ -336,18 +336,18 @@ export async function signup(state: FormState, formData: FormData) { // TODO: // 4. إنشاء جلسة المستخدم - // 5. إعادة توجيه المستخدم + // 5. توجيه المستخدم } ``` ```jsx filename="app/actions/auth.js" switcher export async function signup(state, formData) { - // 1. التحقق من صحة حقول النموذج + // 1. التحقق من حقول النموذج // ... // 2. تحضير البيانات للإدراج في قاعدة البيانات const { name, email, password } = validatedFields.data - // على سبيل المثال: تشفير كلمة مرور المستخدم قبل تخزينها + // مثلاً: تشفير كلمة مرور المستخدم قبل تخزينها const hashedPassword = await bcrypt.hash(password, 10) // 3. إدراج المستخدم في قاعدة البيانات أو استدعاء واجهة برمجة التطبيقات لمكتبة المصادقة @@ -370,11 +370,11 @@ export async function signup(state, formData) { // TODO: // 4. إنشاء جلسة المستخدم - // 5. إعادة توجيه المستخدم + // 5. توجيه المستخدم } ``` -بعد إنشاء حساب المستخدم بنجاح أو التحقق من بيانات الاعتماد، يمكنك إنشاء جلسة لإدارة حالة المصادقة للمستخدم. اعتمادًا على استراتيجية إدارة الجلسات، يمكن تخزين الجلسة في ملف تعريف الارتباط (cookie) أو قاعدة البيانات، أو كليهما. انتقل إلى قسم [إدارة الجلسات](#session-management) لمعرفة المزيد. +بعد إنشاء حساب المستخدم بنجاح أو التحقق من بيانات الاعتماد، يمكنك إنشاء جلسة لإدارة حالة مصادقة المستخدم. اعتمادًا على استراتيجية إدارة الجلسة، يمكن تخزين الجلسة في ملف تعريف الارتباط (cookie) أو قاعدة البيانات، أو كليهما. انتقل إلى قسم [إدارة الجلسة](#session-management) لمعرفة المزيد. > **نصائح:** > @@ -387,12 +387,12 @@ export async function signup(state, formData) { إليك خطوات تنفيذ نموذج تسجيل و/أو تسجيل الدخول: -1. يقدم المستخدم بيانات الاعتماد الخاصة به من خلال نموذج. -2. يرسل النموذج طلبًا يتم معالجته بواسطة مسار API. -3. عند التحقق الناجح، تكتمل العملية، مما يشير إلى نجاح مصادقة المستخدم. -4. إذا فشل التحقق، يتم عرض رسالة خطأ. +١. يقدم المستخدم بيانات الاعتماد الخاصة به من خلال نموذج. +٢. يرسل النموذج طلبًا يتم معالجته بواسطة مسار API. +٣. عند التحقق الناجح، تكتمل العملية، مما يشير إلى نجاح مصادقة المستخدم. +٤. إذا فشل التحقق، يتم عرض رسالة خطأ. -فكر في نموذج تسجيل دخول حيث يمكن للمستخدمين إدخال بيانات الاعتماد الخاصة بهم: +ضع في اعتبارك نموذج تسجيل الدخول حيث يمكن للمستخدمين إدخال بيانات الاعتماد الخاصة بهم: ```tsx filename="pages/login.tsx" switcher import { FormEvent } from 'react' @@ -423,9 +423,9 @@ export default function LoginPage() { return ( - - - + + + ) } @@ -460,17 +460,17 @@ export default function LoginPage() { return (
- - - + + +
) } ``` -يحتوي النموذج أعلاه على حقلين إدخال لجمع بريد المستخدم الإلكتروني وكلمة المرور. عند الإرسال، يتم تشغيل وظيفة ترسل طلب POST إلى مسار API (`/api/auth/login`). +يحتوي النموذج أعلاه على حقلين إدخال لجمع البريد الإلكتروني وكلمة المرور للمستخدم. عند الإرسال، يتم تشغيل وظيفة ترسل طلب POST إلى مسار API (`/api/auth/login`). -يمكنك بعد ذلك استدعاء واجهة برمجة التطبيقات لمزود المصادقة في مسار API لمعالجة المصادقة: +يمكنك بعد ذلك استدعاء واجهة برمجة التطبيقات الخاصة بمزود المصادقة في مسار API لمعالجة المصادقة: ```ts filename="pages/api/auth/login.ts" switcher import type { NextApiRequest, NextApiResponse } from 'next' @@ -516,16 +516,16 @@ export default async function handler(req, res) { -## إدارة الجلسات +## إدارة الجلسة -تضمن إدارة الجلسات الحفاظ على حالة المصادقة للمستخدم عبر الطلبات. وتشمل إنشاء الجلسات وتخزينها وتحديثها وحذفها. +تضمن إدارة الجلسة الحفاظ على حالة مصادقة المستخدم عبر الطلبات. وهي تشمل إنشاء وتخزين وتحديث وحذف الجلسات أو الرموز (tokens). هناك نوعان من الجلسات: -1. [**بدون حالة (Stateless)**](#stateless-sessions): يتم تخزين بيانات الجلسة (أو الرمز المميز) في ملفات تعريف الارتباط (cookies) للمتصفح. يتم إرسال ملف تعريف الارتباط مع كل طلب، مما يسمح بالتحقق من الجلسة على الخادم. هذه الطريقة أبسط، ولكنها قد تكون أقل أمانًا إذا لم يتم تنفيذها بشكل صحيح. -2. [**قاعدة البيانات (Database)**](#database-sessions): يتم تخزين بيانات الجلسة في قاعدة بيانات، مع تلقي متصفح المستخدم فقط لمعرف الجلسة المشفر. هذه الطريقة أكثر أمانًا، ولكنها قد تكون معقدة وتستهلك موارد الخادم. +١. [**بدون حالة (Stateless)**](#stateless-sessions): يتم تخزين بيانات الجلسة (أو الرمز) في ملفات تعريف الارتباط (cookies) للمتصفح. يتم إرسال ملف تعريف الارتباط مع كل طلب، مما يسمح بالتحقق من الجلسة على الخادم. هذه الطريقة أبسط، ولكن يمكن أن تكون أقل أمانًا إذا لم يتم تنفيذها بشكل صحيح. +٢. [**قاعدة البيانات (Database)**](#database-sessions): يتم تخزين بيانات الجلسة في قاعدة بيانات، مع تلقي متصفح المستخدم فقط لمعرف الجلسة المشفر. هذه الطريقة أكثر أمانًا، ولكن يمكن أن تكون معقدة وتستخدم موارد أكثر على الخادم. -> **جيد أن تعرف:** بينما يمكنك استخدام أي من الطريقتين، أو كليهما، نوصي باستخدام مكتبة لإدارة الجلسات مثل [iron-session](https://github.com/vvo/iron-session) أو [Jose](https://github.com/panva/jose). +> **من الجيد معرفة:** بينما يمكنك استخدام أي من الطريقتين، أو كليهما، نوصي باستخدام مكتبة إدارة جلسات مثل [iron-session](https://github.com/vvo/iron-session) أو [Jose](https://github.com/panva/jose). ### الجلسات بدون حالة (Stateless) @@ -533,37 +533,37 @@ export default async function handler(req, res) { لإنشاء وإدارة الجلسات بدون حالة، هناك بعض الخطوات التي تحتاج إلى اتباعها: -1. إنشاء مفتاح سري، والذي سيستخدم لتوقيع جلسة المستخدم، وتخزينه كـ [متغير بيئة](/docs/app/guides/environment-variables). -2. كتابة منطق لتشفير/فك تشفير بيانات الجلسة باستخدام مكتبة إدارة الجلسات. -3. إدارة ملفات تعريف الارتباط باستخدام واجهة برمجة التطبيقات [`cookies`](/docs/app/api-reference/functions/cookies) في Next.js. +١. إنشاء مفتاح سري، والذي سيتم استخدامه لتوقيع جلسة العمل الخاصة بك، وتخزينه كـ [متغير بيئي](/docs/app/guides/environment-variables). +٢. كتابة منطق لتشفير/فك تشفير بيانات الجلسة باستخدام مكتبة إدارة الجلسات. +٣. إدارة ملفات تعريف الارتباط باستخدام واجهة برمجة التطبيقات [`cookies`](/docs/app/api-reference/functions/cookies) الخاصة بـ Next.js. -بالإضافة إلى ما سبق، فكر في إضافة وظيفة [لتحديث (أو تجديد)](#updating-or-refreshing-sessions) الجلسة عندما يعود المستخدم إلى التطبيق، و[حذف](#deleting-the-session) الجلسة عندما يسجل المستخدم خروجًا. +بالإضافة إلى ما سبق، ضع في اعتبارك إضافة وظيفة [لتحديث (أو تجديد)](#updating-or-refreshing-sessions) الجلسة عندما يعود المستخدم إلى التطبيق، و[حذف](#deleting-the-session) الجلسة عندما يقوم المستخدم بتسجيل الخروج. -> **جيد أن تعرف:** تحقق مما إذا كانت [مكتبة المصادقة](#auth-libraries) الخاصة بك تتضمن إدارة الجلسات. +> **من الجيد معرفة:** تحقق مما إذا كانت [مكتبة المصادقة](#auth-libraries) الخاصة بك تتضمن إدارة الجلسات. -#### 1. إنشاء مفتاح سري +#### ١. إنشاء مفتاح سري -هناك عدة طرق يمكنك من خلالها إنشاء مفتاح سري لتوقيع جلسة المستخدم. على سبيل المثال، يمكنك استخدام أمر `openssl` في طرفيتك: +هناك بعض الطرق التي يمكنك من خلالها إنشاء مفتاح سري لتوقيع جلسة العمل الخاصة بك. على سبيل المثال، يمكنك اختيار استخدام أمر `openssl` في طرفيتك: ```bash filename="terminal" openssl rand -base64 32 ``` -ينشئ هذا الأمر سلسلة عشوائية مكونة من 32 حرفًا يمكنك استخدامها كمفتاح سري وتخزينها في [ملف متغيرات البيئة](/docs/app/guides/environment-variables): +ينشئ هذا الأمر سلسلة عشوائية مكونة من 32 حرفًا يمكنك استخدامها كمفتاح سري وتخزينها في [ملف المتغيرات البيئية](/docs/app/guides/environment-variables): ```bash filename=".env" SESSION_SECRET=your_secret_key ``` -يمكنك بعد ذلك الرجوع إلى هذا المفتاح في منطق إدارة الجلسات: +يمكنك بعد ذلك الرجوع إلى هذا المفتاح في منطق إدارة الجلسة: ```js filename="app/lib/session.js" const secretKey = process.env.SESSION_SECRET ``` -#### 2. تشفير وفك تشفير الجلسات +#### ٢. تشفير وفك تشفير الجلسات -بعد ذلك، يمكنك استخدام [مكتبة إدارة الجلسات](#session-management-libraries) المفضلة لديك لتشفير وفك تشفير الجلسات. متابعة للمثال السابق، سنستخدم [Jose](https://www.npmjs.com/package/jose) (متوافق مع [Edge Runtime](/docs/app/api-reference/edge)) وحزمة [`server-only`](https://www.npmjs.com/package/server-only) من React لضمان تنفيذ منطق إدارة الجلسات على الخادم فقط. +بعد ذلك، يمكنك استخدام [مكتبة إدارة الجلسات](#session-management-libraries) المفضلة لديك لتشفير وفك تشفير الجلسات. متابعة من المثال السابق، سنستخدم [Jose](https://www.npmjs.com/package/jose) (متوافق مع [Edge Runtime](/docs/app/api-reference/edge)) وحزمة [`server-only`](https://www.npmjs.com/package/server-only) الخاصة بـ React لضمان تنفيذ منطق إدارة الجلسة فقط على الخادم. ```tsx filename="app/lib/session.ts" switcher import 'server-only' @@ -620,17 +620,17 @@ export async function decrypt(session) { } ``` -> **نصائح**: +> **نصائح:** > -> - يجب أن يحتوي الحمولة (payload) على **الحد الأدنى** من بيانات المستخدم الفريدة التي سيتم استخدامها في الطلبات اللاحقة، مثل معرف المستخدم، الدور، إلخ. لا يجب أن تحتوي على معلومات شخصية مثل رقم الهاتف، عنوان البريد الإلكتروني، معلومات بطاقة الائتمان، إلخ، أو بيانات حساسة مثل كلمات المرور. +> - يجب أن يحتوي الحمولة (payload) على **الحد الأدنى** من بيانات المستخدم الفريدة التي سيتم استخدامها في الطلبات اللاحقة، مثل معرف المستخدم، الدور، إلخ. لا ينبغي أن تحتوي على معلومات تعريف شخصية مثل رقم الهاتف، عنوان البريد الإلكتروني، معلومات بطاقة الائتمان، إلخ، أو بيانات حساسة مثل كلمات المرور. -#### 3. تعيين ملفات تعريف الارتباط (خيارات موصى بها) +#### ٣. تعيين ملفات تعريف الارتباط (خيارات موصى بها) -لتخزين الجلسة في ملف تعريف الارتباط، استخدم واجهة برمجة التطبيقات [`cookies`](/docs/app/api-reference/functions/cookies) في Next.js. يجب تعيين ملف تعريف الارتباط على الخادم، ويتضمن الخيارات الموصى بها: +لتخزين الجلسة في ملف تعريف ارتباط، استخدم واجهة برمجة التطبيقات [`cookies`](/docs/app/api-reference/functions/cookies) الخاصة بـ Next.js. يجب تعيين ملف تعريف الارتباط على الخادم، ويتضمن الخيارات الموصى بها: - **HttpOnly**: يمنع JavaScript من الوصول إلى ملف تعريف الارتباط من جانب العميل. - **Secure**: استخدم https لإرسال ملف تعريف الارتباط. -- **SameSite**: حدد ما إذا كان يمكن إرسال ملف تعريف الارتباط مع طلبات Cross-site. +- **SameSite**: حدد ما إذا كان يمكن إرسال ملف تعريف الارتباط مع طلبات cross-site. - **Max-Age أو Expires**: احذف ملف تعريف الارتباط بعد فترة معينة. - **Path**: حدد مسار URL لملف تعريف الارتباط. @@ -674,21 +674,21 @@ export async function createSession(userId) { } ``` -بالعودة إلى وظيفة الخادم (Server Action)، يمكنك استدعاء وظيفة `createSession()`، واستخدام واجهة برمجة التطبيقات [`redirect()`](/docs/app/guides/redirecting) لإعادة توجيه المستخدم إلى الصفحة المناسبة: +بالعودة إلى إجراء الخادم الخاص بك، يمكنك استدعاء الدالة `createSession()`، واستخدام واجهة برمجة التطبيقات [`redirect()`](/docs/app/guides/redirecting) لتوجيه المستخدم إلى الصفحة المناسبة: ```ts filename="app/actions/auth.ts" switcher import { createSession } from '@/app/lib/session' export async function signup(state: FormState, formData: FormData) { // الخطوات السابقة: - // 1. التحقق من صحة حقول النموذج + // 1. التحقق من حقول النموذج // 2. تحضير البيانات للإدراج في قاعدة البيانات // 3. إدراج المستخدم في قاعدة البيانات أو استدعاء واجهة برمجة التطبيقات لمكتبة المصادقة // الخطوات الحالية: // 4. إنشاء جلسة المستخدم await createSession(user.id) - // 5. إعادة توجيه المستخدم + // 5. توجيه المستخدم redirect('/profile') } ``` @@ -698,22 +698,22 @@ import { createSession } from '@/app/lib/session' export async function signup(state, formData) { // الخطوات السابقة: - // 1. التحقق من صحة حقول النموذج + // 1. التحقق من حقول النموذج // 2. تحضير البيانات للإدراج في قاعدة البيانات // 3. إدراج المستخدم في قاعدة البيانات أو استدعاء واجهة برمجة التطبيقات لمكتبة المصادقة // الخطوات الحالية: // 4. إنشاء جلسة المستخدم await createSession(user.id) - // 5. إعادة توجيه المستخدم + // 5. توجيه المستخدم redirect('/profile') } ``` -> **نصائح**: +> **نصائح:** > -> - **يجب تعيين ملفات تعريف الارتباط على الخادم** لمنع العبث بها من جانب العميل. -> - 🎥 شاهد: تعلم المزيد عن الجلسات بدون حالة والمصادقة مع Next.js → [YouTube (11 دقيقة)](https://www.youtube.com/watch?v=DJvM2lSPn6w). +> - **يجب تعيين ملفات تعريف الارتباط على الخادم** لمنع العبث من جانب العميل. +> - 🎥 شاهد: تعرف على المزيد حول الجلسات بدون حالة والمصادقة مع Next.js → [YouTube (11 دقيقة)](https://www.youtube.com/watch?v=DJvM2lSPn6w). #### تحديث (أو تجديد) الجلسات @@ -871,9 +871,9 @@ export default function handler(req, res) { لإنشاء وإدارة جلسات قاعدة البيانات، ستحتاج إلى اتباع هذه الخطوات: -1. إنشاء جدول في قاعدة البيانات لتخزين الجلسة والبيانات (أو التحقق مما إذا كانت مكتبة المصادقة الخاصة بك تتعامل مع هذا). +1. إنشاء جدول في قاعدة البيانات لتخزين بيانات الجلسة (أو التحقق مما إذا كانت مكتبة المصادقة الخاصة بك تتعامل مع هذا). 2. تنفيذ وظائف لإدراج وتحديث وحذف الجلسات -3. تشفير معرف الجلسة قبل تخزينه في متصفح المستخدم، والتأكد من تزامن قاعدة البيانات وملف تعريف الارتباط (هذا اختياري، ولكنه موصى به للتحقق المتفائل في [الوسيطة](#optimistic-checks-with-middleware-optional)). +3. تشفير معرّف الجلسة قبل تخزينه في متصفح المستخدم، والتأكد من تزامن قاعدة البيانات وملف تعريف الارتباط (هذا اختياري، ولكنه موصى به للتحقق المتفائل من المصادقة في [الوسيط](#optimistic-checks-with-middleware-optional)). @@ -894,12 +894,12 @@ export async function createSession(id: number) { userId: id, expiresAt, }) - // إرجاع معرف الجلسة + // إرجاع معرّف الجلسة .returning({ id: sessions.id }) const sessionId = data[0].id - // 2. تشفير معرف الجلسة + // 2. تشفير معرّف الجلسة const session = await encrypt({ sessionId, expiresAt }) // 3. تخزين الجلسة في ملفات تعريف الارتباط للتحقق المتفائل من المصادقة @@ -929,12 +929,12 @@ export async function createSession(id) { userId: id, expiresAt, }) - // إرجاع معرف الجلسة + // إرجاع معرّف الجلسة .returning({ id: sessions.id }) const sessionId = data[0].id - // 2. تشفير معرف الجلسة + // 2. تشفير معرّف الجلسة const session = await encrypt({ sessionId, expiresAt }) // 3. تخزين الجلسة في ملفات تعريف الارتباط للتحقق المتفائل من المصادقة @@ -951,7 +951,7 @@ export async function createSession(id) { > **نصائح**: > -> - للوصول الأسرع، يمكنك النظر في إضافة تخزين مؤقت على الخادم لمدة حياة الجلسة. يمكنك أيضًا الاحتفاظ ببيانات الجلسة في قاعدة البيانات الأساسية الخاصة بك، وجمع طلبات البيانات لتقليل عدد الاستعلامات. +> - للوصول الأسرع، يمكنك التفكير في إضافة تخزين مؤقت على الخادم لمدة الجلسة. يمكنك أيضًا الاحتفاظ ببيانات الجلسة في قاعدة البيانات الرئيسية، وجمع طلبات البيانات لتقليل عدد الاستعلامات. > - يمكنك اختيار استخدام جلسات قاعدة البيانات لحالات استخدام أكثر تقدمًا، مثل تتبع آخر مرة قام فيها المستخدم بتسجيل الدخول، أو عدد الأجهزة النشطة، أو منح المستخدمين القدرة على تسجيل الخروج من جميع الأجهزة. بعد تنفيذ إدارة الجلسات، ستحتاج إلى إضافة منطق التفويض للتحكم فيما يمكن للمستخدمين الوصول إليه والقيام به داخل تطبيقك. تابع إلى قسم [التفويض](#authorization) لمعرفة المزيد. @@ -1014,23 +1014,23 @@ export default async function handler(req, res) { هناك نوعان رئيسيان من عمليات التحقق من التفويض: -1. **المتفائل**: يتحقق مما إذا كان المستخدم مخولًا للوصول إلى مسار أو تنفيذ إجراء باستخدام بيانات الجلسة المخزنة في ملف تعريف الارتباط. هذه الفحوصات مفيدة للعمليات السريعة، مثل إظهار/إخفاء عناصر واجهة المستخدم أو إعادة توجيه المستخدمين بناءً على الأذونات أو الأدوار. -2. **الآمن**: يتحقق مما إذا كان المستخدم مخولًا للوصول إلى مسار أو تنفيذ إجراء باستخدام بيانات الجلسة المخزنة في قاعدة البيانات. هذه الفحوصات أكثر أمانًا وتستخدم للعمليات التي تتطلب الوصول إلى بيانات حساسة أو إجراءات. +1. **المتفائل**: يتحقق مما إذا كان المستخدم مخولاً للوصول إلى مسار أو تنفيذ إجراء باستخدام بيانات الجلسة المخزنة في ملف تعريف الارتباط. هذه الفحوصات مفيدة للعمليات السريعة، مثل إظهار/إخفاء عناصر واجهة المستخدم أو إعادة توجيه المستخدمين بناءً على الأذونات أو الأدوار. +2. **الآمن**: يتحقق مما إذا كان المستخدم مخولاً للوصول إلى مسار أو تنفيذ إجراء باستخدام بيانات الجلسة المخزنة في قاعدة البيانات. هذه الفحوصات أكثر أمانًا وتستخدم للعمليات التي تتطلب الوصول إلى بيانات حساسة أو إجراءات. -لكلا الحالتين، نوصي بـ: +لكلا الحالتين، نوصي بما يلي: -- إنشاء [طبقة وصول البيانات](#creating-a-data-access-layer-dal) لمركزية منطق التفويض الخاص بك +- إنشاء [طبقة وصول البيانات](#creating-a-data-access-layer-dal) لمركزية منطق التفويض - استخدام [كائنات نقل البيانات (DTO)](#using-data-transfer-objects-dto) لإرجاع البيانات الضرورية فقط -- استخدام [الوسيطة](#optimistic-checks-with-middleware-optional) اختياريًا لإجراء فحوصات متفائلة. +- استخدام [الوسيط](#optimistic-checks-with-middleware-optional) اختياريًا لإجراء فحوصات متفائلة. -### فحوصات متفائلة مع الوسيطة (اختياري) +### فحوصات متفائلة باستخدام الوسيط (اختياري) -هناك بعض الحالات التي قد ترغب فيها في استخدام [الوسيطة](/docs/app/building-your-application/routing/middleware) وإعادة توجيه المستخدمين بناءً على الأذونات: +هناك بعض الحالات التي قد ترغب في استخدام [الوسيط](/docs/app/building-your-application/routing/middleware) وإعادة توجيه المستخدمين بناءً على الأذونات: -- لإجراء فحوصات متفائلة. نظرًا لأن الوسيطة تعمل في كل مسار، فهي طريقة جيدة لمركزية منطق إعادة التوجيه وتصفية مسبقة للمستخدمين غير المصرح لهم. +- لإجراء فحوصات متفائلة. نظرًا لأن الوسيط يعمل على كل مسار، فهو طريقة جيدة لمركزية منطق إعادة التوجيه وتصفية المستخدمين غير المصرح لهم مسبقًا. - لحماية المسارات الثابتة التي تشارك البيانات بين المستخدمين (مثل المحتوى خلف جدار الدفع). -ومع ذلك، نظرًا لأن الوسيطة تعمل في كل مسار، بما في ذلك المسارات [المحملة مسبقًا](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching)، من المهم قراءة الجلسة فقط من ملف تعريف الارتباط (فحوصات متفائلة)، وتجنب فحوصات قاعدة البيانات لمنع مشكلات الأداء. +ومع ذلك، نظرًا لأن الوسيط يعمل على كل مسار، بما في ذلك المسارات [المحملة مسبقًا](/docs/app/getting-started/linking-and-navigating#prefetching)، فمن المهم قراءة الجلسة فقط من ملف تعريف الارتباط (فحوصات متفائلة)، وتجنب فحوصات قاعدة البيانات لمنع مشكلات الأداء. على سبيل المثال: @@ -1070,7 +1070,7 @@ export default async function middleware(req: NextRequest) { return NextResponse.next() } -// المسارات التي لا يجب أن تعمل عليها الوسيطة +// المسارات التي لا يجب أن يعمل عليها الوسيط export const config = { matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'], } @@ -1112,19 +1112,19 @@ export default async function middleware(req) { return NextResponse.next() } -// المسارات التي لا يجب أن تعمل عليها الوسيطة +// المسارات التي لا يجب أن يعمل عليها الوسيط export const config = { matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'], } ``` -بينما يمكن أن تكون الوسيطة مفيدة للفحوصات الأولية، لا يجب أن تكون خط دفاعك الوحيد في حماية بياناتك. يجب إجراء معظم فحوصات الأمان بالقرب من مصدر البيانات قدر الإمكان، راجع [طبقة وصول البيانات](#creating-a-data-access-layer-dal) لمزيد من المعلومات. +بينما يمكن أن يكون الوسيط مفيدًا للفحوصات الأولية، لا يجب أن يكون خط دفاعك الوحيد في حماية بياناتك. يجب إجراء غالبية فحوصات الأمان بالقرب من مصدر البيانات قدر الإمكان، راجع [طبقة وصول البيانات](#creating-a-data-access-layer-dal) لمزيد من المعلومات. > **نصائح**: > -> - في الوسيطة، يمكنك أيضًا قراءة ملفات تعريف الارتباط باستخدام `req.cookies.get('session').value`. -> - تستخدم الوسيطة [وقت تشغيل الحافة (Edge Runtime)](/docs/app/api-reference/edge)، تحقق مما إذا كانت مكتبة المصادقة الخاصة بك ومكتبة إدارة الجلسات متوافقة. -> - يمكنك استخدام خاصية `matcher` في الوسيطة لتحديد المسارات التي يجب أن تعمل عليها الوسيطة. ومع ذلك، للمصادقة، يوصى بأن تعمل الوسيطة على جميع المسارات. +> - في الوسيط، يمكنك أيضًا قراءة ملفات تعريف الارتباط باستخدام `req.cookies.get('session').value`. +> - يستخدم الوسيط [وقت تشغيل الحافة](/docs/app/api-reference/edge)، تحقق مما إذا كانت مكتبة المصادقة ومكتبة إدارة الجلسات متوافقة. +> - يمكنك استخدام خاصية `matcher` في الوسيط لتحديد المسارات التي يجب أن يعمل عليها الوسيط. ومع ذلك، للمصادقة، يوصى بأن يعمل الوسيط على جميع المسارات. @@ -1132,9 +1132,9 @@ export const config = { نوصي بإنشاء DAL لمركزية طلبات البيانات ومنطق التفويض. -يجب أن تتضمن DAL دالة تتحقق من جلسة المستخدم أثناء تفاعله مع تطبيقك. على الأقل، يجب أن تتحقق الدالة مما إذا كانت الجلسة صالحة، ثم تقوم بإعادة التوجيه أو إرجاع معلومات المستخدم اللازمة لإجراء المزيد من الطلبات. +يجب أن تتضمن DAL دالة تتحقق من جلسة المستخدم أثناء تفاعله مع تطبيقك. على الأقل، يجب أن تتحقق الدالة مما إذا كانت الجلسة صالحة، ثم تقوم بإعادة التوجيه أو إرجاع معلومات المستخدم اللازمة لإجراء طلبات إضافية. -على سبيل المثال، قم بإنشاء ملف منفصل لـ DAL يتضمن دالة `verifySession()`. ثم استخدم واجهة برمجة التطبيقات [cache](https://react.dev/reference/react/cache) الخاصة بـ React لحفظ القيمة المرجعة للدالة أثناء تمرير عرض React: +على سبيل المثال، قم بإنشاء ملف منفصل لـ DAL يتضمن دالة `verifySession()`. ثم استخدم واجهة برمجة التطبيقات [cache](https://react.dev/reference/react/cache) من React لحفظ قيمة الإرجاع للدالة أثناء تمرير عرض React: ```tsx filename="app/lib/dal.ts" switcher import 'server-only' @@ -1172,7 +1172,7 @@ export const verifySession = cache(async () => { }) ``` -يمكنك بعد ذلك استدعاء دالة `verifySession()` في طلبات البيانات، إجراءات الخادم، ومعالجات المسار: +يمكنك بعد ذلك استدعاء دالة `verifySession()` في طلبات البيانات، وإجراءات الخادم، ومعالجات المسار: ```tsx filename="app/lib/dal.ts" switcher export const getUser = cache(async () => { @@ -1228,15 +1228,15 @@ export const getUser = cache(async () => { > **نصيحة**: > -> - يمكن استخدام DAL لحماية البيانات التي يتم جلبها في وقت الطلب. ومع ذلك، بالنسبة للمسارات الثابتة التي تشارك البيانات بين المستخدمين، سيتم جلب البيانات في وقت البناء وليس في وقت الطلب. استخدم [الوسيطة](#optimistic-checks-with-middleware-optional) لحماية المسارات الثابتة. -> - بالنسبة للفحوصات الآمنة، يمكنك التحقق مما إذا كانت الجلسة صالحة عن طريق مقارنة معرف الجلسة مع قاعدة البيانات الخاصة بك. استخدم دالة [cache](https://react.dev/reference/react/cache) الخاصة بـ React لتجنب طلبات مكررة غير ضرورية إلى قاعدة البيانات أثناء تمرير العرض. +> - يمكن استخدام DAL لحماية البيانات التي يتم جلبها في وقت الطلب. ومع ذلك، بالنسبة للمسارات الثابتة التي تشارك البيانات بين المستخدمين، سيتم جلب البيانات في وقت البناء وليس في وقت الطلب. استخدم [الوسيط](#optimistic-checks-with-middleware-optional) لحماية المسارات الثابتة. +> - للفحوصات الآمنة، يمكنك التحقق مما إذا كانت الجلسة صالحة عن طريق مقارنة معرّف الجلسة مع قاعدة البيانات الخاصة بك. استخدم دالة [cache](https://react.dev/reference/react/cache) من React لتجنب الطلبات المكررة غير الضرورية إلى قاعدة البيانات أثناء تمرير العرض. > - قد ترغب في توحيد طلبات البيانات ذات الصلة في فئة JavaScript تقوم بتشغيل `verifySession()` قبل أي طرق. ### استخدام كائنات نقل البيانات (DTO) -عند استرجاع البيانات، يُنصح بإرجاع البيانات الضرورية فقط التي سيتم استخدامها في تطبيقك، وليس الكائنات الكاملة. على سبيل المثال، إذا كنت تقوم بجلب بيانات المستخدم، فقد ترجع فقط معرف المستخدم واسمه، بدلاً من كائن المستخدم الكامل الذي قد يحتوي على كلمات المرور وأرقام الهواتف، إلخ. +عند استرجاع البيانات، يُنصح بإرجاع البيانات الضرورية فقط التي سيتم استخدامها في تطبيقك، وليس الكائنات الكاملة. على سبيل المثال، إذا كنت تسترجع بيانات المستخدم، فقد ترجع فقط معرف المستخدم واسمه، بدلاً من كائن المستخدم الكامل الذي قد يحتوي على كلمات المرور وأرقام الهواتف، إلخ. -ومع ذلك، إذا لم يكن لديك تحكم في بنية البيانات المرتجعة، أو كنت تعمل ضمن فريق حيث تريد تجنب تمرير كائنات كاملة إلى العميل، يمكنك استخدام استراتيجيات مثل تحديد الحقول الآمنة للعرض على العميل. +ومع ذلك، إذا لم يكن لديك تحكم في بنية البيانات المُرجعة، أو كنت تعمل ضمن فريق حيث تريد تجنب تمرير كائنات كاملة إلى العميل، يمكنك استخدام استراتيجيات مثل تحديد الحقول الآمنة للعرض على العميل. ```tsx filename="app/lib/dto.ts" switcher import 'server-only' @@ -1300,11 +1300,11 @@ export async function getProfileDTO(slug) { } ``` -من خلال تركيز طلبات البيانات ومنطق التفويض في طبقة الوصول إلى البيانات (DAL) واستخدام كائنات نقل البيانات (DTOs)، يمكنك ضمان أن جميع طلبات البيانات آمنة ومتسقة، مما يسهل الصيانة والمراجعة والتصحيح مع توسع تطبيقك. +من خلال تركيز طلبات البيانات ومنطق التفويض في طبقة الوصول إلى البيانات (DAL) واستخدام كائنات نقل البيانات (DTOs)، يمكنك ضمان أن جميع طلبات البيانات آمنة ومتسقة، مما يسهل الصيانة والتدقيق والتصحيح مع توسع تطبيقك. > **معلومة مفيدة**: > -> - هناك عدة طرق مختلفة لتحديد كائن نقل البيانات (DTO)، بدءًا من استخدام `toJSON()`، إلى دوال فردية كما في المثال أعلاه، أو فئات جافاسكربت. نظرًا لأن هذه أنماط جافاسكربت وليست ميزة في React أو Next.js، نوصي بإجراء بعض البحث للعثور على النمط الأنسب لتطبيقك. +> - هناك عدة طرق مختلفة لتحديد كائن نقل البيانات (DTO)، بدءًا من استخدام `toJSON()`، إلى دوال فردية مثل المثال أعلاه، أو فئات جافاسكريبت. نظرًا لأن هذه أنماط جافاسكريبت وليست ميزة في React أو Next.js، ننصح بإجراء بعض البحث للعثور على النمط الأنسب لتطبيقك. > - تعلم المزيد عن أفضل ممارسات الأمان في [مقال الأمان في Next.js](/blog/security-nextjs-server-components-actions). ### مكونات الخادم (Server Components) @@ -1316,7 +1316,7 @@ import { verifySession } from '@/app/lib/dal' export default function Dashboard() { const session = await verifySession() - const userRole = session?.user?.role // بافتراض أن 'role' جزء من كائن الجلسة + const userRole = session?.user?.role // Assuming 'role' is part of the session object if (userRole === 'admin') { return @@ -1333,7 +1333,7 @@ import { verifySession } from '@/app/lib/dal' export default function Dashboard() { const session = await verifySession() - const userRole = session.role // بافتراض أن 'role' جزء من كائن الجلسة + const userRole = session.role // Assuming 'role' is part of the session object if (userRole === 'admin') { return @@ -1345,15 +1345,15 @@ export default function Dashboard() { } ``` -في المثال، نستخدم الدالة `verifySession()` من طبقة الوصول إلى البيانات (DAL) للتحقق من أدوار 'admin' و'user' والأدوار غير المصرح بها. يضمن هذا النمط أن كل مستخدم يتفاعل فقط مع المكونات المناسبة لدوره. +في المثال، نستخدم الدالة `verifySession()` من طبقة الوصول إلى البيانات (DAL) للتحقق من أدوار 'admin' و'user' والأدوار غير المصرح بها. يضمن هذا النمط تفاعل كل مستخدم فقط مع المكونات المناسبة لدوره. ### التخطيطات وفحوصات التفويض -بسبب [التصيير الجزئي (Partial Rendering)](/docs/app/building-your-application/routing/linking-and-navigating#4-partial-rendering)، كن حذرًا عند إجراء الفحوصات في [التخطيطات (Layouts)](/docs/app/api-reference/file-conventions/layout) لأنها لا تعيد التصيير عند التنقل، مما يعني أن جلسة المستخدم لن يتم التحقق منها في كل تغيير للمسار. +بسبب [التصيير الجزئي (Partial Rendering)](/docs/app/getting-started/linking-and-navigating#client-side-transitions)، كن حذرًا عند إجراء الفحوصات في [التخطيطات (Layouts)](/docs/app/api-reference/file-conventions/layout) لأنها لا تُعيد التصيير أثناء التنقل، مما يعني أن جلسة المستخدم لن يتم التحقق منها في كل تغيير للمسار. بدلاً من ذلك، يجب إجراء الفحوصات بالقرب من مصدر البيانات أو المكون الذي سيتم عرضه بشكل مشروط. -على سبيل المثال، ضع في الاعتبار تخطيطًا مشتركًا يجلب بيانات المستخدم ويعرض صورة المستخدم في شريط التنقل. بدلاً من إجراء فحص التفويض في التخطيط، يجب جلب بيانات المستخدم (`getUser()`) في التخطيط وإجراء فحص التفويض في طبقة الوصول إلى البيانات (DAL). +على سبيل المثال، ضع في الاعتبار تخطيطًا مشتركًا يسترجع بيانات المستخدم ويعرض صورة المستخدم في شريط التنقل. بدلاً من إجراء فحص التفويض في التخطيط، يجب استرجاع بيانات المستخدم (`getUser()`) في التخطيط وإجراء فحص التفويض في طبقة الوصول إلى البيانات (DAL). هذا يضمن أنه في أي مكان يتم فيه استدعاء `getUser()` داخل تطبيقك، يتم إجراء فحص التفويض، ويمنع المطورين من نسيان التحقق من أن المستخدم مصرح له بالوصول إلى البيانات. @@ -1386,7 +1386,7 @@ export const getUser = cache(async () => { const session = await verifySession() if (!session) return null - // الحصول على معرف المستخدم من الجلسة وجلب البيانات + // Get user ID from session and fetch data }) ``` @@ -1395,17 +1395,17 @@ export const getUser = cache(async () => { const session = await verifySession() if (!session) return null - // الحصول على معرف المستخدم من الجلسة وجلب البيانات + // Get user ID from session and fetch data }) ``` > **معلومة مفيدة:** > -> - نمط شائع في التطبيقات ذات الصفحة الواحدة (SPAs) هو `return null` في تخطيط أو مكون رئيسي إذا لم يكن المستخدم مصرحًا له. هذا النمط **غير موصى به** لأن تطبيقات Next.js لديها نقاط دخول متعددة، مما لن يمنع أجزاء المسار المتداخل وإجراءات الخادم من الوصول. +> - النمط الشائع في التطبيقات ذات الصفحة الواحدة (SPAs) هو إرجاع `null` في تخطيط أو مكون رئيسي إذا لم يكن المستخدم مصرحًا له. **لا يُنصح بهذا النمط** لأن تطبيقات Next.js لديها نقاط دخول متعددة، مما لن يمنع أجزاء المسار المتداخلة وإجراءات الخادم (Server Actions) من الوصول. ### إجراءات الخادم (Server Actions) -تعامل مع [إجراءات الخادم](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) بنفس اعتبارات الأمان مثل نقاط نهاية API الموجهة للجمهور، وتحقق مما إذا كان المستخدم مسموحًا له بإجراء التغيير. +عامل [إجراءات الخادم](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) بنفس اعتبارات الأمان مثل نقاط نهاية واجهة برمجة التطبيقات (API) الموجهة للجمهور، وتحقق مما إذا كان المستخدم مسموحًا له بتنفيذ التغيير. في المثال أدناه، نتحقق من دور المستخدم قبل السماح بتنفيذ الإجراء: @@ -1417,12 +1417,12 @@ export async function serverAction(formData: FormData) { const session = await verifySession() const userRole = session?.user?.role - // الإرجاع مبكرًا إذا لم يكن المستخدم مصرحًا له بتنفيذ الإجراء + // Return early if user is not authorized to perform the action if (userRole !== 'admin') { return null } - // المتابعة بالإجراء للمستخدمين المصرح لهم + // Proceed with the action for authorized users } ``` @@ -1434,18 +1434,18 @@ export async function serverAction() { const session = await verifySession() const userRole = session.user.role - // الإرجاع مبكرًا إذا لم يكن المستخدم مصرحًا له بتنفيذ الإجراء + // Return early if user is not authorized to perform the action if (userRole !== 'admin') { return null } - // المتابعة بالإجراء للمستخدمين المصرح لهم + // Proceed with the action for authorized users } ``` ### معالجات المسار (Route Handlers) -تعامل مع [معالجات المسار](/docs/app/building-your-application/routing/route-handlers) بنفس اعتبارات الأمان مثل نقاط نهاية API الموجهة للجمهور، وتحقق مما إذا كان المستخدم مسموحًا له بالوصول إلى معالج المسار. +عامل [معالجات المسار](/docs/app/building-your-application/routing/route-handlers) بنفس اعتبارات الأمان مثل نقاط نهاية واجهة برمجة التطبيقات (API) الموجهة للجمهور، وتحقق مما إذا كان المستخدم مسموحًا له بالوصول إلى معالج المسار. على سبيل المثال: @@ -1453,22 +1453,22 @@ export async function serverAction() { import { verifySession } from '@/app/lib/dal' export async function GET() { - // التحقق من هوية المستخدم ودوره + // User authentication and role verification const session = await verifySession() - // التحقق مما إذا كان المستخدم مصادقًا عليه + // Check if the user is authenticated if (!session) { - // المستخدم غير مصادق عليه + // User is not authenticated return new Response(null, { status: 401 }) } - // التحقق مما إذا كان للمستخدم دور 'admin' + // Check if the user has the 'admin' role if (session.user.role !== 'admin') { - // المستخدم مصادق عليه ولكن ليس لديه الصلاحيات المناسبة + // User is authenticated but does not have the right permissions return new Response(null, { status: 403 }) } - // المتابعة للمستخدمين المصرح لهم + // Continue for authorized users } ``` @@ -1476,22 +1476,22 @@ export async function GET() { import { verifySession } from '@/app/lib/dal' export async function GET() { - // التحقق من هوية المستخدم ودوره + // User authentication and role verification const session = await verifySession() - // التحقق مما إذا كان المستخدم مصادقًا عليه + // Check if the user is authenticated if (!session) { - // المستخدم غير مصادق عليه + // User is not authenticated return new Response(null, { status: 401 }) } - // التحقق مما إذا كان للمستخدم دور 'admin' + // Check if the user has the 'admin' role if (session.user.role !== 'admin') { - // المستخدم مصادق عليه ولكن ليس لديه الصلاحيات المناسبة + // User is authenticated but does not have the right permissions return new Response(null, { status: 403 }) } - // المتابعة للمستخدمين المصرح لهم + // Continue for authorized users } ``` @@ -1499,7 +1499,7 @@ export async function GET() { ## موفرو السياق (Context Providers) -استخدام موفري السياق للتفويض يعمل بسبب [التشابك (interleaving)](/docs/app/getting-started/server-and-client-components#examples#interleaving-server-and-client-components). ومع ذلك، `context` في React غير مدعوم في مكونات الخادم، مما يجعلها قابلة للتطبيق فقط على مكونات العميل. +استخدام موفري السياق للتفويض يعمل بسبب [التداخل (interleaving)](/docs/app/getting-started/server-and-client-components#examples#interleaving-server-and-client-components). ومع ذلك، فإن `context` في React غير مدعوم في مكونات الخادم، مما يجعلها قابلة للتطبيق فقط على مكونات العميل. هذا يعمل، ولكن أي مكونات خادم فرعية سيتم تصييرها على الخادم أولاً، ولن يكون لديها وصول إلى بيانات الجلسة من موفر السياق: @@ -1555,11 +1555,11 @@ export default function Profile() { ### إنشاء طبقة الوصول إلى البيانات (DAL) -#### حماية مسارات API +#### حماية مسارات واجهة برمجة التطبيقات (API Routes) -مسارات API في Next.js ضرورية للتعامل مع منطق الخادم وإدارة البيانات. من الضروري تأمين هذه المسارات لضمان أن المستخدمين المصرح لهم فقط يمكنهم الوصول إلى وظائف معينة. يتضمن هذا عادةً التحقق من حالة مصادقة المستخدم وصلاحياته القائمة على الأدوار. +مسارات واجهة برمجة التطبيقات في Next.js ضرورية للتعامل مع منطق الخادم وإدارة البيانات. من الضروري تأمين هذه المسارات لضمان أن المستخدمين المصرح لهم فقط يمكنهم الوصول إلى وظائف محددة. يتضمن هذا عادةً التحقق من حالة مصادقة المستخدم وأذوناته القائمة على الأدوار. -إليك مثالاً لتأمين مسار API: +إليك مثالًا لتأمين مسار واجهة برمجة التطبيقات: ```ts filename="pages/api/route.ts" switcher import { NextApiRequest, NextApiResponse } from 'next' @@ -1570,7 +1570,7 @@ export default async function handler( ) { const session = await getSession(req) - // التحقق مما إذا كان المستخدم مصادقًا عليه + // Check if the user is authenticated if (!session) { res.status(401).json({ error: 'User is not authenticated', @@ -1578,7 +1578,7 @@ export default async function handler( return } - // التحقق مما إذا كان للمستخدم دور 'admin' + // Check if the user has the 'admin' role if (session.user.role !== 'admin') { res.status(401).json({ error: 'Unauthorized access: User does not have admin privileges.', @@ -1586,8 +1586,8 @@ export default async function handler( return } - // المتابعة مع المسار للمستخدمين المصرح لهم - // ... تنفيذ مسار API + // Proceed with the route for authorized users + // ... implementation of the API Route } ``` @@ -1595,7 +1595,7 @@ export default async function handler( export default async function handler(req, res) { const session = await getSession(req) - // التحقق مما إذا كان المستخدم مصادقًا عليه + // Check if the user is authenticated if (!session) { res.status(401).json({ error: 'User is not authenticated', @@ -1603,7 +1603,7 @@ export default async function handler(req, res) { return } - // التحقق مما إذا كان للمستخدم دور 'admin' + // Check if the user has the 'admin' role if (session.user.role !== 'admin') { res.status(401).json({ error: 'Unauthorized access: User does not have admin privileges.', @@ -1611,18 +1611,18 @@ export default async function handler(req, res) { return } - // المتابعة مع المسار للمستخدمين المصرح لهم - // ... تنفيذ مسار API + // Proceed with the route for authorized users + // ... implementation of the API Route } ``` -يوضح هذا المثال مسار API بفحص أمان من مستويين للمصادقة والتفويض. أولاً يتحقق من وجود جلسة نشطة، ثم يتحقق مما إذا كان المستخدم المسجل دخوله هو 'admin'. يضمن هذا النهج وصولاً آمناً، محدودًا بالمستخدمين المصادق عليهم والمصرح لهم، مع الحفاظ على أمان قوي لمعالجة الطلبات. +يوضح هذا المثال مسار واجهة برمجة التطبيقات بفحص أمان من مستويين للمصادقة والتفويض. أولاً يتحقق من وجود جلسة نشطة، ثم يتحقق مما إذا كان المستخدم المسجل دخوله هو 'admin'. يضمن هذا النهج وصولاً آمنًا، مقصورًا على المستخدمين المصادق عليهم والمصرح لهم، مع الحفاظ على أمان قوي لمعالجة الطلبات. -## الموارد +## موارد -الآن بعد أن تعلمت عن المصادقة في Next.js، إليك مكتبات وموارد متوافقة مع Next.js لمساعدتك في تنفيذ مصادقة آمنة وإدارة الجلسات: +الآن بعد أن تعلمت عن المصادقة في Next.js، إليك مكتبات وموارد متوافقة مع Next.js لمساعدتك في تنفيذ المصادقة الآمنة وإدارة الجلسات: ### مكتبات المصادقة @@ -1650,4 +1650,4 @@ export default async function handler(req, res) { - [كيف تفكر في الأمان في Next.js](/blog/security-nextjs-server-components-actions) - [فهم هجمات XSS](https://vercel.com/guides/understanding-xss-attacks) - [فهم هجمات CSRF](https://vercel.com/guides/understanding-csrf-attacks) -- [The Copenhagen Book](https://thecopenhagenbook.com/) +- [كتاب كوبنهاجن](https://thecopenhagenbook.com/) diff --git a/apps/docs/content/ar/docs/01-app/02-guides/lazy-loading.mdx b/apps/docs/content/ar/docs/01-app/02-guides/lazy-loading.mdx index 4932e21b..144b2bb4 100644 --- a/apps/docs/content/ar/docs/01-app/02-guides/lazy-loading.mdx +++ b/apps/docs/content/ar/docs/01-app/02-guides/lazy-loading.mdx @@ -1,32 +1,32 @@ --- -source-updated-at: 2025-05-16T04:52:11.000Z -translation-updated-at: 2025-06-02T20:00:37.366Z -title: كيفية التحميل المتأخر للمكونات والمكتبات على جانب العميل +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:11:28.550Z +title: كيفية التحميل المتأخر للمكونات (Client Components) والمكتبات nav_title: التحميل المتأخر -description: قم بتأجيل تحميل المكتبات المستوردة ومكونات React لتحسين أداء تحميل تطبيقك. +description: قم بتحميل المكتبات المستوردة ومكونات React بشكل متأخر لتحسين أداء تحميل التطبيق. --- -{/* يتم مشاركة محتوى هذه الوثيقة بين موجه التطبيق وموجه الصفحات. يمكنك استخدام مكون `محتوى` لإضافة محتوى خاص بموجه الصفحات. أي محتوى مشترك يجب ألا يكون مغلفًا في مكون. */} +{/* المحتوى مشترك بين موجه التطبيق (app) وموجه الصفحات (pages). يمكن استخدام مكون `المحتوى` لإضافة محتوى خاص بموجه الصفحات. أي محتوى مشترك يجب ألا يكون مغلفًا بمكون. */} يساعد [التحميل المتأخر](https://developer.mozilla.org/docs/Web/Performance/Lazy_loading) في Next.js على تحسين أداء التحميل الأولي للتطبيق عن طريق تقليل كمية JavaScript المطلوبة لعرض مسار. -يسمح لك بتأجيل تحميل **مكونات العميل** والمكتبات المستوردة، وتضمينها فقط في حزمة العميل عند الحاجة إليها. على سبيل المثال، قد ترغب في تأجيل تحميل نافذة مشروطة حتى ينقر المستخدم لفتحها. +يسمح لك بتأجيل تحميل **المكونات من جانب العميل (Client Components)** والمكتبات المستوردة، وتضمينها فقط في حزمة العميل عند الحاجة إليها. على سبيل المثال، قد ترغب في تأجيل تحميل نافذة منبثقة حتى ينقر المستخدم لفتحها. -هناك طريقتان يمكنك من خلالهما تنفيذ التحميل المتأخر في Next.js: +هناك طريقتان لتنفيذ التحميل المتأخر في Next.js: 1. استخدام [الاستيراد الديناميكي](#nextdynamic) مع `next/dynamic` 2. استخدام [`React.lazy()`](https://react.dev/reference/react/lazy) مع [Suspense](https://react.dev/reference/react/Suspense) -بشكل افتراضي، يتم [تقسيم الكود](https://developer.mozilla.org/docs/Glossary/Code_splitting) تلقائيًا لمكونات الخادم، ويمكنك استخدام [البث](/docs/app/building-your-application/routing/loading-ui-and-streaming) لإرسال أجزاء واجهة المستخدم تدريجيًا من الخادم إلى العميل. ينطبق التحميل المتأخر على مكونات العميل. +بشكل افتراضي، يتم [تقسيم الكود](https://developer.mozilla.org/docs/Glossary/Code_splitting) تلقائيًا للمكونات من جانب الخادم (Server Components)، ويمكنك استخدام [البث التدريجي](/docs/app/api-reference/file-conventions/loading) لإرسال أجزاء واجهة المستخدم تدريجيًا من الخادم إلى العميل. ينطبق التحميل المتأخر على المكونات من جانب العميل (Client Components). ## `next/dynamic` -`next/dynamic` هو مزيج من [`React.lazy()`](https://react.dev/reference/react/lazy) و [Suspense](https://react.dev/reference/react/Suspense). يعمل بنفس الطريقة في كل من دليل `app` و `pages` للسماح بالهجرة التدريجية. +`next/dynamic` هو مزيج من [`React.lazy()`](https://react.dev/reference/react/lazy) و [Suspense](https://react.dev/reference/react/Suspense). يعمل بنفس الطريقة في دليل `app` و `pages` للسماح بالهجرة التدريجية. ## أمثلة -### استيراد مكونات العميل +### استيراد مكونات العميل (Client Components) ```jsx filename="app/page.js" 'use client' @@ -58,24 +58,24 @@ export default function ClientComponentExample() { } ``` -> **ملاحظة:** عندما يقوم مكون الخادم باستيراد مكون عميل ديناميكيًا، فإن [تقسيم الكود](https://developer.mozilla.org/docs/Glossary/Code_splitting) التلقائي غير مدعوم حاليًا. +> **ملاحظة:** عندما يقوم مكون الخادم (Server Component) باستيراد مكون عميل (Client Component) بشكل ديناميكي، فإن تقسيم الكود التلقائي غير مدعوم حاليًا. ### تخطي SSR -عند استخدام `React.lazy()` و Suspense، سيتم [التصيير المسبق](https://github.com/reactwg/server-components/discussions/4) (SSR) لمكونات العميل بشكل افتراضي. +عند استخدام `React.lazy()` و Suspense، سيتم [التقديم المسبق](https://github.com/reactwg/server-components/discussions/4) (SSR) لمكونات العميل افتراضيًا. -> **ملاحظة:** خيار `ssr: false` سيعمل فقط مع مكونات العميل، قم بنقله إلى مكونات العميل لضمان عمل تقسيم الكود بشكل صحيح. +> **ملاحظة:** خيار `ssr: false` يعمل فقط مع مكونات العميل، قم بنقله إلى مكونات العميل لضمان عمل تقسيم الكود بشكل صحيح. -إذا كنت ترغب في تعطيل التصيير المسبق لمكون عميل، يمكنك استخدام خيار `ssr` بقيمة `false`: +إذا كنت تريد تعطيل التقديم المسبق لمكون عميل، يمكنك استخدام خيار `ssr` بقيمة `false`: ```jsx const ComponentC = dynamic(() => import('../components/C'), { ssr: false }) ``` -### استيراد مكونات الخادم +### استيراد مكونات الخادم (Server Components) -إذا قمت باستيراد مكون خادم ديناميكيًا، فسيتم تأجيل تحميل مكونات العميل التابعة فقط - وليس مكون الخادم نفسه. -سيساعد أيضًا في تحميل مسبق للأصول الثابتة مثل CSS عند استخدامها في مكونات الخادم. +إذا قمت باستيراد مكون خادم (Server Component) بشكل ديناميكي، فسيتم تأجيل تحميل مكونات العميل التابعة فقط - وليس مكون الخادم نفسه. +كما سيساعد في تحميل الأصول الثابتة مسبقًا مثل CSS عند استخدامه في مكونات الخادم. ```jsx filename="app/page.js" import dynamic from 'next/dynamic' @@ -92,7 +92,7 @@ export default function ServerComponentExample() { } ``` -> **ملاحظة:** خيار `ssr: false` غير مدعوم في مكونات الخادم. سترى خطأ إذا حاولت استخدامه في مكونات الخادم. +> **ملاحظة:** خيار `ssr: false` غير مدعوم في مكونات الخادم. سيظهر خطأ إذا حاولت استخدامه في مكونات الخادم. > `ssr: false` غير مسموح به مع `next/dynamic` في مكونات الخادم. يرجى نقله إلى مكون عميل. ### تحميل المكتبات الخارجية @@ -153,9 +153,9 @@ export default function Page() { } ``` -### استيراد الصادرات المسماة +### استيراد التصديرات المسماة -لاستيراد تصدير معين ديناميكيًا، يمكنك إعادته من Promise الذي تُعيده دالة [`import()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import): +لاستيراد تصدير مسما بشكل ديناميكي، يمكنك إعادته من Promise الذي تُرجعها دالة [`import()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import): ```jsx filename="components/hello.js" 'use client' @@ -177,7 +177,7 @@ const ClientComponent = dynamic(() => -باستخدام `next/dynamic`، لن يتم تضمين مكون الرأس في حزمة JavaScript الأولية للصفحة. ستعرض الصفحة أولاً `fallback` الخاص بـ Suspense، ثم مكون `Header` عند حل حد Suspense. +باستخدام `next/dynamic`، لن يتم تضمين مكون الرأس في حزمة JavaScript الأولية للصفحة. ستقوم الصفحة بعرض `fallback` الخاص بـ Suspense أولاً، متبوعًا بمكون `Header` عند حل حد Suspense. ```jsx import dynamic from 'next/dynamic' @@ -191,11 +191,11 @@ export default function Home() { } ``` -> **معلومة مفيدة**: في `import('مسار/إلى/المكون')`، يجب كتابة المسار بشكل صريح. لا يمكن أن يكون سلسلة قوالب ولا متغيرًا. بالإضافة إلى ذلك، يجب أن تكون `import()` داخل استدعاء `dynamic()` لكي تتمكن Next.js من مطابقة حزم webpack / معرفات الوحدات مع استدعاء `dynamic()` المحدد وتحميلها مسبقًا قبل التصيير. لا يمكن استخدام `dynamic()` داخل تصيير React لأنه يجب وسمه في المستوى العلوي للوحدة لكي يعمل التحميل المسبق، مشابهًا لـ `React.lazy`. +> **معلومة مفيدة**: في `import('path/to/component')`، يجب كتابة المسار بشكل صريح. لا يمكن أن يكون سلسلة قوالب ولا متغيرًا. بالإضافة إلى ذلك، يجب أن تكون `import()` داخل استدعاء `dynamic()` لكي تتمكن Next.js من مطابقة حزم webpack / معرّفات الوحدات مع استدعاء `dynamic()` المحدد وتحميلها مسبقًا قبل التقديم. لا يمكن استخدام `dynamic()` داخل عرض React لأنه يجب وضعه في المستوى العلوي للوحدة لكي يعمل التحميل المسبق، مشابهًا لـ `React.lazy`. -## مع الصادرات المسماة +## مع التصديرات المسماة -لاستيراد تصدير معين ديناميكيًا، يمكنك إعادته من [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) الذي تُعيده [`import()`](https://github.com/tc39/proposal-dynamic-import#example): +لاستيراد تصدير مسما بشكل ديناميكي، يمكنك إعادته من [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) الذي تُرجعها [`import()`](https://github.com/tc39/proposal-dynamic-import#example): ```jsx filename="components/hello.js" export function Hello() { @@ -212,7 +212,7 @@ const DynamicComponent = dynamic(() => ## بدون SSR -لتحميل مكون ديناميكيًا على جانب العميل، يمكنك استخدام خيار `ssr` لتعطيل التصيير من جانب الخادم. هذا مفيد إذا كانت تبعية خارجية أو مكون يعتمد على واجهات برمجة متصفح مثل `window`. +لتحميل مكون ديناميكيًا على جانب العميل، يمكنك استخدام خيار `ssr` لتعطيل التقديم من جانب الخادم. هذا مفيد إذا كانت تبعية خارجية أو مكون يعتمد على واجهات برمجة المتصفح مثل `window`. ```jsx 'use client' @@ -226,7 +226,7 @@ const DynamicHeader = dynamic(() => import('../components/header'), { ## مع المكتبات الخارجية -هذا المثال يستخدم المكتبة الخارجية `fuse.js` للبحث الضبابي. يتم تحميل الوحدة فقط في المتصفح بعد إدخال المستخدم في حقل البحث. +يستخدم هذا المثال المكتبة الخارجية `fuse.js` للبحث الضبابي. يتم تحميل الوحدة فقط في المتصفح بعد إدخال المستخدم في حقل البحث. ```jsx import { useState } from 'react' diff --git a/apps/docs/content/ar/docs/01-app/02-guides/migrating/app-router-migration.mdx b/apps/docs/content/ar/docs/01-app/02-guides/migrating/app-router-migration.mdx index 9bfa854c..a2cac9e0 100644 --- a/apps/docs/content/ar/docs/01-app/02-guides/migrating/app-router-migration.mdx +++ b/apps/docs/content/ar/docs/01-app/02-guides/migrating/app-router-migration.mdx @@ -1,16 +1,16 @@ --- -source-updated-at: 2025-06-01T01:32:20.000Z -translation-updated-at: 2025-06-02T20:18:37.875Z -title: كيفية الانتقال من Pages إلى App Router -nav_title: App Router -description: تعلم كيفية ترقية تطبيق Next.js الحالي من Pages Router إلى App Router. +source-updated-at: 2025-06-08T05:18:05.000Z +translation-updated-at: 2025-06-08T22:22:43.932Z +title: كيفية الانتقال من صفحات (Pages) إلى موجه التطبيق (App Router) +nav_title: موجه التطبيق (App Router) +description: تعلم كيفية ترقية تطبيق Next.js الحالي من موجه الصفحات (Pages Router) إلى موجه التطبيق (App Router). --- سيساعدك هذا الدليل في: - [تحديث تطبيق Next.js من الإصدار 12 إلى الإصدار 13](#nextjs-version) -- [ترقية الميزات التي تعمل في كل من دليل `pages` و `app`](#upgrading-new-features) -- [الانتقال التدريجي للتطبيق الحالي من `pages` إلى `app`](#migrating-from-pages-to-app) +- [ترقية الميزات التي تعمل في كل من دليل `pages` ودليل `app`](#upgrading-new-features) +- [الانتقال التدريجي لتطبيقك الحالي من `pages` إلى `app`](#migrating-from-pages-to-app) ## الترقية @@ -20,7 +20,7 @@ description: تعلم كيفية ترقية تطبيق Next.js الحالي من ### إصدار Next.js -لتحديث Next.js إلى الإصدار 13، قم بتنفيذ الأمر التالي باستخدام مدير الحزم المفضل لديك: +لتحديث Next.js إلى الإصدار 13، قم بتشغيل الأمر التالي باستخدام مدير الحزم المفضل لديك: ```bash filename="Terminal" npm install next@latest react@latest react-dom@latest @@ -28,100 +28,100 @@ npm install next@latest react@latest react-dom@latest ### إصدار ESLint -إذا كنت تستخدم ESLint، فأنت بحاجة إلى ترقية إصدار ESLint: +إذا كنت تستخدم ESLint، فستحتاج إلى ترقية إصدار ESLint: ```bash filename="Terminal" npm install -D eslint-config-next@latest ``` -> **معلومة مفيدة**: قد تحتاج إلى إعادة تشغيل خادم ESLint في VS Code لتفعيل تغييرات ESLint. افتح لوحة الأوامر (`cmd+shift+p` على Mac؛ `ctrl+shift+p` على Windows) وابحث عن `ESLint: Restart ESLint Server`. +> **معلومة مفيدة**: قد تحتاج إلى إعادة تشغيل خادم ESLint في VS Code حتى يتم تطبيق تغييرات ESLint. افتح لوحة الأوامر (`cmd+shift+p` على Mac؛ `ctrl+shift+p` على Windows) وابحث عن `ESLint: Restart ESLint Server`. ## الخطوات التالية بعد التحديث، راجع الأقسام التالية للخطوات التالية: -- [ترقية الميزات الجديدة](#upgrading-new-features): دليل لمساعدتك في الترقية إلى ميزات جديدة مثل مكونات Image و Link المحسنة. +- [ترقية الميزات الجديدة](#upgrading-new-features): دليل لمساعدتك في الترقية إلى ميزات جديدة مثل مكونات الصورة والرابط المحسنة. - [الانتقال من دليل `pages` إلى `app`](#migrating-from-pages-to-app): دليل خطوة بخطوة لمساعدتك في الانتقال التدريجي من دليل `pages` إلى `app`. ## ترقية الميزات الجديدة -أدخل Next.js 13 [App Router](/docs/app/building-your-application/routing) الجديد مع ميزات واتفاقيات جديدة. Router الجديد متاح في دليل `app` ويتعايش مع دليل `pages`. +أدخل Next.js 13 [موجه التطبيق الجديد (App Router)](/docs/app/building-your-application/routing) مع ميزات واتفاقيات جديدة. يتوفر الموجه الجديد في دليل `app` ويتعايش مع دليل `pages`. -لا تتطلب الترقية إلى Next.js 13 استخدام App Router. يمكنك الاستمرار في استخدام `pages` مع الميزات الجديدة التي تعمل في كلا الدليلين، مثل مكون [Image](#image-component) المحدث، ومكون [Link](#link-component)، ومكون [Script](#script-component)، و[تحسين الخطوط](#font-optimization). +لا تتطلب الترقية إلى Next.js 13 استخدام موجه التطبيق. يمكنك الاستمرار في استخدام `pages` مع ميزات جديدة تعمل في كلا الدليلين، مثل مكون [الصورة المحدث](#image-component)، ومكون [الرابط](#link-component)، ومكون [النص البرمجي](#script-component)، و[تحسين الخطوط](#font-optimization). ### مكون `` -أدخل Next.js 12 تحسينات جديدة على مكون Image مع استيراد مؤقت: `next/future/image`. تضمنت هذه التحسينات كمية أقل من JavaScript على جانب العميل، وطرق أسهل لتوسيع وتصميم الصور، وإمكانية وصول أفضل، وتحميل كسول متصفح أصلي. +قدم Next.js 12 تحسينات جديدة لمكون الصورة باستخدام استيراد مؤقت: `next/future/image`. شملت هذه التحسينات كمية أقل من JavaScript على جانب العميل، وطرق أسهل لتوسيع وتصميم الصور، وإمكانية وصول أفضل، وتحميل كسول متصفح أصلي. في الإصدار 13، أصبح هذا السلوك الجديد هو الافتراضي لـ `next/image`. -هناك اثنان من codemods لمساعدتك في الانتقال إلى مكون Image الجديد: +هناك اثنان من أدوات التعديل التلقائي لمساعدتك في الانتقال إلى مكون الصورة الجديد: -- [**codemod `next-image-to-legacy-image`**](/docs/app/guides/upgrading/codemods#next-image-to-legacy-image): يعيد تسمية استيرادات `next/image` إلى `next/legacy/image` بشكل آلي وآمن. سيحافظ المكونات الحالية على نفس السلوك. -- [**codemod `next-image-experimental`**](/docs/app/guides/upgrading/codemods#next-image-experimental): يضيف أنماط مضمنة بشكل خطير ويزيل الخصائص غير المستخدمة. سيغير هذا سلوك المكونات الحالية لتتناسب مع الإعدادات الافتراضية الجديدة. لاستخدام هذا codemod، يجب عليك تشغيل codemod `next-image-to-legacy-image` أولاً. +- [**أداة التعديل التلقائي `next-image-to-legacy-image`**](/docs/app/guides/upgrading/codemods#next-image-to-legacy-image): تعيد تسمية استيرادات `next/image` إلى `next/legacy/image` بأمان وتلقائيًا. ستحافظ المكونات الحالية على نفس السلوك. +- [**أداة التعديل التلقائي `next-image-experimental`**](/docs/app/guides/upgrading/codemods#next-image-experimental): تضيف أنماط مضمنة بشكل خطير وتزيل الخصائص غير المستخدمة. سيغير هذا سلوك المكونات الحالية لتتناسب مع الإعدادات الافتراضية الجديدة. لاستخدام هذه الأداة، تحتاج أولاً إلى تشغيل أداة `next-image-to-legacy-image`. ### مكون `` -لم يعد مكون [``](/docs/app/building-your-application/routing/linking-and-navigating#link-component) يتطلب إضافة علامة `` يدويًا كطفل. تمت إضافة هذا السلوك كخيار تجريبي في [الإصدار 12.2](https://nextjs.org/blog/next-12-2) وأصبح الآن الافتراضي. في Next.js 13، يقوم `` دائمًا بعرض `` ويسمح لك بإعادة توجيه الخصائص إلى العلامة الأساسية. +لم يعد مكون [``](/docs/app/api-reference/components/link) يتطلب إضافة علامة `` يدويًا كطفل. تمت إضافة هذا السلوك كخيار تجريبي في [الإصدار 12.2](https://nextjs.org/blog/next-12-2) وأصبح الآن الافتراضي. في Next.js 13، يُظهر `` دائمًا `` ويسمح لك بتمرير الخصائص إلى العلامة الأساسية. على سبيل المثال: ```jsx import Link from 'next/link' -// Next.js 12: يجب تضمين `` وإلا سيتم استبعادها +// Next.js 12: يجب تداخل `` وإلا سيتم استبعادها About -// Next.js 13: يقوم `` دائمًا بعرض `` في الخلفية +// Next.js 13: يُظهر `` دائمًا `` في الخلفية About ``` -لترقية الروابط إلى Next.js 13، يمكنك استخدام [codemod `new-link`](/docs/app/guides/upgrading/codemods#new-link). +لترقية روابطك إلى Next.js 13، يمكنك استخدام [أداة التعديل التلقائي `new-link`](/docs/app/guides/upgrading/codemods#new-link). ### مكون `