From e299cc39d452fd968a07c9ab627da6df18f66194 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:12:48 +0900 Subject: [PATCH] =?UTF-8?q?enhance(i18n):=20i18nRedirector=E3=81=ABdefault?= =?UTF-8?q?Locale=E3=81=AE=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AEmeta?= =?UTF-8?q?=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vitepress/config/index.ts | 25 +++++++- .vitepress/config/shared.ts | 1 + .vitepress/scripts/gen-i18n-redirector.ts | 69 ++++++++++++++++------- 3 files changed, 73 insertions(+), 22 deletions(-) diff --git a/.vitepress/config/index.ts b/.vitepress/config/index.ts index e23b4c4..4954dc5 100644 --- a/.vitepress/config/index.ts +++ b/.vitepress/config/index.ts @@ -5,7 +5,7 @@ import { shared } from './shared'; import { ja } from './ja'; import { en } from './en'; -import { genI18nRedirector } from '../scripts/gen-i18n-redirector'; +import { createGenI18nRedirector } from '../scripts/gen-i18n-redirector'; const locales = { ja: { label: '日本語', ...ja }, @@ -16,14 +16,24 @@ export const mainLocale = 'ja' as const satisfies keyof typeof locales; export const baseUrl = 'https://aiscript-dev.github.io'; +const { registerRouteMeta, genI18nRedirector } = createGenI18nRedirector(); + export default defineConfig({ ...shared, locales, transformHead(context) { - const head: HeadConfig[] = []; + const head: HeadConfig[] = [ ...context.head ]; if (!context.pageData.isNotFound) { const localesRegex = new RegExp(`^/(${Object.keys(locales).join('|')})`); - const canonical = '/' + context.page.replace(/\.md$/, '.html').replace(/\/index\.html$/, '/'); + const canonical = '/' + context.page.replace(/index\.(md|html)$/, '').replace(/\.md$/, context.siteConfig.cleanUrls ? '' : '.html'); + const defaultLocalePath = canonical.replace(localesRegex, `/${mainLocale}`); + + if (canonical.startsWith(`/${mainLocale}`)) { + registerRouteMeta(canonical.slice(1), { + title: context.title, + description: context.description, + }); + } for (const locale of Object.keys(locales)) { const localePath = canonical.replace(localesRegex, `/${locale}`); @@ -37,6 +47,15 @@ export default defineConfig({ }, ]); } + + head.push([ + 'link', + { + rel: 'alternate', + hreflang: 'x-default', + href: baseUrl + defaultLocalePath, + }, + ]); head.push([ 'link', diff --git a/.vitepress/config/shared.ts b/.vitepress/config/shared.ts index 7dd6ce8..a9ee277 100644 --- a/.vitepress/config/shared.ts +++ b/.vitepress/config/shared.ts @@ -28,6 +28,7 @@ export const shared = defineConfig({ head: [ ['link', { rel: 'icon', href: '/favicon.ico' }], ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/icons/apple-touch-icon.png' }], + ['meta', { property: 'og:site_name', content: 'AiScript' }], ], markdown: { diff --git a/.vitepress/scripts/gen-i18n-redirector.ts b/.vitepress/scripts/gen-i18n-redirector.ts index d871b5a..82a6cfd 100644 --- a/.vitepress/scripts/gen-i18n-redirector.ts +++ b/.vitepress/scripts/gen-i18n-redirector.ts @@ -1,7 +1,13 @@ +// @ts-expect-error Node import fs from 'fs'; import { mainLocale, baseUrl } from '../config'; import type { SiteConfig } from 'vitepress'; +type RouteMeta = { + title: string; + description?: string; +}; + async function createFile(path: string, content: string) { const dir = path.replace(/\/[^/]+$/, ''); await fs.promises.writeFile(path, content).catch((err) => { @@ -11,25 +17,43 @@ async function createFile(path: string, content: string) { }); } -export async function genI18nRedirector(siteConfig: SiteConfig) { - const routes = siteConfig.pages - .filter((page) => page.startsWith(`${mainLocale}/`)) - .map((page) => page.replace(new RegExp(`^${mainLocale}\/`), '').replace(/\.md$/, '.html')); +export function createGenI18nRedirector() { + const routeMeta = new Map(); + + function registerRouteMeta(route: string, meta: RouteMeta) { + routeMeta.set(route, meta); + } + + async function genI18nRedirector(siteConfig: SiteConfig) { + const genStartedAt = performance.now(); + + const routes = siteConfig.pages + .filter((page) => page.startsWith(`${mainLocale}/`)); + + const promises = routes.map(async (route) => { + const routePath = route.replace(new RegExp(`^${mainLocale}\/`), ''); + const routePathForWrite = routePath.replace(/\.md$/, '.html'); + const routePathForRender = routePath.replace(/index\.(md|html)$/, '').replace(/\.md$/, siteConfig.cleanUrls ? '' : '.html'); - const promises = routes.map((route) => { - const localeNames = Object.keys(siteConfig.site.locales); - const routeForRender = route.replace(/index\.html$/, ''); - const linkAlternate = localeNames.map((name) => ``).join('\n '); - const fallbackLinks = localeNames.map((name) => `${siteConfig.site.locales[name].label}`).join(', '); - const content = ` - + let title = 'Redirecting...'; + let description: string | null = null; + if (routeMeta.has(`${mainLocale}/${routePathForRender}`)) { + title = routeMeta.get(`${mainLocale}/${routePathForRender}`)?.title ?? title; + description = routeMeta.get(`${mainLocale}/${routePathForRender}`)?.description ?? null; + } + + const localeNames = Object.keys(siteConfig.site.locales); + const linkAlternate = localeNames.map((name) => ``).join('\n '); + const fallbackLinks = localeNames.map((name) => `${siteConfig.site.locales[name].label}`).join(', '); + const content = ` + - Redirecting... + ${title}${description ? `\n \n` : ''} ${linkAlternate} - - + + @@ -37,10 +61,17 @@ export async function genI18nRedirector(siteConfig: SiteConfig) { `; - return createFile(`${siteConfig.outDir}/${route}`, content); - }); - - await Promise.allSettled(promises); + await createFile(`${siteConfig.outDir}/${routePathForWrite}`, content); + }); + + await Promise.allSettled(promises); + + const genFinishedAt = performance.now(); + console.log(`I18n redirector generated in ${Math.round((genFinishedAt - genStartedAt) / 10) / 100}s`); + } - console.log('I18n redirector generated'); + return { + registerRouteMeta, + genI18nRedirector, + }; }