Tip ๐ก ์ด ํฌ์คํธ๋
next-intl์ ๋ํ ์ฌ์ ์ง์์ด ์๋ ๋ถ์ ๋์์ผ๋ก ์์ฑ๋์์ต๋๋ค.
next-intl์ ์์ํ๋ ๋ฐฉ๋ฒ์ ์๋ ํฌ์คํธ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
๐ Next.js์์ ๋ค๊ตญ์ด ์ง์ํ๊ธฐ (next-intl)
next-intl์์๋ useTranslations()๋ฅผ ์ฌ์ฉํด ์๋์ ๊ฐ์ด json ํ์ผ์ ์๋ ํ
์คํธ(๋ฉ์ธ์ง)๋ฅผ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
import {useTranslations} from 'next-intl';
export default function Index() {
const t = useTranslations('Index');
return <h1>{t('title')}</h1>;
}
์์ ์์๋ ๋ฉ์ธ์ง๋ฅผ ์ฌ์ฉํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ(Static messages)์ด๋ฉฐ, next-intl๋ ์ด ์ธ์๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์ด ํฌ์คํธ์์๋ ICU message๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ค์ ์๊ฐํด ๋ณด๊ฒ ์ต๋๋ค.
์ฐธ๊ณ ์๋ฃ ๐
next-intlDocs > Usage guide > Messages
Dynamic value๋ฅผ ๋ฃ์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ ๋ ์ด๋ฒ์ copyright footer๋ฅผ ๋ง๋ค๋ฉด์ ํ์ฌ ์ฐ๋๋ฅผ ๋ณด์ฌ์ค ์ ์๋๋ก ์ฐ๋ ๋ถ๋ถ์ dynamic value๋ก ์ฌ์ฉํด ๋ณด์์ต๋๋ค.
json ํ์ผ์ dynamic value๋ฅผ {} ์์ ์์ฑํด ์ฃผ์ธ์.// messages/en.json
"Footer": {
"copyright": "ยฉ Hailey Kim {year}"
}
๋ฉ์ธ์ง๋ฅผ ์ฌ์ฉํ ํ์ผ์์ useTranslations()์ผ๋ก ๊ฐ์ ธ์ค์ธ์.
(์ ๋ ์์ ์ปดํฌ๋ํธ์์ const t = useTranslations('Footer');๋ก ๊ฐ์ ธ์ค๊ณ t๋ฅผ props๋ก ๋๊ฒจ์ฃผ์์ต๋๋ค.).
t() ์์ (ํค ๊ฐ, dynamic value)๋ฅผ ์์ฑํด ์ฃผ์ธ์.
(dynamic value๋ object๋ก ๊ฐ์ธ์ ๋๊ฒจ์ฃผ์
์ผ ํฉ๋๋ค. {value ์ด๋ฆ: ๊ฐ})
// components/common/footer.tsx
import { Translation } from '@/types/intl';
export default function Footer({ t }: { t: Translation }) {
const year = new Date().getFullYear();
return (
<footer className="mt-20 w-72 mx-auto">
{t('copyright', { year })}
</footer>
);
}
๐ ์ ๋
t๋ฅผ props๋ก ๋๊ฒจ์ฃผ์๊ณ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๊ธฐ ๋๋ฌธ์ ํ์ ์ ๋ช ์ํด์ผ ๋ผ์ ์๋์ ๊ฐ์ดuseTranslations()์ ๋ฆฌํด ๊ฐ(t)์ ๋ํ ํ์ ์ ๋ฐ๋ก ์์ฑํ๊ณfooter์ import ํ์ฌ ์ฌ์ฉํ์ต๋๋ค.
// types/intl.ts
import { TranslationValues, Formats } from 'next-intl';
export type Translation = {
<TargetKey>(
key: TargetKey,
values?: TranslationValues | undefined,
formats?: Partial<Formats> | undefined
): string;
};
์๋์ ๊ฐ์ด ํ์ฌ ์ฐ๋(2024)๊ฐ ์ ๋์ค๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.

