
لا تحتاج إلى إعادة ترجمة كل شيء: كيف يعمل الترجمة التفاضلية في التكامل المستمر
By Robert M
لست بحاجة لإعادة ترجمة كل شيء: كيف تعمل الترجمة التفاضلية في CI
بمجرد أن تقوم بربط الترجمة الآلية في خط أنابيب CI الخاص بك، يظهر سؤال طبيعي بسرعة: هل يعيد هذا ترجمة ملف اللغة بالكامل في كل مرة يقوم فيها شخص ما بدفع تغيير؟
بدون وضع التفاضل، نعم. كل دفع يمس ملف اللغة المصدر الخاص بك يرسل الملف كاملاً إلى API، كل مفتاح، كل سلسلة، سواء تغيرت أم لا. بالنسبة لمشروع صغير في بدايته، هذا جيد. بالنسبة لمشروع ناضج يحتوي على مئات مفاتيح الترجمة عبر 10 أو 20 لغة، فأنت تستهلك رموزًا على سلاسل لم تتغير منذ التشغيل الأخير وتحصل على نفس المخرجات كميزة.
تحل الترجمة التفاضلية هذه المشكلة. بدلاً من إرسال الملف الكامل، يقارن الإجراء ملف المصدر الحالي مع خط الأساس المخزن، ويحدد فقط المفاتيح التي تمت إضافتها أو تعديلها، ويرسل فقط تلك إلى API. يتم أخذ المخرجات للمفاتيح غير المتغيرة من الملفات المترجمة الموجودة. ينخفض استخدام الرموز ليطابق العمل الفعلي المنجز.
كيف يعمل خط الأساس
عندما يعمل وضع التفاضل لأول مرة، أو عندما تجبر على تحديث كامل، يقوم الإجراء بترجمة ملف المصدر الكامل ويخزن تمثيل JSON مسطح له كملف خط أساس في مستودعك. في التشغيلات اللاحقة، يقوم الإجراء بتحميل ذلك الخط الأساس، ويقارن الفرق مع ملف المصدر الحالي، ويبني حمولة تحتوي فقط على المفاتيح التي تغيرت.
لملفات لغة JSON يتم تخزين خط الأساس كـ .polylingo-baseline.json في دليل الرسائل الخاص بك. لملفات لغة YAML يتم تخزينه كـ .polylingo-yaml-baseline.json في دليل اللغات. لملفات Laravel PHP lang يتم تخزينه كـ .polylingo-laravel-php-baseline.json في دليل lang.
يتم الالتزام بخط الأساس جنبًا إلى جنب مع ملفات الترجمة الخاصة بك بحيث يسافر مع المستودع. أي مطور يقوم باستنساخ المستودع يحصل على نفس خط الأساس الذي يعمل منه خط الأنابيب.
ما الذي يُعتبر تغييرًا
يعمل الفرق على تمثيل المفتاح المسطح لملف المصدر الخاص بك. يتم تسطيح الهياكل المتداخلة إلى مفاتيح بنقطة قبل المقارنة:
{
"nav.home": "الرئيسية",
"nav.about": "معلومات عنا",
"hero.title": "مرحبًا بك في منصتنا",
"hero.cta": "ابدأ الآن"
}
يتم تضمين المفتاح في حمولة التفاضل إذا:
- كان موجودًا في ملف المصدر الحالي وليس في خط الأساس (مفتاح جديد)
- كان موجودًا في كلاهما لكن القيمة تغيرت (مفتاح معدل) المفاتيح التي توجد في خط الأساس ولكن ليست في ملف المصدر الحالي (مفاتيح محذوفة) تُزال تلقائيًا من ملفات المخرجات المترجمة. المفاتيح المتطابقة في كلاهما تُتخطى تمامًا وتُترك ترجماتها الحالية في مكانها.
كيف يبدو هذا في الممارسة
لنفترض أن لديك مشروع Next.js يحتوي على 200 مفتاح ترجمة في messages/en.json، مترجمة بالفعل إلى 12 لغة. يقوم مطور بتحديث نص قسم البطل ويضيف مفتاحين جديدين لإعلان ميزة. هذا يعني 4 مفاتيح تغيرت من أصل 200.
بدون وضع التفاضل، يرسل خط الأنابيب جميع المفاتيح الـ 200 مضروبة عبر 12 لغة في كل دفع. مع وضع التفاضل يرسل 4 مفاتيح فقط. استخدام الرموز لذلك التشغيل هو حوالي 2% من تكلفة الترجمة الكاملة. كما أن خط الأنابيب أسرع لأنه هناك أقل لإرساله وأقل للانتظار.
على مدار شهر من التطوير المنتظم، يتراكم التوفير بشكل كبير. معظم الدفعات تمس عددًا قليلاً من السلاسل. إعادة الترجمة الكاملة تحدث فقط عند إضافة لغة جديدة أو إعادة تعيين خط الأساس صراحة.
الثلاثة إجراءات PolyLingo على GitHub
وضع التفاضل متاح عبر جميع إجراءات الترجمة الثلاثة من PolyLingo. كل واحد مبني لنوع محتوى وهيكل مشروع محدد.
translateAction — JSON و Markdown
الإجراء الأصلي. يتعامل مع ملفات لغة JSON المسطحة بأسلوب next-intl و i18next، مع تمرير توثيق Markdown اختياري عبر API الوظائف غير المتزامنة للملفات الأكبر.
- uses: UsePolyLingo/translate-action@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
source_file: messages/en.json
locales: fr,de,es,ja,zh
delta: true
commit: true
commit_message: "chore(i18n): sync translations"
خط أساس التفاضل: messages/.polylingo-baseline.json
github.com/UsePolyLingo/translateAction — عرض على السوق
translate-action-yaml — ملفات لغة YAML
للمشاريع التي تستخدم ملفات لغة YAML المتداخلة: Rails i18n، Vue i18n، وأي إطار عمل آخر يستخدم صيغة YAML. يتعامل الإجراء مع اتفاقية Rails لمفتاح لغة الجذر تلقائيًا — en.yml يحتوي على مفتاح جذر en:، وكل ملف مخرجات يحصل على مفتاح اللغة الهدف الصحيح (fr:, de: إلخ).
نظرًا لأن API الخاص بـ PolyLingo يعمل مع JSON بشكل أصلي، يقوم الإجراء بتسطيح YAML المتداخل إلى JSON بنقطة قبل الإرسال، يترجم، ثم يعيد بناء الهيكل المتداخل ويكتب مخرجات YAML صالحة. تحذير واحد في الإصدار v1 يستحق المعرفة: المفاتيح التي تحتوي على نقاط بشكل طبيعي غير مدعومة، لأنها تتعارض مع تسطيح النقطة.
- uses: UsePolyLingo/translate-action-yaml@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
locales_dir: config/locales
source_file: config/locales/en.yml
locales: fr,de,es,ja
delta: true
commit: true
خط أساس التفاضل: config/locales/.polylingo-yaml-baseline.json
github.com/UsePolyLingo/translate-action-yaml — عرض على السوق
translate-action-laravel — ملفات Laravel lang
لمشاريع Laravel التي تستخدم إما ملفات ترجمة JSON (lang/en.json، تدعم الهياكل المتداخلة والمسطحة بأسلوب Laravel 9+)، أو ملفات PHP array lang (lang/en/*.php). يكتشف الإجراء تلقائيًا أي صيغة يستخدمها مشروعك عبر php_format: auto — يتحقق أولاً من lang/en.json ثم يرجع إلى ملفات PHP array إذا لم يتم العثور عليها.
لملفات PHP، يستخدم CLI الخاص بـ PHP لقراءة ملفات المصدر ويحول المخرجات المترجمة مرة أخرى إلى صيغة مصفوفة PHP صالحة في JavaScript، بدون تبعيات إضافية. مشغلات GitHub المستضافة ubuntu-latest تتضمن PHP 8.x بشكل افتراضي لذا لا حاجة لخطوة إعداد إضافية. مطلوب PHP 7.4 أو أحدث.
تحذير واحد في الإصدار v1: المفاتيح التي تحتوي على نقاط غير مدعومة في وضع PHP بسبب استراتيجية تسطيح النقطة.
- uses: UsePolyLingo/translate-action-laravel@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
lang_dir: lang
source_locale: en
locales: fr,de,es,pt,nl
php_format: auto
delta: true
open_pr: true
خط أساس التفاضل: lang/.polylingo-laravel-json-baseline.json أو lang/.polylingo-laravel-php-baseline.json حسب الصيغة.
github.com/UsePolyLingo/translate-action-laravel — عرض على السوق
وضع PR مقابل وضع الالتزام
جميع الإجراءات الثلاثة تدعم وضعين للإخراج.
وضع الالتزام (commit: true) يكتب الملفات المترجمة ويلتزم بها مباشرة إلى الفرع الحالي. إعداد بسيط، جيد للفرق التي تعامل الترجمة كعملية آلية لا تحتاج مراجعة.
وضع PR (open_pr: true) ينشئ فرعًا جديدًا (polylingo/yaml-<sha>, polylingo/laravel-<sha> إلخ)، يكتب الملفات المترجمة هناك، ويفتح طلب سحب ضد فرع الأساس الخاص بك. أفضل للفرق التي تريد خطوة مراجعة بشرية قبل دمج المحتوى المترجم، أو للمشاريع التي تؤثر جودة الترجمة فيها مباشرة على تجربة المستخدم.
عندما يتم تعيين كلاهما، يفوز وضع PR.
يتطلب وضع PR أذونات pull-requests: write في أذونات سير العمل:
permissions:
contents: write
pull-requests: write
فرض تحديث كامل
يقارن وضع التفاضل مع خط الأساس المخزن. إذا كنت تريد إعادة ترجمة كل شيء بغض النظر عما يظهره خط الأساس، اضبط delta: false. هذا أيضًا يحدث خط الأساس ليطابق ملف المصدر الحالي، لذا تبدأ تشغيلات التفاضل اللاحقة من الحالة الجديدة.
التحديث الكامل مفيد عند إضافة لغة هدف جديدة، أو عندما تريد التقاط تحسينات جودة الترجمة في نسخة نموذج جديدة، أو عندما ينحرف خط الأساس عن الواقع لأي سبب.
- uses: UsePolyLingo/translate-action-yaml@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
locales_dir: config/locales
locales: fr,de,es,ja,zh,ko,ar
delta: false # تحديث كامل، يحدث خط الأساس
commit: true
المخرجات للخطوات اللاحقة
جميع الإجراءات الثلاثة تعرض نفس المخرجات حتى تتمكن من استخدامها في خطوات سير العمل التالية:
- uses: UsePolyLingo/translate-action@v1
id: translate
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
source_file: messages/en.json
locales: fr,de,es
delta: true
commit: true
- name: Log translation stats
run: |
echo "Locales translated: ${{ steps.translate.outputs.locales_translated }}"
echo "Files changed: ${{ steps.translate.outputs.files_changed }}"
echo "Tokens used: ${{ steps.translate.outputs.tokens_used }}"
كل تشغيل يكتب أيضًا جدول ملخص إلى ملخص خطوة GitHub Actions حتى تتمكن من رؤية استخدام الرموز ونتائج الترجمة دون الحاجة للتنقيب في السجلات.
البدء
جميع الإجراءات الثلاثة متاحة على سوق GitHub. ستحتاج إلى مفتاح API من PolyLingo، متاح مجانًا على usepolylingo.com. يشمل المستوى المجاني 50,000 رمز شهريًا. مع تمكين وضع التفاضل، ستبقى معظم المشاريع ضمن هذا الحد في دفعات التطوير الروتينية.
أضف مفتاح API الخاص بك كسري في المستودع (POLYLINGO_API_KEY) وضع الإجراء المناسب في سير العمل الخاص بك. يقوم التشغيل الأول بترجمة كاملة ويحدد خط الأساس. كل تشغيل بعد ذلك يترجم فقط ما تغير.