feat: add i18n settings

This commit is contained in:
yoosangwook 2024-08-05 17:58:22 +09:00
parent 0043851e5c
commit 2e5346a387
29 changed files with 277 additions and 15 deletions

View File

@ -17,6 +17,7 @@
"mathjs": "^13.0.2",
"mongodb": "^6.8.0",
"next": "14.2.3",
"next-international": "^1.2.4",
"react": "^18",
"react-datepicker": "^7.3.0",
"react-dom": "^18",

View File

@ -0,0 +1,11 @@
'use client'
import { I18nProviderClient } from '@/locales/client'
export function LocaleProvider({ locale, children }) {
return (
<I18nProviderClient locale={locale} fallback={<p>Loading...</p>}>
{children}
</I18nProviderClient>
)
}

View File

@ -0,0 +1,4 @@
.test {
@apply bg-red-500;
@apply text-2xl;
}

View File

@ -0,0 +1,73 @@
'use client'
import { Button, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react'
import Hero from '@/components/Hero'
import QSelect from '@/components/ui/QSelect'
import styles from './changelog.module.css'
import { get } from '@/lib/Axios'
export default function changelogPage() {
const testVar = process.env.NEXT_PUBLIC_TEST
const handleUsers = async () => {
const users = await get('/api/user/find-all')
console.log(users)
}
const data = [
{
id: 1,
author: 'SWYOO',
contents: '버튼 정리(템플릿 적용)',
date: '2024.07.16',
},
{
id: 2,
author: 'SWYOO',
contents: 'README.md 파일 이미지 경로 수정',
date: '2024.07.17',
},
{
id: 3,
author: 'SWYOO',
contents: '',
date: '',
},
]
return (
<>
<Hero title="Change log" />
<div className={styles.test}> 영역은 테스트입니다.</div>
<div>
<Table isStriped>
<TableHeader>
<TableColumn>DATE</TableColumn>
<TableColumn>NAME</TableColumn>
<TableColumn>CONTENTS</TableColumn>
</TableHeader>
<TableBody>
{data.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.date}</TableCell>
<TableCell>{item.author}</TableCell>
<TableCell>{item.contents}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="m-2">
<QSelect />
</div>
<div className="w-full bg-orange-300 m-2">{testVar}</div>
<div>
<div className="m-2">
<Button onClick={handleUsers}>Button</Button>
</div>
</div>
<div className="test">
<p className="text-white">Sass 테스트입니다.</p>
</div>
</>
)
}

View File

@ -0,0 +1,15 @@
'use client'
export default function ServerError() {
return (
<section className="bg-white dark:bg-gray-900">
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
<div className="mx-auto max-w-screen-sm text-center">
<h1 className="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-primary-600 dark:text-primary-500">500</h1>
<p className="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">Internal Server Error.</p>
<p className="mb-4 text-lg font-light text-gray-500 dark:text-gray-400">We are already working to solve the problem. </p>
</div>
</div>
</section>
)
}

View File

@ -6,7 +6,6 @@ import Intro from '@/components/Intro'
export default function IntroPage() {
return (
<>
<Hero title="Common Components Intro Page" />
<div className="container mx-auto p-4 m-4 border">
<Intro />
</div>

View File

@ -0,0 +1,13 @@
'use client'
import { useCurrentLocale } from '@/locales/client'
import { LocaleProvider } from './LocaleProvider'
export default function LocaleLayout({ children }) {
const locale = useCurrentLocale()
return (
<>
<LocaleProvider locale={locale}>{children}</LocaleProvider>
</>
)
}

View File

@ -0,0 +1,25 @@
'use client'
import Link from 'next/link'
export default function NotFound() {
return (
<section className="bg-white dark:bg-gray-900">
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
<div className="mx-auto max-w-screen-sm text-center">
<h1 className="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-primary-600 dark:text-primary-500">404</h1>
<p className="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">Something's missing.</p>
<p className="mb-4 text-lg font-light text-gray-500 dark:text-gray-400">
Sorry, we can't find that page. You'll find lots to explore on the home page.{' '}
</p>
<Link
href="/"
className="inline-flex text-white bg-primary-600 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:focus:ring-primary-900 my-4"
>
Back to Homepage
</Link>
</div>
</div>
</section>
)
}

19
src/app/[locale]/page.js Normal file
View File

@ -0,0 +1,19 @@
import MainPage from '@/components/Main'
import { getCurrentLocale } from '@/locales/server'
export default function page() {
const currentLocale = getCurrentLocale()
const mainPageProps = {
currentLocale,
}
return (
<>
<div className="m-4">
<h3>Main</h3>
<MainPage {...mainPageProps} />
</div>
</>
)
}

View File

@ -2,7 +2,7 @@ import Link from 'next/link'
export default function Headers() {
return (
<div className="w-full absolute z-10">
<div className="w-full">
<nav className="container relative flex flex-wrap items-center justify-between mx-auto p-8">
<Link href="/" className="font-bold text-3xl">
Home

View File

@ -1,5 +1,27 @@
import Hero from './Hero'
'use client'
export default function Main() {
return <Hero title="Q.CAST III - Prototype" />
import { useChangeLocale, useI18n } from '@/locales/client'
import { Button, Chip } from '@nextui-org/react'
export default function MainPage(props) {
const { currentLocale } = props
const t = useI18n()
const changeLocale = useChangeLocale()
const handleChangeLocale = () => {
currentLocale === 'ja' ? changeLocale('ko') : changeLocale('ja')
}
console.log('MainPage', currentLocale)
return (
<>
<h3>{t('locale', { locale: <Chip color="primary">{currentLocale}</Chip> })}</h3>
<div>{t('hello')}</div>
<div>{t('welcome', { name: '효준' })}</div>
<div>
<Button onClick={handleChangeLocale}>Change Locale</Button>
</div>
</>
)
}

18
src/locales/client.js Normal file
View File

@ -0,0 +1,18 @@
'use client'
import { createI18nClient } from 'next-international/client'
export const { useI18n, useScopedI18n, I18nProviderClient, useChangeLocale, defineLocale, useCurrentLocale } = createI18nClient(
{
ko: () => import('./ko'),
ja: () => import('./ja'),
},
{
// Uncomment to set base path
// basePath: '/base',
// Uncomment to use custom segment name
// segmentName: 'locale',
// Uncomment to set fallback locale
// fallbackLocale: en,
},
)

7
src/locales/ja.js Normal file
View File

@ -0,0 +1,7 @@
console.log('Loaded JA')
export default {
hello: 'こんにちは',
welcome: 'こんにちは {name}!',
locale: '現在のロケールは {locale} です。',
}

7
src/locales/ko.js Normal file
View File

@ -0,0 +1,7 @@
console.log('Loaded KO')
export default {
hello: '안녕',
welcome: '안녕 {name}!',
locale: '현재 로케일은 {locale}입니다.',
}

14
src/locales/server.js Normal file
View File

@ -0,0 +1,14 @@
import { createI18nServer } from 'next-international/server'
export const { getI18n, getScopedI18n, getCurrentLocale, getStaticParams } = createI18nServer(
{
ko: () => import('./ko'),
ja: () => import('./ja'),
},
{
// Uncomment to use custom segment name
// segmentName: 'locale',
// Uncomment to set fallback locale
// fallbackLocale: en,
},
)

View File

@ -1,12 +1,27 @@
import { NextRequest, NextResponse } from 'next/server'
import { createI18nMiddleware } from 'next-international/middleware'
const I18nMiddleware = createI18nMiddleware({
locales: ['ko', 'ja'],
defaultLocale: 'ko',
})
export function middleware(request) {
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-pathname', request.nextUrl.pathname)
return NextResponse.next({
request: {
headers: requestHeaders,
},
})
return I18nMiddleware(request)
}
export const config = {
matcher: ['/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)'],
}
// import { NextRequest, NextResponse } from 'next/server'
// export function middleware(request) {
// const requestHeaders = new Headers(request.headers)
// requestHeaders.set('x-pathname', request.nextUrl.pathname)
// return NextResponse.next({
// request: {
// headers: requestHeaders,
// },
// })
// }

View File

@ -2314,7 +2314,7 @@ chownr@^2.0.0:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
client-only@0.0.1:
client-only@0.0.1, client-only@^0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
@ -2773,6 +2773,11 @@ inherits@2, inherits@^2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
international-types@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/international-types/-/international-types-0.8.1.tgz#c0e593d9911c1a23f64bbd6eb1abb2941fe2353f"
integrity sha512-tajBCAHo4I0LIFlmQ9ZWfjMWVyRffzuvfbXCd6ssFt5u1Zw15DN0UBpVTItXdNa1ls+cpQt3Yw8+TxsfGF8JcA==
intl-messageformat@^10.1.0:
version "10.5.14"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.14.tgz#e5bb373f8a37b88fbe647d7b941f3ab2a37ed00a"
@ -3097,6 +3102,15 @@ nanoid@^3.3.6, nanoid@^3.3.7:
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
next-international@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/next-international/-/next-international-1.2.4.tgz#abe50b2aa3ba7ecf92d41f87537796a4b2dd0ba3"
integrity sha512-JQvp+h2iSgA/t8hu5S/Lwow1ZErJutQRdpnplxjv4VTlCiND8T95fYih8BjkHcVhQbtM+Wu9Mb1CM32wD9hlWQ==
dependencies:
client-only "^0.0.1"
international-types "^0.8.1"
server-only "^0.0.1"
next@14.2.3:
version "14.2.3"
resolved "https://registry.npmjs.org/next/-/next-14.2.3.tgz"
@ -3523,6 +3537,11 @@ semver@^7.3.5:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
server-only@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/server-only/-/server-only-0.0.1.tgz#0f366bb6afb618c37c9255a314535dc412cd1c9e"
integrity sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"