From 473b13d0abdf9ad69de92bc877ea223cd2a5bd28 Mon Sep 17 00:00:00 2001 From: radishzzz Date: Mon, 17 Mar 2025 18:15:17 +0000 Subject: [PATCH] refactor: optimize all i18n route pages --- pnpm-lock.yaml | 8 +-- src/i18n/path.ts | 12 ++++ src/pages/[...about].astro | 17 +++-- src/pages/[...index].astro | 23 +++---- src/pages/[...posts_slug].astro | 108 ++++++++++++++------------------ src/pages/[...tags].astro | 35 ++++------- src/pages/[...tags_tag].astro | 40 +++++------- src/utils/content.ts | 15 ++++- 8 files changed, 125 insertions(+), 133 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c384e0..fc6d179 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1818,8 +1818,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 - eslint-plugin-jsdoc@50.6.7: - resolution: {integrity: sha512-8JrJRI6oSCHAdr5MvOD1L8nwywmiusk5RKfTisqq2rN5t65QmzmfBzAUkK0lbvwZ442HN33x+IbUon8d+axKoA==} + eslint-plugin-jsdoc@50.6.8: + resolution: {integrity: sha512-PPZVqhoXaalMQwDGzcQrJtPSPIPOYsSMtvkjYAdsIazOW20yhYtVX4+jLL+XznD4zYTXyZbPWPRKkNev4D4lyw==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -3862,7 +3862,7 @@ snapshots: eslint-plugin-antfu: 3.1.1(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-command: 3.1.0(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-import-x: 4.8.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - eslint-plugin-jsdoc: 50.6.7(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-jsdoc: 50.6.8(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-jsonc: 2.19.1(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-n: 17.16.2(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-no-only-tests: 3.3.0 @@ -5769,7 +5769,7 @@ snapshots: - supports-color - typescript - eslint-plugin-jsdoc@50.6.7(eslint@9.22.0(jiti@2.4.2)): + eslint-plugin-jsdoc@50.6.8(eslint@9.22.0(jiti@2.4.2)): dependencies: '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 diff --git a/src/i18n/path.ts b/src/i18n/path.ts index 8b83dbb..0afd4b8 100644 --- a/src/i18n/path.ts +++ b/src/i18n/path.ts @@ -2,6 +2,18 @@ import { defaultLocale, moreLocales } from '@/config' import { getLangFromPath, getNextGlobalLang } from '@/i18n/lang' import { cleanPath } from '@/utils/page' +/** + * Get path to tag page with language support + * @param tagName Tag name + * @param lang Current language code + * @returns Path to tag page + */ +export function getTagPath(tagName: string, lang: string): string { + return lang === defaultLocale + ? `/tags/${tagName}/` + : `/${lang}/tags/${tagName}/` +} + // Generates a localized path based on current language export function getLocalizedPath(path: string, currentLang?: string) { const clean = cleanPath(path) diff --git a/src/pages/[...about].astro b/src/pages/[...about].astro index 173ae84..eff0074 100644 --- a/src/pages/[...about].astro +++ b/src/pages/[...about].astro @@ -1,5 +1,5 @@ --- -import { allLocales, defaultLocale } from '@/config' +import { defaultLocale, moreLocales } from '@/config' import Layout from '@/layouts/Layout.astro' import { getCollection } from 'astro:content' @@ -13,18 +13,16 @@ export async function getStaticPaths() { // Default locale paths.push({ - params: { about: 'about' }, + params: { about: 'about/' }, props: { lang: defaultLocale }, }) // More locales - allLocales.forEach((lang: string) => { - if (lang !== defaultLocale) { - paths.push({ - params: { about: `${lang}/about` }, - props: { lang }, - }) - } + moreLocales.forEach((lang: string) => { + paths.push({ + params: { about: `${lang}/about/` }, + props: { lang }, + }) }) return paths @@ -32,6 +30,7 @@ export async function getStaticPaths() { const { lang } = Astro.props +// Get about page content with different language const allAboutEntries = await getCollection('about') const aboutEntry = allAboutEntries.find(entry => entry.data.lang === lang) || allAboutEntries.find(entry => entry.data.lang === '') diff --git a/src/pages/[...index].astro b/src/pages/[...index].astro index 2a69fd0..e973097 100644 --- a/src/pages/[...index].astro +++ b/src/pages/[...index].astro @@ -1,11 +1,10 @@ --- import PostList from '@/components/PostList.astro' -import { allLocales, defaultLocale } from '@/config' +import { defaultLocale, moreLocales } from '@/config' import Layout from '@/layouts/Layout.astro' import { getPinnedPosts, getPostsByYear } from '@/utils/content' export async function getStaticPaths() { - // 定义路径数组的类型 type PathItem = { params: { index: string | undefined } props: { lang: string } @@ -13,31 +12,31 @@ export async function getStaticPaths() { const paths: PathItem[] = [] - // 默认语言的首页 + // Default locale paths.push({ params: { index: undefined }, props: { lang: defaultLocale }, }) - // 更多语言的首页 - allLocales.forEach((lang: string) => { - if (lang !== defaultLocale) { - paths.push({ - params: { index: lang }, - props: { lang }, - }) - } + // More locales + moreLocales.forEach((lang: string) => { + paths.push({ + params: { index: `${lang}/` }, + props: { lang }, + }) }) return paths } const { lang } = Astro.props + const pinnedPosts = await getPinnedPosts(lang) const postsByYear = await getPostsByYear(lang) ---
+ {pinnedPosts.length > 0 && (
@@ -45,6 +44,7 @@ const postsByYear = await getPostsByYear(lang)
)} + {[...postsByYear.entries()].map(([_year, posts]) => (
@@ -52,5 +52,6 @@ const postsByYear = await getPostsByYear(lang)
))} +
diff --git a/src/pages/[...posts_slug].astro b/src/pages/[...posts_slug].astro index 8e4a2d9..4acb973 100644 --- a/src/pages/[...posts_slug].astro +++ b/src/pages/[...posts_slug].astro @@ -2,52 +2,48 @@ import type { CollectionEntry } from 'astro:content' import Comments from '@/components/Comments/index.astro' import PostDate from '@/components/PostDate.astro' -import { allLocales, defaultLocale } from '@/config' +import { allLocales, defaultLocale, moreLocales } from '@/config' +import { getTagPath } from '@/i18n/path' import Layout from '@/layouts/Layout.astro' -import { checkSlugDuplication } from '@/utils/content' +import { checkPostSlugDuplication } from '@/utils/content' import { generateDescription } from '@/utils/description' import { getCollection } from 'astro:content' export async function getStaticPaths() { const posts = await getCollection('posts') - const duplicates = await checkSlugDuplication(posts) + // Check if there are duplicate post slugs + const duplicates = await checkPostSlugDuplication(posts) if (duplicates.length > 0) { - throw new Error(`Slug conflicts found:\n${duplicates.join('\n')}`) + throw new Error(`Duplicate post slugs:\n${duplicates.join('\n')}`) } - // 创建slug到语言的映射 - const slugToLangs: Record = {} - - // 填充映射 - posts.forEach((post: CollectionEntry<'posts'>) => { + // Use a Map to store the relationship between post slugs and their supported languages + // Set is used to store the supported languages for each post + const slugToLangsMap = posts.reduce((map, post) => { const slug = post.data.abbrlink || post.slug - const lang = post.data.lang || defaultLocale + const lang = post.data.lang - // 如果文章没有指定语言,初始化为所有支持的语言 - if (!slugToLangs[slug]) { - if (!post.data.lang) { - slugToLangs[slug] = [...allLocales] // 文章支持所有语言 - } - else { - slugToLangs[slug] = [defaultLocale] // 仅默认语言和指定语言 - } + if (!map.has(slug)) { + map.set(slug, new Set(lang ? [lang] : allLocales)) + } + else if (lang) { + map.get(slug)?.add(lang) } - if (!slugToLangs[slug].includes(lang)) { - slugToLangs[slug].push(lang) - } - }) + return map + }, new Map>()) - // 对每个文章的supportedLangs按照allLocales的顺序排序 - Object.keys(slugToLangs).forEach((slug) => { - // 按照allLocales的顺序排序 - slugToLangs[slug].sort((a, b) => { - return allLocales.indexOf(a) - allLocales.indexOf(b) - }) - }) + // Convert Map> to Record structure + // Sort languages according to the order defined in allLocales + const slugToLangs = Object.fromEntries( + Array.from(slugToLangsMap.entries()).map(([slug, langs]) => [ + slug, + [...langs].sort((a, b) => allLocales.indexOf(a) - allLocales.indexOf(b)), + ]), + ) - // 定义路径数组的类型 + // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> type PathItem = { params: { posts_slug: string } props: { post: any, lang: string, supportedLangs: string[] } @@ -55,16 +51,16 @@ export async function getStaticPaths() { const paths: PathItem[] = [] - // 默认语言的文章页面 (没有语言前缀) + // Default locale posts.forEach((post: CollectionEntry<'posts'>) => { + // Show drafts in dev mode only if (import.meta.env.DEV || !post.data.draft) { const slug = post.data.abbrlink || post.slug - const postLang = post.data.lang || defaultLocale + const lang = post.data.lang - // 只有当文章语言是默认语言或没有指定语言时才生成默认语言路径 - if (postLang === defaultLocale || post.data.lang === '') { + if (lang === defaultLocale || lang === '') { paths.push({ - params: { posts_slug: `posts/${slug}` }, + params: { posts_slug: `posts/${slug}/` }, props: { post, lang: defaultLocale, @@ -75,23 +71,22 @@ export async function getStaticPaths() { } }) - // 更多语言的文章页面 (有语言前缀) - allLocales.forEach((lang: string) => { - if (lang !== defaultLocale) { - posts.forEach((post: CollectionEntry<'posts'>) => { - if ((import.meta.env.DEV || !post.data.draft) && (post.data.lang === lang || post.data.lang === '')) { - const slug = post.data.abbrlink || post.slug - paths.push({ - params: { posts_slug: `${lang}/posts/${slug}` }, - props: { - post, - lang, - supportedLangs: slugToLangs[slug] || [], - }, - }) - } - }) - } + // More locales + moreLocales.forEach((lang: string) => { + posts.forEach((post: CollectionEntry<'posts'>) => { + // Process posts with matching language or no language specified + if ((import.meta.env.DEV || !post.data.draft) && (post.data.lang === lang || post.data.lang === '')) { + const slug = post.data.abbrlink || post.slug + paths.push({ + params: { posts_slug: `${lang}/posts/${slug}/` }, + props: { + post, + lang, + supportedLangs: slugToLangs[slug] || [], + }, + }) + } + }) }) return paths @@ -100,13 +95,6 @@ export async function getStaticPaths() { const { post, lang, supportedLangs } = Astro.props const description = generateDescription(post, 'meta') const { Content, remarkPluginFrontmatter } = await post.render() - -// 构建标签链接 -function getTagUrl(tagName: string): string { - return lang === defaultLocale - ? `/tags/${tagName}/` - : `/${lang}/tags/${tagName}/` -} --- {post.data.tags.map((tag: string) => ( {tag} diff --git a/src/pages/[...tags].astro b/src/pages/[...tags].astro index ec53bdc..c01ddab 100644 --- a/src/pages/[...tags].astro +++ b/src/pages/[...tags].astro @@ -1,10 +1,10 @@ --- -import { allLocales, defaultLocale } from '@/config' +import { defaultLocale, moreLocales } from '@/config' +import { getTagPath } from '@/i18n/path' import Layout from '@/layouts/Layout.astro' import { getAllTags } from '@/utils/content' export async function getStaticPaths() { - // 定义路径数组的类型 type PathItem = { params: { tags: string } props: { lang: string } @@ -12,20 +12,18 @@ export async function getStaticPaths() { const paths: PathItem[] = [] - // 默认语言的标签索引页 + // Default locale paths.push({ - params: { tags: 'tags' }, + params: { tags: 'tags/' }, props: { lang: defaultLocale }, }) - // 更多语言的标签索引页 - allLocales.forEach((lang: string) => { - if (lang !== defaultLocale) { - paths.push({ - params: { tags: `${lang}/tags` }, - props: { lang }, - }) - } + // More locales + moreLocales.forEach((lang: string) => { + paths.push({ + params: { tags: `${lang}/tags/` }, + props: { lang }, + }) }) return paths @@ -33,24 +31,17 @@ export async function getStaticPaths() { const { lang } = Astro.props const allTags = await getAllTags(lang) - -// 构建标签链接 -function getTagUrl(tagName: string): string { - return lang === defaultLocale - ? `/tags/${tagName}/` - : `/${lang}/tags/${tagName}/` -} ---
diff --git a/src/pages/[...tags_tag].astro b/src/pages/[...tags_tag].astro index ff94257..3e8d118 100644 --- a/src/pages/[...tags_tag].astro +++ b/src/pages/[...tags_tag].astro @@ -1,11 +1,11 @@ --- import PostList from '@/components/PostList.astro' -import { allLocales, defaultLocale } from '@/config' +import { allLocales, defaultLocale, moreLocales } from '@/config' +import { getTagPath } from '@/i18n/path' import Layout from '@/layouts/Layout.astro' import { getAllTags, getPostsByTag } from '@/utils/content' export async function getStaticPaths() { - // 定义路径数组的类型 type PathItem = { params: { tags_tag: string } props: { tag: string, lang: string } @@ -13,26 +13,24 @@ export async function getStaticPaths() { const paths: PathItem[] = [] - // 默认语言的标签页面 (没有语言前缀) + // Default locale const defaultTags = await getAllTags(defaultLocale) defaultTags.forEach((tag: string) => { paths.push({ - params: { tags_tag: `tags/${tag}` }, + params: { tags_tag: `tags/${tag}/` }, props: { tag, lang: defaultLocale }, }) }) - // 更多语言的标签页面 (有语言前缀) - for (const lang of allLocales) { - if (lang !== defaultLocale) { - const langTags = await getAllTags(lang) - langTags.forEach((tag: string) => { - paths.push({ - params: { tags_tag: `${lang}/tags/${tag}` }, - props: { tag, lang }, - }) + // More locales + for (const lang of moreLocales) { + const langTags = await getAllTags(lang) + langTags.forEach((tag: string) => { + paths.push({ + params: { tags_tag: `${lang}/tags/${tag}/` }, + props: { tag, lang }, }) - } + }) } return paths @@ -42,22 +40,16 @@ const { tag, lang } = Astro.props const posts = await getPostsByTag(tag, lang) const allTags = await getAllTags(lang) -// 获取当前标签在每种语言下是否有文章 +// Check if tag has posts in each language, return language code if exists, null if not const tagSupportedLangs = await Promise.all( allLocales.map(async (locale) => { const postsInLang = await getPostsByTag(tag, locale) return postsInLang.length > 0 ? locale : null }), ) -// 过滤出支持当前标签的语言列表 -const supportedLangs = tagSupportedLangs.filter(Boolean) as string[] -// 构建标签链接 -function getTagUrl(tagName: string): string { - return lang === defaultLocale - ? `/tags/${tagName}/` - : `/${lang}/tags/${tagName}/` -} +// Filter to get supported languages +const supportedLangs = tagSupportedLangs.filter(Boolean) as string[] --- @@ -65,7 +57,7 @@ function getTagUrl(tagName: string): string {