diff --git a/src/components/Navbar.astro b/src/components/Navbar.astro index 25787a9..18e69f4 100644 --- a/src/components/Navbar.astro +++ b/src/components/Navbar.astro @@ -2,7 +2,22 @@ import Button from "./control/Button.astro"; import { Icon } from 'astro-icon/components'; import DisplaySetting from "./widget/DisplaySetting.astro"; +import {getConfig} from "../utils/config-utils"; +import I18nKey from "../i18n/i18nKey"; +import {i18n} from "../i18n/translation"; const className = Astro.props.class; + +function isI18nKey(key: string): key is I18nKey { + return Object.values(I18nKey).includes(key); +} + +function getLinkName(name: string) { + if (isI18nKey(name)) { + return i18n(name); + } + return name; +} + ---
- - - + {Object.keys(getConfig().menu).map((key) => { + return + })}
diff --git a/src/components/PostMetadata.astro b/src/components/PostMetadata.astro index 522bc51..97c8632 100644 --- a/src/components/PostMetadata.astro +++ b/src/components/PostMetadata.astro @@ -1,6 +1,8 @@ --- import {formatDateToYYYYMMDD} from "../utils/date-utils"; import { Icon } from 'astro-icon/components'; +import {i18n} from "../i18n/translation"; +import I18nKey from "../i18n/i18nKey"; interface Props { class: string; @@ -38,7 +40,7 @@ const className = Astro.props.class; {category}
)} - {!categories &&
Uncategorized
} + {!categories &&
{i18n(I18nKey.uncategorized)}
}
@@ -49,7 +51,7 @@ const className = Astro.props.class;
- {tags.map(tag =>
)} + {!tags &&
{i18n(I18nKey.noTags)}
}
diff --git a/src/components/TitleCardNew.astro b/src/components/TitleCardNew.astro index 1e58c04..27eef5f 100644 --- a/src/components/TitleCardNew.astro +++ b/src/components/TitleCardNew.astro @@ -19,6 +19,8 @@ import ImageBox from "./misc/ImageBox.astro"; import ButtonTag from "./control/ButtonTag.astro"; import { Icon } from 'astro-icon/components'; import Button from "./control/Button.astro"; +import {i18n} from "../i18n/translation"; +import I18nKey from "../i18n/i18nKey"; // tags = ['Foo', 'Bar', 'Baz', 'Qux', 'Quux']; @@ -51,9 +53,9 @@ const { remarkPluginFrontmatter } = await entry.render();
-
{remarkPluginFrontmatter.words} words
+
{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}
|
-
{remarkPluginFrontmatter.minutes} minutes
+
{remarkPluginFrontmatter.minutes} {" " + i18n(I18nKey.minutesCount)}
diff --git a/src/components/widget/DisplaySetting.astro b/src/components/widget/DisplaySetting.astro index d337a3a..19971d5 100644 --- a/src/components/widget/DisplaySetting.astro +++ b/src/components/widget/DisplaySetting.astro @@ -1,5 +1,7 @@ --- import {getConfig} from "../../utils/config-utils"; +import {i18n} from "../../i18n/translation"; +import I18nKey from "../../i18n/i18nKey"; const hueSet: number[] = [0, 30, 60, 180, 250, 270, 300, 330, 345]; const enableBanner = getConfig().banner.enable; @@ -13,7 +15,7 @@ const enableBanner = getConfig().banner.enable; before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)] before:absolute before:left-[-12px] before:top-[5.5px]" > - Primary Color + {i18n(I18nKey.primaryColor)}
{0} diff --git a/src/components/widget/RecentPost.astro b/src/components/widget/RecentPost.astro index b14b934..b40c112 100644 --- a/src/components/widget/RecentPost.astro +++ b/src/components/widget/RecentPost.astro @@ -2,6 +2,8 @@ import WidgetLayout from "./WidgetLayout.astro"; import ButtonLink from "../control/ButtonLink.astro"; import {getPostUrlBySlug, getSortedPosts} from "../../utils/content-utils"; +import {i18n} from "../../i18n/translation"; +import I18nKey from "../../i18n/i18nKey"; let posts = await getSortedPosts() @@ -11,7 +13,7 @@ posts = posts.slice(0, LIMIT) // console.log(posts) --- - + {posts.map(post => {post.data.title} )} diff --git a/src/components/widget/Tag.astro b/src/components/widget/Tag.astro index 33c1c72..96b3903 100644 --- a/src/components/widget/Tag.astro +++ b/src/components/widget/Tag.astro @@ -3,11 +3,13 @@ import WidgetLayout from "./WidgetLayout.astro"; import ButtonTag from "../control/ButtonTag.astro"; import {getTagList} from "../../utils/content-utils"; +import {i18n} from "../../i18n/translation"; +import I18nKey from "../../i18n/i18nKey"; const tags = await getTagList(); --- - +
{tags.map(t => ( diff --git a/src/i18n/i18nKey.ts b/src/i18n/i18nKey.ts new file mode 100644 index 0000000..347046f --- /dev/null +++ b/src/i18n/i18nKey.ts @@ -0,0 +1,26 @@ +enum I18nKey { + home = "home", + about = "about", + archive = "archive", + + 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", + + primaryColor = "primaryColor", +} + +export default I18nKey; \ No newline at end of file diff --git a/src/i18n/languages/en.ts b/src/i18n/languages/en.ts new file mode 100644 index 0000000..a155b37 --- /dev/null +++ b/src/i18n/languages/en.ts @@ -0,0 +1,27 @@ +import type { Translation } from "../translation.ts"; +import Key from "../i18nKey.ts"; + +export const en: Translation = { + [Key.home]: "Home", + [Key.about]: "About", + [Key.archive]: "Archive", + + [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.primaryColor]: "Primary Color", +}; diff --git a/src/i18n/languages/zh_CN.ts b/src/i18n/languages/zh_CN.ts new file mode 100644 index 0000000..8cffc66 --- /dev/null +++ b/src/i18n/languages/zh_CN.ts @@ -0,0 +1,27 @@ +import type { Translation } from "../translation.ts"; +import Key from "../i18nKey.ts"; + +export const zh_CN: Translation = { + [Key.home]: "主页", + [Key.about]: "关于", + [Key.archive]: "归档", + + [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.primaryColor]: "主题色", +}; \ No newline at end of file diff --git a/src/i18n/languages/zh_TW.ts b/src/i18n/languages/zh_TW.ts new file mode 100644 index 0000000..2482217 --- /dev/null +++ b/src/i18n/languages/zh_TW.ts @@ -0,0 +1,27 @@ +import type { Translation } from "../translation.ts"; +import Key from "../i18nKey.ts"; + +export const zh_TW: Translation = { + [Key.home]: "首頁", + [Key.about]: "關於", + [Key.archive]: "彙整", + + [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.primaryColor]: "主題色", +}; diff --git a/src/i18n/translation.ts b/src/i18n/translation.ts new file mode 100644 index 0000000..ed1e979 --- /dev/null +++ b/src/i18n/translation.ts @@ -0,0 +1,30 @@ +import {en} from "./languages/en.ts"; +import {zh_TW} from "./languages/zh_TW.ts"; +import {zh_CN} from "./languages/zh_CN.ts"; +import type I18nKey from "./i18nKey.ts"; +import {getConfig} from "../utils/config-utils.ts"; + +export type Translation = { + [K in I18nKey]: string; +} + +const defaultTranslation = en; + +const map: { [key: string]: Translation } = { + "en": en, + "en_us": en, + "en_gb": en, + "en_au": en, + "zh_cn": zh_CN, + "zh_tw": zh_TW, +} + +export function getTranslation(lang: string): Translation { + lang = lang.toLowerCase(); + return map[lang] || defaultTranslation; +} + +export function i18n(key: I18nKey): string { + const lang = getConfig().lang || "en"; + return getTranslation(lang)[key]; +} \ No newline at end of file diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index f77cd20..0200b98 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -54,6 +54,11 @@ if (!banner || typeof banner !== 'string' || banner.trim() === '') { // TODO don't use post cover as banner for now banner = viConf.banner.url; +let pageTitle = getConfig().title; +if (title) { + pageTitle = `${title} - ${pageTitle}`; +} + --- @@ -61,6 +66,8 @@ banner = viConf.banner.url; + {pageTitle} + diff --git a/src/pages/about.astro b/src/pages/about.astro index d5b38fc..7f79402 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -3,13 +3,15 @@ import MainGridLayout from "../layouts/MainGridLayout.astro"; import { getEntry } from 'astro:content' +import {i18n} from "../i18n/translation"; +import I18nKey from "../i18n/i18nKey"; const aboutPost = await getEntry('spec', 'about') const { Content } = await aboutPost.render() --- - +
diff --git a/src/pages/archive/category/[category].astro b/src/pages/archive/category/[category].astro index 00cfebf..dd4071b 100644 --- a/src/pages/archive/category/[category].astro +++ b/src/pages/archive/category/[category].astro @@ -3,6 +3,8 @@ import {getSortedPosts} from "../../../utils/content-utils"; import MainGridLayout from "../../../layouts/MainGridLayout.astro"; import ArchivePanel from "../../../components/ArchivePanel.astro"; +import {i18n} from "../../../i18n/translation"; +import I18nKey from "../../../i18n/i18nKey"; export async function getStaticPaths() { @@ -30,6 +32,6 @@ const { category } = Astro.params; --- - + diff --git a/src/pages/archive/index.astro b/src/pages/archive/index.astro index 5d2544f..85d6fae 100644 --- a/src/pages/archive/index.astro +++ b/src/pages/archive/index.astro @@ -2,9 +2,11 @@ import { getCollection, getEntry } from "astro:content"; import MainGridLayout from "../../layouts/MainGridLayout.astro"; import ArchivePanel from "../../components/ArchivePanel.astro"; +import {i18n} from "../../i18n/translation"; +import I18nKey from "../../i18n/i18nKey"; --- - + diff --git a/src/pages/archive/tag/[tag].astro b/src/pages/archive/tag/[tag].astro index f57a0b7..466cba4 100644 --- a/src/pages/archive/tag/[tag].astro +++ b/src/pages/archive/tag/[tag].astro @@ -3,7 +3,8 @@ import {getSortedPosts} from "../../../utils/content-utils"; import MainGridLayout from "../../../layouts/MainGridLayout.astro"; import ArchivePanel from "../../../components/ArchivePanel.astro"; - +import {i18n} from "../../../i18n/translation"; +import I18nKey from "../../../i18n/i18nKey"; export async function getStaticPaths() { @@ -29,6 +30,6 @@ const { tag } = Astro.params; --- - + diff --git a/src/pages/posts/[slug].astro b/src/pages/posts/[slug].astro index 37eefcd..f00efd0 100644 --- a/src/pages/posts/[slug].astro +++ b/src/pages/posts/[slug].astro @@ -9,6 +9,8 @@ import PostMetadata from "../../components/PostMetadata.astro"; import {getPostUrlBySlug} from "../../utils/content-utils"; import Button from "../../components/control/Button.astro"; import {getConfig} from "../../utils/config-utils"; +import {i18n} from "../../i18n/translation"; +import I18nKey from "../../i18n/i18nKey"; export async function getStaticPaths() { const blogEntries = await getCollection('posts'); @@ -25,7 +27,7 @@ const { remarkPluginFrontmatter } = await entry.render(); const enableBanner = getConfig().banner.enable; --- - +
-
{remarkPluginFrontmatter.words} words
+
{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}
-
{remarkPluginFrontmatter.minutes} minutes
+
{remarkPluginFrontmatter.minutes} {" " + i18n(I18nKey.minutesCount)}
diff --git a/src/utils/config-utils.ts b/src/utils/config-utils.ts index f2a9e22..d2c69a7 100644 --- a/src/utils/config-utils.ts +++ b/src/utils/config-utils.ts @@ -1,9 +1,12 @@ +// @ts-ignore import _config from '../../vivia.config.yml'; interface ViviaConfig { + title: string; menu: { [key: string]: string; }; + lang: string; appearance: { hue: number; }; diff --git a/vivia.config.yml b/vivia.config.yml index 8b5e76a..5c6be76 100644 --- a/vivia.config.yml +++ b/vivia.config.yml @@ -1,6 +1,14 @@ +title: Fuwari +menu: + home: / + archive: /archive + about: /about + appearance: hue: 250 +lang: en + banner: enable: true url: https://saicaca.github.io/vivia-preview/assets/banner.jpg