Handlebars

ترجمة قوالب Handlebars باستخدام Lingo.dev CLI

ما هو Handlebars؟

Handlebars هو محرك قوالب شائع يوفر القوة اللازمة لبناء قوالب دلالية بفعالية. يستخدم بناء جملة نظيفاً ويقوم بتجميع القوالب إلى دوال JavaScript، مما يجعله مستخدماً على نطاق واسع لإنشاء HTML في تطبيقات جانب العميل والخادم على حد سواء.

ما هو Lingo.dev CLI؟

Lingo.dev CLI هو واجهة سطر أوامر مجانية ومفتوحة المصدر لترجمة التطبيقات والمحتوى باستخدام الذكاء الاصطناعي. تم تصميمه ليحل محل برامج إدارة الترجمة التقليدية مع التكامل مع خطوط الأنابيب الحالية.

لمعرفة المزيد، راجع نظرة عامة.

حول هذا الدليل

يشرح هذا الدليل كيفية ترجمة قوالب Handlebars باستخدام Lingo.dev CLI.

ستتعلم كيفية:

  • هيكلة ملفات الترجمة لمشاريع Handlebars
  • تكوين خط أنابيب الترجمة
  • إنشاء الترجمات باستخدام الذكاء الاصطناعي

المتطلبات الأساسية

لاستخدام Lingo.dev CLI، تأكد من تثبيت Node.js الإصدار 18 أو أحدث:

❯ node -v
v22.17.0

نهج ترجمة Handlebars

يجب أن تشير قوالب Handlebars إلى المحتوى القابل للترجمة من ملفات JSON بدلاً من احتواء نص مشفر بشكل ثابت. يوفر هذا النهج:

  • فصل واضح: بنية القالب مقابل المحتوى القابل للترجمة
  • التحكم في الإصدار: تتبع الترجمات في ملفات JSON
  • عدم الغموض: تحديد ما هو قابل للترجمة بشكل صريح

للوصول إلى الترجمات في القوالب، ستحتاج إلى دالة مساعدة للترجمة. تشمل الخيارات الشائعة:

مساعد مخصص بسيط:

{{t "product.title"}}
{{t "greeting" name="John"}}

handlebars-i18n - غني بالميزات مع التنسيق:

{{__ "product.title"}}
{{_date releaseDate}}
{{_price amount "USD"}}

npm | GitHub

handlebars-i18next - تكامل بديل مع i18next:

{{t "product.title"}}

npm | GitHub

يستخدم هذا الدليل {{t}} في الأمثلة، لكن سير العمل ينطبق على أي اختيار مساعد آخر.

الخطوة 1. إعداد المشروع

في دليل مشروعك، أنشئ ملف i18n.json:

{
  "$schema": "https://lingo.dev/schema/i18n.json",
  "version": "1.10",
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {}
}

يحدد هذا الملف سلوك خط أنابيب الترجمة، بما في ذلك اللغات المراد الترجمة بينها ومكان وجود المحتوى القابل للترجمة في نظام الملفات.

لمعرفة المزيد حول الخصائص المتاحة، راجع i18n.json.

الخطوة 2. تكوين اللغة المصدر

اللغة المصدر هي اللغة والمنطقة الأصلية التي كُتب بها محتواك. لتكوين اللغة المصدر، اضبط خاصية locale.source في ملف i18n.json:

{
  "$schema": "https://lingo.dev/schema/i18n.json",
  "version": "1.10",
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {}
}

يجب توفير اللغة المصدر كـ علامة لغة BCP 47.

للحصول على القائمة الكاملة لرموز اللغات التي يدعمها Lingo.dev CLI، راجع رموز اللغات المدعومة.

الخطوة 3. تكوين اللغات المستهدفة

اللغات المستهدفة هي اللغات والمناطق التي تريد ترجمة محتواك إليها. لتكوين اللغات المستهدفة، اضبط خاصية locale.targets في ملف i18n.json:

{
  "$schema": "https://lingo.dev/schema/i18n.json",
  "version": "1.10",
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {}
}

الخطوة 4. إنشاء المحتوى المصدر

أنشئ ملفات JSON تحتوي على محتواك القابل للترجمة. يجب تنظيم هذه الملفات في بنية دليل تتضمن رمز اللغة المصدر:

project/
├── locales/
│   └── en/
│       ├── common.json
│       └── store.json
├── templates/
│   └── product.handlebars
└── i18n.json

سيتم إنشاء دليل es/ والملفات المترجمة تلقائيًا بواسطة Lingo.dev CLI عند إنشاء الترجمات في الخطوة 8.

أمثلة على ملفات JSON

locales/en/common.json:

