كيف قمنا بترجمة موقعنا إلى 9 لغات باستخدام Astro
أطلقنا توجيه اللغات المحلية لـ9 لغات في هذا السبرنت. إليك النسخة الصادقة لكيفية حدوث ذلك — بما في ذلك الخلل الذي كان يؤذينا بهدوء في الإنتاج قبل أن نلاحظه.
الاكتشاف
في السبرنت 1، بنينا سقالة i18n التي قد تتوقعها: ملفات JSON للغة المحلية لجميع اللغات التسع (الإنجليزية، الإسبانية، العربية، الألمانية، الفرنسية، اليابانية، البرتغالية، الروسية، الصينية)، ودالة مساعدة getTranslation()، ودالة getLocalePath() لبناء روابط تراعي اللغة المحلية، وعلامات hreflang في كل صفحة تشير إلى جميع المتغيرات اللغوية التسعة.
ما لم نبنِه: أي صفحات فعلية عند تلك الروابط المحلية.
كل صفحة في src/pages/ كانت مُثبَّتة بشكل صريح على const locale = "en" as const. كانت بنية الترجمة موجودة وتعمل — لكن لم يكن هناك شيء خلفها. هذا يعني أن BaseLayout.astro كان يُصدر علامات hreflang مثل https://proman365.com/es/pricing/ في كل صفحة، لروابط كانت تُرجع خطأ 404 في الإنتاج.
هذا ليس خللًا تجميليًا. تستخدم محركات البحث علامات hreflang لفهم أي الروابط هي متغيرات لغوية لبعضها البعض. الإعلان عن أخطاء 404 على نطاق واسع هو إشارة سلبية فعّالة لتحسين محركات البحث — يخبر الزواحف بأن بيانات موقعك الوصفية لا تطابق الواقع، ما يقوّض الثقة بكل بياناتك الوصفية، لا الجزء المعطوب فقط.
الإصلاح: استخلاص القوالب، لا التكرار
الإصلاح الساذج هو نسخ كل صفحة 8 مرات، مرة لكل لغة غير إنجليزية، وتثبيت ثابت لغة مختلف يدويًا في كل نسخة. رفضنا ذلك فورًا — 8 أضعاف الملفات يعني 8 أضعاف التعفن لحظة أن يلمس أحد صفحة وينسى النسخ السبع الأخرى.
النهج الذي اتبعناه بدلاً من ذلك: استخلاص محتوى كل صفحة إلى مكوّن قالب يأخذ locale كخاصية (prop)، ثم عرض ذلك القالب من نوعين من المسارات.
للصفحات الاثنتي عشرة من الفئة الأولى (الرئيسية، الأسعار، التواصل، الشركاء، المساعدة، وصفحات الميزات الست)، انتقلت كل واحدة من src/pages/*.astro إلى src/page-templates/*.astro، مع استبدال ثابت اللغة المُثبَّت بـ:
interface Props {
locale: Locale;
}
const { locale } = Astro.props;
يصبح المسار الإنجليزي الأصلي غلافًا رقيقًا — بضعة أسطر تستورد القالب فقط وتعرضه مع locale="en". مسار مرآة جديد تحت src/pages/[locale]/ يعرض نفس القالب لـ8 لغات غير إنجليزية، باستخدام getStaticPaths() لتوليد صفحة واحدة لكل لغة.
نجح هذا بسلاسة لأن منطق كل صفحة من الفئة الأولى — getTranslation(locale)، ومُنشئو علامات الميتا، وترميز المخطط — كان بالفعل موسَّطًا على ذلك الثابت locale الواحد من سقالة السبرنت 1. لم نكن نعيد تركيب i18n في هذه الصفحات؛ كنا أخيرًا نوصّل i18n الذي كان جالسًا دون استخدام.
النتيجة: 96 صفحة ثابتة جديدة (12 صفحة × 8 لغات) من طرح الفئة الأولى، تلاها تمرير ثانٍ يوسّع النمط نفسه إلى 64 صفحة مقارنة (8 منافسين × 8 لغات).
حجب hreflang خلف خاصية localized
إصلاح فجوة التوجيه لا يصلح تلقائيًا مشكلة hreflang — لا تزال بحاجة إلى أن تدّعي العلامات فقط ما هو صحيح فعليًا. أضفنا خاصية localized?: boolean إلى BaseLayout وPageLayout، بقيمة افتراضية false.
عندما تكون localized هي false، تُصدر الصفحة علامتي hreflang فقط: en وx-default. عندما تكون true، تُصدر المجموعة الكاملة من 10 (جميع اللغات التسع بالإضافة إلى x-default). فقط قوالب الفئة الأولى وصفحات المقارنة تمرر localized={true}.
كان جعل القيمة الافتراضية false خيار أمان مقصودًا. يجب على الصفحة أن تختار الادعاء بأن لديها 9 متغيرات لغوية. إذا أضاف أحدهم صفحة جديدة غدًا ونسي التفكير في اللغات، فإنها تفشل بأمان — بيانات وصفية إنجليزية فقط، لا جولة أخرى من الروابط الوهمية.
ما لم نترجمه عن قصد
لم يحصل كل شيء على معاملة اللغة المحلية، وكان ذلك قرارًا، لا سهوًا:
- المدونة تبقى بالإنجليزية فقط إلى أجل غير مسمى. هذه ممارسة معيارية لمدونات تسويق SaaS، والترجمة الآلية للمحتوى الطويل تنتج نصًا أسوأ من عدم ترجمته أصلاً. إذا برّرت التحليلات في النهاية محتوى مخصصًا لكل لغة، سنعيد النظر.
- الصفحات القانونية (الخصوصية، الشروط، سياسة ملفات تعريف الارتباط) تبقى بالإنجليزية. ذلك النص مُولَّد بواسطة Termly كنص قانوني؛ ترجمته ليست قرارًا نحن مؤهلون لاتخاذه من طرف واحد.
- صفحة 404 تبقى بالإنجليزية — الاستضافة الثابتة تخدم خطأ 404 واحدًا بغض النظر عن المسار المطلوب، فلا توجد طريقة نظيفة لترجمته دون نموذج استضافة مختلف.
- RSS كان بالفعل إنجليزيًا فقط ومستبعدًا بشكل صحيح من hreflang؛ لا حاجة لتغييرات هناك.
قائمة النقاط الرئيسية
إذا كنت تفعل شيئًا مشابهًا على موقع Astro ثابت:
- دقّق قبل أن تبني. تحقق مما إذا كانت علامات hreflang لديك تشير إلى صفحات موجودة فعليًا. إذا كانت سقالة i18n لديك تسبق التوجيه، فقد يكون لديك بالفعل هذا الخلل.
- استخلص القوالب، لا تكرر الصفحات. قالب واحد لكل صفحة، ومسارات غلاف رقيقة خاصة باللغة فوقها. يحدث التعفن على طبقة الغلاف إن حدث على الإطلاق، والأغلفة رخيصة الحفاظ على تزامنها.
- اجعل ادعاءات البيانات الوصفية الافتراضية أضيق بيان صحيح. علامة
localizedبقيمة افتراضية “لا” تعني أن الصفحات الجديدة لا يمكنها المبالغة في الادعاء بالخطأ. - قرر ما يبقى غير مترجم، عن قصد، ودوّنه. المدونة، والصفحات القانونية، وصفحات الأخطاء مرشحات معقولة للاستبعاد — لكن اجعله قرارًا موثَّقًا، لا صمتًا.
- الترجمة والتوجيه مشكلتان منفصلتان. إطلاق المسارات لا يتطلب إنهاء الترجمات — نص إنجليزي احتياطي في مسار لغة محلية حقيقي أكثر صدقًا من مفتاح ترجمة يعمل دون مسار خلفه.
لا يزال أمامنا عمل ترجمة يدوي — الكثير من النصوص في ملفات اللغة غير الإنجليزية هي عناصر نائبة إنجليزية بانتظار مترجم بشري. لكن الروابط حقيقية الآن، وتوقفت البيانات الوصفية عن الكذب. كانت تلك هي المشكلة الأكثر إلحاحًا.
Alex Rivera
مدير مشاريع ومستشار سير عمل. يساعد الفرق في إيجاد الأدوات التي تناسب طريقة عملها الفعلية.