chore: localize theme wording for zh-TW

This commit is contained in:
2025-09-17 10:11:58 +08:00
parent edcb6cb794
commit 087612e9d7
21 changed files with 63 additions and 63 deletions

View File

@@ -1,7 +1,7 @@
import SmartLink from '@/components/SmartLink' import SmartLink from '@/components/SmartLink'
/** /**
* 上一篇,下一文章 * 上一則與下一文章
* @param {prev,next} param0 * @param {prev,next} param0
* @returns * @returns
*/ */

View File

@@ -6,7 +6,7 @@ import { formatDateFmt } from '@/lib/utils/formatDate'
import NotionIcon from '@/components/NotionIcon' import NotionIcon from '@/components/NotionIcon'
/** /**
* 文章描述 * 文章說明
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
@@ -27,7 +27,7 @@ export default function ArticleInfo(props) {
<header className='text-md text-[var(--primary-color)] dark:text-gray-300 flex-wrap flex items-center leading-6'> <header className='text-md text-[var(--primary-color)] dark:text-gray-300 flex-wrap flex items-center leading-6'>
<div className='space-x-2'> <div className='space-x-2'>
<span className='text-sm'> <span className='text-sm'>
发布于 發佈於
<SmartLink <SmartLink
className='p-1 hover:text-red-400 transition-all duration-200' className='p-1 hover:text-red-400 transition-all duration-200'
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}> href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}>

View File

@@ -2,10 +2,10 @@ import { useGlobal } from '@/lib/global'
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
/** /**
* 加密文章校验组 * 加密文章驗證元
* @param {password, validPassword} props * @param {password, validPassword} props
* @param password 正的密 * @param password 正的密
* @param validPassword(bool) 回调函数,校验正确回调入参为true * @param validPassword(bool) 回呼函式,驗證正確回呼參數為 true
* @returns * @returns
*/ */
export default function ArticleLock (props) { export default function ArticleLock (props) {
@@ -24,7 +24,7 @@ export default function ArticleLock (props) {
} }
const passwordInputRef = useRef(null) const passwordInputRef = useRef(null)
useEffect(() => { useEffect(() => {
// 中密码输入框并将其聚焦 // 中密碼輸入框並將其聚焦
passwordInputRef.current.focus() passwordInputRef.current.focus()
}, []) }, [])
@@ -38,7 +38,7 @@ export default function ArticleLock (props) {
submitPassword() submitPassword()
} }
}} }}
ref={passwordInputRef} // 绑定ref到passwordInputRef变量 ref={passwordInputRef} // 綁定 ref 到 passwordInputRef 變數
className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg font-light leading-10 text-black dark:bg-gray-500 bg-gray-50' className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg font-light leading-10 text-black dark:bg-gray-500 bg-gray-50'
></input> ></input>
<div onClick={submitPassword} className="px-3 whitespace-nowrap cursor-pointer items-center justify-center py-2 rounded-r duration-300 bg-gray-300" > <div onClick={submitPassword} className="px-3 whitespace-nowrap cursor-pointer items-center justify-center py-2 rounded-r duration-300 bg-gray-300" >

View File

@@ -1,7 +1,7 @@
import SmartLink from '@/components/SmartLink' import SmartLink from '@/components/SmartLink'
/** /**
* 归档分组文章 * 歸檔文章清單
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */

View File

@@ -16,11 +16,11 @@ export const BlogItem = props => {
siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post.blockMap siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post.blockMap
return ( return (
<div key={post.id} className='h-42 mt-6 mb-10'> <div key={post.id} className='h-42 mt-6 mb-10'>
{/* 文章标题 */} {/* 文章標題 */}
<div className='flex'> <div className='flex'>
<div className='article-cover h-full'> <div className='article-cover h-full'>
{/* 片封面 */} {/* 片封面 */}
{showPageCover && ( {showPageCover && (
<div className='overflow-hidden mr-2 w-56 h-full'> <div className='overflow-hidden mr-2 w-56 h-full'>
<SmartLink href={post.href} passHref legacyBehavior> <SmartLink href={post.href} passHref legacyBehavior>
@@ -45,11 +45,11 @@ export const BlogItem = props => {
</SmartLink> </SmartLink>
</h2> </h2>
{/* 文章信息 */} {/* 文章資訊 */}
<header className='text-md text-[var(--primary-color)] dark:text-gray-300 flex-wrap flex items-center leading-6'> <header className='text-md text-[var(--primary-color)] dark:text-gray-300 flex-wrap flex items-center leading-6'>
<div className='space-x-2'> <div className='space-x-2'>
<span className='text-sm'> <span className='text-sm'>
发布于 發佈於
<SmartLink <SmartLink
className='p-1 hover:text-red-400 transition-all duration-200' className='p-1 hover:text-red-400 transition-all duration-200'
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}> href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}>

View File

@@ -7,7 +7,7 @@ import CONFIG from '../config'
import { BlogItem } from './BlogItem' import { BlogItem } from './BlogItem'
/** /**
* 博客列表 * 部落格文章列表
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
@@ -19,7 +19,7 @@ export default function BlogListPage(props) {
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE) const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
const currentPage = +page const currentPage = +page
// 博客列表嵌入广 // 部落格列表插入廣
const TYPOGRAPHY_POST_AD_ENABLE = siteConfig( const TYPOGRAPHY_POST_AD_ENABLE = siteConfig(
'TYPOGRAPHY_POST_AD_ENABLE', 'TYPOGRAPHY_POST_AD_ENABLE',
false, false,

View File

@@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { BlogItem } from './BlogItem' import { BlogItem } from './BlogItem'
/** /**
* 滚动博客列表 * 捲動部落格列表
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
@@ -30,7 +30,7 @@ export default function BlogListScroll(props) {
const targetRef = useRef(null) const targetRef = useRef(null)
// 监听滚动自动分页加载 // 監聽滾動自動分頁載入
const scrollTrigger = useCallback( const scrollTrigger = useCallback(
throttle(() => { throttle(() => {
const scrollS = window.scrollY + window.outerHeight const scrollS = window.scrollY + window.outerHeight

View File

@@ -1,7 +1,7 @@
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
/** /**
* 文章列表上方嵌入 * 文章列表上方區塊
* @param {*} props * @param {*} props
* @returns * @returns
*/ */

View File

@@ -4,26 +4,26 @@ import { uuidToId } from 'notion-utils'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
/** /**
* 目录导航组 * 目錄導覽元
* @param toc * @param toc
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */
const Catalog = ({ post }) => { const Catalog = ({ post }) => {
const { locale } = useGlobal() const { locale } = useGlobal()
// 目录自动滚动 // 目錄自動滾動
const tRef = useRef(null) const tRef = useRef(null)
// 同步中目事件 // 同步中目事件
const [activeSection, setActiveSection] = useState(null) const [activeSection, setActiveSection] = useState(null)
// 监听滚动事件 // 監聽滾動事件
useEffect(() => { useEffect(() => {
// 如果有文章或目,不行任何操作 // 如果有文章或目,不行任何操作
if (!post || !post?.toc || post?.toc?.length < 1) { if (!post || !post?.toc || post?.toc?.length < 1) {
return return
} }
const throttleMs = 100 // 降低节流时间提高响应速度 const throttleMs = 100 // 降低節流時間提高響應速度
const actionSectionScrollSpy = throttle(() => { const actionSectionScrollSpy = throttle(() => {
const sections = document.getElementsByClassName('notion-h') const sections = document.getElementsByClassName('notion-h')
@@ -32,34 +32,34 @@ const Catalog = ({ post }) => {
let prevBBox = null let prevBBox = null
let currentSectionId = null let currentSectionId = null
// 先检查当前视口中的所有标题 // 先檢查當前視窗中的所有標題
for (let i = 0; i < sections.length; ++i) { for (let i = 0; i < sections.length; ++i) {
const section = sections[i] const section = sections[i]
if (!section || !(section instanceof Element)) continue if (!section || !(section instanceof Element)) continue
const bbox = section.getBoundingClientRect() const bbox = section.getBoundingClientRect()
const offset = 100 // 固定移量,避免算不 const offset = 100 // 固定移量,避免算不
// 如果标题在视口上方或接近部,认为是当前标题 // 如果標題在視窗上方或接近部,認為是當前標題
if (bbox.top - offset < 0) { if (bbox.top - offset < 0) {
currentSectionId = section.getAttribute('data-id') currentSectionId = section.getAttribute('data-id')
prevBBox = bbox prevBBox = bbox
} else { } else {
// 找到第一个在视口下方的标题就停止 // 找到第一個在視窗下方的標題就停止
break break
} }
} }
// 如果找到任何标题在视口上方,使用第一个标题 // 如果找到任何標題在視窗上方,使用第一個標題
if (!currentSectionId && sections.length > 0) { if (!currentSectionId && sections.length > 0) {
currentSectionId = sections[0].getAttribute('data-id') currentSectionId = sections[0].getAttribute('data-id')
} }
// 只有 ID 变化时才更新状态,减少不必要的渲染 // 只有 ID 變化時才更新狀態,減少不必要的渲染
if (currentSectionId !== activeSection) { if (currentSectionId !== activeSection) {
setActiveSection(currentSectionId) setActiveSection(currentSectionId)
// 查找目录中对应的索引并滚动 // 查找目錄中對應的索引並滾動
const index = post?.toc?.findIndex( const index = post?.toc?.findIndex(
obj => uuidToId(obj.id) === currentSectionId obj => uuidToId(obj.id) === currentSectionId
) )
@@ -73,20 +73,20 @@ const Catalog = ({ post }) => {
const content = document.querySelector('#container-inner') const content = document.querySelector('#container-inner')
if (!content) return // 防止 content 不存在 if (!content) return // 防止 content 不存在
// 添加滚动和内容变化的监听 // 添加滾動和內容變化的監聽
content.addEventListener('scroll', actionSectionScrollSpy) content.addEventListener('scroll', actionSectionScrollSpy)
// 初始行一次 // 初始行一次
setTimeout(() => { setTimeout(() => {
actionSectionScrollSpy() actionSectionScrollSpy()
}, 300) // 延迟执行确保 DOM 已完全加载 }, 300) // 延遲執行確保 DOM 已完全載入
return () => { return () => {
content?.removeEventListener('scroll', actionSectionScrollSpy) content?.removeEventListener('scroll', actionSectionScrollSpy)
} }
}, [post]) }, [post])
// 无目录就直接返回空 // 無目錄就直接返回空
if (!post || !post?.toc || post?.toc?.length < 1) { if (!post || !post?.toc || post?.toc?.length < 1) {
return <></> return <></>
} }

View File

@@ -2,10 +2,10 @@ import { useGlobal } from '@/lib/global'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
/** /**
* 跳转到网页顶 * 跳轉到網頁頂
* 当屏幕下滑500像素后会出现该控件 * 當畫面下滑 500 像素後會出現此按鈕
* @param targetRef 关联高度的目html标签 * @param targetRef 連結高度的目html 元素
* @param showPercent 是否示百分比 * @param showPercent 是否示百分比
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */

View File

@@ -3,7 +3,7 @@ import SmartLink from '@/components/SmartLink'
import { useState } from 'react' import { useState } from 'react'
/** /**
* 折叠菜单 * 收合選單
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */
@@ -64,7 +64,7 @@ export const MenuItemCollapse = props => {
)} )}
</div> </div>
{/* 折叠子菜单 */} {/* 收合子選單 */}
{hasSubMenu && ( {hasSubMenu && (
<Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}> <Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}>
{link.subMenus.map((sLink, index) => { {link.subMenus.map((sLink, index) => {

View File

@@ -49,7 +49,7 @@ export const MenuItemDrop = ({ link }) => {
)} )}
</div> </div>
{/* 子單 */} {/* 子單 */}
<ul <ul
className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} absolute glassmorphism md:left-28 md:top-0 top-6 w-full border-gray-100 transition-all duration-300 z-20 block`}> className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} absolute glassmorphism md:left-28 md:top-0 top-6 w-full border-gray-100 transition-all duration-300 z-20 block`}>
{link?.subMenus?.map((sLink, index) => { {link?.subMenus?.map((sLink, index) => {

View File

@@ -8,7 +8,7 @@ import { MenuItemCollapse } from './MenuItemCollapse'
import { MenuItemDrop } from './MenuItemDrop' import { MenuItemDrop } from './MenuItemDrop'
/** /**
* 菜单导航 * 選單導覽
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
@@ -53,7 +53,7 @@ export const MenuList = ({ customNav, customMenu }) => {
links = links.concat(customNav) links = links.concat(customNav)
} }
// 如果 开启自定义菜单,则覆盖 Page 生成的菜单 // 如果 開啟自訂選單,則覆蓋 Page 生成的選單
if (siteConfig('CUSTOM_MENU')) { if (siteConfig('CUSTOM_MENU')) {
links = customMenu links = customMenu
} }
@@ -64,13 +64,13 @@ export const MenuList = ({ customNav, customMenu }) => {
return ( return (
<> <>
{/* 大屏模式菜单 - 垂直排列 */} {/* 大螢幕模式選單 - 垂直排列 */}
<div id='nav-menu-pc' className='hidden md:flex md:flex-col md:gap-2'> <div id='nav-menu-pc' className='hidden md:flex md:flex-col md:gap-2'>
{links?.map((link, index) => ( {links?.map((link, index) => (
<MenuItemDrop key={index} link={link} /> <MenuItemDrop key={index} link={link} />
))} ))}
</div> </div>
{/* 移动端小屏菜单 - 水平排列 */} {/* 行動端小螢幕選單 - 水平排列 */}
<div <div
id='nav-menu-mobile' id='nav-menu-mobile'
className='flex md:hidden my-auto justify-center space-x-4'> className='flex md:hidden my-auto justify-center space-x-4'>

View File

@@ -7,7 +7,7 @@ import SocialButton from './SocialButton'
import SmartLink from '@/components/SmartLink' import SmartLink from '@/components/SmartLink'
/** /**
* 菜单导航 * 選單導覽
* @param {*} props * @param {*} props
* @returns * @returns
*/ */

View File

@@ -4,7 +4,7 @@ import CONFIG from '../config'
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
/** /**
* 示文章推 * 示文章推
*/ */
const RecommendPosts = ({ recommendPosts }) => { const RecommendPosts = ({ recommendPosts }) => {
const { locale } = useGlobal() const { locale } = useGlobal()

View File

@@ -1,7 +1,7 @@
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
/** /**
* 社交联系方式按钮组 * 社交聯絡方式按鈕組
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */

View File

@@ -1,7 +1,7 @@
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
/** /**
* 标题栏 * 標題區塊
* @param {*} props * @param {*} props
* @returns * @returns
*/ */

View File

@@ -2,7 +2,7 @@ import CONFIG from '../config'
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
/** /**
* 网站顶部 提示 * 網站上方提示
* @returns * @returns
*/ */
export default function TopBar (props) { export default function TopBar (props) {

View File

@@ -1,17 +1,17 @@
const CONFIG = { const CONFIG = {
// 博客標題 雙語言 // 部落格標題 雙語言
TYPOGRAPHY_BLOG_NAME: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || '活字印刷', TYPOGRAPHY_BLOG_NAME: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || '活字印刷',
TYPOGRAPHY_BLOG_NAME_EN: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME_EN || process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || 'Typography', TYPOGRAPHY_BLOG_NAME_EN: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME_EN || process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || 'Typography',
TYPOGRAPHY_POST_AD_ENABLE: process.env.NEXT_PUBLIC_TYPOGRAPHY_POST_AD_ENABLE || false, // 文章列表是否插入广 TYPOGRAPHY_POST_AD_ENABLE: process.env.NEXT_PUBLIC_TYPOGRAPHY_POST_AD_ENABLE || false, // 文章列表是否插入
TYPOGRAPHY_POST_COVER_ENABLE: process.env.NEXT_PUBLIC_TYPOGRAPHY_POST_COVER_ENABLE || false, // 是否展示博客封面 TYPOGRAPHY_POST_COVER_ENABLE: process.env.NEXT_PUBLIC_TYPOGRAPHY_POST_COVER_ENABLE || false, // 是否展示部落格封面
TYPOGRAPHY_ARTICLE_RECOMMEND_POSTS: process.env.NEXT_PUBLIC_TYPOGRAPHY_ARTICLE_RECOMMEND_POSTS || true, // 文章情底部示推 TYPOGRAPHY_ARTICLE_RECOMMEND_POSTS: process.env.NEXT_PUBLIC_TYPOGRAPHY_ARTICLE_RECOMMEND_POSTS || true, // 文章情底部示推
// 菜单配置 // 選單設定
TYPOGRAPHY_MENU_CATEGORY: true, // 示分 TYPOGRAPHY_MENU_CATEGORY: true, // 示分
TYPOGRAPHY_MENU_TAG: true, // 显示标签 TYPOGRAPHY_MENU_TAG: true, // 顯示標籤
TYPOGRAPHY_MENU_ARCHIVE: true, // 显示归档 TYPOGRAPHY_MENU_ARCHIVE: true, // 顯示歸檔
} }
export default CONFIG export default CONFIG

View File

@@ -20,7 +20,7 @@ const Layout404 = props => {
const article = document.querySelector('#article-wrapper #notion-article') const article = document.querySelector('#article-wrapper #notion-article')
if (!article) { if (!article) {
router.push('/404').then(() => { router.push('/404').then(() => {
console.warn('找不到面', router.asPath) console.warn('找不到面', router.asPath)
}) })
} }
}, waiting404) }, waiting404)

View File

@@ -1,7 +1,7 @@
/* eslint-disable react/no-unknown-property */ /* eslint-disable react/no-unknown-property */
/** /**
* 此处样式只对当前主生效 * 此處樣式只對當前主生效
* 此不支 tailwindCSS 的 @apply * 此不支 tailwindCSS 的 @apply
* @returns * @returns
*/ */
const Style = () => { const Style = () => {
@@ -29,7 +29,7 @@ const Style = () => {
.dark body { .dark body {
background-color: rgb(35, 34, 34); background-color: rgb(35, 34, 34);
} }
// 文不可 // 文不可
.forbid-copy { .forbid-copy {
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;