Next.js 앱을 번역하는 가장 쉬운 방법 (페이지 설정 포함)
프로덕션 환경에서 next-i18next (페이지 디렉토리)를 사용하고 있고 초능력을 발휘하고 싶다면 이 블로그 게시물을 살펴보세요.
앱 디렉토리와 함께 Next.js 13/14를 사용하는 경우 next-i18next가 필요하지 않으며 이 블로그 게시물에 설명된 대로 i18next 및 React-i18next를 직접 사용할 수 있습니다.
Next.js는 국제화된 라우팅을 직접 제공하지만 번역 콘텐츠 관리나 실제 번역 기능 자체는 처리하지 않습니다. Next.js가 하는 일은 로케일과 URL을 동기화하는 것뿐입니다.
이를 보완하기 위해 next-i18next
SSG/SSR, 다중 네임스페이스, 코드 분할 등을 완벽하게 지원하면서 번역 콘텐츠 관리 및 React 구성 요소를 번역하기 위한 구성 요소/후크 등 나머지 기능을 제공합니다.
next-i18next
내부적으로 i18next와 반응-i18next를 사용하지만, next-i18next
사용자는 번역 콘텐츠를 JSON 파일로 포함하기만 하면 되며 다른 것에 대해 걱정할 필요가 없습니다.
여기에서 라이브 데모를 볼 수 있습니다. 이 데모 앱은 단순한 예입니다. 그 이상도 그 이하도 아닙니다.
손쉬운 설정, 손쉬운 사용: 몇 단계만 거치면 설정이 완료되고 구성도 간단합니다.
다른 요구 사항 없음: next-i18next
추가 종속성 없이 Next.js 앱의 국제화를 단순화합니다.
프로덕션 준비: next-i18next
SSG/SSR 지원을 통해 변환 및 구성 옵션을 소품으로 페이지에 전달하는 것을 지원합니다.
next-i18next.config.js
파일은 next-i18next
에 대한 구성을 제공합니다. 구성 후 appWithTranslation
사용하면 후크를 통해 구성 요소에서 t
(번역) 기능을 사용할 수 있습니다.
그런 다음 페이지 수준 구성 요소의 getStaticProps 또는 getServerSideProps(경우에 따라)에 serverSideTranslation
추가합니다.
이제 Next.js 앱이 완전히 번역 가능해졌습니다!
yarn add next-i18next react-i18next i18next
또한 react
및 next
설치가 필요합니다.
기본적으로 next-i18next
번역이 다음과 같이 구성될 것으로 예상합니다.
.
└── public
└── locales
├── en
| └── common.json
└── de
└── common.json
이 구조는 간단한 예에서도 볼 수 있습니다.
사용자 정의 방식으로 번역/네임스페이스를 구조화하려면 수정된 localePath
및 localeStructure
값을 초기화 구성에 전달해야 합니다.
먼저 프로젝트 루트에 next-i18next.config.js
파일을 만듭니다. 중첩된 i18n
객체의 구문은 Next.js에서 직접 가져옵니다.
이는 next-i18next
defaultLocale
및 기타 로캘이 무엇인지 알려주므로 서버에 번역을 미리 로드할 수 있습니다.
next-i18next.config.js
/** @type {import('next-i18next').UserConfig} */
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
}
이제 i18n
객체를 next.config.js
파일에 전달하여 next.config.js
파일을 생성하거나 수정하여 지역화된 URL 라우팅을 활성화합니다.
next.config.js
const { i18n } = require ( './next-i18next.config' )
module . exports = {
i18n ,
}
next-i18next
가 내보내는 세 가지 기능이 있으며, 프로젝트를 번역하는 데 사용해야 합니다.
이것은 _app
을 래핑하는 HOC입니다.
import { appWithTranslation } from 'next-i18next'
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp )
appWithTranslation
HOC는 주로 I18nextProvider
추가를 담당합니다.
이는 getStaticProps
또는 getServerSideProps
(사용 사례에 따라 다름)를 통해 페이지 수준 구성 요소에 포함해야 하는 비동기 함수입니다.
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
export async function getStaticProps ( { locale } ) {
return {
props : {
... ( await serverSideTranslations ( locale , [
'common' ,
'footer' ,
] ) ) ,
// Will be passed to the page component as props
} ,
}
}
serverSideTranslations
next-i18next/serverSideTranslations
에서 가져와야 합니다. 이는 NodeJs 관련 코드가 포함된 별도의 모듈입니다.
또한 serverSideTranslations
서버 환경 에서만 실행할 수 있으므로 getInitialProps
와 호환되지 않는 반면, getInitialProps
페이지 간을 탐색할 때 클라이언트 측에서 호출됩니다.
serverSideTranslations
HOC는 번역 및 구성 옵션을 페이지에 소품으로 전달하는 일을 주로 담당합니다. 번역이 있는 모든 페이지에 이를 추가해야 합니다.
이것은 실제로 번역 자체를 수행하는 데 사용할 후크입니다. useTranslation
후크는 react-i18next
에서 제공되지만 next-i18next
에서 직접 가져와야 합니다.
react-i18next
의 useTranslation
내보내기를 사용하지 말고 next-i18next
의 내보내기만 사용하세요!
import { useTranslation } from 'next-i18next'
export const Footer = ( ) => {
const { t } = useTranslation ( 'footer' )
return (
< footer >
< p > { t ( 'description' ) } < / p >
< / footer >
)
}
기본적으로 next-i18next
각 초기 요청 시 모든 네임스페이스를 클라이언트로 보냅니다. 이는 콘텐츠가 적은 소규모 앱에 적합한 접근 방식일 수 있지만 경로를 기반으로 네임스페이스를 분할하면 많은 앱이 이점을 누릴 수 있습니다.
이를 위해 각 페이지에 필요한 네임스페이스 배열을 serverSideTranslations
에 전달할 수 있습니다. example/simple/pages/index.tsx에서 이 접근 방식을 볼 수 있습니다. 필수 네임스페이스의 빈 배열을 전달하면 네임스페이스가 전송되지 않습니다.
참고: useTranslation
이를 사용하는 구성 요소에 네임스페이스를 제공합니다. 그러나 serverSideTranslations
전체 React 트리에 사용 가능한 전체 네임스페이스를 제공하며 페이지 수준에 속합니다. 둘 다 필요합니다.
기본적으로 next-i18next
각 요청마다 활성 로케일만 클라이언트로 보냅니다. 이렇게 하면 클라이언트로 전송되는 초기 페이로드의 크기를 줄이는 데 도움이 됩니다. 그러나 어떤 경우에는 런타임 시 다른 언어에 대한 번역도 필요할 수 있습니다. 예를 들어 useTranslation
후크의 getFixedT를 사용하는 경우입니다.
동작을 변경하고 추가 로케일을 로드하려면 로케일 배열을 serverSideTranslations
의 마지막 인수로 전달하면 됩니다.
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
export async function getStaticProps({ locale }) {
return {
props: {
- ...(await serverSideTranslations(locale, ['common', 'footer'])),
+ ...(await serverSideTranslations(locale, ['common', 'footer'], null, ['en', 'no'])),
},
};
}
결과적으로 no
및 en
로캘에 대한 번역은 현재 언어에 관계없이 항상 로드됩니다.
참고:
getFixedT
함수를 사용하는 모든 페이지에는 추가 인수를 추가해야 합니다.
기본적으로 next-i18next
defaultLocale
대체 항목으로 추가합니다. 이를 변경하려면 fallbackLng
설정할 수 있습니다. i18next
에서 지원하는 모든 값( string
, array
, object
및 function
)은 next-i18next
에서도 지원됩니다.
또한 nonExplicitSupportedLngs
true
로 설정하면 각각에 대해 JSON 파일을 제공할 필요 없이 언어의 모든 변형을 지원할 수 있습니다. next.js
내에서 라우팅을 활성화하려면 모든 변형이 locales
에 포함되어야 합니다.
참고:
fallbackLng
와nonExplicitSupportedLngs
는 동시에 사용할 수 있습니다. 단 하나의 예외가 있습니다.nonExplicitSupportedLngs
true
인 경우fallbackLng
에 대한 함수를 사용할 수 없습니다.
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'fr' , 'de-AT' , 'de-DE' , 'de-CH' ] ,
} ,
fallbackLng : {
default : [ 'en' ] ,
'de-CH' : [ 'fr' ] ,
} ,
nonExplicitSupportedLngs : true ,
// de, fr and en will be loaded as fallback languages for de-CH
}
fallbackLng
및 nonExplicitSupportedLngs
를 사용하면 페이지의 초기 크기가 쉽게 늘어날 수 있습니다.
참고: fallbackLng
false
로 설정하면 대체 언어(일반적으로 defaultLocale
)가 직렬화되지 않습니다. 이렇게 하면 초기 페이지 로드 크기가 줄어듭니다.
고급 구성 옵션을 수정해야 하는 경우 next-i18next.config.js
를 통해 전달할 수 있습니다. 예를 들어:
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
localePath :
typeof window === 'undefined'
? require ( 'path' ) . resolve ( './my-custom/path' )
: '/public/my-custom/path' ,
ns : [ 'common' ] ,
}
일부 i18next
플러그인( config.use
에 전달할 수 있음)은 함수 및 기타 JavaScript 기본 요소를 포함하므로 직렬화할 수 없습니다.
사용 사례가 더 발전된 경우 이 문제가 발생할 수 있습니다. Next.js에서 다음과 같은 오류가 발생하는 것을 볼 수 있습니다.
Error: Error serializing `._nextI18Next.userConfig.use[0].process` returned from `getStaticProps` in "/my-page".
Reason: `function` cannot be serialized as JSON. Please only return JSON serializable data types.
이 문제를 해결하려면 config.serializeConfig
false
로 설정하고 구성을 appWithTranslation
에 수동으로 전달해야 합니다.
import { appWithTranslation } from 'next-i18next'
import nextI18NextConfig from '../next-i18next.config.js'
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp , nextI18NextConfig )
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import nextI18NextConfig from '../next-i18next.config.js'
export const getStaticProps = async ( { locale } ) => ( {
props : {
... ( await serverSideTranslations (
locale ,
[ 'common' , 'footer' ] ,
nextI18NextConfig
) ) ,
} ,
} )
getStaticPaths
및 fallback: true
또는 fallback: 'blocking'
사용하여 서버 측 생성 페이지에서 사용할 때 위에 표시된 기본 설정으로 인해 로드할 때마다 앱이 마운트 해제되었다가 다시 마운트되어 모든 useEffect(() => {...}, [])
호출과 같은 다양한 불리한 결과가 발생합니다. useEffect(() => {...}, [])
두 번 후크되고 약간의 성능 저하가 발생합니다.
이는 해당 페이지의 경우 Next.js가 빈 serverSideProps
사용하여 첫 번째 렌더링을 수행한 다음 next-i18next
번역을 포함하는 serverSideProps
사용하여 두 번째 렌더링을 수행하기 때문입니다. 기본 설정에서는 serverSideProps
가 empty
있을 때 i18n
인스턴스가 처음에 undefined
마운트 해제-다시 마운트가 발생합니다.
이 문제를 완화하려면 다음을 수행할 수 있습니다.
import { UserConfig } from 'next-i18next' ;
import nextI18NextConfig from '../next-i18next.config.js'
const emptyInitialI18NextConfig : UserConfig = {
i18n : {
defaultLocale : nextI18NextConfig . i18n . defaultLocale ,
locales : nextI18NextConfig . i18n . locales ,
} ,
} ;
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp , emptyInitialI18NextConfig ) // Makes sure the initial i18n instance is not undefined
이는 대체 페이지 상태에서 클라이언트 측 코드가 번역을 표시하려고 시도하지 않는 한 작동합니다. 그렇지 않으면 Next.js에서 "서버-클라이언트 불일치" 오류가 발생합니다( 서버의 html에 실제 번역이 있고 클라이언트 html의 번역 키가 같은 위치에 있다는 사실).
이것은 정상적이고 괜찮습니다. 어쨌든 사용자에게 번역 키를 표시하면 안 됩니다!
v11.0.0부터 next-i18next는 클라이언트 측 번역 로딩도 지원합니다.
일부 사용 사례에서는 serverSideTranslations
사용하지 않고도 번역 파일을 동적으로 로드할 수 있습니다. 이는 페이지 속도 저하를 원하지 않는 지연 로드 구성 요소에 특히 유용할 수 있습니다.
이에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
서버가 시작될 때 리소스가 한 번 로드되므로 개발 중인 번역 JSON 파일에 대한 변경 사항은 서버가 다시 시작될 때까지 로드되지 않습니다.
프로덕션에서는 이것이 문제가 되지 않는 경향이 있지만 개발에서는 매번 개발 서버를 다시 시작하지 않고도 번역 JSON 파일에 대한 업데이트를 확인하고 싶을 수 있습니다. 이렇게 하려면 reloadOnPrerender
구성 옵션을 true
로 설정하세요.
이 옵션은 serverSideTranslations
호출될 때마다( getStaticProps
또는 getServerSideProps
에서) 번역을 다시 로드합니다. getServerSideProps
에서 serverSideTranslations
사용하는 경우 각 서버 호출에서 리소스를 다시 로드하지 않도록 프로덕션 환경에서 reloadOnPrerender
비활성화하는 것이 좋습니다.
열쇠 | 기본값 | 메모 |
---|---|---|
defaultNS | 'common' | |
localePath | './public/locales' | 함수일 수 있습니다. 아래 참고를 참조하세요. (여기처럼 구성을 통해 리소스 옵션을 직접 전달하는 경우 null일 수도 있음) |
localeExtension | 'json' | localePath 함수인 경우 무시됩니다. |
localeStructure | '{{lng}}/{{ns}}' | localePath 함수인 경우 무시됩니다. |
reloadOnPrerender | false | |
serializeConfig | true | |
use (플러그인용) | [] | |
onPreInitI18next | undefined | 즉 (i18n) => i18n.on('failedLoading', handleFailedLoading) |
함수로서의 localePath
(locale: string, namespace: string, missing: boolean) => string
으로 파일 이름과 확장자를 포함한 전체 경로를 반환합니다. missing
이 true인 경우 i18next-fs-backend
의 addPath
옵션에 대한 경로를 반환하고, false인 경우 loadPath
옵션에 대한 경로를 반환합니다. i18next-fs-backend
저장소에서 더 많은 정보를 확인하세요.
localePath가 함수인 경우 ns 옵션도 정의해야 합니다. 왜냐하면 서버 측에서는 네임스페이스를 미리 로드할 수 없기 때문입니다.
다른 모든 i18next 옵션과 반응-i18next 옵션도 전달할 수 있습니다.
localePath
null
로 설정하는 것과 함께 resources
직접 전달할 수도 있습니다.
기본적으로 i18next는 보간을 위해 접두어로 {{
사용하고 접미어로 }}
사용합니다. 이러한 보간 설정을 재정의하거나 재정의해야 하는 경우 사용자 지정 접두사 및 접미사와 일치하는 대체 localeStructure
설정도 지정 해야 합니다 .
예를 들어, {
및 }
사용하려는 경우 구성은 다음과 같습니다.
{
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'nl' ] ,
} ,
interpolation : {
prefix : '{' ,
suffix : '}' ,
} ,
localeStructure : '{lng}/{ns}' ,
}
next-i18next.config.js
경로 기본 구성 경로를 변경하려면 환경 변수 I18NEXT_DEFAULT_CONFIG_PATH
를 설정할 수 있습니다.
예를 들어 .env
파일 내에서 정적 경로를 설정할 수 있습니다.
I18NEXT_DEFAULT_CONFIG_PATH=/path/to/project/apps/my-app/next-i18next.config.js
또는 동적 경로에 대한 트릭을 사용하고 next.config.js
내부에 다음을 설정할 수 있습니다.
process . env . I18NEXT_DEFAULT_CONFIG_PATH = ` ${ __dirname } /next-i18next.config.js` ;
// ... Some other imports
const { i18n } = require ( './next-i18next.config' ) ;
// ... Some other code
module . exports = {
i18n ,
...
} ;
이는 i18n 구성 파일이 next.config.js
와 동일한 디렉토리에 있으며 현재 작업 디렉토리가 어디에 있는지는 중요하지 않음을 의미합니다. 이는 예를 들어 단일 저장소가 있고 프로젝트 루트에서 애플리케이션을 시작했지만 애플리케이션이 apps/{appName}
에 있는 경우 nx
에 도움이 됩니다.
주의 사항 next-i18next.config.js
구성이 next.config.js
와 동일한 디렉터리에 없으면 수동으로(또는 사용자 정의 스크립트를 통해) 복사해야 합니다.
프로젝트에 next-i18next를 점진적으로 추가할 계획이라면 문제를 방지하기 위해 next-i18next.config
appWithTranslation
에 전달하는 것이 좋습니다.
즉
import nextI18nextConfig from '../../next-i18next.config' ;
//...
export default appWithTranslation ( MyApp , nextI18nextConfig ) ;
자세한 내용은 문제 #2259를 참조하세요.
일부 서버리스 PaaS는 번역 경로를 찾지 못해 추가 구성이 필요할 수 있습니다. serverSideTranslations
사용하는 데 파일 시스템 문제가 있는 경우 path.resolve
사용하도록 config.localePath
설정하세요. 여기에서 예를 찾을 수 있습니다.
Docker 배포의 경우 Next.js 문서의 Dockerfile
사용하는 경우 next.config.js
및 next-i18next.config.js
Docker 이미지에 복사하는 것을 잊지 마세요.
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js
내장된 i18next-fs-backend와 다른 i18next 백엔드를 사용하기로 선택한 경우 t
함수를 호출하기 전에 번역 리소스가 로드되었는지 확인해야 합니다. SSR에서는 React 서스펜스가 아직 지원되지 않으므로 이 문제는 두 가지 방법으로 해결할 수 있습니다.
1) 네임스페이스를 미리 로드합니다.
이 예와 같이 ns
옵션을 설정합니다. 이렇게 하면 초기화 시 모든 번역 리소스가 로드됩니다.
2) 준비 플래그를 확인합니다.
ns
배열을 제공할 수 없거나 제공하고 싶지 않은 경우 t
함수를 호출하면 네임스페이스가 즉시 로드됩니다. 이는 ready === true
또는 props.tReady === true
확인하여 "준비되지 않음" 상태를 처리해야 함을 의미합니다. 그렇지 않으면 번역이 로드되기 전에 렌더링되어 실제로 번역이 존재하더라도(아직 로드되지 않음) "저장 누락"이 호출됩니다. 이는 useTranslation 후크 또는 withTranslation HOC를 사용하여 수행할 수 있습니다.
next export
실행하여 정적 HTML 내보내기를 생성하려고 하는데 이 오류가 발생합니까?
오류: i18n 지원은 다음 내보내기와 호환되지 않습니다. 배포에 대한 자세한 내용은 여기를 참조하세요: https://nextjs.org/docs/deployment
하지만 다음 언어 감지기의 도움으로 이 문제를 해결할 수 있는 방법이 있습니다. 이 블로그 게시물과 이 예제 프로젝트를 확인하세요.
하위 구성 요소에서 t 함수를 사용하는 방법에는 여러 가지가 있습니다.
t
함수를 자식에게 전달합니다.useTranslation
함수를 사용하세요.다음-i18다음/예제/단순/구성 요소/Footer.tsx
e6b5085의 6번째 줄
withTranslation
기능을 사용하세요일반적으로 serverSideTranslations에 트리에 필요한 모든 네임스페이스가 포함되어 있는지 항상 확인해야 합니다.
다음 멋진 분들에게 감사드립니다(이모지 키):
롭 카펠리니 | 알렉산더 카츠카예프 ? ? | 마티아스 뵈베 ? | 루카스 펠리시아노 ? ? | 라이언 렁 | 네이선 프리멜 ? | 아이작 힌만 ️️️️♿️ ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ?️ ? |
아드리아노 라이아노 ️️️️♿️ ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ?️ ? | 펠릭스 모세예프 ? | 세바스티앙 반벨트헴 ? ? |
이 프로젝트는 모든 기여자 사양을 따릅니다. 어떤 종류의 기여도 환영합니다!
서비스로서의 현지화 - locize.com
번역 관리가 필요하십니까? InContext Editor로 번역을 편집하고 싶으십니까? i18next 관리자가 제공한 원본을 사용하세요!
locize를 사용하면 i18next 및 next-i18next의 미래를 직접적으로 지원할 수 있습니다.