mirror of
https://github.com/reonokiy/blog.nokiy.net.git
synced 2025-06-16 03:32:51 +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
|
@ -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)
|
||||
|
|
|
@ -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 === '')
|
||||
|
|
|
@ -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)
|
||||
---
|
||||
<Layout>
|
||||
<main>
|
||||
|
||||
<!-- Pinned Posts -->
|
||||
{pinnedPosts.length > 0 && (
|
||||
<section class="mb-7.5 lg:mb-9.5">
|
||||
|
@ -45,6 +44,7 @@ const postsByYear = await getPostsByYear(lang)
|
|||
<PostList posts={pinnedPosts} lang={lang} />
|
||||
</section>
|
||||
)}
|
||||
|
||||
<!-- Regular Posts -->
|
||||
{[...postsByYear.entries()].map(([_year, posts]) => (
|
||||
<section class="mb-7.5 lg:mb-9.5">
|
||||
|
@ -52,5 +52,6 @@ const postsByYear = await getPostsByYear(lang)
|
|||
<PostList posts={posts} lang={lang} />
|
||||
</section>
|
||||
))}
|
||||
|
||||
</main>
|
||||
</Layout>
|
||||
|
|
|
@ -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<string, string[]> = {}
|
||||
|
||||
// 填充映射
|
||||
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<string, Set<string>>())
|
||||
|
||||
// 对每个文章的supportedLangs按照allLocales的顺序排序
|
||||
Object.keys(slugToLangs).forEach((slug) => {
|
||||
// 按照allLocales的顺序排序
|
||||
slugToLangs[slug].sort((a, b) => {
|
||||
return allLocales.indexOf(a) - allLocales.indexOf(b)
|
||||
})
|
||||
})
|
||||
// Convert Map<slug, Set<langs>> to Record<slug, langs[]> 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}/`
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
|
@ -148,7 +136,7 @@ function getTagUrl(tagName: string): string {
|
|||
<div class="uno-tags-wrapper">
|
||||
{post.data.tags.map((tag: string) => (
|
||||
<a
|
||||
href={getTagUrl(tag)}
|
||||
href={getTagPath(tag, lang)}
|
||||
class="uno-tags-style"
|
||||
>
|
||||
{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 { 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}/`
|
||||
}
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<div class="uno-decorative-line"></div>
|
||||
<div class="uno-tags-wrapper">
|
||||
{allTags.map(tagName => (
|
||||
{allTags.map(tag => (
|
||||
<a
|
||||
href={getTagUrl(tagName)}
|
||||
href={getTagPath(tag, lang)}
|
||||
class="uno-tags-style"
|
||||
>
|
||||
{tagName}
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -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[]
|
||||
---
|
||||
|
||||
<Layout supportedLangs={supportedLangs}>
|
||||
|
@ -65,7 +57,7 @@ function getTagUrl(tagName: string): string {
|
|||
<div class="uno-tags-wrapper">
|
||||
{allTags.map(tagName => (
|
||||
<a
|
||||
href={getTagUrl(tagName)}
|
||||
href={getTagPath(tagName, lang)}
|
||||
class={`uno-tags-style ${
|
||||
tag === tagName
|
||||
? 'border-secondary/75 text-primary'
|
||||
|
|
|
@ -18,8 +18,12 @@ async function getPostMeta(post: CollectionEntry<'posts'>): Promise<Post> {
|
|||
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 duplicates: string[] = []
|
||||
|
||||
|
@ -33,7 +37,12 @@ export async function checkSlugDuplication(posts: Post[]): Promise<string[]> {
|
|||
|
||||
const slugSet = slugMap.get(lang)!
|
||||
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 {
|
||||
slugSet.add(slug)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue