Skip to content

Commit d5a0409

Browse files
committed
feat: 支持国际化
1 parent 041f5bf commit d5a0409

File tree

20 files changed

+360
-186
lines changed

20 files changed

+360
-186
lines changed

config/router.ts

+41-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
FaSolidUserFriends,
88
MdiFlask,
99
} from '@/components/icons/menu-collection';
10+
import { getUserLocale } from '@/lib/getLocale';
1011

1112
export interface IHeaderMenu {
1213
title: string;
@@ -16,7 +17,7 @@ export interface IHeaderMenu {
1617
subMenu?: IHeaderMenu[];
1718
}
1819

19-
export const headerMenuConfig: IHeaderMenu[] = [
20+
const zhMenu: IHeaderMenu[] = [
2021
{
2122
title: '首页',
2223
path: '/',
@@ -32,17 +33,54 @@ export const headerMenuConfig: IHeaderMenu[] = [
3233
},
3334
{
3435
title: '友链',
35-
icon: React.createElement(FaSolidUserFriends),
3636
path: '/friends',
37+
icon: React.createElement(FaSolidUserFriends),
3738
},
3839
{
3940
title: '项目',
40-
icon: React.createElement(MdiFlask),
4141
path: '/projects',
42+
icon: React.createElement(MdiFlask),
4243
},
4344
{
4445
title: '自述',
4546
path: '/about',
4647
icon: React.createElement(FaSolidComments),
4748
},
4849
];
50+
51+
const enMenu: IHeaderMenu[] = [
52+
{
53+
title: 'Home',
54+
path: '/',
55+
type: 'Home',
56+
icon: React.createElement(FaSolidDotCircle),
57+
subMenu: [],
58+
},
59+
{
60+
title: 'Notes',
61+
type: 'Note',
62+
path: '/list',
63+
icon: React.createElement(FaSolidFeatherAlt),
64+
},
65+
{
66+
title: 'Friends',
67+
path: '/friends',
68+
icon: React.createElement(FaSolidUserFriends),
69+
},
70+
{
71+
title: 'Projects',
72+
path: '/projects',
73+
icon: React.createElement(MdiFlask),
74+
},
75+
{
76+
title: 'About',
77+
path: '/about',
78+
icon: React.createElement(FaSolidComments),
79+
},
80+
];
81+
82+
export function headerMenuConfig(): IHeaderMenu[] {
83+
const locale = getUserLocale();
84+
85+
return locale === 'en' ? enMenu : zhMenu;
86+
}

src/app/(app)/(home)/page.tsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,29 @@ import { getPostData } from '@/core';
22
import { FocusCards } from '@/components/ui/focus-cards.tsx';
33
import { Hero } from '@/components/modules/home/Hero';
44
import { WindVane } from '@/components/modules/home/WindVane/WindVane';
5+
import localeValues, { type HomeLocaleValues } from '@/locale';
6+
import { getUserLocale } from '@/lib/getLocale';
57

68
const { postDataList } = await getPostData();
79

8-
export default function Home() {
10+
export default async function Home() {
11+
const lang = getUserLocale();
12+
const homeLocale = localeValues[lang].home;
13+
914
return (
1015
<div>
1116
<Hero />
12-
<BlogCardList />
13-
<WindVane />
17+
<BlogCardList homeLocale={homeLocale} />
18+
<WindVane homeLocale={homeLocale} />
1419
</div>
1520
);
1621
}
1722

18-
const BlogCardList = () => {
23+
const BlogCardList = ({ homeLocale }: { homeLocale: HomeLocaleValues }) => {
1924
return (
2025
<div className=" w-full mt-10 md:mt-16 flex flex-col gap-y-8 px-4">
2126
<span className="text-2xl font-medium leading-loose justify-center md:justify-start md:ml-4 font-mono gap-x-2 items-center flex">
22-
最近文章
27+
{homeLocale.recentPosts}
2328
<span className=" i-material-symbols-kid-star-outline cursor-pointer hover:rotate-[720deg] animate-ease-out duration-150" />
2429
</span>
2530
<FocusCards postCards={postDataList} />

src/app/(app)/about/page.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import { NoteMarkdown } from '../notes/[nid]/pageExtra';
22

3+
import { getUserLocale } from '@/lib/getLocale';
4+
import localeValues from '@/locale';
35
import content from '~/introduction.md';
46

57
export default function About() {
8+
const lang = getUserLocale();
9+
const aboutLocale = localeValues[lang].about;
10+
611
return (
712
<div>
813
<header className="prose font-mono !mb-2">
9-
<h2>关于我</h2>
14+
<h2>{aboutLocale.about}</h2>
1015
</header>
1116

1217
<main className="flex w-full flex-col with-indent with-serif prose relative max-w-full">

src/app/(app)/friends/page.tsx

+9-59
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
'use client';
2-
3-
import { m } from 'framer-motion';
4-
import { memo, useState } from 'react';
5-
import Image from 'next/image';
6-
7-
import { friendsList, type FriendModel } from '~/index';
1+
import { friendsList } from '~/index';
2+
import { getUserLocale } from '@/lib/getLocale';
3+
import localeValues from '@/locale';
4+
import { FriendCardList } from '@/components/modules/friends/FriendsCardList';
85

96
export default function Friends() {
7+
const lang = getUserLocale();
8+
const friendsLocale = localeValues[lang].friends;
9+
1010
return (
1111
<div>
1212
<header className="prose prose-p:my-2 font-mono">
13-
<h2>朋友们</h2>
14-
<h3>海内存知己,天涯若比邻</h3>
13+
<h2>{friendsLocale.friends}</h2>
14+
<h3>{friendsLocale.quote}</h3>
1515
</header>
1616

1717
<main className="mt-10 flex w-full flex-col">
@@ -20,53 +20,3 @@ export default function Friends() {
2020
</div>
2121
);
2222
}
23-
24-
const FriendCardList = ({ data }: { data: FriendModel[] }) => (
25-
<div className="grid grid-cols-2 gap-6 md:grid-cols-3">
26-
{data.map((friendModel) => {
27-
return <FriendCard key={friendModel.url} friendModel={friendModel} />;
28-
})}
29-
</div>
30-
);
31-
32-
const FriendCard = ({ friendModel }: { friendModel: FriendModel }) => {
33-
const [enter, setEnter] = useState(false);
34-
35-
return (
36-
<m.div
37-
role="link"
38-
aria-label={`Go to ${friendModel.name}'s website`}
39-
className="relative flex flex-col items-center justify-center cursor-pointer"
40-
onMouseEnter={() => setEnter(true)}
41-
onMouseLeave={() => setEnter(false)}
42-
onClick={() => window.open(friendModel.url, '_blank')}
43-
rel="noreferrer"
44-
>
45-
{enter && <LayoutBg />}
46-
<Image
47-
src={friendModel.avatar}
48-
height={64}
49-
width={64}
50-
alt={`Avatar of ${friendModel.name}`}
51-
className=" rounded-md"
52-
/>
53-
<span className="flex h-full flex-col items-center justify-center space-y-2 py-3">
54-
<span className="text-lg font-medium">{friendModel.name}</span>
55-
<span className="line-clamp-2 text-balance break-all text-center text-sm text-base-content/80">
56-
{friendModel.desc}
57-
</span>
58-
</span>
59-
</m.div>
60-
);
61-
};
62-
const LayoutBg = memo(() => {
63-
return (
64-
<m.span
65-
layoutId="bg"
66-
className="absolute -inset-2 z-[-1] rounded-md bg-slate-200/80 dark:bg-neutral-600/80 pointer-events-none"
67-
initial={{ opacity: 0.8, scale: 0.8 }}
68-
animate={{ opacity: 1, scale: 1 }}
69-
exit={{ opacity: 0, scale: 0.8, transition: { delay: 0.2 } }}
70-
/>
71-
);
72-
});

src/app/(app)/notes/[nid]/page.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { LayoutRightSidePortal } from '@/providers/shared/LayoutRightSideProvide
1616
import { ArticleRightAside } from '@/components/modules/shared/ArticleRightAside';
1717
import { Signature } from '@/components/modules/shared/signature';
1818
import Gisus from '@/components/modules/comment/Giscus';
19+
import { getUserLocale } from '@/lib/getLocale';
1920

2021
const { postDataMap } = await getPostData();
2122

@@ -59,13 +60,14 @@ export const generateMetadata = async ({ params }: { params: any }): Promise<Met
5960
export default async function Page({ params }: { params: Record<string, any> }) {
6061
const { nid } = params;
6162
const postData = postDataMap[nid];
63+
const lang = getUserLocale();
6264

6365
return (
6466
<PageTransition>
6567
<PaperLayout>
6668
<PageInner postData={postData} />
6769
</PaperLayout>
68-
<Gisus />
70+
<Gisus lang={lang} />
6971
</PageTransition>
7072
);
7173
}

src/app/(app)/projects/page.tsx

+9-69
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
'use client';
2-
3-
import Image from 'next/image';
4-
import Link from 'next/link';
5-
61
import { GitHubBrandIcon } from '@/components/icons/platform/GitHubBrandIcon';
7-
import { cn } from '@/lib/helper';
8-
import { ProjectModel, projectList } from '~/index';
2+
import { ProjectCardList } from '@/components/modules/projects/ProjectCardList';
3+
import { projectList } from '~/index';
4+
import { getUserLocale } from '@/lib/getLocale';
5+
import localeValues from '@/locale';
96

107
export default function Projects() {
8+
const lang = getUserLocale();
9+
const projectsLocale = localeValues[lang].projects;
10+
1111
return (
1212
<div>
1313
<header className="prose prose-p:my-2 font-mono">
1414
<h1 className=" flex items-center">
15-
项目
15+
{projectsLocale.projects}
1616
<a
17-
href={`https://github.com/coderz-w`}
17+
href="https://github.com/coderz-w"
1818
className="ml-2 inline-flex !text-inherit"
1919
target="_blank"
2020
aria-label="view on GitHub"
@@ -31,63 +31,3 @@ export default function Projects() {
3131
</div>
3232
);
3333
}
34-
35-
const ProjectCardList = ({ data }: { data: ProjectModel[] }) => (
36-
<div className="grid min-w-0 grid-cols-2 gap-6 lg:grid-cols-3">
37-
{data.map((projectModel) => {
38-
return <ProjectCard key={projectModel.name} project={projectModel} />;
39-
})}
40-
</div>
41-
);
42-
const ProjectCard = ({ project }: { project: ProjectModel }) => {
43-
return (
44-
<Link
45-
href={project.url}
46-
key={project.id}
47-
className="group flex shrink-0 grid-cols-[60px_2fr] flex-col items-center gap-4 md:grid"
48-
>
49-
<ProjectIcon
50-
className="size-16 group-hover:-translate-y-2 group-hover:shadow-out-sm md:size-auto"
51-
avatar={project.avatar}
52-
name={project.name}
53-
/>
54-
<span className="flex shrink-0 grow flex-col gap-2 text-left">
55-
<h2 className="m-0 text-balance p-0 text-center font-medium md:text-left">
56-
{project.name}
57-
</h2>
58-
<span className="line-clamp-5 text-balance text-center text-sm md:line-clamp-4 md:text-left lg:line-clamp-2">
59-
{project.desc}
60-
</span>
61-
</span>
62-
</Link>
63-
);
64-
};
65-
66-
const ProjectIcon = (props: { avatar?: string; name?: string; className?: string }) => {
67-
const { avatar, name, className } = props;
68-
69-
return (
70-
<div
71-
className={cn(
72-
'project-icon flex shrink-0 grow items-center justify-center',
73-
avatar
74-
? 'ring-2 ring-slate-200 dark:ring-neutral-800'
75-
: 'bg-slate-300 text-white dark:bg-neutral-800 text-3xl',
76-
'mask mask-squircle aspect-square transition-all duration-300',
77-
className,
78-
)}
79-
>
80-
{avatar ? (
81-
<Image
82-
src={avatar}
83-
height={64}
84-
width={64}
85-
alt={`Avatar of ${name}`}
86-
className=" rounded-xl duration-300 transition-all aspect-square"
87-
/>
88-
) : (
89-
<> {name?.charAt(0).toUpperCase() || ''}</>
90-
)}
91-
</div>
92-
);
93-
};

src/components/layout/Footer/Footer.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ import Link from 'next/link';
22

33
import { PrefetchLink } from '@/components/modules/shared/PrefetchLink';
44
import ThemeSwitcher from '@/components/ui/ThemeSwitcher';
5+
import localeValues from '@/locale';
6+
import { getUserLocale } from '@/lib/getLocale';
57

68
const Footer = () => {
9+
const lang = getUserLocale();
10+
const homeLocale = localeValues[lang].home;
11+
712
return (
813
<footer
914
data-hide-print
@@ -15,14 +20,14 @@ const Footer = () => {
1520
<span className="">
1621
<PrefetchLink href={'/about'}>
1722
<span className=" relative before:content-[''] before:absolute before:bottom-[-2px] before:w-[0px] hover:before:w-[100%] before:h-[1px] before:bg-[var(--accent-color)] before:transition-all before:duration-300">
18-
关于我
23+
{homeLocale.aboutMe}
1924
</span>
2025
</PrefetchLink>
2126
</span>
2227
<span className="">
2328
<Link href={'https://github.com/coderz-w/blog'}>
2429
<span className=" relative before:content-[''] before:absolute before:bottom-[-2px] before:w-[0px] hover:before:w-[100%] before:h-[1px] before:bg-[var(--accent-color)] before:transition-all before:duration-300">
25-
此项目
30+
{homeLocale.thisProject}
2631
</span>
2732
</Link>
2833
</span>

src/components/layout/Header/Header.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ import styles from './header.module.css';
99
import { HeaderMeta } from './HeaderMeta';
1010
import { HeaderDrawerButton } from './HeaderDrawerButton';
1111

12+
import { headerMenuConfig } from '~/router';
1213
import { cn } from '@/lib/helper';
1314
import { getPostData } from '@/core';
1415

1516
const { postDataMap } = await getPostData();
1617

17-
const Header = () => {
18+
const Header = async () => {
19+
const headerMenu = await headerMenuConfig();
20+
1821
return (
1922
<HeaderWithShadow>
2023
<BlurredBackground />
@@ -25,7 +28,7 @@ const Header = () => {
2528
)}
2629
>
2730
<HeaderLeftButtonArea>
28-
<HeaderDrawerButton />
31+
<HeaderDrawerButton headerMenu={headerMenu} />
2932
</HeaderLeftButtonArea>
3033

3134
<HeaderLogoArea>
@@ -37,7 +40,7 @@ const Header = () => {
3740
</HeaderLogoArea>
3841
<div className=" sr-only"></div>
3942
<HeaderCenterArea>
40-
<HeaderCenterContent />
43+
<HeaderCenterContent headerMenu={headerMenu} />
4144
<HeaderMeta postDataMap={postDataMap} />
4245
</HeaderCenterArea>
4346

0 commit comments

Comments
 (0)