mirror of
https://github.com/reonokiy/blog.nokiy.net.git
synced 2025-06-16 11:41:17 +02:00
refactor: optimize all i18n route pages
This commit is contained in:
parent
0888b59c5f
commit
473b13d0ab
8 changed files with 125 additions and 133 deletions
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
|
@ -1818,8 +1818,8 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0
|
eslint: ^8.57.0 || ^9.0.0
|
||||||
|
|
||||||
eslint-plugin-jsdoc@50.6.7:
|
eslint-plugin-jsdoc@50.6.8:
|
||||||
resolution: {integrity: sha512-8JrJRI6oSCHAdr5MvOD1L8nwywmiusk5RKfTisqq2rN5t65QmzmfBzAUkK0lbvwZ442HN33x+IbUon8d+axKoA==}
|
resolution: {integrity: sha512-PPZVqhoXaalMQwDGzcQrJtPSPIPOYsSMtvkjYAdsIazOW20yhYtVX4+jLL+XznD4zYTXyZbPWPRKkNev4D4lyw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
|
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-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-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-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-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-n: 17.16.2(eslint@9.22.0(jiti@2.4.2))
|
||||||
eslint-plugin-no-only-tests: 3.3.0
|
eslint-plugin-no-only-tests: 3.3.0
|
||||||
|
@ -5769,7 +5769,7 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- 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:
|
dependencies:
|
||||||
'@es-joy/jsdoccomment': 0.49.0
|
'@es-joy/jsdoccomment': 0.49.0
|
||||||
are-docs-informative: 0.0.2
|
are-docs-informative: 0.0.2
|
||||||
|
|
|
@ -2,6 +2,18 @@ import { defaultLocale, moreLocales } from '@/config'
|
||||||
import { getLangFromPath, getNextGlobalLang } from '@/i18n/lang'
|
import { getLangFromPath, getNextGlobalLang } from '@/i18n/lang'
|
||||||
import { cleanPath } from '@/utils/page'
|
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
|
// Generates a localized path based on current language
|
||||||
export function getLocalizedPath(path: string, currentLang?: string) {
|
export function getLocalizedPath(path: string, currentLang?: string) {
|
||||||
const clean = cleanPath(path)
|
const clean = cleanPath(path)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import { allLocales, defaultLocale } from '@/config'
|
import { defaultLocale, moreLocales } from '@/config'
|
||||||
import Layout from '@/layouts/Layout.astro'
|
import Layout from '@/layouts/Layout.astro'
|
||||||
import { getCollection } from 'astro:content'
|
import { getCollection } from 'astro:content'
|
||||||
|
|
||||||
|
@ -13,18 +13,16 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
// Default locale
|
// Default locale
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { about: 'about' },
|
params: { about: 'about/' },
|
||||||
props: { lang: defaultLocale },
|
props: { lang: defaultLocale },
|
||||||
})
|
})
|
||||||
|
|
||||||
// More locales
|
// More locales
|
||||||
allLocales.forEach((lang: string) => {
|
moreLocales.forEach((lang: string) => {
|
||||||
if (lang !== defaultLocale) {
|
paths.push({
|
||||||
paths.push({
|
params: { about: `${lang}/about/` },
|
||||||
params: { about: `${lang}/about` },
|
props: { lang },
|
||||||
props: { lang },
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
@ -32,6 +30,7 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const { lang } = Astro.props
|
const { lang } = Astro.props
|
||||||
|
|
||||||
|
// Get about page content with different language
|
||||||
const allAboutEntries = await getCollection('about')
|
const allAboutEntries = await getCollection('about')
|
||||||
const aboutEntry = allAboutEntries.find(entry => entry.data.lang === lang)
|
const aboutEntry = allAboutEntries.find(entry => entry.data.lang === lang)
|
||||||
|| allAboutEntries.find(entry => entry.data.lang === '')
|
|| allAboutEntries.find(entry => entry.data.lang === '')
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
---
|
---
|
||||||
import PostList from '@/components/PostList.astro'
|
import PostList from '@/components/PostList.astro'
|
||||||
import { allLocales, defaultLocale } from '@/config'
|
import { defaultLocale, moreLocales } from '@/config'
|
||||||
import Layout from '@/layouts/Layout.astro'
|
import Layout from '@/layouts/Layout.astro'
|
||||||
import { getPinnedPosts, getPostsByYear } from '@/utils/content'
|
import { getPinnedPosts, getPostsByYear } from '@/utils/content'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
// 定义路径数组的类型
|
|
||||||
type PathItem = {
|
type PathItem = {
|
||||||
params: { index: string | undefined }
|
params: { index: string | undefined }
|
||||||
props: { lang: string }
|
props: { lang: string }
|
||||||
|
@ -13,31 +12,31 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const paths: PathItem[] = []
|
const paths: PathItem[] = []
|
||||||
|
|
||||||
// 默认语言的首页
|
// Default locale
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { index: undefined },
|
params: { index: undefined },
|
||||||
props: { lang: defaultLocale },
|
props: { lang: defaultLocale },
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更多语言的首页
|
// More locales
|
||||||
allLocales.forEach((lang: string) => {
|
moreLocales.forEach((lang: string) => {
|
||||||
if (lang !== defaultLocale) {
|
paths.push({
|
||||||
paths.push({
|
params: { index: `${lang}/` },
|
||||||
params: { index: lang },
|
props: { lang },
|
||||||
props: { lang },
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
const { lang } = Astro.props
|
const { lang } = Astro.props
|
||||||
|
|
||||||
const pinnedPosts = await getPinnedPosts(lang)
|
const pinnedPosts = await getPinnedPosts(lang)
|
||||||
const postsByYear = await getPostsByYear(lang)
|
const postsByYear = await getPostsByYear(lang)
|
||||||
---
|
---
|
||||||
<Layout>
|
<Layout>
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
<!-- Pinned Posts -->
|
<!-- Pinned Posts -->
|
||||||
{pinnedPosts.length > 0 && (
|
{pinnedPosts.length > 0 && (
|
||||||
<section class="mb-7.5 lg:mb-9.5">
|
<section class="mb-7.5 lg:mb-9.5">
|
||||||
|
@ -45,6 +44,7 @@ const postsByYear = await getPostsByYear(lang)
|
||||||
<PostList posts={pinnedPosts} lang={lang} />
|
<PostList posts={pinnedPosts} lang={lang} />
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<!-- Regular Posts -->
|
<!-- Regular Posts -->
|
||||||
{[...postsByYear.entries()].map(([_year, posts]) => (
|
{[...postsByYear.entries()].map(([_year, posts]) => (
|
||||||
<section class="mb-7.5 lg:mb-9.5">
|
<section class="mb-7.5 lg:mb-9.5">
|
||||||
|
@ -52,5 +52,6 @@ const postsByYear = await getPostsByYear(lang)
|
||||||
<PostList posts={posts} lang={lang} />
|
<PostList posts={posts} lang={lang} />
|
||||||
</section>
|
</section>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -2,52 +2,48 @@
|
||||||
import type { CollectionEntry } from 'astro:content'
|
import type { CollectionEntry } from 'astro:content'
|
||||||
import Comments from '@/components/Comments/index.astro'
|
import Comments from '@/components/Comments/index.astro'
|
||||||
import PostDate from '@/components/PostDate.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 Layout from '@/layouts/Layout.astro'
|
||||||
import { checkSlugDuplication } from '@/utils/content'
|
import { checkPostSlugDuplication } from '@/utils/content'
|
||||||
import { generateDescription } from '@/utils/description'
|
import { generateDescription } from '@/utils/description'
|
||||||
import { getCollection } from 'astro:content'
|
import { getCollection } from 'astro:content'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection('posts')
|
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) {
|
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到语言的映射
|
// Use a Map to store the relationship between post slugs and their supported languages
|
||||||
const slugToLangs: Record<string, string[]> = {}
|
// Set is used to store the supported languages for each post
|
||||||
|
const slugToLangsMap = posts.reduce((map, post) => {
|
||||||
// 填充映射
|
|
||||||
posts.forEach((post: CollectionEntry<'posts'>) => {
|
|
||||||
const slug = post.data.abbrlink || post.slug
|
const slug = post.data.abbrlink || post.slug
|
||||||
const lang = post.data.lang || defaultLocale
|
const lang = post.data.lang
|
||||||
|
|
||||||
// 如果文章没有指定语言,初始化为所有支持的语言
|
if (!map.has(slug)) {
|
||||||
if (!slugToLangs[slug]) {
|
map.set(slug, new Set(lang ? [lang] : allLocales))
|
||||||
if (!post.data.lang) {
|
}
|
||||||
slugToLangs[slug] = [...allLocales] // 文章支持所有语言
|
else if (lang) {
|
||||||
}
|
map.get(slug)?.add(lang)
|
||||||
else {
|
|
||||||
slugToLangs[slug] = [defaultLocale] // 仅默认语言和指定语言
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!slugToLangs[slug].includes(lang)) {
|
return map
|
||||||
slugToLangs[slug].push(lang)
|
}, new Map<string, Set<string>>())
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 对每个文章的supportedLangs按照allLocales的顺序排序
|
// Convert Map<slug, Set<langs>> to Record<slug, langs[]> structure
|
||||||
Object.keys(slugToLangs).forEach((slug) => {
|
// Sort languages according to the order defined in allLocales
|
||||||
// 按照allLocales的顺序排序
|
const slugToLangs = Object.fromEntries(
|
||||||
slugToLangs[slug].sort((a, b) => {
|
Array.from(slugToLangsMap.entries()).map(([slug, langs]) => [
|
||||||
return allLocales.indexOf(a) - allLocales.indexOf(b)
|
slug,
|
||||||
})
|
[...langs].sort((a, b) => allLocales.indexOf(a) - allLocales.indexOf(b)),
|
||||||
})
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
// 定义路径数组的类型
|
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
type PathItem = {
|
type PathItem = {
|
||||||
params: { posts_slug: string }
|
params: { posts_slug: string }
|
||||||
props: { post: any, lang: string, supportedLangs: string[] }
|
props: { post: any, lang: string, supportedLangs: string[] }
|
||||||
|
@ -55,16 +51,16 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const paths: PathItem[] = []
|
const paths: PathItem[] = []
|
||||||
|
|
||||||
// 默认语言的文章页面 (没有语言前缀)
|
// Default locale
|
||||||
posts.forEach((post: CollectionEntry<'posts'>) => {
|
posts.forEach((post: CollectionEntry<'posts'>) => {
|
||||||
|
// Show drafts in dev mode only
|
||||||
if (import.meta.env.DEV || !post.data.draft) {
|
if (import.meta.env.DEV || !post.data.draft) {
|
||||||
const slug = post.data.abbrlink || post.slug
|
const slug = post.data.abbrlink || post.slug
|
||||||
const postLang = post.data.lang || defaultLocale
|
const lang = post.data.lang
|
||||||
|
|
||||||
// 只有当文章语言是默认语言或没有指定语言时才生成默认语言路径
|
if (lang === defaultLocale || lang === '') {
|
||||||
if (postLang === defaultLocale || post.data.lang === '') {
|
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { posts_slug: `posts/${slug}` },
|
params: { posts_slug: `posts/${slug}/` },
|
||||||
props: {
|
props: {
|
||||||
post,
|
post,
|
||||||
lang: defaultLocale,
|
lang: defaultLocale,
|
||||||
|
@ -75,23 +71,22 @@ export async function getStaticPaths() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更多语言的文章页面 (有语言前缀)
|
// More locales
|
||||||
allLocales.forEach((lang: string) => {
|
moreLocales.forEach((lang: string) => {
|
||||||
if (lang !== defaultLocale) {
|
posts.forEach((post: CollectionEntry<'posts'>) => {
|
||||||
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 === '')) {
|
if ((import.meta.env.DEV || !post.data.draft) && (post.data.lang === lang || post.data.lang === '')) {
|
||||||
const slug = post.data.abbrlink || post.slug
|
const slug = post.data.abbrlink || post.slug
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { posts_slug: `${lang}/posts/${slug}` },
|
params: { posts_slug: `${lang}/posts/${slug}/` },
|
||||||
props: {
|
props: {
|
||||||
post,
|
post,
|
||||||
lang,
|
lang,
|
||||||
supportedLangs: slugToLangs[slug] || [],
|
supportedLangs: slugToLangs[slug] || [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
@ -100,13 +95,6 @@ export async function getStaticPaths() {
|
||||||
const { post, lang, supportedLangs } = Astro.props
|
const { post, lang, supportedLangs } = Astro.props
|
||||||
const description = generateDescription(post, 'meta')
|
const description = generateDescription(post, 'meta')
|
||||||
const { Content, remarkPluginFrontmatter } = await post.render()
|
const { Content, remarkPluginFrontmatter } = await post.render()
|
||||||
|
|
||||||
// 构建标签链接
|
|
||||||
function getTagUrl(tagName: string): string {
|
|
||||||
return lang === defaultLocale
|
|
||||||
? `/tags/${tagName}/`
|
|
||||||
: `/${lang}/tags/${tagName}/`
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout
|
<Layout
|
||||||
|
@ -148,7 +136,7 @@ function getTagUrl(tagName: string): string {
|
||||||
<div class="uno-tags-wrapper">
|
<div class="uno-tags-wrapper">
|
||||||
{post.data.tags.map((tag: string) => (
|
{post.data.tags.map((tag: string) => (
|
||||||
<a
|
<a
|
||||||
href={getTagUrl(tag)}
|
href={getTagPath(tag, lang)}
|
||||||
class="uno-tags-style"
|
class="uno-tags-style"
|
||||||
>
|
>
|
||||||
{tag}
|
{tag}
|
||||||
|
|
|
@ -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 Layout from '@/layouts/Layout.astro'
|
||||||
import { getAllTags } from '@/utils/content'
|
import { getAllTags } from '@/utils/content'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
// 定义路径数组的类型
|
|
||||||
type PathItem = {
|
type PathItem = {
|
||||||
params: { tags: string }
|
params: { tags: string }
|
||||||
props: { lang: string }
|
props: { lang: string }
|
||||||
|
@ -12,20 +12,18 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const paths: PathItem[] = []
|
const paths: PathItem[] = []
|
||||||
|
|
||||||
// 默认语言的标签索引页
|
// Default locale
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { tags: 'tags' },
|
params: { tags: 'tags/' },
|
||||||
props: { lang: defaultLocale },
|
props: { lang: defaultLocale },
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更多语言的标签索引页
|
// More locales
|
||||||
allLocales.forEach((lang: string) => {
|
moreLocales.forEach((lang: string) => {
|
||||||
if (lang !== defaultLocale) {
|
paths.push({
|
||||||
paths.push({
|
params: { tags: `${lang}/tags/` },
|
||||||
params: { tags: `${lang}/tags` },
|
props: { lang },
|
||||||
props: { lang },
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
@ -33,24 +31,17 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const { lang } = Astro.props
|
const { lang } = Astro.props
|
||||||
const allTags = await getAllTags(lang)
|
const allTags = await getAllTags(lang)
|
||||||
|
|
||||||
// 构建标签链接
|
|
||||||
function getTagUrl(tagName: string): string {
|
|
||||||
return lang === defaultLocale
|
|
||||||
? `/tags/${tagName}/`
|
|
||||||
: `/${lang}/tags/${tagName}/`
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<div class="uno-decorative-line"></div>
|
<div class="uno-decorative-line"></div>
|
||||||
<div class="uno-tags-wrapper">
|
<div class="uno-tags-wrapper">
|
||||||
{allTags.map(tagName => (
|
{allTags.map(tag => (
|
||||||
<a
|
<a
|
||||||
href={getTagUrl(tagName)}
|
href={getTagPath(tag, lang)}
|
||||||
class="uno-tags-style"
|
class="uno-tags-style"
|
||||||
>
|
>
|
||||||
{tagName}
|
{tag}
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
import PostList from '@/components/PostList.astro'
|
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 Layout from '@/layouts/Layout.astro'
|
||||||
import { getAllTags, getPostsByTag } from '@/utils/content'
|
import { getAllTags, getPostsByTag } from '@/utils/content'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
// 定义路径数组的类型
|
|
||||||
type PathItem = {
|
type PathItem = {
|
||||||
params: { tags_tag: string }
|
params: { tags_tag: string }
|
||||||
props: { tag: string, lang: string }
|
props: { tag: string, lang: string }
|
||||||
|
@ -13,26 +13,24 @@ export async function getStaticPaths() {
|
||||||
|
|
||||||
const paths: PathItem[] = []
|
const paths: PathItem[] = []
|
||||||
|
|
||||||
// 默认语言的标签页面 (没有语言前缀)
|
// Default locale
|
||||||
const defaultTags = await getAllTags(defaultLocale)
|
const defaultTags = await getAllTags(defaultLocale)
|
||||||
defaultTags.forEach((tag: string) => {
|
defaultTags.forEach((tag: string) => {
|
||||||
paths.push({
|
paths.push({
|
||||||
params: { tags_tag: `tags/${tag}` },
|
params: { tags_tag: `tags/${tag}/` },
|
||||||
props: { tag, lang: defaultLocale },
|
props: { tag, lang: defaultLocale },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更多语言的标签页面 (有语言前缀)
|
// More locales
|
||||||
for (const lang of allLocales) {
|
for (const lang of moreLocales) {
|
||||||
if (lang !== defaultLocale) {
|
const langTags = await getAllTags(lang)
|
||||||
const langTags = await getAllTags(lang)
|
langTags.forEach((tag: string) => {
|
||||||
langTags.forEach((tag: string) => {
|
paths.push({
|
||||||
paths.push({
|
params: { tags_tag: `${lang}/tags/${tag}/` },
|
||||||
params: { tags_tag: `${lang}/tags/${tag}` },
|
props: { tag, lang },
|
||||||
props: { tag, lang },
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
@ -42,22 +40,16 @@ const { tag, lang } = Astro.props
|
||||||
const posts = await getPostsByTag(tag, lang)
|
const posts = await getPostsByTag(tag, lang)
|
||||||
const allTags = await getAllTags(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(
|
const tagSupportedLangs = await Promise.all(
|
||||||
allLocales.map(async (locale) => {
|
allLocales.map(async (locale) => {
|
||||||
const postsInLang = await getPostsByTag(tag, locale)
|
const postsInLang = await getPostsByTag(tag, locale)
|
||||||
return postsInLang.length > 0 ? locale : null
|
return postsInLang.length > 0 ? locale : null
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
// 过滤出支持当前标签的语言列表
|
|
||||||
const supportedLangs = tagSupportedLangs.filter(Boolean) as string[]
|
|
||||||
|
|
||||||
// 构建标签链接
|
// Filter to get supported languages
|
||||||
function getTagUrl(tagName: string): string {
|
const supportedLangs = tagSupportedLangs.filter(Boolean) as string[]
|
||||||
return lang === defaultLocale
|
|
||||||
? `/tags/${tagName}/`
|
|
||||||
: `/${lang}/tags/${tagName}/`
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout supportedLangs={supportedLangs}>
|
<Layout supportedLangs={supportedLangs}>
|
||||||
|
@ -65,7 +57,7 @@ function getTagUrl(tagName: string): string {
|
||||||
<div class="uno-tags-wrapper">
|
<div class="uno-tags-wrapper">
|
||||||
{allTags.map(tagName => (
|
{allTags.map(tagName => (
|
||||||
<a
|
<a
|
||||||
href={getTagUrl(tagName)}
|
href={getTagPath(tagName, lang)}
|
||||||
class={`uno-tags-style ${
|
class={`uno-tags-style ${
|
||||||
tag === tagName
|
tag === tagName
|
||||||
? 'border-secondary/75 text-primary'
|
? 'border-secondary/75 text-primary'
|
||||||
|
|
|
@ -18,8 +18,12 @@ async function getPostMeta(post: CollectionEntry<'posts'>): Promise<Post> {
|
||||||
return { ...post, remarkPluginFrontmatter }
|
return { ...post, remarkPluginFrontmatter }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the slug is duplicated under the same language
|
/**
|
||||||
export async function checkSlugDuplication(posts: Post[]): Promise<string[]> {
|
* Check if the post slug is duplicated under the same language
|
||||||
|
* @param posts Array of blog posts
|
||||||
|
* @returns Array of duplicate slugs with language information
|
||||||
|
*/
|
||||||
|
export async function checkPostSlugDuplication(posts: Post[]): Promise<string[]> {
|
||||||
const slugMap = new Map<string, Set<string>>()
|
const slugMap = new Map<string, Set<string>>()
|
||||||
const duplicates: string[] = []
|
const duplicates: string[] = []
|
||||||
|
|
||||||
|
@ -33,7 +37,12 @@ export async function checkSlugDuplication(posts: Post[]): Promise<string[]> {
|
||||||
|
|
||||||
const slugSet = slugMap.get(lang)!
|
const slugSet = slugMap.get(lang)!
|
||||||
if (slugSet.has(slug)) {
|
if (slugSet.has(slug)) {
|
||||||
duplicates.push(`Duplicate slug "${slug}" found in language "${lang || 'default'}"`)
|
if (!lang) {
|
||||||
|
duplicates.push(`Duplicate slug "${slug}" found in universal post (applies to all languages)`)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
duplicates.push(`Duplicate slug "${slug}" found in "${lang}" language post`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
slugSet.add(slug)
|
slugSet.add(slug)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue