All Systems Operational
Powered By
profound-logo
profound-logoProfound CMS
⌘K
Admin

البرمجة في منشئ القوالب

دليل عملي لكتابة تعبيرات CEL في نظام إدارة المحتوى.

Continue Reading
Previous‹العرض الثابت مع دعم وضع التحريرNextإنشاء بروفوند نكست›

هجين

مشروع المعالجالتوجيه البارامتريأنواع المكوّناتSseإعداد وكيل لوحة التحكّم الإداريةالعرض الثابت مع دعم وضع التحريرالبرمجة في منشئ القوالبإنشاء بروفوند نكست

بدون رأس

البدء السريعجسون وClaude Codeسحب-مكوّن-Zod

Mcp

Mcp

ميزات نظام إدارة المحتوى

ميزة قالب الوثائقميزة منشئ القالبميزة المترجمميزة المنظمة

تحفيز

نهجنا

مصطلحات

هجيني مقابل بدون واجهة

دليل عملي لكتابة تعبيرات CEL في نظام إدارة المحتوى.


كيف تعمل CEL

CEL (لغة التعبير المشتركة) هي لغة برمجة نصية خفيفة مدمجة في نظام إدارة المحتوى لدينا. تتيح لك كتابة تعبيرات ديناميكية يمكنها سحب البيانات من المستندات، وقراءة معلمات عنوان URL، وحساب القيم أثناء التنفيذ.

إليك ما يحدث عند تشغيل نص CEL:

برنامجك النصي                   المحرك                         النتيجة
    |                              |                              |
    v                              v                              v
documents.get("article", "intro") --> يجلب من قاعدة البيانات --> { headline: "مرحبًا", body: "..." }
         .headline                --> يستخرج الحقل            --> "مرحبًا"

اعتبر CEL لغة استعلام للقراءة فقط. لا يمكنها تعديل أي شيء في قاعدة البيانات؛ فهي تقرأ البيانات وتعيد نتيجة محسوبة فحسب. وهذا يجعل استخدامها آمنًا في أي مكان داخل نظام إدارة المحتوى.


اللبنات الأساسية

كل تعبير CEL يمكنه الوصول إلى ثلاثة عناصر:

الكائنماهيتهمثال
documentsجلب أي مستند من نظام إدارة المحتوىdocuments.get("country", "us")
metaمعلومات عن الطلب الحالي (الإعداد اللغوي، معلمات URL)meta.locale, meta.params.slug
schemaتعريفات حقول المستند الحاليschema.fields

جلب المستندات

أقوى ميزة في CEL هي إمكانية جلب المستندات من أي مكان داخل نظام إدارة المحتوى لديك.

الحصول على مستند واحد

الصياغة: documents.get(schemaName, identifier)

لنفترض أن لديك مستند article مخزنًا بالمعرِّف "welcome-post":

// مخزن في نظام إدارة المحتوى كالتالي: article / welcome-post
{
  "headline": "مرحبًا بكم في منصتنا",
  "author": "سارة تشين",
  "body": "نحن متحمسون للإعلان...",
  "tags": ["إعلان", "أخبار"]
}

لجلب المستند بالكامل:

documents.get("article", "welcome-post")

يعيد:

{
  "headline": "مرحبًا بكم في منصتنا",
  "author": "سارة تشين",
  "body": "نحن متحمسون للإعلان...",
  "tags": ["إعلان", "أخبار"]
}

لجلب العنوان فقط:

documents.get("article", "welcome-post").headline

يعيد: "مرحبًا بكم في منصتنا"

لجلب اسم المؤلف:

documents.get("article", "welcome-post").author

يعيد: "سارة تشين"


استخدام معلمات عنوان URL

عندما تحتوي صفحتك على مسارات ديناميكية (مثل /articles/[slug])، يمكنك استخدام meta.params للحصول على معلمة عنوان URL وجلب المستند الصحيح.

إذا زار أحدهم /articles/welcome-post:

documents.get("article", meta.params.slug).headline

يعيد: "مرحبًا بكم في منصتنا"

هكذا تبني صفحات ديناميكية؛ إذ يعمل نص CEL نفسه مع أي مقال، مستخدمًا أي قيمة slug موجودة في عنوان URL.


جلب عدة مستندات

الصياغة: documents.find(schemaName) أو documents.find(schemaName, filter)

// جلب جميع البلدان
documents.find("country")

يعيد:

