diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a95f602..a6c421b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -307,9 +307,15 @@ packages:
'@emmetio/stream-reader@2.2.0':
resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==}
+ '@emnapi/core@1.3.1':
+ resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==}
+
'@emnapi/runtime@1.3.1':
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
+ '@emnapi/wasi-threads@1.0.1':
+ resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==}
+
'@es-joy/jsdoccomment@0.49.0':
resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==}
engines: {node: '>=16'}
@@ -684,6 +690,9 @@ packages:
'@mdx-js/mdx@3.1.0':
resolution: {integrity: sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==}
+ '@napi-rs/wasm-runtime@0.2.7':
+ resolution: {integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -699,6 +708,61 @@ packages:
'@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
+ '@oxc-resolver/binding-darwin-arm64@5.0.0':
+ resolution: {integrity: sha512-zwHAf+owoxSWTDD4dFuwW+FkpaDzbaL30H5Ltocb+RmLyg4WKuteusRLKh5Y8b/cyu7UzhxM0haIqQjyqA1iuA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-resolver/binding-darwin-x64@5.0.0':
+ resolution: {integrity: sha512-1lS3aBNVjVQKBvZdHm13+8tSjvu2Tl1Cv4FnUyMYxqx6+rsom2YaOylS5LhDUwfZu0zAgpLMwK6kGpF/UPncNg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-resolver/binding-freebsd-x64@5.0.0':
+ resolution: {integrity: sha512-q9sRd68wC1/AJ0eu6ClhxlklVfe8gH4wrUkSyEbIYTZ8zY5yjsLY3fpqqsaCvWJUx65nW+XtnAxCGCi5AXr1Mw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-resolver/binding-linux-arm-gnueabihf@5.0.0':
+ resolution: {integrity: sha512-catYavWsvqViYnCveQjhrK6yVYDEPFvIOgGLxnz5r2dcgrjpmquzREoyss0L2QG/J5HTTbwqwZ1kk+g56hE/1A==}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-arm64-gnu@5.0.0':
+ resolution: {integrity: sha512-l/0pWoQM5kVmJLg4frQ1mKZOXgi0ex/hzvFt8E4WK2ifXr5JgKFUokxsb/oat7f5YzdJJh5r9p+qS/t3dA26Aw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-arm64-musl@5.0.0':
+ resolution: {integrity: sha512-bx0oz/oaAW4FGYqpIIxJCnmgb906YfMhTEWCJvYkxjpEI8VKLJEL3PQevYiqDq36SA0yRLJ/sQK2fqry8AFBfA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-x64-gnu@5.0.0':
+ resolution: {integrity: sha512-4PH++qbSIhlRsFYdN1P9neDov4OGhTGo5nbQ1D7AL6gWFLo3gdZTc00FM2y8JjeTcPWEXkViZuwpuc0w5i6qHg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-x64-musl@5.0.0':
+ resolution: {integrity: sha512-mLfQFpX3/5y9oWi0b+9FbWDkL2hM0Y29653beCHiHxAdGyVgb2DsJbK74WkMTwtSz9by8vyBh8jGPZcg1yLZbQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-resolver/binding-wasm32-wasi@5.0.0':
+ resolution: {integrity: sha512-uEhsAZSo65qsRi6+IfBTEUUFbjg7T2yruJeLYpFfEATpm3ory5Mgo5vx3L0c2/Cz1OUZXBgp3A8x6VMUB2jT2A==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-resolver/binding-win32-arm64-msvc@5.0.0':
+ resolution: {integrity: sha512-8DbSso9Jp1ns8AYuZFXdRfAcdJrzZwkFm/RjPuvAPTENsm685dosBF8G6gTHQlHvULnk6o3sa9ygZaTGC/UoEw==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-resolver/binding-win32-x64-msvc@5.0.0':
+ resolution: {integrity: sha512-ylppfPEg63NuRXOPNsXFlgyl37JrtRn0QMO26X3K3Ytp5HtLrMreQMGVtgr30e1l2YmAWqhvmKlCryOqzGPD/g==}
+ cpu: [x64]
+ os: [win32]
+
'@pkgr/core@0.1.1':
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -857,6 +921,9 @@ packages:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
+ '@tybys/wasm-util@0.9.0':
+ resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+
'@types/acorn@4.0.6':
resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
@@ -1745,8 +1812,8 @@ packages:
peerDependencies:
eslint: '>=8'
- eslint-plugin-import-x@4.6.1:
- resolution: {integrity: sha512-wluSUifMIb7UfwWXqx7Yx0lE/SGCcGXECLx/9bCmbY2nneLwvAZ4vkd1IXDjPKFvdcdUgr1BaRnaRpx3k2+Pfw==}
+ eslint-plugin-import-x@4.7.0:
+ resolution: {integrity: sha512-LHxq8V6SJ99hSFYAexxUKk3gVsjb8fuNRGsbMinwlJGvcuREP9SVzCCNKJ3POdDowEHdExy/bPN6YfjraueIXA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -2634,6 +2701,10 @@ packages:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
+ minimatch@10.0.1:
+ resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
+ engines: {node: 20 || >=22}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -2721,6 +2792,9 @@ packages:
overlayscrollbars@2.11.1:
resolution: {integrity: sha512-kogaNaBTIizRenQ2GTzt2cpkEH9B0nUBXseRxqQblH/YicJ3TaWuvn8E5TXPPfJCVoHYSgBYZzzva40kCERKHg==}
+ oxc-resolver@5.0.0:
+ resolution: {integrity: sha512-66fopyAqCN8Mx4tzNiBXWbk8asCSuxUWN62gwTc3yfRs7JfWhX/eVJCf+fUrfbNOdQVOWn+o8pAKllp76ysMXA==}
+
p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
@@ -3178,8 +3252,8 @@ packages:
spdx-license-ids@3.0.21:
resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}
- stable-hash@0.0.4:
- resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
+ stable-hash@0.0.5:
+ resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
stream-replace-string@2.0.0:
resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
@@ -3791,7 +3865,7 @@ snapshots:
eslint-merge-processors: 2.0.0(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-import-x: 4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ eslint-plugin-import-x: 4.7.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
eslint-plugin-jsdoc: 50.6.6(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))
@@ -4003,11 +4077,22 @@ snapshots:
'@emmetio/stream-reader@2.2.0': {}
+ '@emnapi/core@1.3.1':
+ dependencies:
+ '@emnapi/wasi-threads': 1.0.1
+ tslib: 2.8.1
+ optional: true
+
'@emnapi/runtime@1.3.1':
dependencies:
tslib: 2.8.1
optional: true
+ '@emnapi/wasi-threads@1.0.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@es-joy/jsdoccomment@0.49.0':
dependencies:
comment-parser: 1.4.1
@@ -4321,6 +4406,13 @@ snapshots:
- acorn
- supports-color
+ '@napi-rs/wasm-runtime@0.2.7':
+ dependencies:
+ '@emnapi/core': 1.3.1
+ '@emnapi/runtime': 1.3.1
+ '@tybys/wasm-util': 0.9.0
+ optional: true
+
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -4335,6 +4427,41 @@ snapshots:
'@oslojs/encoding@1.1.0': {}
+ '@oxc-resolver/binding-darwin-arm64@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-darwin-x64@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-freebsd-x64@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm-gnueabihf@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm64-gnu@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm64-musl@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-linux-x64-gnu@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-linux-x64-musl@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-wasm32-wasi@5.0.0':
+ dependencies:
+ '@napi-rs/wasm-runtime': 0.2.7
+ optional: true
+
+ '@oxc-resolver/binding-win32-arm64-msvc@5.0.0':
+ optional: true
+
+ '@oxc-resolver/binding-win32-x64-msvc@5.0.0':
+ optional: true
+
'@pkgr/core@0.1.1': {}
'@playform/pipe@0.1.2':
@@ -4469,6 +4596,11 @@ snapshots:
'@trysound/sax@0.2.0': {}
+ '@tybys/wasm-util@0.9.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@types/acorn@4.0.6':
dependencies:
'@types/estree': 1.0.6
@@ -5623,21 +5755,20 @@ snapshots:
eslint: 9.22.0(jiti@2.4.2)
eslint-compat-utils: 0.5.1(eslint@9.22.0(jiti@2.4.2))
- eslint-plugin-import-x@4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
+ eslint-plugin-import-x@4.7.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
dependencies:
'@types/doctrine': 0.0.9
- '@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
debug: 4.4.0
doctrine: 3.0.0
- enhanced-resolve: 5.18.1
eslint: 9.22.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
get-tsconfig: 4.10.0
is-glob: 4.0.3
- minimatch: 9.0.5
+ minimatch: 10.0.1
+ oxc-resolver: 5.0.0
semver: 7.7.1
- stable-hash: 0.0.4
+ stable-hash: 0.0.5
tslib: 2.8.1
transitivePeerDependencies:
- supports-color
@@ -6969,6 +7100,10 @@ snapshots:
min-indent@1.0.1: {}
+ minimatch@10.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@@ -7060,6 +7195,20 @@ snapshots:
overlayscrollbars@2.11.1: {}
+ oxc-resolver@5.0.0:
+ optionalDependencies:
+ '@oxc-resolver/binding-darwin-arm64': 5.0.0
+ '@oxc-resolver/binding-darwin-x64': 5.0.0
+ '@oxc-resolver/binding-freebsd-x64': 5.0.0
+ '@oxc-resolver/binding-linux-arm-gnueabihf': 5.0.0
+ '@oxc-resolver/binding-linux-arm64-gnu': 5.0.0
+ '@oxc-resolver/binding-linux-arm64-musl': 5.0.0
+ '@oxc-resolver/binding-linux-x64-gnu': 5.0.0
+ '@oxc-resolver/binding-linux-x64-musl': 5.0.0
+ '@oxc-resolver/binding-wasm32-wasi': 5.0.0
+ '@oxc-resolver/binding-win32-arm64-msvc': 5.0.0
+ '@oxc-resolver/binding-win32-x64-msvc': 5.0.0
+
p-limit@3.1.0:
dependencies:
yocto-queue: 0.1.0
@@ -7679,7 +7828,7 @@ snapshots:
spdx-license-ids@3.0.21: {}
- stable-hash@0.0.4: {}
+ stable-hash@0.0.5: {}
stream-replace-string@2.0.0: {}
diff --git a/src/components/PostList.astro b/src/components/PostList.astro
index 0eec1c7..b6c62c5 100644
--- a/src/components/PostList.astro
+++ b/src/components/PostList.astro
@@ -1,5 +1,6 @@
---
import PostTime from '@/components/PostTime.astro'
+import { defaultLocale } from '@/i18n/config'
interface Post {
data: {
@@ -27,8 +28,8 @@ export interface Props {
function getPostPath(post: Post) {
// If abbrlink is set, it will be used instead of slug
const postPath = post.data.abbrlink || post.slug
- // Add language prefix to URL if current page is in a language subdirectory
- return lang ? `/${lang}/posts/${postPath}/` : `/posts/${postPath}/`
+ // 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}/`
}
---
diff --git a/src/pages/[...about].astro b/src/pages/[...about].astro
new file mode 100644
index 0000000..6b7db7d
--- /dev/null
+++ b/src/pages/[...about].astro
@@ -0,0 +1,47 @@
+---
+import { allLocales, defaultLocale } from '@/i18n/config'
+import Layout from '@/layouts/Layout.astro'
+
+export async function getStaticPaths() {
+ // 定义路径数组的类型
+ type PathItem = {
+ params: { about: string }
+ props: { lang: string }
+ }
+
+ const paths: PathItem[] = []
+
+ // 默认语言的关于页面
+ paths.push({
+ params: { about: 'about' },
+ props: { lang: defaultLocale },
+ })
+
+ // 更多语言的关于页面
+ allLocales.forEach((lang: string) => {
+ if (lang !== defaultLocale) {
+ paths.push({
+ params: { about: `${lang}/about` },
+ props: { lang },
+ })
+ }
+ })
+
+ return paths
+}
+
+const { lang } = Astro.props
+---
+
+
+
+
+ {lang === 'en'
+? (
+
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.
+ )
+: (
+
Retypeset 是一款基于Astro框架的静态博客主题,设计灵感来自Typography。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。
+ )}
+
+
diff --git a/src/pages/[lang]/index.astro b/src/pages/[...index].astro
similarity index 54%
rename from src/pages/[lang]/index.astro
rename to src/pages/[...index].astro
index 5b05c91..f4974fa 100644
--- a/src/pages/[lang]/index.astro
+++ b/src/pages/[...index].astro
@@ -1,18 +1,41 @@
---
import PostList from '@/components/PostList.astro'
-import { getMultiLangRoutes } from '@/i18n/route'
+import { allLocales, defaultLocale } from '@/i18n/config'
import Layout from '@/layouts/Layout.astro'
import { getPinnedPosts, getPostsByYear } from '@/utils/content'
-export function getStaticPaths() {
- return getMultiLangRoutes()
+export async function getStaticPaths() {
+ // 定义路径数组的类型
+ type PathItem = {
+ params: { index: string | undefined }
+ props: { lang: string }
+ }
+
+ const paths: PathItem[] = []
+
+ // 默认语言的首页
+ paths.push({
+ params: { index: undefined },
+ props: { lang: defaultLocale },
+ })
+
+ // 更多语言的首页
+ allLocales.forEach((lang: string) => {
+ if (lang !== defaultLocale) {
+ paths.push({
+ params: { index: lang },
+ props: { lang },
+ })
+ }
+ })
+
+ return paths
}
-const { lang } = Astro.params
+const { lang } = Astro.props
const pinnedPosts = await getPinnedPosts(lang)
const postsByYear = await getPostsByYear(lang)
---
-
diff --git a/src/pages/[...posts_slug].astro b/src/pages/[...posts_slug].astro
new file mode 100644
index 0000000..a209314
--- /dev/null
+++ b/src/pages/[...posts_slug].astro
@@ -0,0 +1,145 @@
+---
+import Comments from '@/components/Comments/index.astro'
+import PostTime from '@/components/PostTime.astro'
+import { allLocales, defaultLocale } from '@/i18n/config'
+import Layout from '@/layouts/Layout.astro'
+import { checkSlugDuplication } 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)
+ if (duplicates.length > 0) {
+ throw new Error(`Slug conflicts found:\n${duplicates.join('\n')}`)
+ }
+
+ // 创建slug到语言的映射
+ const slugToLangs: Record = {}
+
+ // 填充映射
+ 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)
+ }
+ })
+
+ // 定义路径数组的类型
+ type PathItem = {
+ params: { posts_slug: string }
+ props: { post: any, lang: string, supportedLangs: string[] }
+ }
+
+ const paths: PathItem[] = []
+
+ // 默认语言的文章页面 (没有语言前缀)
+ posts.forEach((post) => {
+ if (!post.data.draft) {
+ const slug = post.data.abbrlink || post.slug
+ paths.push({
+ params: { posts_slug: `posts/${slug}` },
+ props: {
+ post,
+ lang: defaultLocale,
+ supportedLangs: slugToLangs[slug] || [],
+ },
+ })
+ }
+ })
+
+ // 更多语言的文章页面 (有语言前缀)
+ allLocales.forEach((lang: string) => {
+ if (lang !== defaultLocale) {
+ posts.forEach((post) => {
+ if (!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
+}
+
+const { post, lang, supportedLangs } = Astro.props
+const description = generateDescription(post)
+const { Content, remarkPluginFrontmatter } = await post.render()
+
+// 构建标签链接
+function getTagUrl(tagName: string): string {
+ return lang === defaultLocale
+ ? `/tags/${tagName}/`
+ : `/${lang}/tags/${tagName}/`
+}
+---
+
+
+
+
+
+ {post.data.title}
+
+
+
+
+
+
+
+
+ {post.data.tags && post.data.tags.length > 0 && (
+
+
+ )}
+
+
+
diff --git a/src/pages/[...tags].astro b/src/pages/[...tags].astro
new file mode 100644
index 0000000..dd6d526
--- /dev/null
+++ b/src/pages/[...tags].astro
@@ -0,0 +1,57 @@
+---
+import { allLocales, defaultLocale } from '@/i18n/config'
+import Layout from '@/layouts/Layout.astro'
+import { getAllTags } from '@/utils/content'
+
+export async function getStaticPaths() {
+ // 定义路径数组的类型
+ type PathItem = {
+ params: { tags: string }
+ props: { lang: string }
+ }
+
+ const paths: PathItem[] = []
+
+ // 默认语言的标签索引页
+ paths.push({
+ params: { tags: 'tags' },
+ props: { lang: defaultLocale },
+ })
+
+ // 更多语言的标签索引页
+ allLocales.forEach((lang: string) => {
+ if (lang !== defaultLocale) {
+ paths.push({
+ params: { tags: `${lang}/tags` },
+ props: { lang },
+ })
+ }
+ })
+
+ return paths
+}
+
+const { lang } = Astro.props
+const allTags = await getAllTags()
+
+// 构建标签链接
+function getTagUrl(tagName: string): string {
+ return lang === defaultLocale
+ ? `/tags/${tagName}/`
+ : `/${lang}/tags/${tagName}/`
+}
+---
+
+
+
+
+
diff --git a/src/pages/[...tags_tag].astro b/src/pages/[...tags_tag].astro
new file mode 100644
index 0000000..db7a98e
--- /dev/null
+++ b/src/pages/[...tags_tag].astro
@@ -0,0 +1,73 @@
+---
+import PostList from '@/components/PostList.astro'
+import { allLocales, defaultLocale } from '@/i18n/config'
+import Layout from '@/layouts/Layout.astro'
+import { getAllTags, getPostsByTag } from '@/utils/content'
+
+export async function getStaticPaths() {
+ const tags = await getAllTags()
+
+ // 定义路径数组的类型
+ type PathItem = {
+ params: { tags_tag: string }
+ props: { tag: string, lang: string }
+ }
+
+ const paths: PathItem[] = []
+
+ // 默认语言的标签页面 (没有语言前缀)
+ tags.forEach((tag: string) => {
+ paths.push({
+ params: { tags_tag: `tags/${tag}` },
+ props: { tag, lang: defaultLocale },
+ })
+ })
+
+ // 更多语言的标签页面 (有语言前缀)
+ allLocales.forEach((lang: string) => {
+ if (lang !== defaultLocale) {
+ tags.forEach((tag: string) => {
+ paths.push({
+ params: { tags_tag: `${lang}/tags/${tag}` },
+ props: { tag, lang },
+ })
+ })
+ }
+ })
+
+ return paths
+}
+
+const { tag, lang } = Astro.props
+const posts = await getPostsByTag(tag, lang)
+const allTags = await getAllTags()
+
+// 构建标签链接
+function getTagUrl(tagName: string): string {
+ return lang === defaultLocale
+ ? `/tags/${tagName}/`
+ : `/${lang}/tags/${tagName}/`
+}
+---
+
+
+
+
+
+
+
diff --git a/src/pages/[lang]/about.astro b/src/pages/[lang]/about.astro
deleted file mode 100644
index 8659753..0000000
--- a/src/pages/[lang]/about.astro
+++ /dev/null
@@ -1,15 +0,0 @@
----
-import { getMultiLangRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-
-export function getStaticPaths() {
- return getMultiLangRoutes()
-}
----
-
-
-
-
-
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.
-
-
diff --git a/src/pages/[lang]/posts/[slug].astro b/src/pages/[lang]/posts/[slug].astro
deleted file mode 100644
index 5aeb047..0000000
--- a/src/pages/[lang]/posts/[slug].astro
+++ /dev/null
@@ -1,74 +0,0 @@
----
-import Comments from '@/components/Comments/index.astro'
-import PostTime from '@/components/PostTime.astro'
-import { getMultiLangPostRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-import { checkSlugDuplication } 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)
- if (duplicates.length > 0) {
- throw new Error(`Slug conflicts found:\n${duplicates.join('\n')}`)
- }
-
- return getMultiLangPostRoutes(posts)
-}
-
-const { lang } = Astro.params
-const { post, supportedLangs = [] } = Astro.props
-const description = generateDescription(post)
-const { Content, remarkPluginFrontmatter } = await post.render()
----
-
-
-
-
-
- {post.data.title}
-
-
-
-
-
-
-
-
- {post.data.tags && post.data.tags.length > 0 && (
-
-
- )}
-
-
-
diff --git a/src/pages/[lang]/tags/[tag].astro b/src/pages/[lang]/tags/[tag].astro
deleted file mode 100644
index c0be869..0000000
--- a/src/pages/[lang]/tags/[tag].astro
+++ /dev/null
@@ -1,38 +0,0 @@
----
-import PostList from '@/components/PostList.astro'
-import { getMultiLangTagRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-import { getAllTags, getPostsByTag } from '@/utils/content'
-
-export async function getStaticPaths() {
- const tags = await getAllTags()
- return getMultiLangTagRoutes(tags)
-}
-
-const { lang } = Astro.params
-const { tag } = Astro.props
-const posts = await getPostsByTag(tag, lang)
-const allTags = await getAllTags()
----
-
-
-
-
-
-
-
diff --git a/src/pages/[lang]/tags/index.astro b/src/pages/[lang]/tags/index.astro
deleted file mode 100644
index ef9e752..0000000
--- a/src/pages/[lang]/tags/index.astro
+++ /dev/null
@@ -1,26 +0,0 @@
----
-import { getMultiLangRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-import { getAllTags } from '@/utils/content'
-
-export function getStaticPaths() {
- return getMultiLangRoutes()
-}
-
-const { lang } = Astro.params
-const allTags = await getAllTags()
----
-
-
-
-
-
diff --git a/src/pages/about.astro b/src/pages/about.astro
deleted file mode 100644
index bd2e192..0000000
--- a/src/pages/about.astro
+++ /dev/null
@@ -1,10 +0,0 @@
----
-import Layout from '@/layouts/Layout.astro'
----
-
-
-
-
-
Retypeset 是一款基于Astro框架的静态博客主题,设计灵感来自Typography。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。
-
-
diff --git a/src/pages/index.astro b/src/pages/index.astro
deleted file mode 100644
index 5d959ed..0000000
--- a/src/pages/index.astro
+++ /dev/null
@@ -1,27 +0,0 @@
----
-import PostList from '@/components/PostList.astro'
-import Layout from '@/layouts/Layout.astro'
-import { getPinnedPosts, getPostsByYear } from '@/utils/content'
-
-const pinnedPosts = await getPinnedPosts()
-const postsByYear = await getPostsByYear()
----
-
-
-
-
- {pinnedPosts.length > 0 && (
-
- )}
-
- {[...postsByYear.entries()].map(([_year, posts]) => (
-
- ))}
-
-
diff --git a/src/pages/posts/[slug].astro b/src/pages/posts/[slug].astro
deleted file mode 100644
index e1ca80f..0000000
--- a/src/pages/posts/[slug].astro
+++ /dev/null
@@ -1,73 +0,0 @@
----
-import Comments from '@/components/Comments/index.astro'
-import PostTime from '@/components/PostTime.astro'
-import { getPostRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-import { checkSlugDuplication } 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)
- if (duplicates.length > 0) {
- throw new Error(`Slug conflicts found:\n${duplicates.join('\n')}`)
- }
-
- return getPostRoutes(posts)
-}
-
-const { post, supportedLangs = [] } = Astro.props
-const description = generateDescription(post)
-const { Content, remarkPluginFrontmatter } = await post.render()
----
-
-
-
-
-
- {post.data.title}
-
-
-
-
-
-
-
-
- {post.data.tags && post.data.tags.length > 0 && (
-
-
- )}
-
-
-
diff --git a/src/pages/tags/[tag].astro b/src/pages/tags/[tag].astro
deleted file mode 100644
index f1f49d9..0000000
--- a/src/pages/tags/[tag].astro
+++ /dev/null
@@ -1,37 +0,0 @@
----
-import PostList from '@/components/PostList.astro'
-import { getTagRoutes } from '@/i18n/route'
-import Layout from '@/layouts/Layout.astro'
-import { getAllTags, getPostsByTag } from '@/utils/content'
-
-export async function getStaticPaths() {
- const tags = await getAllTags()
- return getTagRoutes(tags)
-}
-
-const { tag } = Astro.props
-const posts = await getPostsByTag(tag)
-const allTags = await getAllTags()
----
-
-
-
-
-
-
-
diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro
deleted file mode 100644
index bbd4785..0000000
--- a/src/pages/tags/index.astro
+++ /dev/null
@@ -1,20 +0,0 @@
----
-import Layout from '@/layouts/Layout.astro'
-import { getAllTags } from '@/utils/content'
-
-const allTags = await getAllTags()
----
-
-
-
-
-
diff --git a/src/styles/heti.css b/src/styles/heti.css
index edc4473..fe5e183 100644
--- a/src/styles/heti.css
+++ b/src/styles/heti.css
@@ -74,7 +74,7 @@
margin-block-end:24px;
text-align:justify
}
-.heti p:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti p:not(:lang(zh)) {
+.heti p:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)) {
text-align:start
}
.heti pre {
@@ -104,7 +104,7 @@
background-color:rgba(0,0,0,0);
color:inherit
}
-.heti:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti:not(:lang(zh)) {
+.heti:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)) {
letter-spacing:0
}
.heti a,.heti abbr,.heti code,.heti heti-spacing,.heti [lang=en-US] {
@@ -118,8 +118,7 @@
font-weight:600
}
.heti .post-title {
- --at-apply: 'c-primary mb-2 font-bold text-9 leading-12';
- line-height:48px
+ --at-apply: 'c-primary mb-2 font-bold text-9 leading-12 text-balance leading-12';
}
.heti h1 {
--at-apply: 'mb-6';
@@ -149,7 +148,7 @@
.heti h1,.heti h2,.heti h3 {
letter-spacing:.05em
}
-.heti h1:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti h1:not(:lang(zh)),.heti h2:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti h2:not(:lang(zh)),.heti h3:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti h3:not(:lang(zh)) {
+.heti h1:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti h1:not(:lang(zh)),.heti h2:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti h2:not(:lang(zh)),.heti h3:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti h3:not(:lang(zh)) {
letter-spacing:0
}
.heti h1+h2,.heti h2+h3,.heti h3+h4,.heti h4+h5,.heti h5+h6 {
@@ -229,7 +228,7 @@
.heti dfn {
font-weight:600
}
-.heti dfn:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti dfn:not(:lang(zh)) {
+.heti dfn:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti dfn:not(:lang(zh)) {
font-weight:400
}
.heti em {
@@ -266,7 +265,7 @@
}.heti q {
quotes:"「" "」" "『" "』"
}
-.heti q:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti q:not(:lang(zh)) {
+.heti q:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti q:not(:lang(zh)) {
quotes:initial;
quotes:auto
}
@@ -314,7 +313,7 @@
.heti address,.heti cite,.heti dfn,.heti dt,.heti em {
font-style:normal
}
-.heti address:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti address:not(:lang(zh)),.heti cite:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti cite:not(:lang(zh)),.heti dfn:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti dfn:not(:lang(zh)),.heti dt:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti dt:not(:lang(zh)),.heti em:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)),.heti em:not(:lang(zh)) {
+.heti address:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti address:not(:lang(zh)),.heti cite:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti cite:not(:lang(zh)),.heti dfn:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti dfn:not(:lang(zh)),.heti dt:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti dt:not(:lang(zh)),.heti em:not(:lang(zh)):not(:lang(zh-TW)):not(:lang(ja)):not(:lang(ko)),.heti em:not(:lang(zh)) {
font-style:italic
}
.heti .heti del,.heti ins,.heti s,.heti u {
diff --git a/src/utils/rss.ts b/src/utils/rss.ts
index 8d0faa9..d1631f4 100644
--- a/src/utils/rss.ts
+++ b/src/utils/rss.ts
@@ -36,7 +36,7 @@ export async function generateRSS({ lang }: GenerateRSSOptions = {}) {
)
return rss({
- title: lang ? `${title} (${lang})` : title,
+ title: lang ? `${title}_${lang}` : title,
description,
site: url,
items: posts.map((post: CollectionEntry<'posts'>) => ({
diff --git a/uno.config.ts b/uno.config.ts
index 3fd506d..10941e4 100644
--- a/uno.config.ts
+++ b/uno.config.ts
@@ -33,7 +33,7 @@ export default defineConfig({
},
},
shortcuts: {
- 'uno-article-underline': 'underline mx-0.25em decoration-secondary/50 font-medium underline-0.075em underline-offset-0.2em hover:(c-primary decoration-primary/75 transition)',
+ 'uno-article-underline': 'underline mx-0.25em decoration-secondary/25 font-medium underline-0.075em underline-offset-0.2em hover:(c-primary decoration-secondary/75 transition)',
'uno-tags-style': 'inline-block whitespace-nowrap border border-secondary/25 rounded-full px-3.2 py-0.7 c-secondary transition-colors hover:(border-secondary/75 text-primary)',
'uno-tag-active': 'border-secondary/75 text-primary',
'uno-decorative-line': 'h-0.25 w-10 bg-secondary opacity-25',