لماذا يظهر النص المترجم مربّعات
ترجمت اللعبة، وانتهى التصدير بلا أخطاء، وصندوق الحوار مليء بـ □□□. هذه ليست مشكلة ترجمة في الغالب الأعم — إنها مشكلة خط، وإصلاحها يختلف عن العطلين اللذين يخلط الناس بينها وبينهما. إليك كيف تميّز رسم الحرف المفقود عن الحرف المحذوف عن تشويش الترميز، وكيف يُصلَح كل واحد منها في Unity وTextMeshPro وRen'Py وأدوات التشغيل.
انتهى التصدير، وانطلقت اللعبة، وكل سطر حوار صفٌّ من مستطيلات فارغة متطابقة. لا شيء في الترجمة خاطئ. النص في الملف هو تمامًا ما أعاده المزوّد، وإن فتحت ذلك الملف في محرّر نصوص قرأته صحيحًا. وما فشل هو آخر خطوة في السلسلة: الخط الذي تسلّمه اللعبة إلى مُظهِر الرسوم لا يملك رسمًا لتلك الحروف.
ما هو مربّع التوفو فعلًا
الخط جدول بحث من نقطة ترميز Unicode إلى شكل. وحين يُطلب من المُظهِر رسم نقطة ترميز لا يحويها الخط، يستبدل بها رسم الحرف المفقود الخاص بالخط — وهو عادةً مستطيل فارغ أو مشطوب، يُسمّى رسميًا .notdef ويُعرف في كل مكان آخر بـمربّع التوفو. وكل مربّع يساوي حرفًا واحدًا عجز الخط عن رسمه. هذه هي الآلية كاملة.
ويترتّب على ذلك أمران، وكلاهما مفيد في التشخيص. أولًا، عدد المربّعات يطابق عدد الأحرف: خمسة أحرف تايلندية تنتج خمسة مربّعات، لا سلسلة مشوّهة أقصر. ثانيًا، النص سليم في الذاكرة — لا تزال اللعبة تستطيع قياسه ومقارنته وحفظه وإعادة تحميله. البكسلات وحدها مفقودة. ولهذا يمكن أن تكون قائمة مترجمة غير مقروءة تمامًا ومع ذلك يعمل التنقّل فيها بشكل صحيح.
ثلاثة أعراض، وثلاث مشاكل مختلفة
معظم الالتباس حول "ترجمتي معطوبة" هو أناس يطبّقون إصلاح واحدة منها على أخرى. اقرأ شكل الضرر قبل أن تغيّر أي شيء.
- مربّعات □□□ — الحروف صحيحة، والخط عاجز عن رسمها. أصلح الخط.
- ???? — الحروف ذهبت. أعاد شيء ما ترميز النص إلى مجموعة محارف أضيق واستبدل بكل ما عجز عن تمثيله. ولا خط يستطيع إعادتها. أصلح الترميز، أو اختر لغة هدف تحتملها الصيغة.
- لاتينية مشوّهة مثل
テã‚ストأوテキストتظهرテキスト— تشويش ترميز (mojibake). البايتات صحيحة والمفكّك خاطئ: نصٌّ كُتب بترميز يُقرأ بترميز آخر. أصلح الترميز الذي يُقرأ به.
فاصل سريع: المربّعات والتشويش كلاهما يبقي عدد البايتات متناسبًا تقريبًا مع الأصل، لكن التشويش ينتج محارف نفاية ظاهرة ومتنوّعة، بينما ينتج التوفو مستطيلات متطابقة ومنتظمة. فالمنتظم يعني "خط". والمتنوّع يعني "ترميز".
المربّعات: رسم حرف مفقود
شحنت اللعبة بخط يغطي ما احتاجته هي وحدها. لا شيء في المسار معطوب — أنت طلبت نقطة ترميز لم يضمّنها الفنّان قط. والإصلاح دائمًا أن تعطي المُظهِر خطًا يملك الرسم، إمّا باستبدال الخط وإمّا بإضافة خط احتياطي يرجع إليه المُظهِر حين يعجز الخط الأساسي.
علامات الاستفهام: الحروف حُذفت
حين يجب كتابة نص عائدًا في صيغة تخزّن النصوص بترميز قديم أحادي أو ثنائي البايت، لا بدّ أن يصير كل حرف خارج ذلك الترميز شيئًا ما. وعُرفًا يكون ذلك الشيء ?. ويحتمل Shift-JIS وcp932 اليابانية وASCII وقليلًا جدًا غير ذلك؛ ولا يحتمل حقل ASCII صارم شيئًا من اليونانية أو السيريلية أو التايلندية أو CJK. وهذه خاصية في صيغة الملف لا في الخط، وتقع عند التصدير — فبحلول قراءة اللعبة للملف تكون المعلومة قد ضاعت.
وفي RuneTranslate محرّك واحد يمثّل فيه هذا حدًّا فعليًا، وهو مذكور لا مخفيّ: YU-RIS يعيد ترميز نصوصه بـ cp932، وهو ودود للمخرجات الإنجليزية وغيرها من اللاتينية لكنه يشحن التايلندية ?. والأهداف خارج cp932 على هذا المحرك تحتاج حيلة خط لم تُبنَ بعد.
اللاتينية المشوّهة: mojibake
النص الياباني المكتوب بـ Shift-JIS ثم المقروء بـ UTF-8 (أو العكس) ينتج سلاسل طويلة من حروف لاتينية بعلامات ومحارف رسم صناديق. ويظهر ذلك حين تكتب أداة ملفًا بالترميز الخطأ، أو حين يفترض محمّل اللعبة نفسه ترميزًا لم يستخدمه تصديرك. والإصلاح أن تكتب الملف بالترميز الذي يتوقّعه المحرك — لا أن تبدّل الخط، فذلك لن يغيّر شيئًا.
لماذا تتضرّر CJK والتايلندية أكثر من غيرها
تحتاج اللاتينية نحو مئة رسم حرف. وتحتاج اليابانية عدة آلاف، والصينية أكثر. وملفات الخطوط كبيرة، فتشحن الألعاب أصغر خط يغطي كتابتها هي، والتغطية التي ترثها تعتمد كليًا على اللغة التي بُنيت اللعبة لها.
- اللعبة المبنية لـاليابانية تحمل عادةً الكانا والكانجي الشائعة وASCII. ترجمها إلى الروسية أو اليونانية أو التايلندية أو الكورية وسيسقط كل حرف خارج ASCII.
- واللعبة المبنية لـالإنجليزية تحمل عادةً اللاتينية وحدها — فتفشل اليابانية والصينية والكورية والتايلندية واليونانية والسيريلية دفعةً واحدة.
- التايلندية هي أسوأ حالة عمليًا: فهي خارج كل خطوط الألعاب الشائعة، وتحتاج كذلك علامات حركات ونبرات تتركّب فوق الحرف الأساسي وتحته، فالخط الذي يملك نقاط الترميز تقنيًا قد يعرضها رديئة رغم ذلك.
- واللاتينية ليست آمنة تلقائيًا. تستخدم البولندية والتشيكية والمجرية والتركية والفيتنامية والرومانية محارف لاتينية موسّعة كثيرًا ما يغفلها خط بُني للإنجليزية أو اليابانية. ويضمّن RuneTranslate خطًا أوسع لتلك الأهداف تحديدًا على Ren'Py لأن "اللاتينية بخير" تبيّن أنها غير صحيحة.
Unity وTextMeshPro تحديدًا
لدى Unity نظاما نصوص، وهما يفشلان بشكل مختلف. يستخدم Text القديم في uGUI كائن Font. أما TextMeshPro — الذي تستخدمه معظم الألعاب الحديثة — فلا يستخدم ملف خط أثناء التشغيل إطلاقًا. بل يستخدم أصل خط TMP: أطلس نسيج من صور رسوم الحروف المُعدّة مسبقًا، مع جدول يربط نقاط الترميز بمواضعها في ذلك الأطلس.
ولهذا يملك أصل خط TMP مجموعة محارف ثابتة. فحين ولّده المطوّر اختار نطاق محارف — عادةً لغة الشحن وحدها — وخبز TMP تلك الرسوم بالضبط في الأطلس. وأصل الخط الساكن لا يستطيع عرض أي شيء خارج تلك المجموعة أبدًا، مهما أطعمته. أما أصل الخط الديناميكي فيحتفظ بمرجع إلى ملف الخط المصدر ويستطيع توليد رسوم جديدة عند الطلب، وهو الوضع الوحيد الذي يمكن أن يتوسّع ليغطي لغة لم يفكّر فيها المطوّر قط.
ومخرج TMP هو قائمة الاحتياط. لكل أصل خط قائمة m_fallbackFontAssets، ولإعدادات TMP قائمة احتياط عامة؛ وحين لا يملك الأصل الأساسي رسمًا لنقطة ترميز، يمشي TMP على تلك القوائم باحثًا عن واحد يملكه. وهذا هو الموضع الصحيح للتدخّل، لأنه يترك خط اللعبة نفسه مسؤولًا عن كل ما يستطيع رسمه — فتحتفظ الواجهة بمظهرها المقصود ولا تأتي من مكان آخر إلا المحارف التي تعجز عنها.
إصلاحها بأداة أثناء التشغيل
يربط XUnity.AutoTranslator اللعبة وهي تعمل، ويستطيع تبديل الخطوط من ملف إعداداته. والإعدادات المعنية، تحت [Behaviour]:
OverrideFont— يستبدل الخط الذي تستخدمه مكوّناتTextفي واجهة Unity القديمة. ويأخذ اسم خط تستطيع اللعبة أو النظام تحديده.OverrideFontTextMeshPro— يستبدل أصل خط TMP كليًا. وجّهه إلى ملف AssetBundle لخط TMP، أو إلى اسم أصل تملكه اللعبة أصلًا.FallbackFontTextMeshPro— الأأمن بين الاثنين: يضيف خطًا لا يرجع إليه TMP إلا للرسوم التي يفتقدها أصل اللعبة، تاركًا المحرف الأصلي في مكانه في كل ما عداها.- tmp_font_assetbundles — المجموعة التي يصونها المجتمع من حزم AssetBundle الجاهزة لخطوط TMP، وهي ما يُوجَّه إليه عادةً
OverrideFontTextMeshProوFallbackFontTextMeshPro. وهي مبنية لكل إصدار Unity، والحزمة المبنية لإصدار Unity غير إصدار اللعبة ستفشل في التحميل — ومطابقة الإصدار هي الخطوة التي يغفلها الناس.
والأداة أثناء التشغيل لكل جهاز ولكل إعداد: تصلح اللعبة على الحاسوب المثبّتة عليه، وأي شخص آخر يشغّل تلك النسخة يحتاج الإعداد نفسه. ويستطيع RuneTranslate قراءة ملف _AutoGeneratedTranslations.txt الخاص بالإضافة والكتابة فيه، فالمشروع الذي يستخدمها بالفعل ليس طريقًا مسدودًا — انظر المقارنة لمعرفة أين يناسب كل نهج.
إصلاحها على مستوى الملفات
يسلك RuneTranslate طريق الاحتياط مباشرةً في بيانات اللعبة. فعند تصدير Unity يحدّد إعدادات TMP في اللعبة، وأصل خط يصلح قالبًا، وخطًا، ثم يبني أصل خط TMP جديدًا في وضع Dynamic حول خط مضمّن يغطي الكتابة الهدف، ويلحقه بقائمة الاحتياط. وتُترك مدخلات الاحتياط الموجودة دون مساس، ويبقى خط اللعبة نفسه أساسيًا — فاللعبة اليابانية المترجمة إلى التايلندية تحتفظ بتنسيقها الأصلي لكل ما هو لاتيني، وتسحب رسوم التايلندية من الأصل المحقون.
وملاحظتان صادقتان على ذلك. يحتاج الأمر وجود إعدادات TMP وقالب أصل خط صالح وFont في الحاوية نفسها من أصول اللعبة؛ واللعبة التي ترتّبها بشكل مختلف قد تقع خارج ذلك. وحين يُتخطّى الحقن، يقول التصدير ذلك في تحذيراته بدل أن ينتهي أخضر — فالتصدير الذي يُشحن مربّعات يجب ألّا يبدو مطابقًا لتصدير ناجح. وإن رأيت ذلك التحذير، فطريق أداة التشغيل أعلاه هو الخطة البديلة.
ويصل Ren'Py إلى النتيجة نفسها بآلية أخرى، لأن Ren'Py بلا TMP: يستطيع RuneTranslate تضمين خط CJK أو غير لاتيني في النسخة المصدَّرة وتسجيله عبر config.font_replacement_map الخاص بـ Ren'Py، فيستبدله المحرك حيثما يقصّر خط اللعبة.
قائمة عمل
- انظر إلى الضرر. مستطيلات منتظمة، أو محارف
?، أو حروف مشوّهة — قرّر أيًّا من الثلاثة لديك قبل أن تلمس شيئًا. - إن كانت
?، فافتح الملف المصدَّر. فإن كانت علامات الاستفهام في الملف، فالحروف ضاعت وقت الكتابة ولن يفيد أي خط؛ تحقّق مما إذا كان ترميز نصوص المحرك يحتمل لغتك الهدف. - وإن كانت حروفًا مشوّهة، فتحقّق من الترميز الذي يتوقّعه المحرك لذلك الملف بدل الخط.
- وإن كانت مربّعات، فتأكّد أن محتوى الملف صحيح — وهو كذلك في الغالب — وعاملها كمهمة خط.
- على Unity، فضّل إضافة خط احتياطي على استبدال خط اللعبة. فالاستبدال يغيّر مظهر كل نص، بما فيه ما كان يُعرض جيدًا.
- وإن استخدمت AssetBundle لخط TMP، فطابقه مع إصدار Unity الخاص باللعبة.
- أعد التصدير وافحص المحارف بعينها التي كانت تفشل، لا أول سطر حوار فقط. فغالبًا ما تنجو اللاتينية الموسّعة وعلامات التايلندية من فحص عابر ثم تفشل في مكان آخر.
إلى أين بعد ذلك
للمسار الكامل في Unity — ما النص الذي تُخرجه Unity فعلًا، وما يبقى بعيد المنال — اقرأ كيفية ترجمة ألعاب Unity وصفحة محرك Unity. أما النص المخبوز في الرسومات بدل البيانات فمشكلة منفصلة بأداة منفصلة: انظر ترجمة الصور. والأسئلة الشائعة تغطي بقية مفاجآت التشغيل الأول الشائعة.
RuneTranslate مجاني الاستخدام مع فتح كل محرّك وكل مزوّد، منها ثلاثة لا تحتاج مفتاح واجهة إطلاقًا. يحلّل ملفات اللعبة نفسها ويصدّر نسخة مترجمة قابلة للعب تحتفظ بها. نزّله أو تصفّح المحرّكات المدعومة.
مستعد لتجربة RuneTranslate؟
تفتح الباقة المجانية كل محرك + كل مزود ترجمة. باقة Supporter ($3/mo) تفتح السرعة الكاملة.
التنزيل لنظام Windows
