My Personal Page

Creating a personal website to showcase my projects, skills, and experiences. This website is built with Next.js, TailwindCSS, and TypeScript in SSG mode.

Features

  • Theming: Support for Dark/Light mode.
  • Localization (i18n): Support for English and Chinese locales.

Technology

  • Next.js 14
  • TailwindCSS
  • Shadcn UI
  • TypeScript
  • SSG (Static Site Generation)

Development Insights

  • Challenge: Implementing dark mode without getting flickering.

    • First I was trying to create the website with Ant Design, but i faced dark theme flickering issues. So, i need to use TailwindCSS related UI framework as TailwindCSS and have be able to set the dark class to the element before the page is generate, which can avoid the flickering issues. I also start to use more related UI library like Shadcn UI. Although user may need to customize the component, but it still more easy than I think it was as the community is growing fast !
  • Challenge: Adding multilingual support (i18n) for both English and Chinese.

    • Well, SSG is different to SSR. On SSR, we can use middleware and headers. But SSG doesn't. SSG is to hard coding everything lol. I first got stuck on how to generate locales support with next-Intl without using middleware and headers, but it seem the library do not support it. Finally, I found that I just making things complicated. What I need is to create a custom function to read the locale, while i can get the locale from the generateStaticParams. Thats all lol.
const supportedLocales = ['en', 'zh-tw'] // Add your supported locales here
const supportedSlugs = ['1', '2', '3']   // Add your supported slugs here

// Generate all combinations of locale and slug
export async function generateStaticParams() {
    const params: any = []
    supportedLocales.forEach((locale) => {
        supportedSlugs.forEach((slug) => {
            params.push({ locale, slug })
        })
    })
    return params
}

export async function generateMetadata({params,}: {
    params: { locale: string; slug: string }
}): Promise<Metadata> {
    const this_project_details = DATA.home_projects_list.find(
        (project) => project.id === Number(params.slug)
    )

    // This is not a function, but object
    const getT = await getTranslationMessages(params.locale)
    const t = getT.home.projectDetails