개요
nextjs 를 global service 출시를 해보면서 정리한 내용 + 경험을 정리함.
Nextjs 세팅
nextjs 10.0.0 버젼 이후로 내부적으로 i18n 지원 기능이 있다. locale list, default locale, 등을 제공하고 설정을 추가하면 nextjs 에서 자동으로 라우팅이 된다. (i18n routing)
next.config.js
next.config.js 를 설정한 것만으로 internationalized routing 을 구현할 수 있다.
Locale Identifier
일반적으로 locale identifier 은 language, region, script 로 구성된다 (language-region-script). 하지만 region, script 는 optional
•
en-US - English as spoken in the United States
•
nl-NL - Dutch as spoken in the Netherlands
•
nl - Dutch, no specific region
sub path
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
JavaScript
복사
위와 같이 설정했을 때, en-US 는 default path 로 설정될 것이고, fr, nl-nl 은 locale 이 prefix 된 path 를 추가해야 적용될 것이다. 예를들어, pages/blog.js 로 라우팅 된 경로는 다음과 같이 적용될 것이다
•
/blog - en-US
•
/fr/blog
•
/nl-nl/blog
domain
locale 별로 다른 도메인을 설정할 수 있다.
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
defaultLocale: 'en-US',
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
// specify other locales that should be redirected
// to this domain
locales: ['nl-BE'],
},
],
},
}
JavaScript
복사
•
example.com/blog
•
example.fr/blog
•
example.nl/blog
•
example.nl/nl-BE/blog
Automatic locale detection
Accept-Language 헤더를 기준으로 locale 을 자동으로 감지 가능
만약 domain routing 을 적용하고 Accept-Language 가 fr;q=0.9 유저가 example.com 에 방문하면 example.kr 로 redirect 된다.
다음 설정을 통해서 automatic locale detection 을 설정 끌 수 있다
// next.config.js
module.exports = {
i18n: {
localeDetection: false,
},
}
Plain Text
복사
위 설정을 끄면 자동으로 locale 을 감지하고 redirect 하지 않고, 설정한 routing 을 통해서 locale 값을 반환한다.
Accessing the locale information
다음 방법을 통해서 locale 정보에 접근할 수 있다.
•
useRouter() 를 사용
const router = useRouter();
const {
locale, // current locale
locales, // all configured locales
defaultLocale,
} = router;
JavaScript
복사
•
SEO
•
nextjs 가 lang attribute 를 자동으로 html 태그에 추가시킴
•
Edge Network
vercel 을 통해서 배포하면 Edge Network 를 사용해 sub path 나 domain 을 통해서 dynamic routing 을 구현한다. Edge Network 는 다음 의 링크에 자세히 보자
global hitple project 적용
•
일본, 대만, 베트남 타겟
•
app 단위의 size 가 아니라 Product Detail Page 단일 페이지
•
각 국가별로 마케팅 컨텐츠 및 링크 사용
◦
도메인 기반 locale 사용
◦
auto locale detection off
// next.config.js
module.exports = {
...
i18n: {
localeDetection: false,
locales: ["ja", "ko", "zh-tw", "vi"],
defaultLocale: "ko",
domains: [
{
domain: "vn.hitple.com",
defaultLocale: "vi",
},
{
domain: "tw.hitple.com",
defaultLocale: "zh-tw",
},
{
domain: "jp.hitple.com",
defaultLocale: "ja",
},
{
domain: "kr.hitple.com",
defaultLocale: "ko",
},
],
},
...
}
JavaScript
복사
i18next, react-i18next 를 사용
// _app.tsx
...
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import { useRouter } from "next/router";
import Korean from "src/locales/ko.json"; // {title: '안녕하세요'}
import Japanese from "src/locales/ja.json"; // {title: '곤니치와'}
import Taiwan from "src/locales/tw.json"; // {title: 'hello'}
import Vietnamse from "src/locales/vi.json";
export default function MyApp({ Component, pageProps }: AppProps) {
const { locale } = useRouter();
i18n.use(initReactI18next).init({
resources: {
ko: {
translation: Korean,
},
ja: {
translation: Japanese,
},
vi: {
translation: Vietnamse,
},
"zh-tw": {
translation: Taiwan,
},
},
lng: locale ?? Locale.KOREAN,
fallbackLng: Locale.KOREAN,
interpolation: {
escapeValue: false,
},
});
...
return (
...
);
}
JavaScript
복사
// Title.tsx
import React from "react";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
interface Props {
className?: string;
}
const Title = styled.h1``;
const Title = ({
className,
}: Props) => {
const { t } = useTranslation();
return (
<Title className={className}>
{t("title")}
</Title>
);
};
export default ReviewCardImageList;
JavaScript
복사
각 국가별로 필요한 소스 import (리소스 최소화를 위해서)
import React from "react";
import { useRouter } from "next/router";
import { Locale } from "src/interfaces/common";
import LazyloadCSS from "src/components/common/LazyLoadCSS";
const FontStyleSheetImport = () => {
const { locale } = useRouter();
return (
<>
{locale === Locale.JAPANESE ? (
<>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<LazyloadCSS href="/styles/NotoSansJP.min.css" />
<LazyloadCSS href="/styles/ja.css" />
</>
) : locale === Locale.TAIWAN ? (
<>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<LazyloadCSS href="/styles/NotoSansTC.min.css" />
<LazyloadCSS href="/styles/tw.css" />
</>
) : locale === Locale.VIETNAMSE ? (
<>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<LazyloadCSS href="/styles/NotoSans.min.css" />
<LazyloadCSS href="/styles/vi.css" />
</>
) : ( // 한국의 경우 내부적으로 사용하고 있는 폰트를 파일화해서 사용
<>
<link
rel="preload"
href="/NotoSansKR.otf"
as="font"
type="font/otf"
crossOrigin=""
/>
<LazyloadCSS href="/styles/ko.css" />
</>
)}
</>
);
};
export default FontStyleSheetImport;
JavaScript
복사