refactor: update language configuration

This commit is contained in:
radishzzz 2025-03-15 01:02:45 +00:00
parent ff59dc1a7c
commit 22dc899a95
25 changed files with 53 additions and 188 deletions

View file

@ -24,7 +24,7 @@ import remarkSectionize from 'remark-sectionize'
// Project configuration and utilities
import UnoCSS from 'unocss/astro'
import { themeConfig } from './src/config'
import { langMap } from './src/i18n/ui'
import { langMap } from './src/i18n/config'
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'

View file

@ -1,7 +1,6 @@
---
import { themeConfig } from '@/config'
import { defaultLocale } from '@/i18n/config'
import { walineLocaleMap } from '@/i18n/ui'
import { defaultLocale, themeConfig } from '@/config'
import { walineLocaleMap } from '@/i18n/config'
// Theme color configuration
const {

View file

@ -24,7 +24,7 @@ const year = Number(startYear) === currentYear
className,
]}
>
<!-- only show on desktop -->
<!-- Only show on desktop -->
<div class="mb-11.5 ml-1.5 hidden gap-7 lg:flex">
<ThemeToggle />
<LanguageSwitcher supportedLangs={supportedLangs} />

View file

@ -1,6 +1,6 @@
---
import PostTime from '@/components/PostTime.astro'
import { defaultLocale } from '@/i18n/config'
import { defaultLocale } from '@/config'
interface Post {
data: {
@ -16,7 +16,6 @@ interface Post {
}
}
// Get post list and page language parameter from props
const { posts, lang } = Astro.props
export interface Props {
@ -24,9 +23,8 @@ export interface Props {
lang?: string
}
// Get multilingual post URL path
function getPostPath(post: Post) {
// If abbrlink is set, it will be used instead of slug
// Prioritize abbrlink over slug
const postPath = post.data.abbrlink || post.slug
// Add language prefix to URL if current page is in a language subdirectory and not the default language
return lang && lang !== defaultLocale ? `/${lang}/posts/${postPath}/` : `/posts/${postPath}/`

View file

@ -1,5 +1,4 @@
<button
id="theme-toggle"
aria-label="Switch light/dark theme"
class="button-theme-toggle w-4.2 uno-button"
>

View file

@ -171,3 +171,7 @@ export const themeConfig: ThemeConfig = {
}
export default themeConfig
export const defaultLocale = themeConfig.global.locale
export const moreLocales = themeConfig.global.moreLocales
export const allLocales = [defaultLocale, ...moreLocales]

View file

@ -1,5 +1,23 @@
import { themeConfig } from '@/config'
// Global Language Map
export const langMap: Record<string, string[]> = {
'zh': ['zh-CN'],
'zh-tw': ['zh-TW'],
'ja': ['ja-JP'],
'en': ['en-US'],
'es': ['es-ES'],
'ru': ['ru-RU'],
}
export const defaultLocale = themeConfig.global.locale
export const moreLocales = themeConfig.global.moreLocales
export const allLocales = [defaultLocale, ...moreLocales]
// Waline Language Map
// docs: https://waline.js.org/guide/i18n.html
export const walineLocaleMap: Record<string, string> = {
'zh': 'zh-CN',
'zh-tw': 'zh-TW',
'ja': 'jp-JP', // Waline uses jp-JP not ja-JP
'en': 'en-US',
'es': 'es-ES',
'ru': 'ru-RU',
}
// Supported Languages
export const supportedLangs = Object.keys(langMap).flat()

View file

@ -1,4 +1,4 @@
import { allLocales, defaultLocale, moreLocales } from '@/i18n/config'
import { allLocales, defaultLocale, moreLocales } from '@/config'
// Gets the language code from the current path
export function getLangFromPath(path: string) {

View file

@ -1,4 +1,4 @@
import { defaultLocale } from '@/i18n/config'
import { defaultLocale } from '@/config'
import { getLangFromPath, getNextLang } from '@/i18n/lang'
import { cleanPath } from '@/utils/page'

View file

@ -1,125 +0,0 @@
import type { CollectionEntry } from 'astro:content'
import { allLocales, defaultLocale, moreLocales } from '@/i18n/config'
// 生成默认语言标签页面的路由配置
export function getTagRoutes(tags: string[]) {
return tags.map(tag => ({
params: { tag },
props: { tag },
}))
}
// 生成默认语言文章页面的路由配置
export function getPostRoutes(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 getMultiLangRoutes() {
return moreLocales.map(lang => ({
params: { lang },
}))
}
// 生成更多语言标签页面的路由配置
export function getMultiLangTagRoutes(tags: string[]) {
return moreLocales.flatMap(lang => (
tags.map(tag => ({
params: { lang, tag },
props: { tag },
}))
))
}
// 生成更多语言文章页面的路由配置
export function getMultiLangPostRoutes(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]
: moreLocales
// 获取这篇文章支持的所有语言
const supportedLangs = slugToLangs[slug] || []
// 添加非默认语言路径
postLang.forEach((lang) => {
if (lang !== defaultLocale) {
result.push({
params: { lang, slug },
props: { post, supportedLangs },
})
}
})
return result
})
}

View file

@ -1,27 +1,3 @@
// Global Language Map
export const langMap: Record<string, string[]> = {
'zh': ['zh-CN'],
'zh-tw': ['zh-TW'],
'ja': ['ja-JP'],
'en': ['en-US'],
'es': ['es-ES'],
'ru': ['ru-RU'],
}
// Waline Language Map
// docs: https://waline.js.org/guide/i18n.html
export const walineLocaleMap: Record<string, string> = {
'zh': 'zh-CN',
'zh-tw': 'zh-TW',
'ja': 'jp-JP', // Waline uses jp-JP not ja-JP
'en': 'en-US',
'es': 'es-ES',
'ru': 'ru-RU',
}
// Supported Languages
export const supportedLangs = Object.keys(langMap).flat()
export const ui = {
'zh': {
posts: '文章',

View file

@ -1,6 +1,5 @@
---
import themeConfig from '@/config'
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale, themeConfig } from '@/config'
import { ClientRouter } from 'astro:transitions'
interface Props {

View file

@ -80,7 +80,7 @@ const footerMarginClass = isPost && themeConfig.comment?.waline?.serverURL
<ThemeToggle />
</div>
<!--=============================================== Theme Toggle ===============================================-->
<!-- Theme toggle >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<script define:vars={{ lightMode, darkMode }}>
// Update theme
function updateTheme() {

View file

@ -1,9 +1,8 @@
---
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale } from '@/config'
import Layout from '@/layouts/Layout.astro'
export async function getStaticPaths() {
// 定义路径数组的类型
type PathItem = {
params: { about: string }
props: { lang: string }
@ -11,13 +10,13 @@ export async function getStaticPaths() {
const paths: PathItem[] = []
// 默认语言的关于页面
// Default locale
paths.push({
params: { about: 'about' },
props: { lang: defaultLocale },
})
// 更多语言的关于页面
// More locales
allLocales.forEach((lang: string) => {
if (lang !== defaultLocale) {
paths.push({

View file

@ -1,6 +1,6 @@
---
import PostList from '@/components/PostList.astro'
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale } from '@/config'
import Layout from '@/layouts/Layout.astro'
import { getPinnedPosts, getPostsByYear } from '@/utils/content'

View file

@ -1,7 +1,7 @@
---
import Comments from '@/components/Comments/index.astro'
import PostTime from '@/components/PostTime.astro'
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale } from '@/config'
import Layout from '@/layouts/Layout.astro'
import { checkSlugDuplication } from '@/utils/content'
import { generateDescription } from '@/utils/description'

View file

@ -1,5 +1,5 @@
---
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale } from '@/config'
import Layout from '@/layouts/Layout.astro'
import { getAllTags } from '@/utils/content'

View file

@ -1,6 +1,6 @@
---
import PostList from '@/components/PostList.astro'
import { allLocales, defaultLocale } from '@/i18n/config'
import { allLocales, defaultLocale } from '@/config'
import Layout from '@/layouts/Layout.astro'
import { getAllTags, getPostsByTag } from '@/utils/content'

View file

@ -1,5 +1,5 @@
import type { APIContext } from 'astro'
import { moreLocales } from '@/i18n/config'
import { moreLocales } from '@/config'
import { generateRSS } from '@/utils/rss'
// Generate static paths for all supported languages

View file

@ -1,5 +1,5 @@
import type { APIContext } from 'astro'
import { moreLocales } from '@/i18n/config'
import { moreLocales } from '@/config'
import { generateRSS } from '@/utils/rss'
// Generate static paths for all supported languages

View file

@ -1,4 +1,4 @@
import type { supportedLangs } from '@/i18n/ui'
import type { supportedLangs } from '@/i18n/config'
type Exclude<T, U> = T extends U ? never : T

View file

@ -1,6 +1,6 @@
import type { CollectionEntry } from 'astro:content'
import themeConfig from '@/config'
import { supportedLangs } from '@/i18n/ui'
import { supportedLangs } from '@/i18n/config'
import { getCollection } from 'astro:content'
// Type definitions

View file

@ -19,8 +19,7 @@ export function generateExcerpt(content: string, length: number = 98): string {
const normalizedText = plainText.replace(/\s+/g, ' ')
const excerpt = normalizedText.slice(0, length).trim()
// Add ellipsis if text was truncated
const needsEllipsis = normalizedText.length > length
return needsEllipsis ? `${excerpt}...` : excerpt
return normalizedText.length > length ? `${excerpt}...` : excerpt
}
// Automatically generate a description for the article

View file

@ -1,4 +1,4 @@
import { moreLocales } from '@/i18n/config'
import { moreLocales } from '@/config'
import { getLangFromPath } from '@/i18n/lang'
import { getLocalizedPath } from '@/i18n/path'

View file

@ -1,6 +1,5 @@
import type { CollectionEntry } from 'astro:content'
import themeConfig from '@/config'
import { defaultLocale } from '@/i18n/config'
import themeConfig, { defaultLocale } from '@/config'
import rss from '@astrojs/rss'
import { getCollection } from 'astro:content'
import MarkdownIt from 'markdown-it'
@ -10,7 +9,7 @@ const parser = new MarkdownIt()
const { title, description, url } = themeConfig.site
const followConfig = themeConfig.seo?.follow
// Returns first 50 chars with proper truncation
// Returns first 98 chars with proper truncation
function getExcerpt(content: string): string {
if (!content)
return ''
@ -19,8 +18,8 @@ function getExcerpt(content: string): string {
allowedTags: [],
allowedAttributes: {},
})
const excerpt = plainText.slice(0, 50).trim()
return excerpt.length === 50 ? `${excerpt}...` : excerpt
const excerpt = plainText.slice(0, 98).trim()
return excerpt.length === 98 ? `${excerpt}...` : excerpt
}
interface GenerateRSSOptions {