{
  "navigation": {
    "home": "Home",
    "products": "Products",
    "about": "About",
    "contact": "Contact"
  },
  "footer": {
    "copyright": "All rights reserved",
    "privacy": "Privacy Policy",
    "terms": "Terms of Service"
  }
}

locales/en/store.json:

{
  "product": {
    "title": "Wireless Headphones",
    "description": "Premium sound quality with active noise cancellation",
    "price": "Price",
    "inStock": "In Stock",
    "outOfStock": "Out of Stock"
  },
  "cart": {
    "add": "Add to Cart"
  },
  "actions": {
    "buyNow": "Buy Now"
  }
}

الخطوة 5. إنشاء حاوية

  1. في ملف i18n.json، أضف كائن "json" إلى كائن buckets:

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "json": {}
      }
    }
    
  2. في كائن "json"، حدد مصفوفة من نمط واحد أو أكثر من أنماط include:

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "json": {
          "include": ["./locales/[locale]/*.json"]
        }
      }
    }
    

    تحدد هذه الأنماط الملفات المراد ترجمتها.

    الأنماط نفسها:

    • يجب أن تحتوي على [locale] كعنصر نائب للغة المحلية المكونة
    • يمكن أن تشير إلى مسارات الملفات (على سبيل المثال، "locales/[locale]/common.json")
    • يمكن استخدام النجوم كعناصر نائبة بدل (على سبيل المثال، "locales/[locale]/*.json")

    أنماط glob العودية (على سبيل المثال، **/*.json) غير مدعومة.

الخطوة 6. استخدام الترجمات في القوالب

أشر إلى مفاتيح الترجمة في قوالب Handlebars الخاصة بك باستخدام المساعد الذي اخترته:

templates/product.handlebars:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>{{t "product.title"}}</title>
</head>
<body>
  <nav>
    <a href="/">{{t "navigation.home"}}</a>
    <a href="/products">{{t "navigation.products"}}</a>
    <a href="/about">{{t "navigation.about"}}</a>
    <a href="/contact">{{t "navigation.contact"}}</a>
  </nav>

  <main>
    <article>
      <h1>{{t "product.title"}}</h1>
      <p>{{t "product.description"}}</p>

      <div class="price">
        <span>{{t "product.price"}}:</span>
        <span>$299.99</span>
      </div>

      <div class="stock">
        {{#if inStock}}
          <span class="available">{{t "product.inStock"}}</span>
        {{else}}
          <span class="unavailable">{{t "product.outOfStock"}}</span>
        {{/if}}
      </div>

      <div class="actions">
        <button class="primary">{{t "cart.add"}}</button>
        <button class="secondary">{{t "actions.buyNow"}}</button>
      </div>
    </article>
  </main>

  <footer>
    <p>{{t "footer.copyright"}}</p>
    <a href="/privacy">{{t "footer.privacy"}}</a>
    <a href="/terms">{{t "footer.terms"}}</a>
  </footer>
</body>
</html>

تعتمد كيفية تحميل هذه الترجمات وتجميع القوالب الخاصة بك على إعداد البناء الخاص بك ومكتبة المساعد المختارة.

الخطوة 7. تكوين نموذج لغوي كبير

يستخدم Lingo.dev CLI نماذج لغوية كبيرة (LLMs) لترجمة المحتوى باستخدام الذكاء الاصطناعي. لاستخدام أحد هذه النماذج، تحتاج إلى مفتاح API من مزود مدعوم.

للبدء بأسرع ما يمكن، نوصي باستخدام Lingo.dev Engine:

  1. سجل للحصول على حساب Lingo.dev.

  2. قم بتشغيل الأمر التالي:

    npx lingo.dev@latest login
    

    سيؤدي هذا إلى فتح المتصفح الافتراضي الخاص بك ويطلب منك المصادقة.

  3. اتبع التعليمات.

الخطوة 8. إنشاء الترجمات

في الدليل الذي يحتوي على ملف i18n.json، قم بتشغيل الأمر التالي:

npx lingo.dev@latest run

يقوم هذا الأمر بـ:

  1. قراءة ملف i18n.json.
  2. العثور على ملفات JSON التي تحتاج إلى ترجمة.
  3. استخراج المحتوى القابل للترجمة من الملفات.
  4. استخدام نموذج اللغة الكبير المكون لترجمة المحتوى المستخرج.
  5. كتابة المحتوى المترجم مرة أخرى إلى نظام الملفات.

في المرة الأولى التي يتم فيها إنشاء الترجمات، يتم إنشاء ملف i18n.lock. يتتبع هذا الملف المحتوى الذي تمت ترجمته، مما يمنع إعادة الترجمة غير الضرورية في عمليات التشغيل اللاحقة.

مثال

بنية المشروع

handlebars-localization/
├── locales/
│   ├── en/
│   │   ├── common.json
│   │   └── store.json
│   └── es/
│       ├── common.json
│       └── store.json
├── templates/
│   └── product.handlebars
└── i18n.json

locales/en/common.json

{
  "navigation": {
    "home": "Home",
    "products": "Products",
    "about": "About",
    "contact": "Contact"
  },
  "footer": {
    "copyright": "All rights reserved",
    "privacy": "Privacy Policy",
    "terms": "Terms of Service"
  }
}

locales/en/store.json

{
  "product": {
    "title": "Wireless Headphones",
    "description": "Premium sound quality with active noise cancellation",
    "price": "Price",
    "inStock": "In Stock",
    "outOfStock": "Out of Stock"
  },
  "cart": {
    "add": "Add to Cart"
  },
  "actions": {
    "buyNow": "Buy Now"
  }
}

locales/es/common.json

{
  "navigation": {
    "home": "Inicio",
    "products": "Productos",
    "about": "Acerca de",
    "contact": "Contacto"
  },
  "footer": {
    "copyright": "Todos los derechos reservados",
    "privacy": "Política de privacidad",
    "terms": "Términos de servicio"
  }
}

locales/es/store.json

{
  "product": {
    "title": "Auriculares inalámbricos",
    "description": "Calidad de sonido premium con cancelación activa de ruido",
    "price": "Precio",
    "inStock": "En stock",
    "outOfStock": "Agotado"
  },
  "cart": {
    "add": "Añadir al carrito"
  },
  "actions": {
    "buyNow": "Comprar ahora"
  }
}

templates/product.handlebars

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>{{t "product.title"}}</title>
</head>
<body>
  <nav>
    <a href="/">{{t "navigation.home"}}</a>
    <a href="/products">{{t "navigation.products"}}</a>
    <a href="/about">{{t "navigation.about"}}</a>
    <a href="/contact">{{t "navigation.contact"}}</a>
  </nav>

  <main>
    <article>
      <h1>{{t "product.title"}}</h1>
      <p>{{t "product.description"}}</p>

      <div class="price">
        <span>{{t "product.price"}}:</span>
        <span>$299.99</span>
      </div>

      <div class="stock">
        {{#if inStock}}
          <span class="available">{{t "product.inStock"}}</span>
        {{else}}
          <span class="unavailable">{{t "product.outOfStock"}}</span>
        {{/if}}
      </div>

      <div class="actions">
        <button class="primary">{{t "cart.add"}}</button>
        <button class="secondary">{{t "actions.buyNow"}}</button>
      </div>
    </article>
  </main>

  <footer>
    <p>{{t "footer.copyright"}}</p>
    <a href="/privacy">{{t "footer.privacy"}}</a>
    <a href="/terms">{{t "footer.terms"}}</a>
  </footer>
</body>
</html>

i18n.json

{
  "$schema": "https://lingo.dev/schema/i18n.json",
  "version": "1.10",
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {
    "json": {
      "include": ["./locales/[locale]/*.json"]
    }
  }
}

i18n.lock

version: 1
checksums:
  8a4f2c9e1d6b3a7f5e8c2d1b9a3f6e4c:
    navigation.home: 7b2e4f9a1c8d3b6f5e2a9d1c8b4f7e3a
    navigation.products: 3f8e2a9d1c6b4f7e5a2c9d1b8f4e7a3b
    navigation.about: 9d1c8b4f7e3a2f9e1d6b3a7f5e8c2d1b
    navigation.contact: 4f7e3a2c9d1b8f6e5a3f2d9c1b7e4a8f
    footer.copyright: 2c9d1b8f4e7a3b6f5e2a9d1c8b4f7e3a
    footer.privacy: 8b4f7e3a2c9d1b6f5e2a9d1c8f4e7a3b
    footer.terms: 6f5e2a9d1c8b4f7e3a2c9d1b8f4e7a3b
  3b6f5e2a9d1c8b4f7e3a2c9d1b8f4e7a:
    product.title: 1c8b4f7e3a2c9d1b6f5e2a9d1c8f4e7a
    product.description: 7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c9d
    product.price: 9d1b6f5e2a9d1c8b4f7e3a2c9d1b8f4e
    product.inStock: 4f7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c
    product.outOfStock: 2c9d1b6f5e2a9d1c8b4f7e3a2c9d1b8f
    cart.add: 8b4f7e3a2c9d1b6f5e2a9d1c8b4f7e3a
    actions.buyNow: 7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c9d