How to translate a game’s .po and .mo files (gettext)
The .po is the editable source; the .mo is the compiled catalog the game actually loads — which is why editing the .po alone changes nothing. RuneTranslate reads both, protects %s and {count} placeholders, refits plural forms to your language, and writes a working .mo back.
إذا فتحت مجلد لعبة ووجدت دليل locale مليئاً بملفات .po و.mo، فاللعبة مُوطَّنة باستخدام gettext — وصار بإمكان RuneTranslate ترجمتها كاملةً، من إنشاء المشروع حتى تصدير نسخة قابلة للعب.
يشرح هذا الدليل ما هما هذان النوعان من الملفات فعلياً، ولماذا لا يُغيِّر تحرير الملف الذي تستطيع قراءته شيئاً داخل اللعبة في العادة، وكيف تترجمهما بالشكل الصحيح.
.po مقابل .mo — الفارق الذي يتعثر فيه الجميع
هما صورتان للكتالوج نفسه:
- `.po` — Portable Object. ملف نصي عادي يمكنك فتحه في أي محرِّر. كل مدخل يحتوي على
msgid(النص الأصلي) وmsgstr(ترجمته). وهذا هو الملف الذي يعمل عليه المترجمون. - `.mo` — Machine Object. نسخة ثنائية مُصرَّفة من البيانات نفسها، مرتَّبة كي تعثر اللعبة على النص فوراً. وهذا هو الملف الذي تقرأه اللعبة أثناء التشغيل.
هذه النقطة الأخيرة تكلّف الناس بعد ظهيرة كاملة. يمكنك ترجمة كل سطر في ملف .po وحفظه وتشغيل اللعبة — ولا ترى أي تغيير، لأن اللعبة لا تفتح .po أصلاً. إنها تحمّل ملف .mo المجاور، وهو ما يزال يحمل النص القديم. في العادة تُصرِّف أحدهما إلى الآخر بأداة msgfmt من حزمة GNU gettext. أما RuneTranslate فيكتب الاثنين، فلا حاجة إلى خطوة تصريف منفصلة.
كيف يبدو مجلد لعبة تستخدم gettext
البنية المعيارية هي دليل locale مُفهرَس بحسب رمز اللغة:
MyGame/game.exeMyGame/locale/en/LC_MESSAGES/mygame.moMyGame/locale/fr/LC_MESSAGES/mygame.moMyGame/locale/de/LC_MESSAGES/mygame.mo
مجلد LC_MESSAGES جزء من العُرف وليس خطأً، وmygame هو نطاق النص — الاسم الذي تطلبه اللعبة عند تحميل نصوصها. وكثير من الألعاب يستخدم بنية أبسط مثل lang/fr.po، وهي تعمل أيضاً.
ما الألعاب التي تستخدم gettext؟
نشأ gettext في عالم يونكس وصار الطريقة الافتراضية لتوطين البرمجيات المكتوبة بلغة C وPython وكل ما يقوم على GTK. وفي الألعاب يعني ذلك:
- ألعاب Python وpygame
- Solarus وSDL ومحركات C/C++ الأخرى
- الألعاب المُوطَّنة عبر Poedit أو Weblate أو Crowdin، وكلها تتعامل مع PO أصلاً
- بعض مشاريع Godot التي تدعم PO مصدراً للترجمة
وهو أكثر شيوعاً بكثير في الألعاب المستقلة الغربية منه في اليابانية — فالمحركات اليابانية مثل Kirikiri وRPG Maker تحفظ نصوصها بصيغها الخاصة.
ترجمة لعبة gettext باستخدام RuneTranslate
- وجّه RuneTranslate إلى مجلد اللعبة. المجلد الذي يحتوي على
locale/أوlang/أوi18n/. يقرأ الاكتشاف البايتات الفعلية بدل الوثوق بالامتداد، فيُتجاهل ملف.moيكون في الحقيقة مشهداً ثلاثي الأبعاد بدل إنتاج مشروع معطوب. - راجع الملخّص. قبل إنشاء المشروع سترى عدد الكتالوجات، ونسبة ملفات
.moالمُصرَّفة إلى ملفات.poالمصدرية، واللغات التي تتضمنها اللعبة أصلاً، وإجمالي النصوص. - اختر لغة ومزوّد ترجمة. Google أو DeepL المجاني، أو مفتاحك الخاص من DeepL أو OpenAI أو Claude أو DeepSeek — راجع مقارنة المزوّدين.
- راجع ثم صدّر. ستحصل على نسخة كاملة من اللعبة والترجمة في موضعها.
أمران يفسدان ترجمة gettext بصمت
العناصر النائبة. msgid هو سلسلة تنسيق لا نص نهائي. ففي Hello, %s! يُستبدل اسم اللاعب أثناء التشغيل. وتميل المترجمات الآلية إلى حذف %s أو تباعده أو — مع صيغة بايثون المسمّاة %(player)s — ترجمة الكلمة داخله. والنتائج ليست شكلية: فحذف %s واحد يزيح كل الوسائط التالية، ومعظم المحركات تنهار مباشرة. يقنّع RuneTranslate كل عنصر نائب يجده (%s و%d و%(player)s و{count} و{0}) قبل إرسال النص إلى المزوّد، ثم يستعيده بعدها.
صيغ الجمع. للإنجليزية صيغتان («1 coin» و«5 coins»)، ولليابانية والتركية واحدة، وللروسية والبولندية ثلاث. ويعلن الكتالوج في ترويسته كم صيغة يستخدم، فإن لم يطابق هذا العدد اللغةَ تجاوز gettext نهاية القائمة وعاد بصمت إلى الأصل غير المترجَم. يعيد RuneTranslate ملاءمة الصيغ للغتك الهدف ويكتب الترويسة بما يوافقها.
لماذا يكتب التصدير الكتالوج مرتين
ينتج التصدير لغةً جديدة صحيحة — locale/<لغتك>/LC_MESSAGES/ — ونسخةً محدَّثة من الكتالوج الذي كانت اللعبة تحمّله بالفعل.
والثاني هو ما يجعل الترجمة تظهر حقاً. فاللعبة تقرر أي لغة تحمّل بطرق لا يكشفها المجلد: قد تقرأ لغة نظام التشغيل، أو ملف إعدادات، أو راية في المُشغِّل، أو تكون اللغة مثبَّتة في الشيفرة. وإضافة كتالوج عربي إلى لعبة لا تطلب سوى الإنجليزية ستتركك أمام نسخة تبدو بلا تغيير. أما الكتابة فوق الكتالوج الذي تحمّله فعلاً فتزيل هذا التخمين. ويحدث الأمران في النسخة المصدَّرة وحدها — ولا يُعدَّل مجلد اللعبة الأصلي.
أما النصوص التي لم تترجمها فتحتفظ بالترجمة التي شحنتها اللعبة، فلا يُفرِّغ مشروعٌ نصف مكتمل توطين المطوّر نفسه أبداً.
ما لا يستطيع هذا فعله
لا يُترجم إلا النص الموجود أصلاً في كتالوج. فإن كتب المطوّر نصاً مباشرةً في الشيفرة بدل تمريره عبر gettext، فهو ليس في .po ولا في .mo، ولا تستطيع أي أداة PO العثور عليه هناك. وهذا حدٌّ في الصيغة لا في الأداة.
كذلك يعامل RuneTranslate حقل msgid بوصفه النص المصدر، وهو ما يحدده gettext نفسه. وبعض المشاريع تضع msgid بالإنجليزية بينما تكون اللغة الأصلية الحقيقية في msgstr؛ وهذه ستُترجم من الإنجليزية.
وأخيراً، إذا كانت اللعبة تعمل على محرك مدعوم مباشرةً — Godot أو Unity أو Ren’Py — فذلك المحرك هو من يعالجها، حتى يبقى بقية نص اللعبة متاحاً أيضاً لا كتالوجاتها وحدها.
قبل أن تشاركها
شغّل النسخة المصدَّرة واقرأ بضع شاشات. القوائم والأزرار هي أسرع فحص، لأن معظم نص الكتالوج يعيش هناك. وإن كان هناك خلل — لم تُكتشف اللعبة، أو لم تعمل النسخة المصدَّرة، أو بقي النص بلغته الأصلية — فأبلغ عنه من قائمة المساعدة في التطبيق أو عبر Discord. نزّل RuneTranslate وافتح أول كتالوج لك.
مستعد لتجربة RuneTranslate؟
تفتح الباقة المجانية كل محرك + كل مزود ترجمة. باقة Supporter ($3/mo) تفتح السرعة الكاملة.
التنزيل لنظام Windows