mirror of
https://github.com/reonokiy/blog.nokiy.net.git
synced 2025-06-15 11:12:54 +02:00
✨ feat: complete language switching functionality and centralized page routing
This commit is contained in:
parent
4651828dd1
commit
05d3a8034b
26 changed files with 253 additions and 146 deletions
|
@ -1,12 +1,13 @@
|
|||
// Astro integrations
|
||||
import mdx from '@astrojs/mdx'
|
||||
import partytown from '@astrojs/partytown'
|
||||
import sitemap from '@astrojs/sitemap'
|
||||
import { transformerCopyButton } from '@rehype-pretty/transformers'
|
||||
import compress from 'astro-compress'
|
||||
import robotsTxt from 'astro-robots-txt'
|
||||
import { defineConfig } from 'astro/config'
|
||||
|
||||
// Rehype plugins
|
||||
// Rehype plugins (HTML processors)
|
||||
import { defineConfig } from 'astro/config'
|
||||
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
|
||||
import rehypeComponents from 'rehype-components'
|
||||
import rehypeExternalLinks from 'rehype-external-links'
|
||||
|
@ -14,21 +15,21 @@ import rehypeKatex from 'rehype-katex'
|
|||
import rehypePrettyCode from 'rehype-pretty-code'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
|
||||
// Remark plugins
|
||||
// Remark plugins (Markdown processors)
|
||||
import remarkDirective from 'remark-directive'
|
||||
import remarkGithubAdmonitionsToDirectives from 'remark-github-admonitions-to-directives'
|
||||
import remarkMath from 'remark-math'
|
||||
import remarkSectionize from 'remark-sectionize'
|
||||
import UnoCSS from 'unocss/astro'
|
||||
import { themeConfig } from './src/config.js'
|
||||
|
||||
// Local plugins
|
||||
import { AdmonitionComponent } from './src/plugins/rehype-component-admonition.js'
|
||||
import { GithubCardComponent } from './src/plugins/rehype-component-github-card.js'
|
||||
import { parseDirectiveNode } from './src/plugins/remark-directive-rehype.js'
|
||||
import { remarkExcerpt } from './src/plugins/remark-excerpt.js'
|
||||
import { remarkReadingTime } from './src/plugins/remark-reading-time.js'
|
||||
import { langMap } from './src/utils/i18n/ui.js'
|
||||
// Project configuration and utilities
|
||||
import UnoCSS from 'unocss/astro'
|
||||
import { themeConfig } from './src/config'
|
||||
import { langMap } from './src/i18n/ui'
|
||||
import { AdmonitionComponent } from './src/plugins/rehype-component-admonition'
|
||||
import { GithubCardComponent } from './src/plugins/rehype-component-github-card'
|
||||
import { parseDirectiveNode } from './src/plugins/remark-directive-rehype'
|
||||
import { remarkExcerpt } from './src/plugins/remark-excerpt'
|
||||
import { remarkReadingTime } from './src/plugins/remark-reading-time'
|
||||
|
||||
const url = themeConfig.site.url
|
||||
const { light, dark } = themeConfig.color
|
||||
|
|
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
|
@ -1623,8 +1623,8 @@ packages:
|
|||
duplexer@0.1.2:
|
||||
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
||||
|
||||
electron-to-chromium@1.5.117:
|
||||
resolution: {integrity: sha512-G4+CYIJBiQ72N0gi868tmG4WsD8bwLE9XytBdfgXO5zdlTlvOP2ABzWYILYxCIHmsbm2HjBSgm/E/H/QfcnIyQ==}
|
||||
electron-to-chromium@1.5.118:
|
||||
resolution: {integrity: sha512-yNDUus0iultYyVoEFLnQeei7LOQkL8wg8GQpkPCRrOlJXlcCwa6eGKZkxQ9ciHsqZyYbj8Jd94X1CTPzGm+uIA==}
|
||||
|
||||
emmet@2.4.11:
|
||||
resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==}
|
||||
|
@ -5221,7 +5221,7 @@ snapshots:
|
|||
browserslist@4.24.4:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001704
|
||||
electron-to-chromium: 1.5.117
|
||||
electron-to-chromium: 1.5.118
|
||||
node-releases: 2.0.19
|
||||
update-browserslist-db: 1.1.3(browserslist@4.24.4)
|
||||
|
||||
|
@ -5480,7 +5480,7 @@ snapshots:
|
|||
|
||||
duplexer@0.1.2: {}
|
||||
|
||||
electron-to-chromium@1.5.117: {}
|
||||
electron-to-chromium@1.5.118: {}
|
||||
|
||||
emmet@2.4.11:
|
||||
dependencies:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { themeConfig } from '@/config'
|
||||
import { getWalineLang } from '@/utils/i18n/ui'
|
||||
import { getWalineLang } from '@/i18n/ui'
|
||||
|
||||
const {
|
||||
serverURL = '',
|
||||
|
@ -33,8 +33,7 @@ const {
|
|||
>
|
||||
</div>
|
||||
|
||||
<!-- Not use 'is:inline' or 'define:vars' -->
|
||||
<!-- 'define:vars' ≈ 'is:inline' -->
|
||||
<!-- Not use is:inline or define:vars -->
|
||||
<script>
|
||||
import { init } from '@waline/client'
|
||||
import '@waline/client/style'
|
||||
|
|
|
@ -5,9 +5,10 @@ import themeConfig from '@/config'
|
|||
|
||||
interface Props {
|
||||
class?: string
|
||||
supportedLangs?: string[] // 文章支持的语言列表
|
||||
}
|
||||
|
||||
const { class: className } = Astro.props
|
||||
const { class: className, supportedLangs = [] } = Astro.props
|
||||
const { author } = themeConfig.site
|
||||
const { links, startYear } = themeConfig.footer
|
||||
|
||||
|
@ -26,7 +27,7 @@ const year = Number(startYear) === currentYear
|
|||
<!-- only show on desktop -->
|
||||
<div class="mb-11.5 ml-1.5 hidden gap-7 lg:flex">
|
||||
<ThemeToggle />
|
||||
<LanguageSwitcher />
|
||||
<LanguageSwitcher supportedLangs={supportedLangs} />
|
||||
</div>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import themeConfig from '@/config'
|
||||
import { getPagePath } from '@/utils/i18n/path'
|
||||
import { getPagePath } from '@/i18n/path'
|
||||
|
||||
const { title, subtitle } = themeConfig.site
|
||||
const { titleSpace } = themeConfig.global
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import themeConfig from '@/config'
|
||||
import { getPagePath } from '@/utils/i18n/path'
|
||||
import { getPagePath } from '@/i18n/path'
|
||||
|
||||
const { title, subtitle } = themeConfig.site
|
||||
const { titleSpace } = themeConfig.global
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { getPagePath } from '@/utils/i18n/path'
|
||||
import { ui } from '@/utils/i18n/ui'
|
||||
import { getPagePath } from '@/i18n/path'
|
||||
import { ui } from '@/i18n/ui'
|
||||
|
||||
const currentPath = Astro.url.pathname
|
||||
const { currentLang, isHome, isPost, isTag, isAbout, getLocalizedPath }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { themeConfig } from '@/config'
|
||||
import { isPostPage } from '@/utils/i18n/path'
|
||||
import { isPostPage } from '@/i18n/path'
|
||||
|
||||
interface Props {
|
||||
date: Date
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
---
|
||||
import { getNextLangUrl } from '@/utils/i18n/lang'
|
||||
import { getNextLangUrl, getPostNextLangUrl } from '@/i18n/lang'
|
||||
import { isPostPage } from '@/i18n/path'
|
||||
|
||||
// 获取当前路径
|
||||
interface Props {
|
||||
supportedLangs?: string[] // 文章支持的语言列表
|
||||
}
|
||||
|
||||
const { supportedLangs = [] } = Astro.props
|
||||
const currentPath = Astro.url.pathname
|
||||
const isPost = isPostPage(currentPath)
|
||||
|
||||
// 直接获取下一个语言的URL
|
||||
const nextUrl = getNextLangUrl(currentPath)
|
||||
// 根据页面类型选择不同的URL获取函数
|
||||
const nextUrl = isPost && supportedLangs.length > 0
|
||||
? getPostNextLangUrl(currentPath, supportedLangs)
|
||||
: getNextLangUrl(currentPath)
|
||||
---
|
||||
|
||||
<a
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { themeConfig } from '@/config'
|
||||
import themeConfig from '@/config'
|
||||
|
||||
// 从配置中获取默认语言和更多语言配置
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
// const moreLocale = themeConfig.global.moreLocale
|
||||
|
||||
/**
|
||||
* 获取下一个语言代码
|
||||
|
@ -89,6 +93,24 @@ export function getLangFromPath(currentPath: string): string {
|
|||
return currentLang
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章支持的语言
|
||||
* @param lang 文章的语言属性
|
||||
* @returns 支持的语言数组
|
||||
*/
|
||||
export function getSupportedLangs(lang?: string): string[] {
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
const allLocales = [defaultLocale, ...themeConfig.global.moreLocale]
|
||||
|
||||
// 如果指定了语言且不为空
|
||||
if (lang && typeof lang === 'string' && lang.trim() !== '') {
|
||||
return [lang]
|
||||
}
|
||||
|
||||
// 否则返回所有支持的语言
|
||||
return allLocales
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接从当前路径获取下一个语言的URL
|
||||
* @param currentPath 当前页面路径
|
||||
|
@ -104,3 +126,36 @@ export function getNextLangUrl(currentPath: string): string {
|
|||
// 构建下一个语言的URL
|
||||
return buildNextLangUrl(currentPath, currentLang, nextLang)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支持的语言列表获取下一个语言的URL
|
||||
* @param currentPath 当前路径
|
||||
* @param supportedLangs 文章支持的语言列表
|
||||
* @returns 下一个可用语言的URL
|
||||
*/
|
||||
export function getPostNextLangUrl(currentPath: string, supportedLangs: string[]): string {
|
||||
// 从路径提取当前语言
|
||||
const currentLang = getLangFromPath(currentPath)
|
||||
|
||||
// 如果没有提供支持的语言或列表为空,使用普通的语言切换
|
||||
if (!supportedLangs || supportedLangs.length === 0) {
|
||||
return getNextLangUrl(currentPath)
|
||||
}
|
||||
|
||||
// 找到当前语言在支持的语言中的索引
|
||||
const currentIndex = supportedLangs.indexOf(currentLang)
|
||||
|
||||
// 如果当前语言不在支持的语言中,或者路径是根路径,返回第一个支持的语言
|
||||
if (currentIndex === -1 || currentPath === '/') {
|
||||
const nextLang = supportedLangs[0]
|
||||
// 如果下一个语言是默认语言,返回根路径
|
||||
return nextLang === defaultLocale ? '/' : `/${nextLang}/`
|
||||
}
|
||||
|
||||
// 计算下一个语言的索引
|
||||
const nextIndex = (currentIndex + 1) % supportedLangs.length
|
||||
const nextLang = supportedLangs[nextIndex]
|
||||
|
||||
// 构建下一个语言的URL
|
||||
return buildNextLangUrl(currentPath, currentLang, nextLang)
|
||||
}
|
131
src/i18n/route.ts
Normal file
131
src/i18n/route.ts
Normal file
|
@ -0,0 +1,131 @@
|
|||
import type { CollectionEntry } from 'astro:content'
|
||||
import { themeConfig } from '@/config'
|
||||
|
||||
// 默认语言和更多语言
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
const moreLocale = themeConfig.global.moreLocale
|
||||
// 所有支持的语言
|
||||
const allLocales = [defaultLocale, ...moreLocale]
|
||||
|
||||
// 生成默认语言标签页面的路径配置
|
||||
export function generateTagPaths(tags: string[]) {
|
||||
return tags.map(tag => ({
|
||||
params: { tag },
|
||||
props: { tag },
|
||||
}))
|
||||
}
|
||||
|
||||
// 生成默认语言文章页面的路径配置
|
||||
export function generatePostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
// 创建slug到语言的映射
|
||||
const slugToLangs: Record<string, string[]> = {}
|
||||
|
||||
// 填充映射
|
||||
posts.forEach((post) => {
|
||||
const slug = post.data.abbrlink || post.slug
|
||||
const lang = post.data.lang || defaultLocale
|
||||
|
||||
// 如果文章没有指定语言,初始化为所有支持的语言
|
||||
if (!slugToLangs[slug]) {
|
||||
if (!post.data.lang) {
|
||||
slugToLangs[slug] = [...allLocales] // 文章支持所有语言
|
||||
}
|
||||
else {
|
||||
slugToLangs[slug] = [defaultLocale] // 仅默认语言和指定语言
|
||||
}
|
||||
}
|
||||
|
||||
if (!slugToLangs[slug].includes(lang)) {
|
||||
slugToLangs[slug].push(lang)
|
||||
}
|
||||
})
|
||||
|
||||
return posts.map(post => ({
|
||||
params: {
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: {
|
||||
post,
|
||||
supportedLangs: slugToLangs[post.data.abbrlink || post.slug] || [],
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
// 生成更多语言静态路径
|
||||
export function generateMultiLangPaths() {
|
||||
return moreLocale.map(lang => ({
|
||||
params: { lang },
|
||||
}))
|
||||
}
|
||||
|
||||
// 生成更多语言标签页面的路径配置
|
||||
export function generateMultiLangTagPaths(tags: string[]) {
|
||||
return moreLocale.flatMap(lang => (
|
||||
tags.map(tag => ({
|
||||
params: { lang, tag },
|
||||
props: { tag },
|
||||
}))
|
||||
))
|
||||
}
|
||||
|
||||
// 生成更多语言文章页面的路径配置
|
||||
export function generateMultiLangPostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
// 创建slug到语言的映射
|
||||
const slugToLangs: Record<string, string[]> = {}
|
||||
|
||||
// 填充映射
|
||||
posts.forEach((post) => {
|
||||
const slug = post.data.abbrlink || post.slug
|
||||
const lang = post.data.lang || defaultLocale
|
||||
|
||||
// 如果文章没有指定语言,初始化为所有支持的语言
|
||||
if (!slugToLangs[slug]) {
|
||||
if (!post.data.lang) {
|
||||
slugToLangs[slug] = [...allLocales] // 文章支持所有语言
|
||||
}
|
||||
else {
|
||||
slugToLangs[slug] = [defaultLocale] // 仅默认语言和指定语言
|
||||
}
|
||||
}
|
||||
|
||||
if (!slugToLangs[slug].includes(lang)) {
|
||||
slugToLangs[slug].push(lang)
|
||||
}
|
||||
})
|
||||
|
||||
interface PathResult {
|
||||
params: {
|
||||
lang: string
|
||||
slug: string
|
||||
}
|
||||
props: {
|
||||
post: CollectionEntry<'posts'>
|
||||
supportedLangs: string[]
|
||||
}
|
||||
}
|
||||
|
||||
return posts.flatMap((post) => {
|
||||
const result: PathResult[] = []
|
||||
const slug = post.data.abbrlink || post.slug
|
||||
|
||||
// 确定文章的语言支持
|
||||
const postLang = post.data.lang && typeof post.data.lang === 'string' && post.data.lang.trim() !== ''
|
||||
? [post.data.lang]
|
||||
: moreLocale
|
||||
|
||||
// 获取这篇文章支持的所有语言
|
||||
const supportedLangs = slugToLangs[slug] || []
|
||||
|
||||
// 添加非默认语言路径
|
||||
postLang.forEach((lang) => {
|
||||
if (lang !== defaultLocale) {
|
||||
result.push({
|
||||
params: { lang, slug },
|
||||
props: { post, supportedLangs },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
|
@ -9,8 +9,8 @@ import LanguageSwitcher from '@/components/Widgets/LanguageSwitcher.astro'
|
|||
// import Scrollbar from '@/components/Scrollbar.astro'
|
||||
import ThemeToggle from '@/components/Widgets/ThemeToggle.astro'
|
||||
import themeConfig from '@/config'
|
||||
import { getPagePath } from '@/i18n/path'
|
||||
import Head from '@/layouts/Head.astro'
|
||||
import { getPagePath } from '@/utils/i18n/path'
|
||||
|
||||
import '@/styles/font.css'
|
||||
import '@/styles/global.css'
|
||||
|
@ -20,9 +20,10 @@ interface Props {
|
|||
postTitle?: string
|
||||
postDescription?: string
|
||||
postSlug?: string
|
||||
supportedLangs?: string[]
|
||||
}
|
||||
|
||||
const { postTitle, postDescription, postSlug } = Astro.props
|
||||
const { postTitle, postDescription, postSlug, supportedLangs = [] } = Astro.props
|
||||
const { isHome, isPost } = getPagePath(Astro.url.pathname)
|
||||
const { light: { background: lightMode }, dark: { background: darkMode } } = themeConfig.color
|
||||
const fontStyle = themeConfig.global.fontStyle === 'serif' ? 'font-serif' : 'font-sans'
|
||||
|
@ -55,7 +56,7 @@ const footerMarginClass = isPost && themeConfig.comment?.waline?.serverURL
|
|||
<MainHeader />
|
||||
<Navigation />
|
||||
<!-- only show footer on desktop-->
|
||||
<Footer class="fixed hidden lg:block" />
|
||||
<Footer class="fixed hidden lg:block" supportedLangs={supportedLangs} />
|
||||
</div>
|
||||
|
||||
<!-- show simple header on mobile for post pages -->
|
||||
|
@ -67,7 +68,7 @@ const footerMarginClass = isPost && themeConfig.comment?.waline?.serverURL
|
|||
</main>
|
||||
|
||||
<!-- show footer on mobile -->
|
||||
<Footer class={`block lg:hidden ${footerMarginClass}`} />
|
||||
<Footer class={`block lg:hidden ${footerMarginClass}`} supportedLangs={supportedLangs} />
|
||||
</div>
|
||||
<!-- <Scrollbar /> -->
|
||||
<!-- <BackToTop /> -->
|
||||
|
@ -75,7 +76,7 @@ const footerMarginClass = isPost && themeConfig.comment?.waline?.serverURL
|
|||
|
||||
<!-- only show on mobile (fix position issue on ios / fix right distance)-->
|
||||
<div class="absolute right-7.25vw top-13.5 flex gap-6 [@supports(-webkit-touch-callout:none)]:top-12.5 min-[823px]:right-[calc(50vw-22rem)] lg:hidden">
|
||||
<LanguageSwitcher />
|
||||
<LanguageSwitcher supportedLangs={supportedLangs} />
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { generateMultiLangPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { generateLanguagePaths } from '@/utils/i18n/route'
|
||||
|
||||
export function getStaticPaths() {
|
||||
return generateLanguagePaths()
|
||||
return generateMultiLangPaths()
|
||||
}
|
||||
---
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { APIContext } from 'astro'
|
||||
import themeConfig from '@/config'
|
||||
import { generateMultiLangPaths } from '@/i18n/route'
|
||||
import { generateRSS } from '@/utils/rss'
|
||||
|
||||
const { moreLocale } = themeConfig.global
|
||||
|
@ -9,7 +10,7 @@ type SupportedLanguage = typeof moreLocale[number]
|
|||
|
||||
// Generate static paths for all supported languages
|
||||
export function getStaticPaths() {
|
||||
return moreLocale.map((lang: SupportedLanguage) => ({ params: { lang } }))
|
||||
return generateMultiLangPaths()
|
||||
}
|
||||
|
||||
export async function GET({ params }: APIContext) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
---
|
||||
import PostList from '@/components/PostList.astro'
|
||||
import { themeConfig } from '@/config'
|
||||
import { generateMultiLangPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { getPinnedPosts, getPostsByYear } from '@/utils/content'
|
||||
|
||||
export function getStaticPaths() {
|
||||
return themeConfig.global.moreLocale.map(lang => ({
|
||||
params: { lang },
|
||||
}))
|
||||
return generateMultiLangPaths()
|
||||
}
|
||||
|
||||
const { lang } = Astro.params
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import Waline from '@/components/Comments/Waline.astro'
|
||||
import { generateMultiLangPostPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { checkSlugDuplication } from '@/utils/content'
|
||||
import { generateDescription } from '@/utils/description'
|
||||
import { generateMultiLangPostPaths } from '@/utils/i18n/route'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
|
@ -17,7 +17,7 @@ export async function getStaticPaths() {
|
|||
return generateMultiLangPostPaths(posts)
|
||||
}
|
||||
|
||||
const { post } = Astro.props
|
||||
const { post, supportedLangs = [] } = Astro.props
|
||||
const description = generateDescription(post)
|
||||
const { Content, remarkPluginFrontmatter } = await post.render()
|
||||
---
|
||||
|
@ -26,6 +26,7 @@ const { Content, remarkPluginFrontmatter } = await post.render()
|
|||
postTitle={post.data.title}
|
||||
postDescription={description}
|
||||
postSlug={post.slug}
|
||||
supportedLangs={supportedLangs}
|
||||
>
|
||||
<article>
|
||||
<h1>{post.data.title}</h1>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { APIContext } from 'astro'
|
||||
import themeConfig from '@/config'
|
||||
import { generateMultiLangPaths } from '@/i18n/route'
|
||||
import { generateRSS } from '@/utils/rss'
|
||||
|
||||
const { moreLocale } = themeConfig.global
|
||||
|
@ -9,7 +10,7 @@ type SupportedLanguage = typeof moreLocale[number]
|
|||
|
||||
// Generate static paths for all supported languages
|
||||
export function getStaticPaths() {
|
||||
return moreLocale.map((lang: SupportedLanguage) => ({ params: { lang } }))
|
||||
return generateMultiLangPaths()
|
||||
}
|
||||
|
||||
export async function GET({ params }: APIContext) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import { generateMultiLangTagPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { getAllTags, getPostsByTag } from '@/utils/content'
|
||||
import { generateMultiLangTagPaths } from '@/utils/i18n/route'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const tags = await getAllTags()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
import { generateMultiLangPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { getAllTags } from '@/utils/content'
|
||||
import { generateLanguagePaths } from '@/utils/i18n/route'
|
||||
|
||||
export function getStaticPaths() {
|
||||
return generateLanguagePaths()
|
||||
return generateMultiLangPaths()
|
||||
}
|
||||
|
||||
const { lang } = Astro.params
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
import Comments from '@/components/Comments/index.astro'
|
||||
import PostTime from '@/components/PostTime.astro'
|
||||
import { generatePostPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { checkSlugDuplication } from '@/utils/content'
|
||||
import { generateDescription } from '@/utils/description'
|
||||
import { generatePostPaths } from '@/utils/i18n/route'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
|
@ -18,7 +18,7 @@ export async function getStaticPaths() {
|
|||
return generatePostPaths(posts)
|
||||
}
|
||||
|
||||
const { post } = Astro.props
|
||||
const { post, supportedLangs = [] } = Astro.props
|
||||
const description = generateDescription(post)
|
||||
const { Content, remarkPluginFrontmatter } = await post.render()
|
||||
---
|
||||
|
@ -27,6 +27,7 @@ const { Content, remarkPluginFrontmatter } = await post.render()
|
|||
postTitle={post.data.title}
|
||||
postDescription={description}
|
||||
postSlug={post.slug}
|
||||
supportedLangs={supportedLangs}
|
||||
>
|
||||
<article class="heti mb-12.6">
|
||||
<h1 class="post-title">
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
---
|
||||
import PostList from '@/components/PostList.astro'
|
||||
import { generateTagPaths } from '@/i18n/route'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { getAllTags, getPostsByTag } from '@/utils/content'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const tags = await getAllTags()
|
||||
return tags.map(tag => ({
|
||||
params: { tag },
|
||||
props: { tag },
|
||||
}))
|
||||
return generateTagPaths(tags)
|
||||
}
|
||||
|
||||
const { tag } = Astro.props
|
||||
|
|
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import type { langPath } from '@/utils/i18n/ui'
|
||||
import type { langPath } from '@/i18n/ui'
|
||||
|
||||
type Exclude<T, U> = T extends U ? never : T
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { CollectionEntry } from 'astro:content'
|
||||
import themeConfig from '@/config'
|
||||
import { langPath } from '@/utils/i18n/ui'
|
||||
import { langPath } from '@/i18n/ui'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
// Type definitions
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
import type { CollectionEntry } from 'astro:content'
|
||||
import { themeConfig } from '@/config'
|
||||
|
||||
// 获取默认语言
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
|
||||
export function generateLanguagePaths() {
|
||||
return themeConfig.global.moreLocale.map(lang => ({
|
||||
params: { lang },
|
||||
}))
|
||||
}
|
||||
|
||||
export function generatePostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
return posts.map(post => ({
|
||||
params: {
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
}))
|
||||
}
|
||||
|
||||
export function generateMultiLangPostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
interface PathResult {
|
||||
params: {
|
||||
lang: string
|
||||
slug: string
|
||||
}
|
||||
props: {
|
||||
post: CollectionEntry<'posts'>
|
||||
}
|
||||
}
|
||||
|
||||
const result: PathResult[] = []
|
||||
|
||||
posts.forEach((post) => {
|
||||
// 确定这篇文章应该生成哪些语言版本
|
||||
let postLangs: string[] = themeConfig.global.moreLocale
|
||||
|
||||
if (post.data.lang && typeof post.data.lang === 'string' && post.data.lang.trim() !== '') {
|
||||
// 如果lang是单个字符串,转为数组
|
||||
postLangs = [post.data.lang]
|
||||
}
|
||||
|
||||
// 处理非默认语言的路径
|
||||
postLangs.forEach((lang) => {
|
||||
// 跳过默认语言,它将通过 generatePostPaths 生成
|
||||
if (lang !== defaultLocale) {
|
||||
result.push({
|
||||
params: {
|
||||
lang,
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 如果文章支持默认语言,则生成无语言代码的路径
|
||||
// 默认语言条件:未指定lang属性,或lang属性等于defaultLocale
|
||||
const supportsDefaultLang = !post.data.lang
|
||||
|| (typeof post.data.lang === 'string' && post.data.lang === defaultLocale)
|
||||
|
||||
if (supportsDefaultLang) {
|
||||
// 默认语言的路径不包含语言代码,在这里用特殊参数标记
|
||||
// 这将由 [slug].astro 页面处理,不在URL中显示语言代码
|
||||
result.push({
|
||||
params: {
|
||||
lang: 'default',
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export function generateMultiLangTagPaths(tags: string[]) {
|
||||
return themeConfig.global.moreLocale.flatMap(lang =>
|
||||
// 跳过默认语言,它将通过其他路径生成
|
||||
lang !== defaultLocale
|
||||
? tags.map(tag => ({
|
||||
params: { lang, tag },
|
||||
props: { tag },
|
||||
}))
|
||||
: [],
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue