Untitled

 avatar
unknown
plain_text
2 days ago
5.6 kB
3
No Index
import { defineConfig } from "astro/config";

import node from "@astrojs/node";

import auth from "auth-astro";
import type { AstroIntegration, RouteData } from "astro";

import sitemap, { type SitemapOptions } from "@astrojs/sitemap";

interface Route {
  path: string;
  locales: Record<string, string>;
}

function languageIntegration({
  routes,
  sitemapOptions,
}: {
  routes: Route[];
  sitemapOptions: SitemapOptions | false;
}): Array<AstroIntegration | undefined> {
  const paths = new Map<
    string,
    { route: Route; patterns: { pattern: RegExp; lang: string }[] }
  >();
  const sitemapPaths = new Map<
    Route,
    { linkedPaths: { page: string; lang: string; resourceId?: string }[] }
  >();
  const siteResources = new Map<string, string>();
  const sitemapPathsByUrl = new Map<string, Route>();
  return [
    {
      name: "language-route-handler",
      hooks: {
        "astro:config:setup": async ({ injectRoute }) => {
          for (const route of routes) {
            for (const [lang, path] of Object.entries(route.locales)) {
              const pattern = `/${lang}/${path}`;
              paths.set(pattern, { route, patterns: [] });
              injectRoute({
                entrypoint: `src/localized/${route.path}.astro`,
                pattern,
                prerender: true,
              });
            }
          }
        },
        "astro:route:setup": ({ route: routeOptions }) => {
          const route = routeOptions as RouteData;
          const oldGenerate = route.generate;

          if (!paths.has(route.route)) {
            console.log(route);
            return;
          }

          const [_, lang] = route.route.split("/");

          paths
            .get(route.route)
            ?.patterns.push({ pattern: route.pattern, lang });

          if (route.segments.length <= 1 || !lang) {
            return;
          }

          route.segments[0][0].dynamic = true;
          route.segments[0][0].content = "lang";
          route.origin = "project";
          route.pattern = new RegExp(
            route.pattern.source.replace(`^\\/${lang}\\/`, "^\\/([^/]+?)\\/")
          );
          route.params.unshift("lang");
          route.pathname = undefined;


          route.generate = (data) => {
            const res = oldGenerate({
              ...data,
              lang,
            });

            if (data.lang !== lang) {
              return "../";
            }

            if (data._resourceId) {
              siteResources.set(res, data._resourceId);
            }

            return res;
          };
        },
      },
    },
    sitemapOptions
      ? sitemap({
          ...sitemapOptions,
          filter: (page) => {
            const isFiltered = sitemapOptions?.filter?.(page) ?? true;

            if (!isFiltered) {
              return false;
            }

            const url = new URL(page);

            // Find matched pattern, this is pretty expensive, proof of concept though.
            for (const routeData of paths) {
              const { route, patterns } = routeData[1];
              for (const pattern of patterns) {
                if (pattern.pattern.test(url.pathname)) {
                  sitemapPaths.set(route, {
                    linkedPaths: [
                      ...(sitemapPaths.get(route)?.linkedPaths ?? []),
                      {
                        page,
                        lang: pattern.lang,
                        resourceId: siteResources.get(url.pathname.substring(0, url.pathname.length - 1)),
                      },
                    ],
                  });
                  sitemapPathsByUrl.set(page, route);
                }
              }
            }

            return isFiltered;
          },
          serialize(item) {
            const route = sitemapPathsByUrl.get(item.url);

            if (route) {
              const info = sitemapPaths.get(route);
              const url = new URL(item.url);
              const resourceId = siteResources.get(url.pathname.substring(0, url.pathname.length - 1));

              item.links = [
                ...(item.links ?? []),
                ...(info?.linkedPaths
                  .map((path) => ({
                    lang:
                      sitemapOptions.i18n?.locales[route.locales[path.lang]] ??
                      path.lang,
                    url: path.page,
                    resourceId: path.resourceId,
                  }))
                  .filter(
                    (path) => !path.resourceId || path.resourceId === resourceId
                  ) ?? []),
              ];
            }

            return item;
          },
        })
      : undefined,
  ];
}

// https://astro.build/config
export default defineConfig({
  site: "https://test.com",
  adapter: node({
    mode: "standalone",
  }),
  output: "server",

  i18n: {
    locales: ["es", "en", "pl"],
    defaultLocale: "en",
  },
  integrations: [
    auth(),
    ...languageIntegration({
      routes: [
        {
          path: "about-us",
          locales: {
            es: "sobre-nosotros",
            en: "about-us",
            pl: "dobre-nas",
          },
        },
        {
          path: "games/[game]",
          locales: {
            es: "juegos/[game]",
            en: "games/[game]",
            pl: "gry/[game]",
          },
        },
      ],
      sitemapOptions: {
        i18n: {
          defaultLocale: "en",
          locales: {
            en: "en-US",
            es: "es-ES",
            pl: "pl-PL",
          },
        },
      },
    }),
  ],
});
Editor is loading...
Leave a Comment