المؤلف:
    إنشاء:2025-09-22آخر تحديث:2026-06-14

    Intlayer v8 الجديد - ما الجديد؟

    مرحبًا بك في Intlayer v8! يركز هذا الإصدار على تعزيز تجربة المطور من خلال اكتشاف المحتوى التلقائي، وضمان سلامة البيانات عبر التحقق من صحة المخططات، وتوفير مزيد من التحكم في إدارة القواميس.

    youtube.com

    جدول المحتويات

    تطور المحتوى الغني: Markdown و HTML

    يجلب Intlayer v8 تحسينات كبيرة على كيفية التعامل مع المحتوى الغني، حيث يقدم عقد HTML (التي لم تكن موجودة في v7) ويوحد واجهة برمجة التطبيقات مع عقد Markdown (التي كانت موجودة في v7 ولكن تم تحسينها).

    واجهة برمجة التطبيقات الموحدة .use()

    قدمنا طريقة .use() لكل من عقد Markdown و HTML. تتيح لك هذه الطريقة تخصيص وسوم HTML أو المكونات المستخدمة أثناء العرض.

    • استبدال المكونات: يمكنك بسهولة استبدال وسوم HTML أو المكونات المخصصة بمكونات الإطار الخاص بك (مثل استبدال <a> بـ NextLink أو <CustomCmp> بمكون React).
    • سلامة النوع: جميع الدوال الخاصة بتوفير المكونات مكتوبة بالكامل، مما يضمن تلقيك للخصائص الصحيحة.

    سلوك العرض الافتراضي

    في v7، إذا لم يتم تعريف مزود، كانت عقد Markdown تُصير كسلاسل نصية خام، مما يتطلب غالبًا مكتبات خارجية لتحليلها.

    في v8، يتضمن Intlayer محلل Markdown داخلي خاص به. بشكل افتراضي، تُصير عقد Markdown الآن مباشرة كـ HTML دون الحاجة إلى أي مكتبات خارجية.

    أدوات Renderer و Provider الجديدة

    لقد قدمنا دوال ومكونات renderer مستقلة جديدة لمنحك مزيدًا من التحكم خارج تدفق useIntlayer القياسي.

    • Markdown: MarkdownRenderer و useMarkdownRenderer و renderMarkdown. (ملاحظة: كان MarkdownProvider موجودًا في v7 ولكنه يتكامل الآن مع هذه الأدوات الجديدة).
    • HTML: HTMLRenderer و useHTMLRenderer و renderHTML و HTMLProvider.

    أمثلة: أدوات عرض Markdown

    1. استخدام المكون:

    tsx
    import { MarkdownRenderer } from "react-intlayer/markdown";
    
    <MarkdownRenderer
    forceBlock={true}
    components={{
      h1: ({ children }) => <h1 className="text-2xl">{children}</h1>
    }}
    >
    {"# عنواني"}
    </MarkdownRenderer>
    

    2. استخدام Hook:

    tsx
    import { useMarkdownRenderer } from "react-intlayer/markdown";
    
    const renderMarkdown = useMarkdownRenderer({
    components: {
      h1: ({ children }) => <h1 className="text-red-500">{children}</h1>
    }
    });
    
    return <div>{renderMarkdown("# عنواني")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderMarkdown } from "react-intlayer/markdown";
    
    const html = renderMarkdown("# عنواني", {
    forceBlock: true
    });
    

    1. استخدام المكون:

    vue
    <script setup>
    import { MarkdownRenderer } from "vue-intlayer/markdown";
    </script>
    
    <template>
    <MarkdownRenderer :forceBlock="true" content="# عنواني" />
    </template>
    

    1. استخدام المكون:

    svelte
    <script>
    import { MarkdownRenderer } from "svelte-intlayer/markdown";
    </script>
    
    <MarkdownRenderer forceBlock={true} value="# عنواني" />
    

    2. استخدام Hook:

    svelte
    <script>
    import { useMarkdownRenderer } from "svelte-intlayer/markdown";
    const render = useMarkdownRenderer();
    </script>
    
    {@html render("# عنواني")}
    

    3. استخدام أداة المساعدة:

    svelte
    <script>
    import { renderMarkdown } from "svelte-intlayer/markdown";
    </script>
    
    {@html renderMarkdown("# عنواني")}
    

    1. استخدام الخدمة:

    typescript
    import { Component } from "@angular/core";
    import { IntlayerMarkdownService } from "angular-intlayer";
    
    @Component({ ... })
    export class MyComponent {
    constructor(private markdownService: IntlayerMarkdownService) {}
    
    render(markdown: string) {
      return this.markdownService.renderMarkdown(markdown);
    }
    }
    

    1. استخدام المكون:

    tsx
    import { MarkdownRenderer } from "solid-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true}>
    {"# عنواني"}
    </MarkdownRenderer>
    

    2. استخدام Hook:

    tsx
    import { useMarkdownRenderer } from "solid-intlayer/markdown";
    
    const render = useMarkdownRenderer();
    
    return <div>{render("# عنواني")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderMarkdown } from "solid-intlayer/markdown";
    
    return <div>{renderMarkdown("# عنواني")}</div>;
    

    1. استخدام المكون:

    tsx
    import { MarkdownRenderer } from "preact-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true}>
    {"# عنواني"}
    </MarkdownRenderer>
    

    2. استخدام Hook:

    tsx
    import { useMarkdownRenderer } from "preact-intlayer/markdown";
    
    const render = useMarkdownRenderer();
    
    return <div>{render("# عنواني")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderMarkdown } from "preact-intlayer/markdown";
    
    return <div>{renderMarkdown("# عنواني")}</div>;
    

    أمثلة: أدوات عرض HTML

    1. استخدام المكون:

    tsx
    import { HTMLRenderer } from "react-intlayer/html";
    
    <HTMLRenderer
    components={{
      p: ({ children }) => <p className="mb-4">{children}</p>
    }}
    >
    {"<p>Hello World</p>"}
    </HTMLRenderer>
    

    2. استخدام Hook:

    tsx
    import { useHTMLRenderer } from "react-intlayer/html";
    
    const renderHTML = useHTMLRenderer({
    components: {
      strong: ({ children }) => <b className="font-bold">{children}</b>
    }
    });
    
    return <div>{renderHTML("<p>مرحبًا <strong>العالم</strong></p>")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderHTML } from "react-intlayer/html";
    
    const html = renderHTML("<p>Hello World</p>");
    

    1. استخدام المكون:

    vue
    <script setup>
    import { HTMLRenderer } from "vue-intlayer/html";
    </script>
    
    <template>
    <HTMLRenderer content="<p>Hello World</p>" />
    </template>
    

    1. استخدام المكون:

    svelte
    <script>
    import { HTMLRenderer } from "svelte-intlayer/html";
    </script>
    
    <HTMLRenderer value="<p>Hello World</p>" />
    

    2. استخدام Hook:

    svelte
    <script>
    import { useHTMLRenderer } from "svelte-intlayer/html";
    const render = useHTMLRenderer();
    </script>
    
    {@html render("<p>Hello World</p>")}
    

    3. استخدام أداة المساعدة:

    svelte
    <script>
    import { renderHTML } from "svelte-intlayer/html";
    </script>
    
    {@html renderHTML("<p>Hello World</p>")}
    

    1. الاستخدام المباشر:

    في Angular، يمكنك استخدام ربط [innerHTML] القياسي.

    html
    <div [innerHTML]="'<p>Hello World</p>'"></div>
    

    1. استخدام المكون:

    tsx
    import { HTMLRenderer } from "solid-intlayer/html";
    
    <HTMLRenderer>
    {"<p>Hello World</p>"}
    </HTMLRenderer>
    

    2. استخدام Hook:

    tsx
    import { useHTMLRenderer } from "solid-intlayer/html";
    
    const render = useHTMLRenderer();
    
    return <div>{render("<p>Hello World</p>")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderHTML } from "solid-intlayer/html";
    
    return <div>{renderHTML("<p>Hello World</p>")}</div>;
    

    1. استخدام المكون:

    tsx
    import { HTMLRenderer } from "preact-intlayer/html";
    
    <HTMLRenderer>
    {"<p>Hello World</p>"}
    </HTMLRenderer>
    

    2. استخدام Hook:

    tsx
    import { useHTMLRenderer } from "preact-intlayer/html";
    
    const render = useHTMLRenderer();
    
    return <div>{render("<p>Hello World</p>")}</div>;
    

    3. استخدام أداة المساعدة:

    tsx
    import { renderHTML } from "preact-intlayer/html";
    
    return <div>{renderHTML("<p>Hello World</p>")}</div>;
    

    لمزيد من التفاصيل، راجع توثيق محتوى HTML و توثيق Markdown.

    ملفات محتوى YAML و Markdown (v8.10.0)

    يمكنك الآن تعريف المحتوى مباشرة باستخدام امتدادات الملفات .content.md و .content.yaml. هذا مثالي للمحتوى الطويل، المدونات، التوثيقات، وسياسات الخصوصية.

    هذه الملفات قابلة للتحرير بالكامل من المحرر المرئي، مما يوفر سير عمل مبسطًا لأعضاء الفريق غير التقنيين.

    لمزيد من التفاصيل، راجع توثيق ملفات محتوى YAML و توثيق ملفات محتوى Markdown.

    إعادة كتابة عناوين URL المخصصة

    تقدّم Intlayer v8 دعمًا لـ إعادة كتابة عناوين URL المخصصة، مما يتيح لك تعريف مسارات خاصة بكل لغة تختلف عن البنية القياسية /locale/path. هذه ميزة قوية لتحسين الـ SEO المحلي وتوفير تجربة مستخدم أكثر طبيعية للمتحدثين بغير الإنجليزية.

    التحسينات الرئيسية في v8:

    • منسقات الأطر: تمت إضافة nextjsRewrite, svelteKitRewrite, reactRouterRewrite, vueRouterRewrite, solidRouterRewrite, tanstackRouterRewrite, nuxtRewrite, و viteRewrite لتوفير صياغة نمطية ملائمة لكل راوتر.
    • useRewriteURL هوك: هو هوك جديد على جهة العميل يصحح شريط العنوان بهدوء إلى العنوان المحلي الأجمل ("pretty" localized URL) دون تحفيز تنقلات الراوتر.
    • إعادة توجيه SEO التلقائية: الوكلاء المدمجون يعيدون توجيه المستخدمين تلقائيًا من المسارات canonical المكتوبة يدويًا (على سبيل المثال، /fr/about) إلى نسخها المحلية الأجمل (على سبيل المثال، /fr/a-propos).

    مثال على التكوين:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    import { nextjsRewrite } from "intlayer/routing";
    
    const config: IntlayerConfig = {
    internationalization: {
      locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      defaultLocale: Locales.ENGLISH,
    },
    routing: {
      mode: "prefix-no-default",
      rewrite: nextjsRewrite({
        "/[locale]/about": {
          fr: "/[locale]/a-propos",
          es: "/[locale]/acerca-de",
        },
        "/[locale]/products/[id]": {
          fr: "/[locale]/produits/[id]",
          es: "/[locale]/productos/[id]",
        },
      }),
    },
    };
    
    export default config;
    
    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    import { reactRouterRewrite } from "intlayer/routing";
    
    const config: IntlayerConfig = {
    internationalization: {
      locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      defaultLocale: Locales.ENGLISH,
    },
    routing: {
      mode: "prefix-all",
      rewrite: reactRouterRewrite({
        "/:locale/about": {
          fr: "/:locale/a-propos",
          es: "/:locale/acerca-de",
        },
        "/:locale/products/:id": {
          fr: "/:locale/produits/:id",
          es: "/:locale/productos/:id",
        },
      }),
    },
    };
    
    export default config;
    
    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    import { viteRewrite } from "intlayer/routing";
    
    const config: IntlayerConfig = {
    internationalization: {
      locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      defaultLocale: Locales.ENGLISH,
    },
    routing: {
      mode: "prefix-all",
      rewrite: viteRewrite({
        "/:locale/about": {
          fr: "/:locale/a-propos",
          es: "/:locale/acerca-de",
        },
        "/:locale/products/:id": {
          fr: "/:locale/produits/:id",
          es: "/:locale/productos/:id",
        },
      }),
    },
    };
    
    export default config;
    
    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    import { nuxtRewrite } from "intlayer/routing";
    
    const config: IntlayerConfig = {
    internationalization: {
      locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      defaultLocale: Locales.ENGLISH,
    },
    routing: {
      mode: "prefix-all",
      rewrite: nuxtRewrite({
        "/[locale]/about": {
          fr: "/[locale]/a-propos",
          es: "/[locale]/acerca-de",
        },
        "/[locale]/products/[id]": {
          fr: "/[locale]/produits/[id]",
          es: "/[locale]/productos/[id]",
        },
      }),
    },
    };
    
    export default config;
    
    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    import { svelteKitRewrite } from "intlayer/routing";
    
    const config: IntlayerConfig = {
    internationalization: {
      locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      defaultLocale: Locales.ENGLISH,
    },
    routing: {
      mode: "prefix-all",
      rewrite: svelteKitRewrite({
        "/[locale]/about": {
          fr: "/[locale]/a-propos",
          es: "/[locale]/acerca-de",
        },
        "/[locale]/products/[id]": {
          fr: "/[locale]/produits/[id]",
          es: "/[locale]/productos/[id]",
        },
      }),
    },
    };
    
    export default config;
    

    تدعم هذه الميزة مباشرةً في Next.js و Vite عبر بروكسيات Intlayer، ويمكن دمجها بسهولة مع موجهات أخرى مثل TanStack Router و React Router و Vue Router و SvelteKit و Solid Router.

    لمزيد من المعلومات ودلائل التكامل، راجع توثيق إعادة كتابة عناوين URL المخصصة.

    قيم الإدراج المحسّنة

    في الإصدار v8، يمكن لقيم الإدراج الآن قبول عناصر React (أو عقد Vue) بالإضافة إلى السلاسل النصية والأرقام. يتيح لك هذا حقن مكونات غنية وتفاعلية مباشرة في قوالب الإدراج الخاصة بك.

    يتعامل Intlayer الآن بشكل متين مع العقد المتداخلة من React وPreact داخل الإدخالات، مما يضمن الحفاظ على هياكل واجهة المستخدم المعقدة وعرضها بشكل صحيح.

    مثال:

    src/example.content.ts
    import { insert } from "intlayer";
    
    export default {
      key: "my-key",
      content: {
        myInsertion: insert("مرحبًا {{name}}"),
      },
    };
    
    tsx
    import { useIntlayer } from "next-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    
    return (
    <div>
      {myInsertion({
        name: 2, // رقم
        // أو
        name: "John", // نص
        // أو
        name: <span>John</span>, // عنصر React
      })}
    </div>
    );
    
    tsx
    import { useIntlayer } from "react-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    
    return (
    <div>
      {myInsertion({
        name: 2, // عدد
        // أو
        name: "John", // نص
        // أو
        name: <span>John</span>, // عنصر React
      })}
    </div>
    );
    
    vue
    <script setup>
    import { h } from "vue";
    import { useIntlayer } from "vue-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    </script>
    
    <template>
    <div>
      <component
        :is="myInsertion({
          name: 2,
          // أو
          name: 'John',
          // أو
          name: h('span', 'John'),
        })"
      />
    </div>
    </template>
    
    tsx
    import { useIntlayer } from "preact-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    
    return (
    <div>
      {myInsertion({
        name: 2, // رقم
        // أو
        name: "John", // سلسلة
        // أو
        name: <span>John</span>, // عنصر Preact
      })}
    </div>
    );
    
    tsx
    import { useIntlayer } from "solid-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    
    return (
    <div>
      {myInsertion({
        name: 2, // رقم
        // أو
        name: "John", // سلسلة
        // أو
        name: <span>John</span>, // عنصر Solid
      })}
    </div>
    );
    
    svelte
    <script>
    import { useIntlayer } from "svelte-intlayer";
    
    const { myInsertion } = useIntlayer("my-key");
    </script>
    
    <div>
    {myInsertion({
      name: 2, // عدد
      // or
      name: "John", // سلسلة
    })}
    </div>
    
    typescript
    import { Component } from "@angular/core";
    import { useIntlayer } from "angular-intlayer";
    
    @Component({
    selector: "app-insertion-example",
    template: `
      <div>
        {{ content().myInsertion({
          name: 'John'
        }) }}
      </div>
    `,
    })
    export class InsertionExampleComponent {
    content = useIntlayer("my-key");
    }
    

    قواعد الجمع في Unicode CLDR (v8.8.0)

    تم تقديم مساعد عقدة plural جديد يعتمد على قواعد الجمع المحددة بواسطة مشروع Unicode CLDR، مما يحسن دعم اللغات المعقدة.

    src/openings.content.ts
    import { plural, t, type Dictionary } from "intlayer";
    
    const openingsContent = {
      key: "total_openings",
      content: {
        totalOpenings: t({
          en: plural({
            one: "{{count}} opening",
            other: "{{count}} openings",
          }),
          fr: plural({
            one: "{{count}} offre",
            other: "{{count}} offres",
          }),
        }),
      },
    } satisfies Dictionary;
    
    export default openingsContent;
    

    يمكنك بعد ذلك تمرير العدد ديناميكيًا في مكون إطار العمل الخاص بك:

    tsx
    import type { FC } from "react";
    import { useIntlayer } from "react-intlayer";
    
    const OpeningsComponent: FC<{ count: number }> = ({ count }) => {
      const { totalOpenings } = useIntlayer("total_openings");
    
      return (
        <div>
          {/* بالإنجليزية:                                  */}
          {/*  count=0  → "0 openings"   (other)           */}
          {/*  count=1  → "1 opening"    (one)             */}
          {/*  count=2  → "2 openings"   (other)           */}
          {/*  count=21 → "21 openings"  (other)           */}
          <p>{totalOpenings(count)}</p>
        </div>
      );
    };
    

    لمزيد من المعلومات، راجع توثيق الجمع.

    التحقق من صحة مخطط المحتوى

    تقدم Intlayer v8 التحقق من صحة المخططات للقواميس. يمكنك الآن تعريف مخططات تحقق قابلة لإعادة الاستخدام في إعداداتك باستخدام Zod وتطبيقها على ملفات المحتوى الخاصة بك. يضمن ذلك التزام محتواك دائمًا بالهيكل المتوقع واكتشاف الأخطاء أثناء وقت البناء.

    1. تعريف المخططات

    عَرِّف مخططاتك في intlayer.config.ts:

    intlayer.config.ts
    import { z } from "zod";
    
    export default {
      schemas: {
        "seo-metadata": z.object({
          title: z.string().min(50).max(60),
          description: z.string().min(150).max(160),
        }),
      },
    };
    

    2. تطبيق المخططات على القواميس

    أشر إلى مفتاح المخطط في تعريف القاموس الخاص بك:

    src/example.content.ts
    import { type Dictionary } from "intlayer";
    
    const aboutPageMetaContent = {
      key: "about-page-meta",
      schema: "seo-metadata", // <-- اسم المخطط المشار إليه
      content: {
        title: "حول شركتنا - تعرّف علينا أكثر",
        description: "اكتشف مهمة شركتنا وقيمها وفريق العمل.",
      },
    } satisfies Dictionary;
    
    export default aboutPageMetaContent;
    

    إذا لم يتطابق المحتوى مع المخطط (مثلاً، كان العنوان قصيراً جداً)، فستؤدي عملية البناء إلى رفع خطأ.

    TypeScript: IntlayerNode Primitive Accessors

    تم تحديث نوع IntlayerNode للسماح باستدعاء دوال JavaScript البدائية مباشرة على عقد المحتوى. هذا يجعل من الممكن التفاعل مع المحتوى المترجم الخاص بك مباشرة كما لو كان سلسلة نصية قياسية، رقم، قيمة منطقية، أو مصفوفة بدائية.

    مدعوم عبر React، Preact، Solid، Svelte، Vue، و Angular.

    مثال على السلسلة النصية

    typescript
    content.placeholder; // Returns IntlayerNode<string>
    content.placeholder.value; // Returns string
    content.placeholder.toString(); // Returns string
    content.placeholder.toLowerCase(); // Returns string
    String(content.placeholder); // Returns string
    content.placeholder.toUpperCase(); // Returns uppercased string
    content.placeholder.replace("a", "b"); // Returns modified string
    

    مثال على المصفوفة

    typescript
    content.myArrayOfString             // Returns IntlayerNode<Array<string>>
    content.myArrayOfString.find(...)   // Returns element
    content.myArrayOfString.join(', ')  // Returns joined string
    

    الكشف التلقائي المحسَّن للمحتوى

    في الإصدار v8، يقوم Intlayer باكتشاف صيغة Markdown وعلامات HTML وإدراج المتغيرات داخل سلاسل المحتوى بذكاء. هذا يعني أنه يمكنك غالبًا الاستغناء عن دوال المساعدة مثل md()، html()، أو insert().

    هذا السلوك مفعلٌ افتراضيًا. يمكنك الآن ضبط هذا الكشف بدقة إما على مستوى الإعدادات العامة في intlayer.config.ts أو لكل قاموس على حدة.

    تحكم دقيق

    يمكنك تفعيل أو تعطيل أنواع محددة من التحويلات:

    intlayer.config.ts
    export default {
      dictionary: {
        // contentAutoTransformation: false (الافتراضي)
        contentAutoTransformation: {
          markdown: true,
          html: true,
          insertion: false, // تعطيل كشف الإدراج تلقائيًا
        },
      },
    };
    

    سلوك v7 (التغليف اليدوي):

    src/example.content.ts
    import { md, insert } from "intlayer";
    
    export default {
      key: "my-key",
      content: {
        myMarkdown: md("## Hello World"),
        myInsertion: insert("Hi {{name}}"),
      },
    };
    

    سلوك v8 (الكشف التلقائي):

    src/example.content.ts
    export default {
      key: "my-key",
      contentAutoTransformation: true, // يمكن تعيينه أيضًا عبر تعريف القاموس أو عالميًا في intlayer.config.ts
      content: {
        myMarkdown: "## Hello World", // تم اكتشافه تلقائيًا كـ Markdown
        myHTML: "<p>Hello World</p>", // تم اكتشافه تلقائيًا كـ HTML
        myInsertion: "Hi {{name}}", // تم اكتشافه تلقائيًا كـ Insertion
      },
    };
    

    يظل ناتج JSON الأساسي كما هو، محافظًا على معلومات النوع الغنية اللازمة لعملية العرض:

    json
    {
      "key": "my-key",
      "content": {
        "myMarkdown": {
          "nodeType": "markdown",
          "markdown": "## Hello World"
        },
        "myHTML": {
          "nodeType": "html",
          "html": "<p>Hello World</p>"
        },
        "myInsertion": {
          "nodeType": "insertion",
          "insertion": "Hi {{name}}"
        }
      }
    }
    

    التوطين: الخطاف الجديد useIntl

    يتوفر الآن خطاف useIntl() في React وNext.js وVue. يوفر هذا الخطاف كائن Intl مرتبطًا بالـ locale ويستخدم اللغة الحالية تلقائيًا لتنسيق الأرقام والتواريخ والمزيد، دون الحاجة إلى تمرير الـ locale يدويًا.

    tsx
    import { useIntl } from "next-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
    style: "currency",
    currency: "USD",
    }).format(123.45);
    
    tsx
    import { useIntl } from "react-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
    style: "currency",
    currency: "USD",
    }).format(123.45);
    
    vue
    <script setup>
    import { useIntl } from "vue-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
    style: "currency",
    currency: "USD",
    }).format(123.45);
    </script>
    
    tsx
    import { useIntl } from "preact-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
    style: "currency",
    currency: "USD",
    }).format(123.45);
    
    tsx
    import { useIntl } from "solid-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
    style: "currency",
    currency: "USD",
    }).format(123.45);
    
    svelte
    <script>
    import { useIntl } from "svelte-intlayer";
    
    const intl = useIntl();
    
    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    </script>
    
    typescript
    import { Component, computed } from "@angular/core";
    import { useIntl } from "angular-intlayer";
    
    @Component({
    selector: "app-intl-example",
    template: `<div>{{ formattedPrice() }}</div>`,
    })
    export class IntlExampleComponent {
    intl = useIntl();
    
    formattedPrice = computed(() =>
      new (this.intl().NumberFormat)({
        style: "currency",
        currency: "USD",
      }).format(123.45)
    );
    }
    

    الأدوات: تحسينات امتداد VSCode

    تلقى امتداد Intlayer لـ VSCode تحديثات رئيسية في v8 لتبسيط سير عمل الترجمة الخاصة بك:

    • زمن البدء: تحسينات في الأداء عند فتح المشروع.
    • التخزين المؤقت: طبقة تخزين مؤقت محسّنة لتمكين التحقق من الصحة والإكمال التلقائي شبه الفوري.
    • اكتشاف المفاتيح غير المستخدمة والمفاتيح المكررة: ميزات جديدة لاكتشاف المفاتيح غير المستخدمة والمفاتيح المكررة عبر قواميسك تلقائيًا، مما يساعدك على الحفاظ على محتوى نظيف وفعّال.

    الأدوات: مراقب C++ و LSP المعتمد على OXC (v8.12.0)

    يجلب Intlayer v8.12.0 تحسينات كبيرة لتجربة المطور:

    • Parcel Watcher: تم ترحيل مراقب المحتوى من chokidar إلى @parcel/watcher، مستفيدًا من مراقبة الملفات الأصلية بـ C++ لتوفير تحديثات أسرع واستهلاك أقل للذاكرة بشكل ملحوظ.
    • بروتوكول خادم اللغة الجديد (LSP): يتوفر الآن LSP جديد تمامًا. تم بناؤه باستخدام تحليل يعتمد على OXC، ويساعد بيئة التطوير المتكاملة (IDE) ووكلاء الذكاء الاصطناعي على ربط استدعاءات useIntlayer('my-key') بملفات .content المقابلة لها بسلاسة، والعكس صحيح.

    لمزيد من التفاصيل، راجع توثيق LSP.

    تحسينات المجمّع

    يتضمن Intlayer الإصدار 8 طبقة تخزين مؤقت جديدة لمجمّع Markdown وHTML. هذا يضمن أن سلاسل المحتوى المتطابقة بنفس التهيئة يتم تحليلها مرة واحدة فقط، مما يقلل بشكل كبير من العبء أثناء إعادة العرض أو عند استخدام نفس المحتوى في أماكن متعددة.

    babel.config.js
    const {
    intlayerExtractBabelPlugin,
    intlayerOptimizeBabelPlugin,
    getExtractPluginOptions,
    getOptimizePluginOptions,
    } = require('@intlayer/babel');
    
    module.exports = {
    presets: ['next/babel'],
    plugins: [
      // استخراج المحتوى من المكونات إلى القواميس
      [intlayerExtractBabelPlugin, getExtractPluginOptions()],
      // تحسين الاستيراد عن طريق استبدال useIntlayer باستيرادات القواميس المباشرة
      [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],
    ],
    };
    
    vite.config.js
    import { defineConfig } from 'vite';
    import { intlayer, intlayerCompiler } from "vite-intlayer";
    
    export default defineConfig({
    plugins: [intlayer(), intlayerCompiler()],
    });
    

    بالنسبة لـ Vue / Svelte ستحتاج إلى تثبيت حزمة المترجم المناسبة:

    bash
    # من أجل Vue
    npm install @intlayer/vue-compiler
    
    bash
    # من أجل Svelte
    npm install @intlayer/svelte-compiler
    

    تحسينات البناء التجريبية: التصغير والتطهير (Minify & Purge) (v8.7.0)

    يقدم Intlayer v8.7.0 ميزات بناء تجريبية جديدة في ملف intlayer.config.ts الخاص بك، مصممة لتحسين حزمة الإنتاج الخاصة بك:

    • تصغير القواميس (Dictionary Minification): يقوم بتصغير ملفات القواميس لتقليل حجمها.
    • تطهير المفاتيح غير المستخدمة (Unused Key Purging): يقوم بمسح وإزالة مفاتيح الترجمة غير المستخدمة من القواميس، وإعادة تسمية المفاتيح النشطة إلى أحرف قصيرة (مثل "products" -> "a", "pricing" -> "b"). هذا يقلل من حجم الحزمة بنسبة تصل إلى 5%.
    • تعطيل فحوصات TypeScript: تسريع عمليات البناء عن طريق تعطيل فحص أنواع TypeScript أثناء خطوة التجميع.
    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH],
        defaultLocale: Locales.ENGLISH,
      },
      dictionary: {
        importMode: "dynamic",
      },
      build: {
        /**
         * تصغير القواميس لتقليل حجم الحزمة.
         */
        minify: true,
    
        /**
         * تطهير المفاتيح غير المستخدمة في القواميس
         */
        purge: true,
    
        /**
         * يشير إلى ما إذا كان البناء يجب أن يتحقق من أنواع TypeScript
         */
        checkTypes: false,
      },
    };
    
    export default config;
    

    المرونة: وضع استيراد موحّد

    تم إهمال الخاصية البوليانية live لصالح خاصية أكثر شمولاً تسمى importMode. تتيح هذه الخاصية تحديد صريح لكيفية تحميل القواميس: بشكل ثابت، أو ديناميكيًا، أو عبر مزامنة حية.

    الأوضاع

    • static (افتراضي): يتم تجميع القاموس في وقت البناء. الأفضل للأداء.
    • dynamic: يتم تحميل القاموس أثناء وقت التشغيل (مثلاً عبر جلب JSON أو باستخدام suspense).
    • fetch: يتم جلب القاموس من الـ CMS/الخادم أثناء وقت التشغيل ومزامنته.

    الترحيل:

    تكوين v7تكوين v8
    live: trueimportMode: 'fetch'
    live: falseimportMode: 'static' (أو 'dynamic')

    ملاحظة: في Intlayer v8، تم نقل الخاصية importMode من تهيئة build إلى تهيئة dictionary في intlayer.config.ts. هذا يتيح لك تحديد وضع استيراد افتراضي لجميع قواميسك مع الحفاظ على إمكانية تجاوزه على مستوى كل قاموس على حدة.

    مثال التهيئة العامة:

    intlayer.config.ts
    export default {
      dictionary: {
        importMode: "dynamic", // الافتراضي العام
      },
      // ...
    };
    

    مثال القاموس:

    src/example.content.ts
    export default {
        key: 'my-key',
        importMode: "fetch", // يتجاوز التهيئة العامة
        content: { ... }
    }
    

    التحكم في موقع القواميس

    تقدم النسخة v8 الخاصية location لإدارة مكان تواجد القواميس وكيفية تزامنها بشكل صريح. هذا مفيد بشكل خاص في سير عمل هجين يتضمن كلًا من الملفات المحلية ومحتوى أنظمة إدارة المحتوى (CMS) البعيدة.

    الخيارات

    • local: يتواجد القاموس محليًا فقط. لن يتم دفعه إلى نظام إدارة المحتوى (CMS) البعيد.
    • remote: يتم إدارة القاموس عن بُعد. بمجرد دفعه إلى نظام إدارة المحتوى (CMS)، سيتم فصله عن القاموس المحلي. وسيتم سحب القاموس البعيد من الـ CMS.
    • local_and_remote: يتواجد القاموس في كلا الموقعين. التغييرات المحلية تُدفع، والتغييرات البعيدة تُسحب (مزامنة).

    مثال:

    src/example.content.ts
    export default {
        key: 'my-key',
        location: "local", // احتفظ بهذا القاموس محليًا فقط
        content: { ... }
    }
    

    فصل تكوين النظام

    يفصل Intlayer v8 تكوين مصادر المحتوى عن المسارات الداخلية للنظام والإخراج. هذا ينظف خاصية content ويوضح أي الإعدادات مخصصة لإدارة المستخدم مقابل تلك التي يديرها نظام Intlayer.

    تم نقل الخصائص التالية من content إلى خاصية system الجديدة في intlayer.config.ts:

    • dictionariesDir
    • moduleAugmentationDir
    • unmergedDictionariesDir
    • typesDir
    • mainDir
    • configDir
    • cacheDir
    • outputFilesPatternWithPath

    سلوك v7:

    intlayer.config.ts
    export default {
      content: {
        contentDir: ["src"],
        dictionariesDir: ".intlayer/dictionary", // مدموجة مع إعدادات المصدر
      },
    };
    

    سلوك v8:

    intlayer.config.ts
    export default {
      content: {
        contentDir: ["src"],
      },
      system: {
        dictionariesDir: ".intlayer/dictionary", // مفصولة بوضوح
      },
    };
    

    فصل دلائل المحتوى وملفات الشيفرة

    Intlayer v8 يفصل إعدادات تعريف ملفات المحتوى عن إعدادات تحويل الشيفرة. هذا يتيح مراقبة ومسح أدق، مما يحسّن أداء عملية البناء.

    في السابق، كان يتم استخدام contentDir لكل من مراقبة ملفات .content.* ومسح الشيفرة بحثًا عن استدعاءات useIntlayer. الآن:

    • contentDir: مخصّص لملفات تعريف المحتوى الخاصة بك.
    • codeDir: مخصّص لشيفرة التطبيق التي تحتاج إلى تحويل (مثل: pruning، optimization).

    الترحيل:

    إذا كنت قد قمت سابقًا بتعيين contentDir، فسيستخدم Intlayer v8 هذا أيضًا كقيمة افتراضية لـ codeDir، لكنه سيعرض تحذيرًا. يجب عليك تعريف codeDir صراحةً في تكوينك.

    سلوك v7:

    intlayer.config.ts
    export default {
      content: {
        contentDir: ["src", "@packages/design-system"], // يُستخدم لكلٍ من المحتوى والشفرة
      },
    };
    

    سلوك v8:

    intlayer.config.ts
    export default {
      content: {
        contentDir: ["src/content", "@packages/design-system"], // راقب هنا فقط ملفات src/content/*.content.* وملفات @packages/design-system/dist/*.content.*
        codeDir: ["src", "@packages/design-system"], // امسح هنا فقط لتحويل الشفرة وملفات @packages/design-system/src/*.content.*
      },
    };
    

    إطار العمل: تحسينات Svelte

    يتم الآن تحليل محتوى Markdown و HTML في Svelte تلقائيًا إلى HTML عند تحويله إلى سلسلة (stringified). هذا يجعل استخدامه مع تركيب Svelte {@html} أسهل بكثير، إذ يمكنك الآن ببساطة تمرير عقدة المحتوى مباشرة.

    دعم Angular: مجمّع Vite (v8.11.0)

    لمستخدمي Angular، يدعم Intlayer الآن مجمّع Vite بشكل أصلي من خلال مكون إضافي جديد مخصص لـ esbuild، مما يسرع أوقات التطوير والبناء.

    للحصول على تفاصيل حول التكوين، راجع توثيق بيئة Angular.

    إنشاء خريطة الموقع (Sitemap) (v8.6.0)

    يقوم Intlayer الآن بإنشاء خرائط المواقع تلقائيًا بناءً على اللغات ووضع التوجيه الخاص بك. هذا مفيد بشكل خاص لتحسين محركات البحث (SEO) في معماريات الموجهات مثل TanStack Router:

    src/routes/sitemap.xml.ts
    import { createFileRoute } from "@tanstack/react-router";
    import { generateSitemap } from "intlayer";
    
    const SITE_URL = (
      import.meta.env.VITE_SITE_URL ?? "http://localhost:3000"
    ).replace(/\/$/, "");
    
    export const Route = createFileRoute("/sitemap.xml")({
      server: {
        handlers: {
          GET: async () => {
            const sitemap = generateSitemap(
              [
                { path: "/", changefreq: "daily", priority: 1.0 },
                { path: "/about", changefreq: "monthly", priority: 0.8 },
              ],
              { siteUrl: SITE_URL }
            );
    
            return new Response(sitemap, {
              headers: { "Content-Type": "application/xml" },
            });
          },
        },
      },
    });
    

    ملاحظات الترحيل من الإصدار v7

    تغييرات التكوين

    • خاصية live: تمت إزالة خاصية live من القواميس. استخدم importMode: 'fetch' بدلاً منها.
    • importMode: تم إهمال خاصية build.importMode في التكوين. استخدم dictionary.importMode بدلاً منها.
    • contentDir و codeDir: أصبح contentDir مخصّصًا الآن لملفات المحتوى. تمت إضافة خاصية جديدة codeDir لتحويل الكود. إذا لم يتم تعيين codeDir، فسيقوم Intlayer بالرجوع إلى contentDir وتسجيل تحذير.
    • التحقق من المخطط (Schema Validation): لاستخدام ميزة schema الجديدة، تأكد من تثبيت zod في مشروعك.

    روابط مفيدة