كيفية إنشاء خرائط مواقع متعددة اللغات في TanStack Start v1

تنظيم خرائط المواقع حسب اللغة للتوسع

المشكلة

تساعد خرائط المواقع محركات البحث في اكتشاف وزحف جميع صفحات الموقع. يمكن للموقع متعدد اللغات الذي يحتوي على مئات أو آلاف الصفحات لكل لغة أن ينشئ بسرعة خرائط مواقع ضخمة. قد يصبح ملف واحد يسرد كل عنوان URL لكل لغة صعب الاستخدام وقد يتجاوز حدود 50,000 عنوان URL أو حجم 50 ميجابايت المحددة في بروتوكول خريطة الموقع. عندما تقوم بتحديث بنية لغة واحدة، يجب عليك إعادة إنشاء الملف بأكمله والتحقق من صحته. خرائط المواقع الأحادية الكبيرة يصعب صيانتها وبطيئة المعالجة ولا تتوسع مع إضافة لغات أو محتوى.

الحل

قسّم خريطة موقعك إلى ملفات متعددة واستخدم ملف فهرس خريطة الموقع لتقديم العديد من خرائط المواقع في وقت واحد. قم بإنشاء فهرس خريطة موقع على المستوى الأعلى في /sitemap.xml يشير إلى خرائط مواقع منفصلة خاصة باللغة مثل /sitemap-en.xml و /sitemap-es.xml. تنسيق XML لملف فهرس خريطة الموقع مشابه لخريطة الموقع العادية ويتم تحديده بواسطة بروتوكول خريطة الموقع. هذا يبقي الملفات الفردية قابلة للإدارة، ويتيح لك تحديث كل لغة بشكل مستقل، ويتوسع بشكل جيد مع إضافة لغات أو صفحات جديدة.

الخطوات

1. إنشاء مساعد لتوليد XML لخريطة الموقع

قم ببناء وظيفة مساعدة تقوم بإنشاء XML صالح لخريطة الموقع من مصفوفة إدخالات URL.

export function generateSitemapXML(urls: Array<{ loc: string; lastmod?: string; changefreq?: string; priority?: number }>): string {
const entries = urls.map(url => {
  let entry = `  <url>
    <loc>${url.loc}</loc>`
  if (url.lastmod) entry += `
    <lastmod>${url.lastmod}</lastmod>`
  if (url.changefreq) entry += `
    <changefreq>${url.changefreq}</changefreq>`
  if (url.priority !== undefined) entry += `
    <priority>${url.priority}</priority>`
  entry += `
  </url>`
  return entry
}).join('
')

return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${entries}
</urlset>`
}

تقبل هذه الوظيفة مصفوفة من كائنات URL وتعيد سلسلة XML منسقة بشكل صحيح مع المساحة الاسمية والبنية المطلوبة.

2. إنشاء مساعد لتوليد ملف فهرس خريطة الموقع XML

قم ببناء دالة مساعدة ثانية تقوم بإنشاء فهرس خريطة موقع يشير إلى خرائط مواقع فرعية متعددة.

export function generateSitemapIndexXML(sitemaps: Array<{ loc: string; lastmod?: string }>): string {
const entries = sitemaps.map(sitemap => {
  let entry = `  <sitemap>
    <loc>${sitemap.loc}</loc>`
  if (sitemap.lastmod) entry += `
    <lastmod>${sitemap.lastmod}</lastmod>`
  entry += `
  </sitemap>`
  return entry
}).join('
')

return `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${entries}
</sitemapindex>`
}

يستخدم فهرس خريطة الموقع وسم جذر <sitemapindex> ويتضمن إدخال <sitemap> لكل خريطة موقع، مع إدخال فرعي <loc> لكل وسم أصلي.

3. تحديد مسار الخادم لفهرس خريطة الموقع الرئيسية

قم بإنشاء مسار خادم في /sitemap.xml يقوم بإرجاع فهرس خريطة الموقع الذي يسرد جميع خرائط المواقع الخاصة باللغات.

import { createFileRoute } from "@tanstack/react-router";
import { generateSitemapIndexXML } from "~/utils/sitemap";

const SUPPORTED_LOCALES = ["en", "es", "fr", "de"];
const BASE_URL = "https://example.com";

export const Route = createFileRoute("/sitemap")({
  server: {
    handlers: {
      GET: async () => {
        const sitemaps = SUPPORTED_LOCALES.map((locale) => ({
          loc: `${BASE_URL}/sitemap-${locale}.xml`,
          lastmod: new Date().toISOString().split("T")[0],
        }));

        const xml = generateSitemapIndexXML(sitemaps);

        return new Response(xml, {
          headers: {
            "Content-Type": "application/xml",
            "Cache-Control": "public, max-age=3600",
          },
        });
      },
    },
  },
});

يقوم هذا المسار بإنشاء فهرس يشير إلى خريطة موقع واحدة لكل لغة ويقدمها كملف XML مع ترويسات التخزين المؤقت المناسبة.

4. تحديد مسارات الخادم لخرائط المواقع الخاصة باللغات

قم بإنشاء مسار خادم ديناميكي يقوم بإنشاء خريطة موقع لكل لغة بناءً على معلمة اللغة المحلية.

import { createFileRoute } from "@tanstack/react-router";
import { generateSitemapXML } from "~/utils/sitemap";

const BASE_URL = "https://example.com";

async function getUrlsForLocale(locale: string) {
  return [
    { loc: `${BASE_URL}/${locale}`, changefreq: "daily", priority: 1.0 },
    {
      loc: `${BASE_URL}/${locale}/about`,
      changefreq: "monthly",
      priority: 0.8,
    },
    {
      loc: `${BASE_URL}/${locale}/contact`,
      changefreq: "monthly",
      priority: 0.8,
    },
  ];
}

export const Route = createFileRoute("/sitemap-$locale")({
  server: {
    handlers: {
      GET: async ({ params }) => {
        const { locale } = params;
        const urls = await getUrlsForLocale(locale);
        const xml = generateSitemapXML(urls);

        return new Response(xml, {
          headers: {
            "Content-Type": "application/xml",
            "Cache-Control": "public, max-age=3600",
          },
        });
      },
    },
  },
});

تدعم مسارات الخادم معلمات المسار الديناميكية بنفس طريقة TanStack Router، لذلك يقوم الملف المسمى بـ $locale بإنشاء مسار يقبل معلمة لغة محلية ديناميكية. يتم إنشاء كل خريطة موقع خاصة بلغة بشكل مستقل ويمكن تحديثها دون التأثير على اللغات الأخرى.

5. جلب عناوين URL من مصدر البيانات الخاص بك

استبدل دالة getUrlsForLocale المؤقتة بمنطق يجلب عناوين URL الفعلية من قاعدة البيانات أو نظام إدارة المحتوى أو تعريفات المسارات الخاصة بك.

async function getUrlsForLocale(locale: string) {
  const pages = await db.page.findMany({
    where: { locale, published: true },
    select: { slug: true, updatedAt: true },
  });

  return pages.map((page) => ({
    loc: `${BASE_URL}/${locale}/${page.slug}`,
    lastmod: page.updatedAt.toISOString().split("T")[0],
    changefreq: "weekly",
    priority: 0.7,
  }));
}

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