[
  { "code": "us", "name": "الولايات المتحدة", "flag": "US" },
  { "code": "sa", "name": "المملكة العربية السعودية", "flag": "SA" },
  { "code": "gb", "name": "المملكة المتحدة", "flag": "GB" }
// جلب البلدان باستخدام عامل تصفية
documents.find("country", { "where": { "code": "us" } })

يعيد:

[
  { "code": "us", "name": "الولايات المتحدة", "flag": "US" }
]

أمثلة واقعية

المثال 1: عنوان كتلة البطل من مستند آخر

لديك hero-block يجب أن يعرض عنوانًا مأخوذًا من مستند article.

مستند المقال الخاص بك (المعرِّف: "homepage-hero"):

{
  "headline": "ابنِ أسرع، وانشر بذكاء أكبر",
  "subheadline": "نظام إدارة المحتوى الحديث للمطورين"
}

نص CEL في حقل عنوان كتلة البطل:

documents.get("article", "homepage-hero").headline

النتيجة: تعرض كتلة البطل "ابنِ أسرع، وانشر بذكاء أكبر"


المثال 2: اسم البلد من الرمز

تبني صفحة على /countries/[code] وتريد عرض الاسم الكامل للبلد.

مستندات البلد الخاصة بك:

// country / us
{ "code": "us", "name": "الولايات المتحدة", "flag": "US", "languages": ["en", "es"] }

// country / sa
{ "code": "sa", "name": "المملكة العربية السعودية", "flag": "SA", "languages": ["ar", 

نص CEL:

documents.get("country", meta.params.code).name

عندما يزور أحدهم /countries/us:

  • meta.params.code = "us"
  • النتيجة: "الولايات المتحدة"

عندما يزور أحدهم /countries/sa:

  • meta.params.code = "sa"
  • النتيجة: "المملكة العربية السعودية"

المثال 3: محتوى شرطي بناءً على الإعداد اللغوي

اعرض عناوين مختلفة بناءً على إعداد المستخدم اللغوي.

meta.locale == "ar-SA" ? "مرحبًا بكم" : "أهلًا"

إذا كان الإعداد اللغوي "ar-SA": يعيد "مرحبًا بكم" إذا كان أي شيء آخر: يعيد "أهلًا"


المثال 4: عمليات بحث متسلسلة عن المستندات

يحتوي مستند article لديك على حقل countryCode، وتريد الحصول على الاسم الكامل للبلد.

مستند المقال:

{ "headline": "أخبار من الولايات المتحدة", "countryCode": "us" }

نص CEL:

documents.get("country", documents.get("article", "us-news").countryCode).name

ما يحدث:

  1. documents.get("article", "us-news") يعيد { "headline": "أخبار من الولايات المتحدة", "countryCode": "us" }
  2. .countryCode تستخرج "us"
  3. documents.get("country", "us") يعيد { "code": "us", "name": "الولايات المتحدة", ... }
  4. .name تستخرج "الولايات المتحدة"

النتيجة: "الولايات المتحدة"


المثال 5: قيم احتياطية

إذا كان من الممكن ألا يوجد مستند، يمكنك توفير قيمة احتياطية:

documents.get("article", meta.params.slug) != null
  ? documents.get("article", meta.params.slug).headline
  : "المقال غير موجود"

أو تحقق مما إذا كان حقل محدد موجودًا:

documents.get("article", "intro").author != null
  ? documents.get("article", "intro").author
  : "مؤلف غير معروف"

المثال 6: التعامل مع القوائم

مقالك يحتوي على وسوم، وتريد التحقق مما إذا كان وسم محدد موجودًا:

"مميز" in documents.get("article", "welcome-post").tags

يعيد: true إذا كان المقال يحتوي على الوسم "مميز"

الحصول على أول وسم:

documents.get("article", "welcome-post").tags[0]

يعيد: "إعلان" (أول وسم)

عدّ الوسوم:

size(documents.get("article", "welcome-post").tags)

يعيد: 2 (عدد الوسوم)


المسارات البارامترية و meta.params

المسارات البارامترية هي المفتاح لإنشاء صفحات ديناميكية ومحلية. عندما تعرّف نمط مسار مثل /{lang}/landingPage، يقوم نظام إدارة المحتوى باستخراج المعلمات من عنوان URL ويجعلها متاحة عبر meta.params.

كيف تعمل معلمات المسار

تعريف نمط المسار: تستخدم المسارات الصيغة :paramName أو {paramName} لتعريف المقاطع الديناميكية:

النمطعنوان URL مثالالمعلمات المستخرجة
/:lang/landingPage/ko/landingPage{ lang: "ko" }
/{country}/{lang}/products/us/en/products{ country: "us", lang: "en" }
/articles/:slug/articles/welcome-post{ slug: "welcome-post" }

ربط المعلمات: يمكن ربط كل معلمة مسار بمخطط مستند لأغراض التحقق:

{
  "pattern": "/{lang}/landingPage",
  "param_bindings": {
    "lang": "language"
  }
}

يبين هذا الربط لنظام إدارة المحتوى ما يلي:

  1. استخراج مقطع lang من عنوان URL
  2. التحقق من صحته مقابل مخطط language (يبحث عن مستند يطابق فيه content.code)
  3. إذا كان صالحًا، يجعل المستند الكامل متاحًا في المعلمات المحلولة

مثال: صفحة هبوط تعتمد على اللغة

تهيئة المسار:

  • المسار: /{lang}/landingPage
  • النمط: /{lang}/landingPage
  • الربط البارامتري: { "lang": "language" }

مستندات الترحيب الخاصة بك:

// greeting / ko
{ "code": "ko", "headline": "환영합니다", "subheadline": "우리 플랫폼에 오신 것을 환영합니다" }

// greeting / en
{ "code": "en", "headline": "Welcome", "subheadline": "Welcome to our platform" }

// greeting / ja
{ "code": "ja", "headline"

نص CEL لجلب المحتوى المحلي:

documents.get("greeting", meta.params.lang).headline

كيف يتم الحل:

عنوان URLmeta.params.langالنتيجة
/ko/landingPage"ko""환영합니다"
/en/landingPage"en""Welcome"
/ja/landingPage"ja""ようこそ"

نمط متقدم: مسارات البلد + اللغة

للمسارات مثل /{country}/{lang}/products:

تهيئة المسار:

{
  "pattern": "/{country}/{lang}/products",
  "param_bindings": {
    "country": "country",
    "lang": "language"
  }
}

نصوص CEL:

// الحصول على اسم البلد
documents.get("country", meta.params.country).name

// الحصول على قائمة المنتجات المحلية بناءً على البلد
documents.find("product", { "where": { "country": meta.params.country } })

// مدمج: إظهار ترحيب خاص بالبلد بلغة المستخدم
documents.get("greeting", meta.params.lang).headline + " من " + documents.get("country", meta.params.country).name

سلسلة التحقق: يتحقق نظام إدارة المحتوى من المعلمات بشكل هرمي. بالنسبة لمسارات /{country}/{lang}:

  1. يتحقق من معلمة country مقابل مخطط country
  2. يتحقق من معلمة lang مقابل مخطط language
  3. يمكنه اختياريًا التحقق من وجود lang داخل مصفوفة country.languages[] (تحقق هرمي)

meta.segments - الوصول الخام إلى مسار URL

يوفر meta.segments مسار عنوان URL الخام كمصفوفة، وهو مفيد عندما تحتاج إلى الوصول وفقًا للموضع دون معلمات مسماة.

كيف يعمل:

مسار URLmeta.segments
/articles/tech/ai-news["articles", "tech", "ai-news"]
/ko/landingPage["ko", "landingPage"]
/us/en/products/featured["us", "en", "products", "featured"]
/[]

متى تستخدم meta.segments مقابل meta.params

حالة الاستخدامالنهج الأفضل
المعلمات المسماة من نمط المسارmeta.params.lang
الوصول بناءً على الموضعmeta.segments[0]
الحصول على عمق المسارsize(meta.segments)
التحقق مما إذا كان المسار يحتوي على مقطع معين"admin" in meta.segments

أمثلة باستخدام meta.segments

// الحصول على المقطع الأول (غالبًا ما يكون رمز اللغة)
meta.segments[0]

// التحقق من عمق المسار
size(meta.segments) > 2 ? "عميق" : "سطحي"

// التحقق مما إذا كنا في قسم الإدارة
"admin" in meta.segments ? "وضع الإدارة" : "الوضع العام"

// احتياط: استخدام المقطع إذا لم يتم ربط المعلمة
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

المرجع الكامل لكائن meta

يحتوي كائن meta على كل السياق حول الطلب الحالي:

الخاصيةالنوعالوصف
meta.localestringرمز الإعداد اللغوي الحالي (مثل "en-US", "ko-KR", "ar-SA")
meta.paramsRecord<string, string>معلمات المسار المستخرجة من نمط عنوان URL
meta.segmentsstring[]مسار عنوان URL المجزأ إلى مقاطع
meta.docIdstring \| nullمعرّف UUID للمستند الحالي (null للمستندات الجديدة)
meta.titlestringعنوان المستند الحالي

meta.locale

يتبع رمز الإعداد اللغوي تنسيق BCP 47 (اللغة-المنطقة):

// التحقق من الإعدادات اللغوية للغات من اليمين إلى اليسار
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"

// الحصول على جزء اللغة فقط
meta.locale.split("-")[0]  // غير مدعوم - استخدم meta.params.lang بدلاً من ذلك

meta.params

تكون معلمات المسار دائمًا سلاسل نصية. يتحقق نظام إدارة المحتوى منها مقابل المخططات المرتبطة قبل التنفيذ:

// الوصول إلى معلمة مسماة
meta.params.lang           // "ko"
meta.params.country        // "us"
meta.params.slug           // "welcome-post"

// التحقق مما إذا كانت المعلمة موجودة
has(meta.params.category)  // true/false

// الاستخدام في جلب المستندات
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)

meta.segments

مقاطع عنوان URL الخام كمصفوفة:

// الوصول عبر الفهرس (بدءًا من الصفر)
meta.segments[0]           // المقطع الأول
meta.segments[1]           // المقطع الثاني

// التحقق من الطول
size(meta.segments)        // عدد المقاطع

// التحقق من وجود مقطع
"products" in meta.segments  // هل يتضمن المسار "products"؟

meta.docId

معرّف UUID للمستند الحالي، مفيد للنصوص المرجعية الذاتية:

// متاح فقط عند تحرير مستندات موجودة
meta.docId != null ? "تعديل" : "إنشاء جديد"

// الاستخدام في منطق شرطي
meta.docId != null ? documents.get("article", meta.docId).status : "draft"

meta.title

عنوان المستند الحالي:

// للاستخدام في العرض
"تحرير: " + meta.title

// شرط يعتمد على العنوان
meta.title.contains("Draft") ? "قيد العمل" : "منشور"

‎documents.ref()‎ - عمليات بحث متسلسلة

للحصول على صياغة أوضح عندما يكون المخطط معروفًا لكن المعرّف ديناميكيًا:

// النهج التقليدي
documents.get("airports", meta.params.code).name

// استخدام ref() - المخطط منفصل عن المعرّف الديناميكي
documents.ref("airports").get(meta.params.code).name

كلاهما متكافئ، لكن ref() يجعل الجزء الديناميكي أوضح.


مرجع سريع

جلب المستندات

documents.get("schema", "identifier")       // جلب مستند واحد
documents.get("schema", "id").fieldName     // جلب حقل محدد
documents.find("schema")                    // جلب جميع المستندات
documents.find("schema", { "where": {...}}) // استعلام مع عامل تصفية
documents.ref("schema").get(identifier)     // عملية بحث متسلسلة

متغيرات السياق

meta.locale          // "en-US", "ar-SA", إلخ
meta.params.xyz      // معلمة عنوان URL باسم "xyz"
meta.segments        // مسار عنوان URL كمصفوفة: ["articles", "intro"]
meta.segments[0]     // أول مقطع في المسار
meta.docId           // معرّف المستند الحالي (أو null)
meta.title           // عنوان المستند الحالي

المعاملات

// المقارنة
==  !=  <  <=  >  >=

// المنطق
&&  ||  !

// الثلاثي (if-else)
condition ? valueIfTrue : valueIfFalse

// الانتماء
"value" in listOrMap

الدوال الشائعة

size(list)                    // عدد العناصر
size(string)                  // طول السلسلة
"text".startsWith("te")       // true
"text".endsWith("xt")         // true
"text".contains("ex")         // true
has(object.property)          // التحقق من وجود خاصية

رسائل الخطأ

إذا حدث خطأ ما، سترى أحد الرسائل التالية:

الخطأماذا يعني؟
SYNTAX_ERRORخطأ كتابي في النص (علامة اقتباس مفقودة، معامل غير صحيح)
TYPE_ERRORتخلط بين أنواع لا تعمل معًا
RUNTIME_ERRORتم تشغيل النص لكنه واجه مشكلة (متغير غير معرّف)
FETCH_LIMIT_EXCEEDEDتجلب عددًا كبيرًا جدًا من المستندات (الحد الأقصى 50)
TIMEOUTاستغرق النص وقتًا طويلًا (الحد الأقصى 5 ثوانٍ)
AST_DEPTH_EXCEEDEDالتعبير متشعب بعمق كبير (العمق الأقصى: 50)
SCRIPT_TOO_LONGيتجاوز طول النص حد 5000 حرف

القابلية للتوسعة والقدرات المستقبلية

صُمم محرك CEL ليكون قابلاً للتوسعة. تشمل القدرات المخطط لها مستقبلًا ما يلي:

مخطط: تكامل خادم MCP

// مستقبلًا: استدعاء خدمات خارجية عبر MCP
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)

مخطط: قدرات الذكاء الاصطناعي

// مستقبلًا: إنشاء محتوى مدعوم بالذكاء الاصطناعي
ai.summarize(documents.get("article", meta.params.id).body, 100)
ai.translate(meta.params.text, meta.params.targetLang)
ai.classify(meta.params.input, ["إيجابي", "سلبي", "محايد"])

ستتم إضافة هذه القدرات عبر نظام الدوال المسجل، مع الحفاظ على التوافق مع النصوص الحالية.


نصائح

  1. استخدم الإكمال التلقائي - اكتب documents. أو meta. وسيعرض لك المحرر الخيارات المتاحة
  2. ابدأ ببساطة - اختبر باستخدام documents.get("schema", "id") أولًا، ثم أضف .fieldName
  3. تحقق من null - إذا كان هناك احتمال لعدم وجود مستند، أضف قيمة احتياطية باستخدام != null ? ... : ...
  4. لا تفرط في الجلب - كل استدعاء لـ documents.get() أو documents.find() يُحتسب ضمن حد الجلب البالغ 50 مرة
  5. فضّل meta.params على meta.segments - المعلمات المسماة يتم التحقق منها وأكثر موثوقية
  6. استخدم has() للمعلمات الاختيارية - تحقق من has(meta.params.category) قبل الوصول إليها
  7. استخدم documents.ref() للمعرّفات الديناميكية - صياغة أوضح عندما يكون المخطط ثابتًا لكن المعرّف متغيرًا

الملحق أ: مثال كامل لمسار بارامتري

يوضح هذا الدليل كيفية إنشاء صفحة هبوط متعددة اللغات يمكن الوصول إليها عبر /{lang}/landingPage.

الخطوة 1: إنشاء مخطط مستند الترحيب

في لوحة إدارة نظام إدارة المحتوى، أنشئ مخططًا مخصصًا باسم greeting:

{
  "name": "greeting",
  "fields": [
    { "name": "code", "type": "string", "required": true },
    { "name": "headline", "type": "string", "required": true },
    { "name": "subheadline"

الخطوة 2: إنشاء مستندات الترحيب

أنشئ مستندات لكل لغة:

المستند: greeting / ko

{
  "code": "ko",
  "headline": "환영합니다",
  "subheadline": "우리 플랫폼에 오신 것을 환영합니다",
  "ctaText": "시작하기",
  "ctaUrl": "/ko/get-started"
}

المستند: greeting / en

{
  "code": "en",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Get Started",
  "ctaUrl": "/en/get-started"
}

المستند: greeting / ja

{
  "code": "ja",
  "headline": "ようこそ",
  "subheadline": "私たちのプラットフォームへようこそ",
  "ctaText": "始める",
  "ctaUrl": "/ja/get-started"
}

الخطوة 3: إنشاء المسار

أنشئ مسارًا بالإعدادات التالية:

  • المسار: /{lang}/landingPage
  • النمط: /{lang}/landingPage
  • الحالة: مباشر
  • ربط المعلمات:
  {
    "lang": "language"
  }

الخطوة 4: إضافة كتل تحتوي على نصوص CEL

أضف كتلة بطل إلى المسار بهذه النصوص لكل حقل:

حقل العنوان:

documents.get("greeting", meta.params.lang).headline

حقل العنوان الفرعي:

documents.get("greeting", meta.params.lang).subheadline

حقل نص الدعوة لاتخاذ إجراء:

documents.get("greeting", meta.params.lang).ctaText

حقل رابط الدعوة لاتخاذ إجراء:

documents.get("greeting", meta.params.lang).ctaUrl

الخطوة 5: الاستهلاك في Next.js

أنشئ مسارًا يلتقط كل شيء في تطبيق Next.js الخاص بك:

// app/[...slug]/page.tsx
import { getCmsClient } from '@repo/renderer';

interface PageProps {
  params: { slug: string[] };
}

export default async function Page({ params }: PageProps) {

الخطوة 6: اختبار المسارات

زر عناوين URL التالية لمشاهدة المحتوى المحلي:

عنوان URLالعنوان المتوقع
/ko/landingPage환영합니다
/en/landingPageWelcome
/ja/landingPageようこそ

كيف تعمل عملية الحل

عندما يزور المستخدم /ko/landingPage:

  1. مطابقة المسار: يطابق نظام إدارة المحتوى النمط /{lang}/landingPage
  2. استخراج المعلمات: meta.params.lang = "ko"
  3. التحقق: يتحقق نظام إدارة المحتوى من أن "ko" موجود في مخطط language
  4. تقييم CEL: يتم حل النصوص مثل documents.get("greeting", meta.params.lang) إلى محتوى اللغة الكورية
  5. الاستجابة: يتم إرجاع الكتل المحلية إلى العميل

الملحق ب: مرجع تقني

واجهة CelMeta (TypeScript)

interface CelMeta {
  /** رمز الإعداد اللغوي الحالي (مثل 'en-US') */
  locale: string;
  /** معلمات المسار المستخرجة من عنوان URL */
  params: Record<string, string>;
  /** مقاطع مسار عنوان URL */
  segments: string[];
  /** معرّف المستند الحالي (إذا كان يتم تحرير مستند موجود) */

خوارزمية استخراج المعلمات

تعالج دالة extractParams مسارات عناوين URL:

النمط: /{country}/{lang}/products
المسار:    /us/en/products

الخوارزمية:
1. توحيد كلاهما (إزالة الشرط المائل في النهاية)
2. التقسيم إلى مقاطع: ["us", "en", "products"] و["{country}", "{lang}", "products"]

صيغ ربط المعلمات المدعومة

// ربط بسيط (يستخدم حقل "code" للبحث)
{ "lang": "language" }

// ربط تفصيلي (حقل سبيكة مخصص)
{
  "lang": {
    "schemaName": "language",
    "slugField": "code"
  },
  "slug": {
    "schemaName": "article",
    "slugField": "slug"
  }
}

أولوية البحث عن المستندات

عند الجلب باستخدام documents.get(schema, identifier):

  1. مطابقة UUID: إذا كان المعرّف UUID صالحًا، يتم الجلب عبر id
  2. حقل code: التحقق من حقل content.code
  3. حقل slug: التحقق من حقل content.slug
  4. مطابقة العنوان: التحقق من حقل title

يتيح ذلك مرونة في الإشارة إلى المستندات باستخدام أي معرّف فريد.

]
"en"
] }
:
"ようこそ"
,
"subheadline"
:
"私たちのプラットフォームへようこそ"
}
,
"type"
:
"string"
},
{ "name": "ctaText", "type": "string" },
{ "name": "ctaUrl", "type": "string" }
]
}
const
client
=
getCmsClient
({
cmsUrl: process.env.CMS_URL!,
apiKey: process.env.CMS_API_KEY!,
websiteId: process.env.CMS_WEBSITE_ID!,
});
const path = '/' + params.slug.join('/');
// الحصول على المسار والمعلمات المحلولة
const { route, resolvedParams } = await client.routes.getRouteByPath.query({
websiteId: process.env.CMS_WEBSITE_ID!,
path,
});
// جلب الكتل الخاصة بالمسار
const blocks = await client.blocks.getBlocks.query({
websiteId: process.env.CMS_WEBSITE_ID!,
blockIds: route.block_ids,
// تمرير المعلمات المحلولة لسياق CEL
context: {
meta: {
locale: resolvedParams?.lang?.document?.content?.code ?? 'en',
params: Object.fromEntries(
Object.entries(resolvedParams ?? {}).map(([k, v]) => [k, v.value])
),
segments: params.slug,
docId: null,
title: route.title ?? '',
},
schema: {},
},
});
// عرض الكتل
return (
<main>
{blocks.map((block) => (
<BlockRenderer
key={block.id}
block={block}
routeParams={resolvedParams}
language={resolvedParams?.lang?.value}
/>
))}
</main>
);
}
docId
:
string
|
null
;
/** عنوان المستند الحالي */
title: string;
}
3. مطابقة عدد المقاطع (يجب أن يكون متساويًا)
4. لكل زوج من المقاطع:
- إذا بدأ النمط بـ : أو {}، فاستخرجه كمعلمة
- خلاف ذلك، يجب أن يتطابق تمامًا
5. النتيجة: { country: "us", lang: "en" }