From f34b0cb46b9748c5996d3cdf1b8a65febefc113c Mon Sep 17 00:00:00 2001 From: radishzzz Date: Mon, 17 Mar 2025 02:49:02 +0000 Subject: [PATCH] feat: i18n rss url and different excerpt length for different languages --- src/components/Footer.astro | 17 +++++++++++-- src/components/PostList.astro | 2 +- src/config.ts | 6 ++--- src/pages/[...posts_slug].astro | 2 +- src/pages/og/[...image].ts | 5 ++-- src/utils/description.ts | 43 ++++++++++++++++++++++++++++++--- 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/components/Footer.astro b/src/components/Footer.astro index 31fa013..7537859 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -1,7 +1,8 @@ --- import LanguageSwitcher from '@/components/Widgets/LanguageSwitcher.astro' import ThemeToggle from '@/components/Widgets/ThemeToggle.astro' -import themeConfig from '@/config' +import { defaultLocale, themeConfig } from '@/config' +import { getLangFromPath } from '@/i18n/lang' interface Props { class?: string @@ -10,7 +11,19 @@ interface Props { const { class: className, supportedLangs = [] } = Astro.props const { author } = themeConfig.site -const { links, startYear } = themeConfig.footer +const { links: configLinks, startYear } = themeConfig.footer + +// i18n rss path +const currentLang = getLangFromPath(Astro.url.pathname) +const links = configLinks.map((link) => { + if (link.name === 'RSS') { + return { + ...link, + url: currentLang === defaultLocale ? link.url : `/${currentLang}${link.url}/`, + } + } + return link +}) const currentYear = new Date().getFullYear() const year = Number(startYear) === currentYear diff --git a/src/components/PostList.astro b/src/components/PostList.astro index 8192113..00ba3ab 100644 --- a/src/components/PostList.astro +++ b/src/components/PostList.astro @@ -68,7 +68,7 @@ function getPostPath(post: Post) { class="heti hidden" lg="mt-2 block" > -

{generateDescription(post)}

+

{generateDescription(post, 'list')}

diff --git a/src/config.ts b/src/config.ts index 6cb5a03..c911129 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,13 +4,13 @@ export const themeConfig: ThemeConfig = { // SITE INFORMATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START site: { // site title - title: 'Retypeset', + title: '重新编排', // site subtitle - subtitle: 'Revive the beauty of typography', + subtitle: '再现版式之美', // use i18n title/subtitle from src/i18n/ui.ts instead of static ones above i18nTitle: true, // site description - description: 'Retypeset is a static blog theme based on the Astro framework, inspired by Typography. Retypeset establishes a new visual standard and reimagines the layout of all pages, offering a reading experience similar to paper books, reviving the beauty of typography. Details in every sight, elegance in every space.', + description: 'Retypeset 是一款基于Astro框架的静态博客主题,设计灵感来自Typography。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。', // author name author: 'radishzz', // site url diff --git a/src/pages/[...posts_slug].astro b/src/pages/[...posts_slug].astro index c5ea420..8e4a2d9 100644 --- a/src/pages/[...posts_slug].astro +++ b/src/pages/[...posts_slug].astro @@ -98,7 +98,7 @@ export async function getStaticPaths() { } const { post, lang, supportedLangs } = Astro.props -const description = generateDescription(post) +const description = generateDescription(post, 'meta') const { Content, remarkPluginFrontmatter } = await post.render() // 构建标签链接 diff --git a/src/pages/og/[...image].ts b/src/pages/og/[...image].ts index 7533957..a4e9f71 100644 --- a/src/pages/og/[...image].ts +++ b/src/pages/og/[...image].ts @@ -1,3 +1,4 @@ +import type { CollectionEntry } from 'astro:content' import { generateDescription } from '@/utils/description' import { OGImageRoute } from 'astro-og-canvas' import { getCollection } from 'astro:content' @@ -7,11 +8,11 @@ const blogEntries = await getCollection('posts') // Convert to page data objects const pages = Object.fromEntries( - blogEntries.map(post => [ + blogEntries.map((post: CollectionEntry<'posts'>) => [ post.slug, { title: post.data.title, - description: post.data.description || generateDescription(post), + description: post.data.description || generateDescription(post, 'og'), }, ]), ) diff --git a/src/utils/description.ts b/src/utils/description.ts index eacad0c..92962b3 100644 --- a/src/utils/description.ts +++ b/src/utils/description.ts @@ -1,14 +1,46 @@ import type { CollectionEntry } from 'astro:content' +import { defaultLocale } from '@/config' import MarkdownIt from 'markdown-it' import sanitizeHtml from 'sanitize-html' const parser = new MarkdownIt() +type ExcerptScene = 'list' | 'meta' | 'og' + +// Excerpt length in different scenarios +const EXCERPT_LENGTHS: Record = { + list: { + cjk: 120, + other: 240, + }, + meta: { + cjk: 120, + other: 240, + }, + og: { + cjk: 75, + other: 150, + }, +} + +const isCJKLang = (lang: string) => ['zh', 'zh-tw', 'ja'].includes(lang) + // Generate an excerpt from Markdown content -export function generateExcerpt(content: string, length: number = 98): string { +export function generateExcerpt( + content: string, + scene: ExcerptScene, + lang: string, +): string { if (!content) return '' + const length = isCJKLang(lang) + ? EXCERPT_LENGTHS[scene].cjk + : EXCERPT_LENGTHS[scene].other + // Convert Markdown to plain text const plainText = sanitizeHtml(parser.render(content), { allowedTags: [], @@ -23,11 +55,14 @@ export function generateExcerpt(content: string, length: number = 98): string { } // Automatically generate a description for the article -export function generateDescription(post: CollectionEntry<'posts'>): string { +export function generateDescription( + post: CollectionEntry<'posts'>, + scene: ExcerptScene, +): string { // If the article already has a description, return it directly if (post.data.description) return post.data.description - // Otherwise, generate an excerpt from the article content as the description - return generateExcerpt(post.body) + const lang = post.data.lang ?? defaultLocale + return generateExcerpt(post.body, scene, lang) }