오랜만에 쭈꾸미 집을 들려 안부 인사를 묻고 웹사이트는 문제 없냐 물어봤다. 그런데 직원 핸드폰에서는 접속이 잘되는데 가끔 외국인 핸드폰에서는 404 에러가 뜬다고 한다. 아니 이런.. 그게 무슨 말이야?! 왜지 왤까.. 집에가면서 계속 생각을 해봤고 아무래도 vercel 에서 해외 IP 차단을 한 것 일 수도 있다고 생각이 들었다.
부랴부랴 집에 와서 vercel 에서의 내 프로젝트를 확인해 오류 로그를 보려고 하니 아뿔싸 분석기는 따로 import 해서 layout.tsx 에 넣어야 작동을 한다는 것!?
사실 다국어 언어 메뉴를 만들면서 초기구상은 nexti18n 을 사용하기로 했지만, 배움의 부담에 못이겨 하드코딩으로 진행했다. 그러다보니 유지보수는 물론,, 가독성이 완전 제로제로제로였다. 그래서 이를 잘 관리하기 위해 기존 기획했던 nexti18n 을 제대로 적용해보려고 한다.
처음부터 잘못됐던
나는 초반에 nexti18n 라이브러리를 적용하기 위해 설치를 했으나 구글링을 통해 제대로 확인해보니 Next13/14 App 기반 환경은 기존 라이브러리를 지원하지 못한다고 한다!?!
대충 app 에서는 지원하지 않는다는 의미
대신 i18next, react-i18next, i18next-resources-to-backend 라이브러리를 사용해 구성하라고 한다.
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
// Can be imported from a shared config
const locales = ['en', 'ko'];
export default getRequestConfig(async ({locale}) => {
// Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale as any)) notFound();
return {
messages: (await import(`../messages/${locale}.json`)).default
};
});
next-intl은 요청 범위의 구성 객체를 생성하여 사용자의 언어에 따라 메시지 및 기타 옵션을 제공할 수 있으며, 이를 서버 컴포넌트에서 사용할 수 있습니다.
4) middleware.ts
import createMiddleware from 'next-intl/middleware';
export default createMiddleware({
// A list of all locales that are supported
locales: ['en', 'ko'],
// Used when no locale matches
defaultLocale: 'en'
});
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(ko|en)/:path*']
};
middleware 에서는 요청에 따른 언어가 매칭되는지 확인하고 리다이렉트하거나 리라이트 하는 역할을 한다.
5) app/[locale]/layout.tsx
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
export default async function LocaleLayout({
children,
params: {locale}
}: {
children: React.ReactNode;
params: {locale: string};
}) {
// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
6) app/[locale]/page.tsx
import {useTranslations} from 'next-intl';
export default function Index() {
const t = useTranslations('Index');
return <h1>{t('title')}</h1>;
}
[locale] 이라는 파일 명을 통해 미들웨어에서 매칭된 언어인 경우 주소값을 가질 수 있다.
결과
테스트 성공!
기존 웹사이트에 적용하기
이제 next-intl 을 적용되었으니 기존 사이트에 추가해야한다. locale (언어 변수) 를 전역으로 관리해야한다는 아이디어가 생겨 상태를 관리할 수 있는 LanguageContext.tsx 를 만들었다.
여기서 저장된 selectedLanguage 는 다음 함수를 호출함으로 외부에서 사용할 수 있다.
3. useLanguage
export const useLanguage = (): LanguageContextProps => {
const context = useContext(LanguageContext);
if (context === undefined) {
throw new Error('useLanguage must be used within a LanguageProvider');
}
return context;
};
우리 매장은 맛있게 먹는 방법이 있다. 깻잎에 마요네즈가 섞인 천사채와 날치알, 환상의 마요네즈 소스까지 곁들여 쭈꾸미와 함께 쏙하면 기가막힌 천상의 맛이다. 하지만, 외국인들에게 이 맛있는 조합을 소개하기가 매우 어려운 사실.. 이를 해결하기 위해 만들어 보도록 하겠다.