refactor: 移除国际化支持并清理相关代码

移除多语言i18n实现及相关翻译文件,简化代码结构
删除分类功能及相关组件和页面
将硬编码的中文文本直接替换原有国际化调用
清理不再使用的常量和工具函数
This commit is contained in:
二叉树树
2025-08-28 14:53:01 +08:00
parent fa06fdffc1
commit 882e686a44
34 changed files with 45 additions and 550 deletions

View File

@@ -46,11 +46,6 @@
"name": "tags",
"type": "list"
},
{
"title": "category",
"name": "category",
"type": "string"
},
{
"title": "draft",
"name": "draft",

View File

@@ -51,7 +51,7 @@ published: ${getDate()}
description: ''
image: ''
tags: []
category: ''
draft: false
lang: ''
---

View File

@@ -1,16 +1,13 @@
---
import { UNCATEGORIZED } from "@constants/constants";
import I18nKey from "../i18n/i18nKey";
import { i18n } from "../i18n/translation";
import { getSortedPosts } from "../utils/content-utils";
import { getPostUrlBySlug } from "../utils/url-utils";
interface Props {
keyword?: string;
tags?: string[];
categories?: string[];
}
const { tags, categories } = Astro.props;
const { tags } = Astro.props;
let posts = await getSortedPosts();
@@ -22,13 +19,7 @@ if (Array.isArray(tags) && tags.length > 0) {
);
}
if (Array.isArray(categories) && categories.length > 0) {
posts = posts.filter(
(post) =>
(post.data.category && categories.includes(post.data.category)) ||
(!post.data.category && categories.includes(UNCATEGORIZED)),
);
}
const groups: { year: number; posts: typeof posts }[] = (() => {
const groupedPosts = posts.reduce(
@@ -74,7 +65,7 @@ function formatTag(tag: string[]) {
<div class="w-[15%] md:w-[10%]">
<div class="h-3 w-3 bg-none rounded-full outline outline-[var(--primary)] mx-auto -outline-offset-[2px] z-50 outline-3"></div>
</div>
<div class="w-[70%] md:w-[80%] transition text-left text-50">{group.posts.length} {i18n(I18nKey.postsCount)}</div>
<div class="w-[70%] md:w-[80%] transition text-left text-50">{group.posts.length} 篇文章</div>
</div>
{group.posts.map(post => (
<a href={getPostUrlBySlug(post.slug)}

View File

@@ -1,8 +1,7 @@
<script lang="ts">
import type { LIGHT_DARK_MODE } from "@/types/config.ts";
import { AUTO_MODE, DARK_MODE, LIGHT_MODE } from "@constants/constants.ts";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import Icon from "@iconify/svelte";
import {
applyThemeToDocument,
@@ -78,21 +77,21 @@ function hidePanel() {
onclick={() => switchScheme(LIGHT_MODE)}
>
<Icon icon="material-symbols:wb-sunny-outline-rounded" class="text-[1.25rem] mr-3"></Icon>
{i18n(I18nKey.lightMode)}
浅色模式
</button>
<button class="flex transition whitespace-nowrap items-center !justify-start w-full btn-plain scale-animation rounded-lg h-9 px-3 font-medium active:scale-95 mb-0.5"
class:current-theme-btn={mode === DARK_MODE}
onclick={() => switchScheme(DARK_MODE)}
>
<Icon icon="material-symbols:dark-mode-outline-rounded" class="text-[1.25rem] mr-3"></Icon>
{i18n(I18nKey.darkMode)}
深色模式
</button>
<button class="flex transition whitespace-nowrap items-center !justify-start w-full btn-plain scale-animation rounded-lg h-9 px-3 font-medium active:scale-95"
class:current-theme-btn={mode === AUTO_MODE}
onclick={() => switchScheme(AUTO_MODE)}
>
<Icon icon="material-symbols:radio-button-partial-outline" class="text-[1.25rem] mr-3"></Icon>
{i18n(I18nKey.systemMode)}
跟随系统
</button>
</div>
</div>

View File

@@ -2,8 +2,7 @@
import path from "node:path";
import type { CollectionEntry } from "astro:content";
import { Icon } from "astro-icon/components";
import I18nKey from "../i18n/i18nKey";
import { i18n } from "../i18n/translation";
import { getDir } from "../utils/url-utils";
import PostMetadata from "./PostMeta.astro";
import ImageWrapper from "./misc/ImageWrapper.astro";
@@ -17,7 +16,6 @@ interface Props {
published: Date;
updated?: Date;
tags: string[];
category: string;
image: string;
description: string;
draft: boolean;
@@ -30,7 +28,6 @@ const {
published,
updated,
tags,
category,
image,
description,
style,
@@ -65,7 +62,7 @@ const { remarkPluginFrontmatter } = await entry.render();
</a>
<!-- metadata -->
<PostMetadata published={published} updated={updated} tags={tags} category={category} hideTagsForMobile={true} hideUpdateDate={true} class="mb-4"></PostMetadata>
<PostMetadata published={published} updated={updated} tags={tags} hideTagsForMobile={true} hideUpdateDate={true} class="mb-4"></PostMetadata>
<!-- description -->
<div class:list={["transition text-75 mb-3.5 pr-4", {"line-clamp-2 md:line-clamp-1": !description}]}>
@@ -74,9 +71,9 @@ const { remarkPluginFrontmatter } = await entry.render();
<!-- word count, read time and page views -->
<div class="text-sm text-black/30 dark:text-white/30 flex gap-4 transition">
<div>{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}</div>
<div>{remarkPluginFrontmatter.words} </div>
<div>|</div>
<div>{remarkPluginFrontmatter.minutes} {" " + i18n(I18nKey.minutesCount)}</div>
<div>{remarkPluginFrontmatter.minutes} 分钟</div>
<div>|</div>
<div>
<span class="text-50 text-sm font-medium" id={`page-views-${entry.slug}`}>加载中...</span>

View File

@@ -1,7 +1,6 @@
---
import { Icon } from "astro-icon/components";
import I18nKey from "../i18n/i18nKey";
import { i18n } from "../i18n/translation";
import { getDir, url } from "../utils/url-utils";
import { formatDateToYYYYMMDD } from "../utils/date-utils";
import { umamiConfig } from "../config";
@@ -11,7 +10,6 @@ interface Props {
published: Date;
updated?: Date;
tags: string[];
category: string;
hideTagsForMobile?: boolean;
hideUpdateDate?: boolean;
slug?: string;
@@ -20,7 +18,6 @@ const {
published,
updated,
tags,
category,
hideTagsForMobile = false,
hideUpdateDate = false,
slug,
@@ -49,21 +46,6 @@ const className = Astro.props.class;
</div>
)}
<!-- categories -->
<div class="flex items-center">
<div class="meta-icon"
>
<Icon name="material-symbols:book-2-outline-rounded" class="text-xl"></Icon>
</div>
<div class="flex flex-row flex-nowrap items-center">
<a href={url(`/archive/category/${category || 'uncategorized'}/`)} aria-label=`View all posts in the ${category} category`
class="link-lg transition text-50 text-sm font-medium
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
{category || i18n(I18nKey.uncategorized)}
</a>
</div>
</div>
<!-- tags -->
<div class:list={["items-center", {"flex": !hideTagsForMobile, "hidden md:flex": hideTagsForMobile}]}>
<div class="meta-icon"
@@ -79,7 +61,7 @@ const className = Astro.props.class;
{tag}
</a>
))}
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">{i18n(I18nKey.noTags)}</div>}
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">无标签</div>}
</div>
</div>

View File

@@ -14,7 +14,6 @@ const interval = 50;
entry={entry}
title={entry.data.title}
tags={entry.data.tags}
category={entry.data.category}
published={entry.data.published}
updated={entry.data.updated}
url={getPostUrlBySlug(entry.slug)}

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import Icon from "@iconify/svelte";
import { url } from "@utils/url-utils.ts";
import { onMount } from "svelte";
@@ -143,7 +142,7 @@ $: search(keywordMobile, false);
dark:bg-white/5 dark:hover:bg-white/10 dark:focus-within:bg-white/10
">
<Icon icon="material-symbols:search" class="absolute text-[1.25rem] pointer-events-none ml-3 transition my-auto text-black/30 dark:text-white/30"></Icon>
<input placeholder="{i18n(I18nKey.search)}" bind:value={keywordDesktop} on:focus={() => search(keywordDesktop, true)}
<input placeholder="搜索" bind:value={keywordDesktop} on:focus={() => search(keywordDesktop, true)}
class="transition-all pl-10 text-sm bg-transparent outline-0
h-full w-40 active:w-60 focus:w-60 text-black/50 dark:text-white/50"
>

View File

@@ -1,8 +1,7 @@
---
import { Icon } from "astro-icon/components";
import { licenseConfig, profileConfig } from "../../config";
import I18nKey from "../../i18n/i18nKey";
import { i18n } from "../../i18n/translation";
import { formatDateToYYYYMMDD } from "../../utils/date-utils";
interface Props {
@@ -27,15 +26,15 @@ const postUrl = decodeURIComponent(Astro.url.toString());
</a>
<div class="flex gap-6 mt-2">
<div>
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.author)}</div>
<div class="transition text-black/30 dark:text-white/30 text-sm">作者</div>
<div class="transition text-black/75 dark:text-white/75 line-clamp-2">{profileConf.name}</div>
</div>
<div>
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.publishedAt)}</div>
<div class="transition text-black/30 dark:text-white/30 text-sm">发布于</div>
<div class="transition text-black/75 dark:text-white/75 line-clamp-2">{formatDateToYYYYMMDD(pubDate)}</div>
</div>
<div>
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.license)}</div>
<div class="transition text-black/30 dark:text-white/30 text-sm">许可协议</div>
<a href={licenseConf.url} target="_blank" class="link text-[var(--primary)] line-clamp-2">{licenseConf.name}</a>
</div>
</div>

View File

@@ -1,37 +0,0 @@
---
import WidgetLayout from "./WidgetLayout.astro";
import I18nKey from "../../i18n/i18nKey";
import { i18n } from "../../i18n/translation";
import { getCategoryList } from "../../utils/content-utils";
import { getCategoryUrl } from "../../utils/url-utils";
import ButtonLink from "../control/ButtonLink.astro";
const categories = await getCategoryList();
const COLLAPSED_HEIGHT = "7.5rem";
const COLLAPSE_THRESHOLD = 5;
const isCollapsed = categories.length >= COLLAPSE_THRESHOLD;
interface Props {
class?: string;
style?: string;
}
const className = Astro.props.class;
const style = Astro.props.style;
---
<WidgetLayout name={i18n(I18nKey.categories)} id="categories" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT}
class={className} style={style}
>
{categories.map((c) =>
<ButtonLink
url={getCategoryUrl(c.name)}
badge={String(c.count)}
label=`View all posts in the ${c.name} category`
>
{c.name}
</ButtonLink>
)}
</WidgetLayout>

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import Icon from "@iconify/svelte";
import { getDefaultHue, getHue, setHue } from "@utils/setting-utils";
@@ -22,7 +21,7 @@ $: if (hue || hue === 0) {
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
before:absolute before:-left-3 before:top-[0.33rem]"
>
{i18n(I18nKey.themeColor)}
主题色彩
<button aria-label="Reset to Default" class="btn-regular w-7 h-7 rounded-md active:scale-90"
class:opacity-0={hue === defaultHue} class:pointer-events-none={hue === defaultHue} on:click={resetHue}>
<div class="text-[var(--btn-content)]">
@@ -38,7 +37,7 @@ $: if (hue || hue === 0) {
</div>
</div>
<div class="w-full h-6 px-1 bg-[oklch(0.80_0.10_0)] dark:bg-[oklch(0.70_0.10_0)] rounded select-none">
<input aria-label={i18n(I18nKey.themeColor)} type="range" min="0" max="360" bind:value={hue}
<input aria-label="主题色彩" type="range" min="0" max="360" bind:value={hue}
class="slider" id="colorSlider" step="5" style="width: 100%">
</div>
</div>

View File

@@ -1,6 +1,6 @@
---
import type { MarkdownHeading } from "astro";
import Categories from "./Categories.astro";
import Profile from "./Profile.astro";
import Tag from "./Tags.astro";
@@ -16,7 +16,7 @@ const className = Astro.props.class;
<Profile></Profile>
</div>
<div id="sidebar-sticky" class="transition-all duration-700 flex flex-col w-full gap-4 top-4 sticky top-4">
<Categories class="onload-animation" style="animation-delay: 150ms"></Categories>
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
<!-- 赞助标 -->
<div class="overflow-hidden flex justify-center">

View File

@@ -1,7 +1,6 @@
---
import I18nKey from "../../i18n/i18nKey";
import { i18n } from "../../i18n/translation";
import { getTagList } from "../../utils/content-utils";
import { url } from "../../utils/url-utils";
import ButtonTag from "../control/ButtonTag.astro";
@@ -20,7 +19,7 @@ interface Props {
const className = Astro.props.class;
const style = Astro.props.style;
---
<WidgetLayout name={i18n(I18nKey.tags)} id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}>
<WidgetLayout name="标签" id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}>
<div class="flex gap-2 flex-wrap">
{tags.map(t => (
<ButtonTag href={url(`/archive/tag/${t.name}/`)} label={`View all posts with the ${t.name} tag`}>

View File

@@ -1,7 +1,6 @@
---
import { Icon } from "astro-icon/components";
import I18nKey from "../../i18n/i18nKey";
import { i18n } from "../../i18n/translation";
interface Props {
id: string;
name?: string;
@@ -23,7 +22,7 @@ const className = Astro.props.class;
{isCollapsed && <div class="expand-btn px-4 -mb-2">
<button class="btn-plain rounded-lg w-full h-9">
<div class="text-[var(--primary)] flex items-center justify-center gap-2 -translate-x-2">
<Icon name="material-symbols:more-horiz" class="text-[1.75rem]"></Icon> {i18n(I18nKey.more)}
<Icon name="material-symbols:more-horiz" class="text-[1.75rem]"></Icon> 更多
</div>
</button>
</div>}

View File

@@ -1,18 +1,17 @@
import { LinkPreset, type NavBarLink } from "@/types/config";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
export const LinkPresets: { [key in LinkPreset]: NavBarLink } = {
[LinkPreset.Home]: {
name: i18n(I18nKey.home),
name: "首页",
url: "/",
},
[LinkPreset.About]: {
name: i18n(I18nKey.about),
name: "关于",
url: "/about/",
},
[LinkPreset.Archive]: {
name: i18n(I18nKey.archive),
name: "归档",
url: "/archive/",
},
};

View File

@@ -9,7 +9,6 @@ const postsCollection = defineCollection({
description: z.string().optional().default(""),
image: z.string().optional().default(""),
tags: z.array(z.string()).optional().default([]),
category: z.string().optional().default(""),
lang: z.string().optional().default(""),
pinned: z.boolean().optional().default(false),

View File

@@ -1,37 +0,0 @@
enum I18nKey {
home = "home",
about = "about",
archive = "archive",
search = "search",
tags = "tags",
categories = "categories",
recentPosts = "recentPosts",
comments = "comments",
untitled = "untitled",
uncategorized = "uncategorized",
noTags = "noTags",
wordCount = "wordCount",
wordsCount = "wordsCount",
minuteCount = "minuteCount",
minutesCount = "minutesCount",
postCount = "postCount",
postsCount = "postsCount",
themeColor = "themeColor",
lightMode = "lightMode",
darkMode = "darkMode",
systemMode = "systemMode",
more = "more",
author = "author",
publishedAt = "publishedAt",
license = "license",
}
export default I18nKey;

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const en: Translation = {
[Key.home]: "Home",
[Key.about]: "About",
[Key.archive]: "Archive",
[Key.search]: "Search",
[Key.tags]: "Tags",
[Key.categories]: "Categories",
[Key.recentPosts]: "Recent Posts",
[Key.comments]: "Comments",
[Key.untitled]: "Untitled",
[Key.uncategorized]: "Uncategorized",
[Key.noTags]: "No Tags",
[Key.wordCount]: "word",
[Key.wordsCount]: "words",
[Key.minuteCount]: "minute",
[Key.minutesCount]: "minutes",
[Key.postCount]: "post",
[Key.postsCount]: "posts",
[Key.themeColor]: "Theme Color",
[Key.lightMode]: "Light",
[Key.darkMode]: "Dark",
[Key.systemMode]: "System",
[Key.more]: "More",
[Key.author]: "Author",
[Key.publishedAt]: "Published at",
[Key.license]: "License",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const es: Translation = {
[Key.home]: "Inicio",
[Key.about]: "Sobre mí",
[Key.archive]: "Archivo",
[Key.search]: "Buscar",
[Key.tags]: "Etiquetas",
[Key.categories]: "Categorías",
[Key.recentPosts]: "Publicaciones recientes",
[Key.comments]: "Comentarios",
[Key.untitled]: "Sin título",
[Key.uncategorized]: "Sin categoría",
[Key.noTags]: "Sin etiquetas",
[Key.wordCount]: "palabra",
[Key.wordsCount]: "palabras",
[Key.minuteCount]: "minuto",
[Key.minutesCount]: "minutos",
[Key.postCount]: "publicación",
[Key.postsCount]: "publicaciones",
[Key.themeColor]: "Color del tema",
[Key.lightMode]: "Claro",
[Key.darkMode]: "Oscuro",
[Key.systemMode]: "Sistema",
[Key.more]: "Más",
[Key.author]: "Autor",
[Key.publishedAt]: "Publicado el",
[Key.license]: "Licencia",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const ja: Translation = {
[Key.home]: "Home",
[Key.about]: "About",
[Key.archive]: "Archive",
[Key.search]: "検索",
[Key.tags]: "タグ",
[Key.categories]: "カテゴリ",
[Key.recentPosts]: "最近の投稿",
[Key.comments]: "コメント",
[Key.untitled]: "タイトルなし",
[Key.uncategorized]: "カテゴリなし",
[Key.noTags]: "タグなし",
[Key.wordCount]: "文字",
[Key.wordsCount]: "文字",
[Key.minuteCount]: "分",
[Key.minutesCount]: "分",
[Key.postCount]: "件の投稿",
[Key.postsCount]: "件の投稿",
[Key.themeColor]: "テーマカラー",
[Key.lightMode]: "ライト",
[Key.darkMode]: "ダーク",
[Key.systemMode]: "システム",
[Key.more]: "もっと",
[Key.author]: "作者",
[Key.publishedAt]: "公開日",
[Key.license]: "ライセンス",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const ko: Translation = {
[Key.home]: "홈",
[Key.about]: "소개",
[Key.archive]: "아카이브",
[Key.search]: "검색",
[Key.tags]: "태그",
[Key.categories]: "카테고리",
[Key.recentPosts]: "최근 게시물",
[Key.comments]: "댓글",
[Key.untitled]: "제목 없음",
[Key.uncategorized]: "분류되지 않음",
[Key.noTags]: "태그 없음",
[Key.wordCount]: "단어",
[Key.wordsCount]: "단어",
[Key.minuteCount]: "분",
[Key.minutesCount]: "분",
[Key.postCount]: "게시물",
[Key.postsCount]: "게시물",
[Key.themeColor]: "테마 색상",
[Key.lightMode]: "밝은 모드",
[Key.darkMode]: "어두운 모드",
[Key.systemMode]: "시스템 모드",
[Key.more]: "더 보기",
[Key.author]: "저자",
[Key.publishedAt]: "게시일",
[Key.license]: "라이선스",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const th: Translation = {
[Key.home]: "หน้าแรก",
[Key.about]: "เกี่ยวกับ",
[Key.archive]: "คลัง",
[Key.search]: "ค้นหา",
[Key.tags]: "ป้ายกำกับ",
[Key.categories]: "หมวดหมู่",
[Key.recentPosts]: "โพสต์ล่าสุด",
[Key.comments]: "ความคิดเห็น",
[Key.untitled]: "ไม่ได้ตั้งชื่อ",
[Key.uncategorized]: "ไม่ได้จัดหมวดหมู่",
[Key.noTags]: "ไม่มีป้ายกำกับ",
[Key.wordCount]: "คำ",
[Key.wordsCount]: "คำ",
[Key.minuteCount]: "นาที",
[Key.minutesCount]: "นาที",
[Key.postCount]: "โพสต์",
[Key.postsCount]: "โพสต์",
[Key.themeColor]: "สีของธีม",
[Key.lightMode]: "สว่าง",
[Key.darkMode]: "มืด",
[Key.systemMode]: "ตามระบบ",
[Key.more]: "ดูเพิ่ม",
[Key.author]: "ผู้เขียน",
[Key.publishedAt]: "เผยแพร่เมื่อ",
[Key.license]: "สัญญาอนุญาต",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const zh_CN: Translation = {
[Key.home]: "主页",
[Key.about]: "关于&隐私政策",
[Key.archive]: "归档",
[Key.search]: "搜索",
[Key.tags]: "标签",
[Key.categories]: "分类",
[Key.recentPosts]: "最新文章",
[Key.comments]: "评论",
[Key.untitled]: "无标题",
[Key.uncategorized]: "未分类",
[Key.noTags]: "无标签",
[Key.wordCount]: "字",
[Key.wordsCount]: "字",
[Key.minuteCount]: "分钟",
[Key.minutesCount]: "分钟",
[Key.postCount]: "篇文章",
[Key.postsCount]: "篇文章",
[Key.themeColor]: "主题色",
[Key.lightMode]: "亮色",
[Key.darkMode]: "暗色",
[Key.systemMode]: "跟随系统",
[Key.more]: "更多",
[Key.author]: "作者",
[Key.publishedAt]: "发布于",
[Key.license]: "许可协议",
};

View File

@@ -1,38 +0,0 @@
import Key from "../i18nKey";
import type { Translation } from "../translation";
export const zh_TW: Translation = {
[Key.home]: "首頁",
[Key.about]: "關於",
[Key.archive]: "彙整",
[Key.search]: "搜尋",
[Key.tags]: "標籤",
[Key.categories]: "分類",
[Key.recentPosts]: "最新文章",
[Key.comments]: "評論",
[Key.untitled]: "無標題",
[Key.uncategorized]: "未分類",
[Key.noTags]: "無標籤",
[Key.wordCount]: "字",
[Key.wordsCount]: "字",
[Key.minuteCount]: "分鐘",
[Key.minutesCount]: "分鐘",
[Key.postCount]: "篇文章",
[Key.postsCount]: "篇文章",
[Key.themeColor]: "主題色",
[Key.lightMode]: "亮色",
[Key.darkMode]: "暗色",
[Key.systemMode]: "跟隨系統",
[Key.more]: "更多",
[Key.author]: "作者",
[Key.publishedAt]: "發佈於",
[Key.license]: "許可協議",
};

View File

@@ -1,40 +0,0 @@
import { siteConfig } from "../config";
import type I18nKey from "./i18nKey";
import { en } from "./languages/en";
import { es } from "./languages/es";
import { ja } from "./languages/ja";
import { ko } from "./languages/ko";
import { th } from "./languages/th";
import { zh_CN } from "./languages/zh_CN";
import { zh_TW } from "./languages/zh_TW";
export type Translation = {
[K in I18nKey]: string;
};
const defaultTranslation = en;
const map: { [key: string]: Translation } = {
es: es,
en: en,
en_us: en,
en_gb: en,
en_au: en,
zh_cn: zh_CN,
zh_tw: zh_TW,
ja: ja,
ja_jp: ja,
ko: ko,
ko_kr: ko,
th: th,
th_th: th,
};
export function getTranslation(lang: string): Translation {
return map[lang.toLowerCase()] || defaultTranslation;
}
export function i18n(key: I18nKey): string {
const lang = siteConfig.lang || "en";
return getTranslation(lang)[key];
}

View File

@@ -5,8 +5,7 @@ import MainGridLayout from "../layouts/MainGridLayout.astro";
import { getEntry } from "astro:content";
import { render } from "astro:content";
import Markdown from "@components/misc/Markdown.astro";
import I18nKey from "../i18n/i18nKey";
import { i18n } from "../i18n/translation";
const aboutPost = await getEntry("spec", "about");
@@ -16,7 +15,7 @@ if (!aboutPost) {
const { Content } = await render(aboutPost);
---
<MainGridLayout title={i18n(I18nKey.about)} description={i18n(I18nKey.about)}>
<MainGridLayout title="关于" description="关于">
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative min-h-32">
<div class="card-base z-10 px-9 py-6 relative w-full ">
<Markdown class="mt-2">

View File

@@ -1,24 +0,0 @@
---
import ArchivePanel from "@components/ArchivePanel.astro";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import MainGridLayout from "@layouts/MainGridLayout.astro";
import { getCategoryList } from "@utils/content-utils";
export async function getStaticPaths() {
const categories = await getCategoryList();
return categories.map((category) => {
return {
params: {
category: category.name,
},
};
});
}
const category = Astro.params.category as string;
---
<MainGridLayout title={`${category} - ${i18n(I18nKey.categories)}`} description={`${i18n(I18nKey.archive)} - ${category}`}>
<ArchivePanel categories={[category]}></ArchivePanel>
</MainGridLayout>

View File

@@ -1,11 +0,0 @@
---
import ArchivePanel from "@components/ArchivePanel.astro";
import { UNCATEGORIZED } from "@constants/constants";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import MainGridLayout from "@layouts/MainGridLayout.astro";
---
<MainGridLayout title={`${i18n(I18nKey.uncategorized)} - ${i18n(I18nKey.categories)}`} description={`${i18n(I18nKey.archive)} - ${i18n(I18nKey.uncategorized)}`}>
<ArchivePanel categories={[UNCATEGORIZED]}></ArchivePanel>
</MainGridLayout>

View File

@@ -1,11 +1,10 @@
---
import ArchivePanel from "@components/ArchivePanel.astro";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import MainGridLayout from "@layouts/MainGridLayout.astro";
---
<MainGridLayout title={i18n(I18nKey.archive)}>
<MainGridLayout title="归档">
<ArchivePanel></ArchivePanel>
</MainGridLayout>

View File

@@ -1,7 +1,6 @@
---
import ArchivePanel from "@components/ArchivePanel.astro";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import MainGridLayout from "@layouts/MainGridLayout.astro";
import { getSortedPosts } from "@utils/content-utils";
@@ -27,6 +26,6 @@ export async function getStaticPaths() {
const tag = Astro.params.tag as string;
---
<MainGridLayout title={`${tag} - ${i18n(I18nKey.tags)}`} description={`${i18n(I18nKey.archive)} - ${tag}`}>
<MainGridLayout title={`${tag} - 标签`} description={`归档 - ${tag}`}>
<ArchivePanel tags={[tag]}></ArchivePanel>
</MainGridLayout>

View File

@@ -2,8 +2,7 @@
import path from "node:path";
import License from "@components/misc/License.astro";
import Markdown from "@components/misc/Markdown.astro";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
import MainGridLayout from "@layouts/MainGridLayout.astro";
import { getSortedPosts } from "@utils/content-utils";
import { getDir, getPostUrlBySlug } from "@utils/url-utils";
@@ -57,13 +56,13 @@ const jsonLd = {
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/10 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
<Icon name="material-symbols:notes-rounded"></Icon>
</div>
<div class="text-sm">{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}</div>
<div class="text-sm">{remarkPluginFrontmatter.words} </div>
</div>
<div class="flex flex-row items-center">
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/10 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
<Icon name="material-symbols:schedule-outline-rounded"></Icon>
</div>
<div class="text-sm">{remarkPluginFrontmatter.minutes} {" " + i18n(I18nKey.minutesCount)}</div>
<div class="text-sm">{remarkPluginFrontmatter.minutes} 分钟</div>
</div>
</div>
@@ -101,7 +100,6 @@ const jsonLd = {
published={entry.data.published}
updated={entry.data.updated}
tags={entry.data.tags}
category={entry.data.category}
slug={entry.slug}
></PostMetadata>
{!entry.data.image && <div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>}

View File

@@ -105,7 +105,6 @@ export type BlogPostData = {
tags: string[];
draft?: boolean;
image?: string;
category?: string;
prevTitle?: string;
prevSlug?: string;
nextTitle?: string;

View File

@@ -1,6 +1,5 @@
import { getCollection } from "astro:content";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
export async function getSortedPosts() {
const allBlogPosts = await getCollection("posts", ({ data }) => {
@@ -54,35 +53,3 @@ export async function getTagList(): Promise<Tag[]> {
return keys.map((key) => ({ name: key, count: countMap[key] }));
}
export type Category = {
name: string;
count: number;
};
export async function getCategoryList(): Promise<Category[]> {
const allBlogPosts = await getCollection<"posts">("posts", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
const count: { [key: string]: number } = {};
allBlogPosts.map((post: { data: { category: string | number } }) => {
if (!post.data.category) {
const ucKey = i18n(I18nKey.uncategorized);
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1;
return;
}
count[post.data.category] = count[post.data.category]
? count[post.data.category] + 1
: 1;
});
const lst = Object.keys(count).sort((a, b) => {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
const ret: Category[] = [];
for (const c of lst) {
ret.push({ name: c, count: count[c] });
}
return ret;
}

View File

@@ -1,6 +1,3 @@
import i18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
export function pathsEqual(path1: string, path2: string) {
const normalizedPath1 = path1.replace(/^\/|\/$/g, "").toLowerCase();
const normalizedPath2 = path2.replace(/^\/|\/$/g, "").toLowerCase();
@@ -16,11 +13,7 @@ export function getPostUrlBySlug(slug: string): string {
return url(`/posts/${slug}/`);
}
export function getCategoryUrl(category: string): string {
if (category === i18n(i18nKey.uncategorized))
return url("/archive/category/uncategorized/");
return url(`/archive/category/${category}/`);
}
export function getDir(path: string): string {
const lastSlashIndex = path.lastIndexOf("/");