초점과 우선 순위의 변화로 인해 더 이상이 패키지를 유지할 수 없습니다. 업데이트, 버그 수정 또는 새로운 기능을받지 않으며 시간이 지남에 따라 호환되지 않을 수 있습니다. 최신 Next.js 앱 디렉토리를 지원하는 패키지로 전환하는 것이 좋습니다.
next-multilingual 여러 언어가 필요한 Next.js 응용 프로그램에 대한 의견이 많은 엔드 투 엔드 솔루션 입니다.
데모 앱을 확인하십시오!
next 다면 next-multilingual 는 함께 작동합니까? pages 디렉토리. 우리는 여전히 새로운 것을 지원하기위한 솔루션을 다림질하고 있습니까? app 디렉토리 국제화는 더 이상 Next.js의 구성의 일부가 아닙니다.
npm install next-multilingual
useMessages 후크./fr-ca/nous-joindre 의 경우 / /en-us/contact-us us를 사용하는 기능) ✱ . default 기본 로케일 슬러그 는 pages 디렉토리 파일 시스템과 일치해야합니다 (예 : "About Us"의 슬러그는 about-us 디렉토리에 있어야합니다). 필요한 기본 로케일이 파일 시스템에서 지원하는 것 이상으로 문자를 사용하는 경우 테스트되지 않았으며 작동하지 않을 수 있습니다. 풀 요청을 환영합니까?.
next-multilingual 모든 API에 TSDOC를 추가하기 위해 많은 노력을 기울였습니다. 예제에 제공된 특정 API를 사용하는 방법이 확실하지 않은 경우 IDE에서 직접 확인하십시오.
또한 "모범 사례"에 대한 의견을 갖는 것은 쉬운 일이 아닙니다. 이것이 바로 여기에서 상담 할 수있는 특별 문서로 디자인 결정을 문서화 한 이유입니다. API 중 일부가 기대할 수있는 것을 제공하지 않는다고 생각되면 문제를 열기 전에이 문서를 참조하십시오.
행동에 바로 뛰어 들어가는 것을 선호하는 사람들은 example 디렉토리를보고 next-multilingual 의 엔드 투 엔드 구현을 살펴보십시오. 나머지의 경우 아래 섹션은 완전한 단계별 구성 안내서를 제공합니다.
목표를 달성하기 위해 Next.js에서 구성 할 옵션이 많이 있습니다. next-multilingual 주로 다음을 걱정합니다.
이 단계를 단순화하기 위해 두 가지 API를 제공합니다.
getConfig (간단한 구성) 이 함수는 대부분의 사용 사례를 충족시키는 NEXT.JS 구성을 생성합니다. getConfig 다음과 같은 주장을합니다.
applicationId - 메시지 키 접두사로 사용될 고유 응용 프로그램 식별자.locales - 신청서의 로컬.defaultLocale 응용 프로그램의 기본 로케일 ( locales 에도 포함되어 있어야 함)❗
language에 따른 BCP 47 언어 태그 -country형식이 허용됩니다. 이유에 대한 자세한 내용은 디자인 결정 문서를 참조하십시오.
options (선택 사항) - 옵션 Next.js 구성 객체의 옵션 부분. getConfig Next.js 구성 객체를 반환합니다.
이를 사용하려면 응용 프로그램의 다음 코드를 다음 코드를 추가하십시오 next.config.js :
const { getConfig } = require ( 'next-multilingual/config' )
const config = getConfig ( 'exampleApp' , [ 'en-US' , 'fr-CA' ] , 'en-US' , {
// Put your optional options below.
poweredByHeader : false ,
} )
module . exports = config 모든 구성 옵션이 getConfig 에서 지원되지는 않습니다. 하나를 사용하는 경우 오류 메시지가 다음 섹션 인 고급 구성을 직접 지적합니다.
Config (고급 구성) 고급 요구 사항이있는 경우 Config 객체를 직접 사용하여 기존 next.config.js 에서 next-multilingual 직접 필요한 구성을 삽입 할 수 있습니다. Config 인수는 getConfig ( options 을 제외)와 거의 동일합니다. 자세한 내용은 IDE (TSDOC)를 확인하십시오. 다음은 사용 방법의 예입니다.
const { Config , webpackConfigurationHandler } = require ( 'next-multilingual/config' )
const config = new Config ( 'exampleApp' , [ 'en-US' , 'fr-CA' ] , 'en-US' )
module . exports = {
reactStrictMode : true ,
i18n : {
locales : config . getUrlLocalePrefixes ( ) ,
defaultLocale : config . getDefaultUrlLocalePrefix ( ) ,
localeDetection : false ,
} ,
poweredByHeader : false ,
webpack : webpackConfigurationHandler ,
}자신의 웹 팩 구성을 사용자 정의 해야하는 경우 다음과 같은 핸들러를 확장하는 것이 좋습니다.
import Webpack from 'webpack'
import { webpackConfigurationHandler , WebpackContext } from 'next-multilingual/config'
export const myWebpackConfigurationHandler = (
config : Webpack . Configuration ,
context : WebpackContext
) : Webpack . Configuration => {
const myConfig = webpackConfigurationHandler ( config , context )
// Do stuff here.
return myConfig
} 또는 직접 next.config.js 에서 :
// Webpack handler wrapping next-multilingual's handler.
const webpack = ( config , context ) => {
config = webpackConfigurationHandler ( config , context )
// Do stuff here.
return config
} next-multilingual/config 다음 2 가지 작업을 수행합니다. JS의 현재 라우팅 기능 :
next-multilingual/config 또한 Link 구성 요소의 next-multilingual/link/ssr 사용하여 현지화 된 URL의 서버 측 렌더링에 필요한 특수 웹 팩 구성과 Head 부품의 표준 및 대체 링크에 대한 next-multilingual/head/ssr 처리합니다.
UTF-8 문자를 사용하는 이유와 같은 구현에 대한 자세한 내용은 설계 결정 문서를 참조하십시오.
next-multilingual/messages/babel-plugin useMessages() hook로 현지화 된 메시지를 표시하려면 문자열을 페이지와 구성 요소에 자동으로 주입하는 사용자 정의 바벨 플러그인을 구성해야합니다. 이를 수행하는 권장 방법은 응용 프로그램 기반에 .babelrc 포함시키는 것입니다.
{
"presets" : [ " next/babel " ],
"plugins" : [ " next-multilingual/messages/babel-plugin " ]
} 플러그인을 구성하지 않으면 useMessages 사용하려고 할 때 오류가 발생합니다.
App 생성 ( _app.tsx ) pages 디렉토리에 _app.tsx 추가하여 사용자 정의 App 만들어야합니다.
import { useActualLocale } from 'next-multilingual'
import type { AppProps } from 'next/app'
const ExampleApp : React . FC < AppProps > = ( { Component , pageProps } ) => {
useActualLocale ( ) // Forces Next.js to use the actual (proper) locale.
return < Component { ... pageProps } / >
}
export default ExampleApp이것은 기본적으로 주석에 언급 된 바와 같이 두 가지를 수행합니다.
/ )없이 홈페이지를 치면 재사용 할 수 있습니다. next-multilingual 의 로케일 감지를 사용하지 않으려면 대신 useActualLocale(false) 사용할 수 있습니다.Document 만들기 ( _document.tsx ) 또한 pages 디렉토리에 _document.tsx 추가하여 사용자 정의 Document 작성해야합니다.
import { getHtmlLang } from 'next-multilingual'
import { DocumentProps , Head , Html , Main , NextScript } from 'next/document'
const Document : React . FC < DocumentProps > = ( documentProps ) => {
return (
< Html lang = { getHtmlLang ( documentProps ) } translate = "no" className = "notranslate" >
< Head >
< meta name = "google" content = "notranslate" / >
< / Head >
< body >
< Main / >
< NextScript / >
< / body >
< / Html >
)
}
export default Document 이것은 단지 1 목적 만 사용합니다. <html> 태그에 올바른 서버 측 로케일을 표시합니다. 우리는 "가짜"기본 로케일을 사용하고 있기 때문에 특히 동적 로케일을 / /에서 해결할 때 올바른 SSR 마크 업을 유지하는 것이 중요합니다.
next-multilingual/head <Head> 구성 요소를 제공하여 헤더에 정식 링크와 대체 링크를 자동으로 생성합니다. 이것은 Next.js에 의해 상자에서 제공되지 않는 것입니다.
NEXT_PUBLIC_ORIGIN 환경 변수를 추가하십시오 Google에 따라 전송 방법 (HTTP/HTTPS)을 포함하여 대체 링크를 완전히 자격으로해야합니다. Next.js는 빌드 시점에 사용되는 URL을 알지 못하므로 환경 변수에서 사용할 절대 URL을 지정해야합니다. 예를 들어, 개발 환경의 경우 다음 변수를 사용하여 응용 프로그램의 루트에 .env.development 파일을 만듭니다 (설정에 따라 조정).
NEXT_PUBLIC_ORIGIN =http://localhost:3000 환경에 관계없이 next-multilingual 완전히 자격이있는 URL을 생성하기 위해 NEXT_PUBLIC_ORIGIN 이라는 변수를 찾습니다. Next.js ' basePath 사용하는 경우 기본 URL에 자동으로 추가됩니다.
NEXT_PUBLIC_ORIGIN 경로없이 완전히 자격을 갖춘 도메인 (예 : http://example.com ) 만 허용합니다.
next-multilingual 사용? 이제 모든 것이 구성되었으므로 next-multilingual 사용하는 데 중점을 둘 수 있습니다!
next-multilingual 설계된대로 작동하도록하기 위해서는 두 가지 문제에 대한 솔루션을 찾아야했습니다.
undefined 값 : 다음 .js는 로케일이없는 사이트를 지원하기 때문에 기본 유형은 undefined 값을 가질 수있게되므로 우리의 경우 성가신 것이며 추가 캐스팅이 필요합니다.next-multilingual 우리가 결코 사용하지 않는 기본 로케일을 만들어야합니다. 이는 관련 로케일 정보에 액세스하기 위해 다음으로 의존 할 수 없음을 의미합니다. JS 'API.응용 프로그램에서 일관된 로케일 값을 허용하기 위해 다음 API를 만들었습니다.
useRouter 이것은 올바른 로컬을 제공하지만 undefined 반품을 절대 반환하지 않는 Next.js의 useRouter 저우터 위에있는 간단한 래퍼입니다.
import { NextPage } from 'next'
import { useRouter } from 'next-multilingual/router'
const Page : NextPage = ( ) => {
const router = useRouter ( )
return < > { router . locale } < / >
}
export default Page getStaticPropsLocales import { getStaticPropsLocales } from 'next-multilingual'
export const getStaticProps : GetStaticProps = async ( context ) => {
const { locale , locales , defaultLocale } = getStaticPropsLocales ( context )
// do stuff
return { props : { } }
} getStaticPathsLocales import { getStaticPathsLocales } from 'next-multilingual'
export const getStaticPaths : GetStaticProps = async ( context ) => {
const { locales , defaultLocale } = getStaticPathsLocales ( context )
// do stuff
return { props : { } }
} getServerSidePropsLocales import { getServerSidePropsLocales } from 'next-multilingual'
export const getServerSideProps : GetServerSideProps = async ( context ) => {
const { locale , locales , defaultLocale } = getServerSidePropsLocales ( context )
// do stuff
return { props : { } }
}
켈 스마트 로케일 감지를 사용하여 홈페이지를 동적으로 렌더링하는 것이 좋습니다. 이는 전적으로 선택 사항입니다.localeDetection: true와 함께 고급 구성을 사용하면getServerSideProps사용할 필요없이 다음 Next.js 동작을 복원합니다.
홈페이지는 다음과 같은 이유로 동적 로케일 감지 (및 디스플레이)를 구현해야하기 때문에 다른 페이지보다 조금 더 복잡합니다.
/ 에 부정적인 영향을 미칠 수 있으며 최고의 사용자 경험이 아닙니다.next-multilingual 기본 Next.js 구현보다 더 똑똑한 자동 감지를 제공하는 getPreferredLocale API가 제공됩니다.예제에서 전체 구현을 찾을 수 있지만 여기에 제거 된 버전이 있습니다.
import type { GetServerSideProps , NextPage } from 'next'
import { ResolvedLocaleServerSideProps , resolveLocale , useResolvedLocale } from 'next-multilingual'
import { useRouter } from 'next-multilingual/router'
const Homepage : NextPage < ResolvedLocaleServerSideProps > = ( { resolvedLocale } ) => {
// Force Next.js to use a locale that was resolved dynamically on the homepage (this must be the first action on the homepage).
useResolvedLocale ( resolvedLocale )
const { locale } = useRouter ( )
return < h1 > { locale } </ h1 >
}
export default Homepage
export const getServerSideProps : GetServerSideProps < ResolvedLocaleServerSideProps > = async (
context
) => {
return {
props : {
resolvedLocale : resolveLocale ( context ) ,
} ,
}
}간단히 말해서, 이것이 일어나고있는 일입니다.
next-multilingual 의 Locale 쿠키에서 이전에 사용한 로케일을 사용할 수 있는지 확인하십시오.useResolvedLocale 사용하여 라우터의 값을 덮어 씁니다. tsx , ts , jsx 또는 js (compilable) 파일을 만들 때마다 현지화 된 메시지가 필요할 때마다 지원되는 로컬로만이 파일에서만 사용할 수있는 메시지 파일을 만들 수 있습니다. CSS 모듈과 마찬가지로 아이디어는 다른 파일의 로컬 범위와 관련된 메시지 파일을 가질 수 있다는 것입니다. 이는 메시지를보다 모듈화하는 이점이 있으며 다른 상황에서 메시지를 공유하지 않습니다 (디자인 결정의 자세한 내용은 이것이 나쁜 이유에 대한 자세한 내용).
메시지 파일에는 2 가지 주요 사용 사례가 있습니다.
pages 디렉토리의 페이지의 경우 slug 키 식별자를 사용하여 현지화 된 URL 세그먼트 ( / 또는 경로 끝에서 URL의 일부)를 지정할 수 있습니다. 아래 에서이 작업을 수행하는 방법에 대한 자세한 내용.useMessages hook을 사용하여 로컬 범위로만 사용할 수 있습니다. CSS를 상상하지만 현지화 가능한 문자열을 상상해보십시오.요약하려면 :
해당 파일 작성 및 관리는 스타일 시트를 만드는 것만 큼 간단하지만 중요한 세부 사항은 다음과 같습니다.
.properties 파일입니다. 그렇습니다. 이유가 궁금하지만 설계 결정 문서에 문서화 된 충분한 이유가 있습니다.UTF-8 으로 설정되어 있는지 확인하십시오. 그렇게하지 않으면 라틴어가 아닌 문자를 �로 대체합니다 �.properties 파일에 대한 내장 IDE 지원을 활용하려면 엄격한 이름 지정 컨벤션을 따릅니다 <PageFilename>.<locale>.properties<applicationId>.<context>.<id> 엄격한 이름 지정 규칙을 따르는 고유 키가 있어야합니다.next-multilingual/config 에서 설정 한 것과 동일한 값을 사용해야합니다.aboutUsPage 또는 footerComponent 컨텍스트의 좋은 예일 수 있습니다. 각 파일에는 1 개의 컨텍스트 만 포함 할 수 있으며 "키 충돌"(비 유적 키)을 유발할 수 있으므로 많은 파일에서 컨텍스트를 사용해서는 안됩니다.. 또한 1 내지 50 개의 영숫자 문자 만 포함 할 수 있습니다. 가독성을 위해 Camel Case를 사용하는 것이 좋습니다.slug 식별자에 키가 포함 된 메시지 파일을 포함해야합니다.title 식별자와 함께 키를 포함하십시오.next-multilingual/messages 에 제공된 getTitle API를 사용하여 title 과 slug 키 사이를 자동으로 떨어 뜨립니다.useMessages hook을 사용하는 경우에만 필요합니다.또한 메시지의 잠재적 문제에 대한 경고를 콘솔 로그에서 확인하십시오. 먼저 작동 방식에 익숙해지기가 까다로울 수 있지만 문제를 쉽게 감지하고 해결할 수 있도록 노력했습니다. 이러한 로그는 비 생산 환경에서만 표시됩니다.
후크를 사용할 수없는 상태에서 현지화 된 메시지가 필요하지는 않습니다. 예를 들어 Next.js의 핵심 기능 중 하나를 사용하는 것은 내장 API 지원입니다. 이러한 맥락에서, useMessage 사용하는 대신 locale 인수를 지정하면서 간단히 getMessages 사용할 수 있습니다.
앞에서 언급했듯이, id 가 slug pages 에 대한 특별한 키가 하나 있습니다. this-is-a-page 처럼 보이는 전통적인 슬러그와 달리 슬러그를 일반적이고 사람이 읽을 수있는 문장으로 작성하여 다른 문자열처럼 번역 할 수 있습니다. 이것은 여러 언어로 관리하는 데 비용이 많이 들고 복잡 할 수있는 슬러그에 대한 특수 프로세스를 피할 수 있습니다.
기본적으로 slug 는 페이지의 사람이 읽을 수있는 "짧은 설명"이며 URL의 세그먼트 ( / 또는 경로 끝 사이의 부분)를 나타냅니다. URL 세그먼트로 사용하면 다음 변환이 적용됩니다.
- 으로 대체됩니다. 예를 들어, About Us about-us 될 것입니다.
홈페이지의 경우 URL은 항상 / 이므로 slug 키가 현지화 된 URL 세그먼트를 작성하는 데 사용되지 않습니다.
잊지 마십시오. 슬러그는 일반적인 간단한 설명으로 작성되어야합니다. 즉, SEO를 위해 더 짧게 유지하기 위해 단어를 건너 뛰는 것을 의미합니다. 그 주된 이유는 "키워드의 무리"를 쓰면 SEO에 익숙하지 않은 언어 학자가 해당 메시지를 번역하는 데 어려움을 겪을 수 있기 때문입니다. 많은 언어로 SEO 전문가를 갖는 것도 비용이 많이 들고 확장하기가 어려울 것입니다. 이상적인 시나리오에서 시장 별 SEO 페이지는 아마도 모국어로 작성되고 최적화되어야하지만 이는 더 이상 번역 프로세스의 일부가 아닙니다. next-multilingual 의 초점은 많은 언어로 URL을 현지화하기위한 쉽고 간소화 된 솔루션을 제공하는 것입니다.
slug 키는 next-multilingual/messages 에 제공된 getTitle API를 사용할 때 title 키의 폴백으로 사용됩니다. 이 API를 사용하면 슬러그가 불충분 할 때 타이틀을 쉽게 사용자 정의 할 수 있습니다.
켈 slug값을 변경한다는 것은 URL이 변경되는 것을 의미합니다. 다음으로 변경되기 때문에next.config.js에서 다음과 같은 다음으로 변경되므로 JS 구성 변경과 마찬가지로 서버를 다시 시작하여 변경 사항을 확인해야합니다. 기본 구성이 이에 의존하기 때문에 폴더 구조를 변경하는 경우에도 동일하게 적용됩니다.
페이지가없는 디렉토리를 사용하려면 index.<locale>.properties 파일 ( locale 지원하는 지역). 이 옵션이 지원되지만 URL 경로가 더 길어 SEO 모범 사례에 위배되는 경우 사용하지 않습니다.
기본적으로 next-multilingual 사용자 정의 오류 페이지 또는 /api 디렉토리의 API 경로와 같은 일부 파일을 제외합니다. 이 파일에 메시지를 사용할 때는 항상 slug 키를 사용할 수 있지만 로컬 URL을 만드는 데 사용되지 않습니다.
항상 예제를 살펴보면 메시지 파일이 작동하는 것을 볼 수 있지만 다음은 홈페이지에서 사용할 수있는 샘플이 있습니다.
# Homepage title
exampleApp.homepage.title = Homepage
# Homepage headline
exampleApp.homepage.headline = Welcome to the homepage 이제 우리는 홈페이지를 만드는 방법과 일이 어떻게 작동하는지에 대한 세부 사항을 배웠으므로 다른 페이지를 쉽게 만들 수 있습니다. 예제에서 많은 페이지를 만들지 만 about-us.jsx 어떻게 보일 수 있는지에 대한 샘플이 있습니다.
import { NextPage } from 'next'
import { getTitle , useMessages } from 'next-multilingual/messages'
import Layout from '@/layout'
import styles from './index.module.css'
const AboutUs : NextPage = ( ) => {
const messages = useMessages ( )
const title = getTitle ( messages )
return (
< Layout title = { title } >
< h1 className = { styles . headline } > { title } </ h1 >
< p > { messages . format ( 'details' ) } </ p >
</ Layout >
)
}
export default AboutUs 물론이 메시지 파일에 about-us.en-US.properties 가질 것입니다.
# Page localized URL segment (slug) in (translatable) human readable format.
# This key will be "slugified" (e.g, "About Us" will become "about-us"). All non-alphanumeric characters will be replaced by "-".
exampleApp.aboutUsPage.slug = About Us
# Page details.
exampleApp.aboutUsPage.details = This is just some english boilerplate text. next-multilingual 현지화 된 URL의 클라이언트 측 및 서버 측 렌더링을 허용하는 자체 <Link> 구성 요소가 제공됩니다. 사용법은 간단하고 다음과 같이 작동합니다 .JS ' <Link> .
기억해야 할 유일한 중요한 것은 href 속성에 항상 다음.js url을 포함해야한다는 것입니다. 즉, pages 폴더의 파일 구조는 로컬 버전이 아닌 사용되는 것이어야합니다.
다시 말해, 파일 구조는 "비 국적화 된"URL 표현으로 간주되며 <Link> 구조와 다른 경우 URL을 로컬 버전 (메시지 파일에서)으로 교체하는 것을 관리합니다.
API는 next-multilingual/link 에서 사용할 수 있으며 다음과 같이 사용할 수 있습니다.
import Link from 'next-multilingual/link'
import { useMessages } from 'next-multilingual/messages'
const Menu : React . FC = ( ) => {
const messages = useMessages ( )
return (
< nav >
< Link href = "/" >
< a > { messages . format ( 'home' ) } </ a >
</ Link >
< Link href = "/about-us" >
< a > { messages . format ( 'aboutUs' ) } </ a >
</ Link >
< Link href = "/contact-us" >
< a > { messages . format ( 'contactUs' ) } </ a >
</ Link >
</ nav >
)
}
export default Menu 해당 페이지의 메시지 파일에 slug 키가 지정 될 때 이러한 각 링크는 자동으로 현지화됩니다. 예를 들어, 미국 영어에서 "연락처"URL 경로는 /en-us/contact-us 일 것입니다. 캐나다 프랑스어는 /fr-ca/nous-joindre 입니다.
렌더링 중에이 매핑의 데이터를 즉시 사용할 수 없으므로 next-multilingual/link/ssr 서버 측 렌더링 (SSR)을 처리합니다. next-multilingual/config 의 getConfig 사용하면 웹 팩 구성이 자동으로 추가됩니다. 고급 Config 메소드를 사용하는 경우 이전에 제공된 예제에서 특수 웹 팩 구성이 필요한 이유를 설명합니다.
모든 현지화 된 URL이 <Link> 구성 요소를 사용하는 것은 아니기 때문에 다음이 다른 많은 사용 사례에서 사용할 수있는 router.push 메소드가있는 이유이기도합니다. next-multilingual 모든 구성 요소가 사용할 수있는 현지화 된 URL을 반환 할 수있는 useLocalizedUrl 후크를 사용하여 이러한 사용 사례를 지원할 수 있습니다. 다음은 활용 방법에 대한 예입니다.
import { NextPage } from 'next'
import { useMessages } from 'next-multilingual/messages'
import { useLocalizedUrl } from 'next-multilingual/url'
import router from 'next/router'
const Tests : NextPage = ( ) => {
const messages = useMessages ( )
const localizedUrl = useLocalizedUrl ( '/about-us' )
return < button onClick = { ( ) => router . push ( localizedUrl ) } > { messages . format ( 'clickMe' ) } </ button >
}
export default Tests 구성 요소의 상단이 아닌 URL 인라인을 정의하거나 더 고급 URL 조작을 수행 해야하는 경우 URL을 얻기 위해 기능을 반환하는 useGetLocalizedUrl 후크를 사용할 수도 있습니다.
import { NextPage } from 'next'
import { useMessages } from 'next-multilingual/messages'
import { useGetLocalizedUrl } from 'next-multilingual/url'
import router from 'next/router'
const Tests : NextPage = ( ) => {
const messages = useMessages ( )
const { getLocalizedUrl } = useGetLocalizedUrl ( )
return (
< button onClick = { ( ) => router . push ( getLocalizedUrl ( '/about-us' ) ) } >
{ messages . format ( 'clickMe' ) }
</ button >
)
}
export default Tests반응 요소 내부의 URL의 문자열 값을 사용하려면 사전 렌더링과 브라우저가 다르므로 오류가 발생합니다. 그 이유는 클라이언트에서 첫 번째 렌더링에서 Next.js가 다시 쓰기 데이터에 액세스 할 수 없으므로 "반 지역화 된"URL 경로 (예 :
/fr-ca/about-us)를 사용하기 때문입니다. 이것은 Next.js 동작이기 때문에 지금이 문제를 해결하는 가장 간단한 방법은 요소에suppressHydrationWarning={true}추가하는 것입니다. 이 문제를 해결하기 위해useGetLocalizedUrl또한 현지화 된 URL을 클라이언트에서 사용할 수있는 시점을 추적하는 데 사용할 수있는isLoading속성을 반환합니다.
현지화 된 URL을 가져와야하는 상황이 발생할 수 있지만 후크를 사용하는 것은 옵션이 아닙니다. 다음은 next-multilingual/url 의 getLocalizedUrl 들어오는 곳입니다. useLocalizedUrl 과 동일하게 작동하지만 locale 주장은 필수입니다.
Next.js의 API를 사용하여 트랜잭션 이메일을 보내고 구성으로 하드 코딩하지 않고도 next-multilingual 의 현지화 된 URL을 활용하려고한다고 상상해보십시오. 다음은 사용 방법의 예입니다.
import type { NextApiRequest , NextApiResponse } from 'next'
import { isLocale } from 'next-multilingual'
import { getMessages } from 'next-multilingual/messages'
import { getLocalizedUrl } from 'next-multilingual/url'
import { sendEmail } from 'send-email'
/**
* The "/api/send-email" handler.
*/
const handler = ( request : NextApiRequest , response : NextApiResponse ) : Promise < void > => {
const locale = request . headers [ 'accept-language' ]
let emailAddress = ''
try {
emailAddress = JSON . parse ( request . body ) . emailAddress
} catch ( error ) {
response . status ( 400 )
return
}
if ( locale === undefined || ! isLocale ( locale ) || ! emailAddress . length ) {
response . status ( 400 )
return
}
const messages = getMessages ( locale )
sendEmail (
emailAddress ,
messages . format ( 'welcome' , { loginUrl : await getLocalizedUrl ( '/login' , locale , true ) } )
)
response . status ( 200 )
}
export default handler 구성 요소 작성은 페이지와 동일하지만 pages 디렉토리 외부에 거주합니다. 또한 slug 키 (사용 된 경우)는 URL에 영향을 미치지 않습니다. 우리는 자체 설명이어야하는 몇 가지 예제 구성 요소가 있지만 여기에는 Footer.tsx 의 예입니다.
import { useMessages } from 'next-multilingual/messages'
const Footer : React . FC = ( ) => {
const messages = useMessages ( )
return < footer > { messages . format ( 'footerMessage' ) } </ footer >
}
export default Footer그리고 메시지 파일 :
# This is the message in the footer at the bottom of pages
exampleApp.footerComponent.footerMessage = © Footer또한 모든 다국어 응용 프로그램에서 필수 인 언어 스위처 구성 요소 예제를 살펴보십시오.
우리는 메시지를 공유하는 것이 처음부터 나쁜 관행이라는 것을 분명히 알았습니다. 그래서 우리는 여기서 무엇에 대해 이야기하고 있습니까? 사실, 메시지 자체를 공유하는 것은 나쁘지 않습니다. 문제를 일으킬 수있는 것은 다른 상황에서 메시지를 공유 할 때입니다. 예를 들어, yesButton , noButton 키가 포함 된 Button.ts 공유 메시지 파일을 만들려는 유혹이있을 수 있지만 이것은 잘못 될 것입니다. 많은 언어에서 "예"및 "아니오"와 같은 간단한 단어는 버튼이더라도 상황에 따라 다른 철자를 가질 수 있습니다.
메시지를 언제 공유하는 것이 좋습니까? 항목 목록.
예를 들어, 현지화 프로세스를 간단하게 유지하려면 데이터베이스에 현지화 가능한 문자열을 저장하지 않으려 고합니다 (디자인 결정 문서의 이유에 대한 자세한 내용). 데이터베이스에서는 고유 식별자를 사용하여 컨텍스트를 식별하고 메시지 파일에 메시지를 공유하는 메시지 파일에 저장합니다. 여기서 키의 식별자는 데이터베이스의 식별자와 일치합니다.
이것을 설명하기 위해 과일을 사용하여 한 예제를 만들었습니다. 당신이해야 할 일은 다음과 같은 useMessages 라고하는 후크를 만드는 것입니다.
export { useMessages as useFruitsMessages } from 'next-multilingual/messages'hook 후크 외부의 메시지에 액세스 해야하는 경우
getMessages내보내야합니다.
물론 메시지 파일이 같은 디렉토리에 있습니다.
exampleApp.fruits.banana = Banana
exampleApp.fruits.apple = Apple
exampleApp.fruits.strawberry = Strawberry
exampleApp.fruits.grape = Grape
exampleApp.fruits.orange = Orange
exampleApp.fruits.watermelon = Watermelon
exampleApp.fruits.blueberry = Blueberry
exampleApp.fruits.lemon = Lemon그리고 그것을 사용하려면 간단 하게이 훅을 어디서나 가져옵니다.
import { useFruitsMessages } from '../messages/useFruitsMessages'
const FruitList : React . FC ( ) => {
const fruitsMessages = useFruitsMessages ( )
return (
< >
{ fruitsMessages
. getAll ( )
. map ( ( message ) => message . format ( ) )
. join ( ', ' ) }
</ >
)
}
export default FruitList다음과 같은 개별 메시지를 호출 할 수도 있습니다.
fruitsMessages . format ( 'banana' )이러한 항목 목록을 공유하는 아이디어는 다른 구성 요소에서 일관된 경험을 가질 수 있다는 것입니다. 한 페이지에 과일 목록이있는 드롭 다운과 다른 페이지에는 자동 완성 입력을 상상해보십시오. 그러나 기억해야 할 중요한 부분은 목록이 항상 다른 맥락에서 일부 메시지를 재사용하지 않기 위해 동일한 컨텍스트에서 항상 사용해야한다는 것입니다.
모든 메시지에 정적 텍스트가 포함되어 있지 않기 때문에 메시지에서 자리 표시자를 사용하는 것은 중요한 기능입니다. next-multilingual ICU MessageFormat 구문을 상자 밖으로 지원하므로 다음 메시지를 사용할 수 있습니다.
exampleApp.homepage.welcome = Hello {name}!다음을 사용하여 값을 주입하십시오.
messages . format ( 'welcome' , { name : 'John Doe' } ) format 사용 방법 format 사용할 때 명심해야 할 몇 가지 간단한 규칙이 있습니다.
values 인수를 제공하지 않으면 메시지를 정적 텍스트로 출력합니다.values 인수를 제공하는 경우 메시지에 {placeholder} 구문을 사용하여 모든 자리 표시 자의 값을 포함시켜야합니다. 그렇지 않으면 메시지가 표시되지 않습니다.values 제공하면 조용히 무시됩니다. ICU MessageFormat의 주요 장점 중 하나는 유니 코드의 도구 및 표준을 사용하여 응용 프로그램이 대부분의 언어로 유창하게 들리도록하는 것입니다. 많은 엔지니어들은 2 개의 메시지를 가짐으로써 하나의 메시지와 하나는 모든 언어에 능통하기에 충분하다고 믿을 수 있습니다. 실제로 유니 코드는 200 개가 넘는 언어의 복수 규칙을 기록했으며 아랍어와 같은 일부 언어는 최대 6 개의 복수형 형식을 가질 수 있습니다.
문장이 모든 언어에 유창하게 유지되도록하기 위해 다음 메시지를 사용할 수 있습니다.
exampleApp.homepage.mfPlural = {count, plural, =0 {No candy left.} one {Got # candy left.} other {Got # candies left.}}유니 코드에 의해 정의 된 올바른 복수 범주를 사용하여 올바른 복수 형태를 선택합니다.
messages . format ( 'mfPlural' , { count } )이 주제에 대해 배울 것이 많습니다. 유니 코드 문서를 읽고 구문을 직접 시도해보십시오.
{placeholder} 구문을 사용하여 두 자리 표시자를 사용해야하고 메시지에 { 및 } 문자를 표시 해야하는 드문 경우에 { ( { ) 및 } (for } ) HTML 엔티티는 다음과 같은 번역 도구로 인식됩니다.
exampleApp.debuggingPage.variableInfo = Your variable contains the following values: & # x7b;{values}} 값 (자리 표시 자)이없는 메시지가있는 경우 HTML 엔티티로 { 및 } 탈출 할 필요가 없으며 엔티티를 정적 텍스트로 표시합니다.
단일 메시지 내부에 인라인 HTML이 필요한 것은 매우 일반적인 상황입니다. 이를 수행하는 한 가지 방법은 다음과 같습니다.
# Bad example, do not ever do this!
exampleApp.homepage.createAccount1 = Please
exampleApp.homepage.createAccount2 = create your account
exampleApp.homepage.createAccount3 = today for free.그런 다음:
< div >
{ messages . format ( 'createAccount1' ) }
< Link href = "/sign-up" > { messages . format ( 'createAccount2' ) } </ Link >
{ messages . format ( 'createAccount3' ) }
</ div >이 접근법에는 두 가지 문제가 있습니다.
이것은 실제로 연결 이라고 불리는 반포 반대이며 항상 피해야합니다. 이것은 formatJsx 사용하여이를 수행하는 올바른 방법입니다.
exampleApp.homepage.createAccount = Please <link>create your account</link> today for free.그런 다음:
< div > { messages . formatJsx ( 'createAccount' , { link : < Link href = "/sign-up" > </ Link > } ) } </ div > formatJsx 사용하는 방법 formatJsx 자리 표시 자와 JSX 요소를 모두 values 으로 지원합니다. 즉, JSX 요소를 주입하면서 표준 format 기능 (예 : 복수)의 혜택을받을 수 있습니다.
format 사용할 때 명심해야 할 몇 가지 간단한 규칙이 있습니다.
formatJsx 와 인수로 전달하는 JSX 요소에 있어야합니다.<link> xml 태그의 경우 link: <Link href="/"></Link> .<i> , <i2> 등과 <i1> 고유 한 태그를 만들고 jsx 요소로 인수로 그 값을 전달해야한다는 것을 의미합니다.Hello <name>{name}</name> )에 대해 동일한 이름을 사용하는 것은 지원되지 않습니다..properties 파일에 있어야합니다.<Link href="/contact-us><a id="test"></a></Link> .properties 하지만 <div><span1></span1><span2></span2></div> 유효하지 않습니다. > < formatJsx 사용하는 경우 텍스트로 표시하려면 곱슬 괄호를 피해야합니다. 또한 formatJsx 메시지에서 XML을 사용하므로 태그를 식별하는 데 사용되는 < 및 > 에 유사한 규칙이 적용됩니다.
<element></element> (XML) 구문을 사용하여 메시지에 JSX를 주입 해야하는 드문 경우와 메시지에 < 및 > 문자를 표시하려면 < ( < ) 및 > (for > ) HTML 엔티티는 다음과 같은 번역 도구로 인식됩니다.
exampleApp.statsPage.targetAchieved = You achieved your weekly target (& # x3c;5) and are eligible for a <link>reward</link>.앵커 링크는 상단이 아닌 문서의 특정 장소로 이동하는 링크입니다.
next-multilingual 의 핵심 기능 중 하나는 현지화 된 URL을 지원하는 것입니다. 우리의 디자인은 현지화하기 쉽고 SEO 친화적 인 슬러그로 변형되는 일반 문장을 사용하여 구축되었습니다. 우리는 동일한 함수를 사용하여 앵커 링크를 슬러지 할 수 있으므로 /fr-ca/nous-joindre#our-team 대신 /fr-ca/nous-joindre#notre-équipe 가질 수 있습니다.
앵커 링크에는 두 가지 유형이 있습니다.
앵커 링크 .properties 같은 페이지에 있고 다른 페이지에서 참조되지 않은 경우.
# Table of content header
exampleApp.longPage.tableOfContent = Table of Content
# This key will be used both as content and "slugified". Make sure when translating that its value is unique.
exampleApp.longPage.p1Header = Paragraph 1
# "Lorem ipsum" text to make the (long) page scroll
exampleApp.longPage.p1 = Lorem ipsum dolor sit amet... 그런 다음 페이지는 slugify 기능을 사용하여 URL 조각을 가리키려는 요소와 관련된 고유 식별자에 링크 할 수 있습니다.
import { NextPage } from 'next'
import Link from 'next-multilingual/link'
import { slugify , useMessages } from 'next-multilingual/messages'
import { useRouter } from 'next/router'
const LongPage : NextPage = ( ) => {
const messages = useMessages ( )
const { locale } = useRouter ( )
return (
< div >
< div >
< h2 > { messages . format ( 'tableOfContent' ) } </ h2 >
< ul >
< li >
< Link href = { `# ${ slugify ( messages . format ( 'p1Header' ) , locale ) } ` } >
{ messages . format ( 'p1Header' ) }
</ Link >
</ li >
</ ul >
</ div >
< div >
< h2 id = { slugify ( messages . format ( 'p1Header' ) , locale ) } > { messages . format ( 'p1Header' ) } </ h2 >
< p > { messages . format ( 'p1' ) } </ p >
</ div >
</ div >
)
}
export default LongPage 또한 페이지에서 앵커 링크를 사용하여 링크를 클릭하면 브라우저에 해당 페이지에 관련 콘텐츠가 직접 표시됩니다. 이렇게하려면 "공유 메시지"와 같이 작동하는이 간단한 내보내기를 추가하여 페이지의 메시지를 다른 페이지에 사용할 수 있도록해야합니다.
export const useLongPageMessages = useMessages그런 다음 다른 페이지 에서이 후크를 사용할 수 있습니다.
import { NextPage } from 'next'
import Link from 'next-multilingual/link'
import { slugify , useMessages } from 'next-multilingual/messages'
import { useRouter } from 'next/router'
import { useLongPageMessages } from './long-page'
const AnchorLinks : NextPage = ( ) => {
const messages = useMessages ( )
const { locale , pathname } = useRouter ( )
const longPageMessages = useLongPageMessages ( )
return (
< div >
< div >
< Link
href = { ` ${ pathname } /long-page# ${ slugify ( longPageMessages . format ( 'p3Header' ) , locale ) } ` }
>
{ messages . format ( 'linkAction' ) }
</ Link >
</ div >
</ div >
)
}
export default AnchorLinks이 패턴은 구성 요소에도 작동합니다. 이를 수행하는 이점은 페이지를 삭제하거나 리팩터링하면 관련 앵커 링크가 항상 페이지와 함께 유지된다는 것입니다.
앵커 링크에 대해 별도의 공유 메시지 구성 요소를 만들 수 있지만 근접성 원칙이 나옵니다.
앵커 링크의 전체 예는 예제 응용 프로그램에서 찾을 수 있습니다.
Next.js에서 누락 된 기능 중 하나는 SEO에 사용되는 중요한 HTML 태그를 관리하는 것입니다. html <head> 에 사는 매우 중요한 두 가지 태그를 처리하기 위해 <Head> 구성 요소를 추가했습니다.
<link rel=canonical> ) : 검색 엔진에 페이지 브라우징에 대한 진실의 출처 가이 URL이라고 알려줍니다. 중복 컨텐츠에 대한 처벌을 피하는 것이 매우 중요합니다. 특히 URL은 사례에 민감하지 않지만 Google은이를 대변인으로 취급합니다.<link rel=alternate> ) : 검색 엔진에 검색되는 페이지가 다른 언어로도 사용할 수 있으며 사이트의 크롤링을 용이하게합니다. API는 next-multilingual/head 에서 사용할 수 있으며 다음과 같이 가져올 수 있습니다.
import Head from 'next-multilingual/head' <Link> 와 마찬가지로 <Head> Next.js ' <Head> 구성 요소의 드롭 인 대체품입니다. 이 예에서는 다음과 같은 레이아웃 구성 요소에서 사용합니다.
< Head >
< title > { title } </ title >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" > </ meta >
</ Head > 이 모든 것은 검색 엔진이 응용 프로그램을 더 잘 기어 올릴 수 있도록 표준 및 대체 링크를 삽입하는 것입니다. 예를 들어, /en-us/about-us 페이지에있는 경우 다음 HTML이 html <head> 태그 아래에 자동으로 추가됩니다.
< link rel =" canonical " href =" http://localhost:3000/en-us/about-us " />
< link rel =" alternate " href =" http://localhost:3000/en-us/about-us " hreflang =" en-US " />
< link rel =" alternate " href =" http://localhost:3000/fr-ca/%C3%A0-propos-de-nous " hreflang =" fr-CA " /> SEO 마크 업의 혜택을 받으려면 모든 페이지에 <Head> 포함되어야합니다. 이를 달성하는 방법에는 여러 가지가 있지만 예에서는 모든 페이지에서 사용되는 <Layout> 구성 요소를 만들었습니다.
대부분의 사이트와 마찬가지로 Next.js의 사용자 정의 오류 페이지 기능을 활용하려고합니다. useMessages() 사용하면 다른 페이지를 만드는 것만 큼 쉽습니다. 예를 들어, 404 오류의 경우 404.tsx 만들 수 있습니다.
import { NextPage } from 'next'
import Link from 'next-multilingual/link'
import { getTitle , useMessages } from 'next-multilingual/messages'
import Layout from '@/layout'
const Error404 : NextPage = ( ) => {
const messages = useMessages ( )
const title = getTitle ( messages )
return (
< Layout title = { title } >
< h1 > { title } </ h1 >
< Link href = "/" >
< a > { messages . format ( 'goBack' ) } </ a >
</ Link >
</ Layout >
)
}
export default Error404 물론, 귀하의 메시지, 예를 들어 404.en-US.properties :
# Page title
exampleApp.pageNotFoundError.title = 404 - Page Not Found
# Go back link text
exampleApp.pageNotFoundError.goBack = Go back homeAPI는 종종 현지화되어야합니다. 다음은 "Hello API"예입니다.
import type { NextApiRequest , NextApiResponse } from 'next'
import { getMessages } from 'next-multilingual/messages'
/**
* Example API schema.
*/
type Schema = {
message : string
}
/**
* The "hello API" handler.
*/
const handler = ( request : NextApiRequest , response : NextApiResponse < Schema > ) : void => {
const locale = request . headers [ 'accept-language' ]
if ( locale === undefined || ! isLocale ( locale ) ) {
response . status ( 400 )
return
}
const messages = getMessages ( locale )
response . status ( 200 ) . json ( { message : messages . format ( 'message' ) } )
} 이는 예제 응용 프로그램에서 구현 된 API와 매우 유사합니다. 우리는 Accept-Language HTTP 헤더를 사용하여 API에 어떤 로케일이 원하는지 알려주고 있습니다. 현재 로케일의 컨텍스트가있는 useMessages 훅과 달리, 우리는 어떤 로케일에 메시지를 반환 할 것인지 getMessages 알려야합니다.
hello.en-US.properties 파일은 API Route 파일 옆에 하나를 작성하는 데 필요한 useMessages 와 정확히 동일합니다.
# API message
exampleApp.helloApi.message = Hello, from API.다른 반응 기반 API 호출과 마찬가지로 모든 페이지에서이를 구현할 수 있습니다.
const SomePage : NextPage = ( ) => {
const [ apiError , setApiError ] = useState ( null )
const [ isApiLoaded , setApiIsLoaded ] = useState ( false )
const [ apiMessage , setApiMessage ] = useState ( '' )
useEffect ( ( ) => {
setApiIsLoaded ( false )
const requestHeaders : HeadersInit = new Headers ( )
requestHeaders . set ( 'Accept-Language' , normalizeLocale ( router . locale as string ) )
fetch ( '/api/hello' , { headers : requestHeaders } )
. then ( ( result ) => result . json ( ) )
. then (
( result ) => {
setApiIsLoaded ( true )
setApiMessage ( result . message )
} ,
( apiError ) => {
setApiIsLoaded ( true )
setApiError ( apiError )
}
)
} , [ router . locale ] )
const showApiMessage : React . FC = ( ) => {
if ( apiError ) {
return (
< >
{ messages . format ( 'apiError' ) }
{ ( apiError as Error ) . message }
</ >
)
} else if ( ! isApiLoaded ) {
return < > { messages . format ( 'apiLoading' ) } </ >
} else {
return < > { apiMessage } </ >
}
}
return (
< div >
< h2 > { messages . format ( 'apiHeader' ) } </ h2 >
< div > { showApiMessage ( { } ) } </ div >
</ div >
)
} normalizeLocale 은 필수가 아니라 권장 ISO 3166 컨벤션입니다. 다음 .js는 로케일을 URL 접두사로 사용하기 때문에 구성이 저지로 사용되며 필요에 따라 다시 정규화 할 수 있습니다.
dynamic 동적 경로는 복잡하고 국소화되면 훨씬 더 복잡합니다. 현지화를 추가하기 전에이 Next.js 기능이 어떻게 작동하는지 잘 알고 있는지 확인하십시오.
동적 경로는 매우 일반적이며 Next.js에 의해 상자에서 지원됩니다. 버전 3.0이므로 next-multilingual 동적 경로 측면에서 다음.js와 동일한지지를 제공합니다. 동적 경로가 next-multilingual 와 함께 작동하도록하려면 다음과 같은 몇 가지 패턴이 있습니다.
<Link> 의 href 속성 및 useLocalizedUrl / useGetLocalizedUrl / getLocalizedUrl url 인수는 문자열 URL 만 허용합니다.<Link> component which accepts a UrlObject , we preferred to streamline our types since urlObject.href can easily be used instead.userRouter().asPath (most common scenario) by providing localized parameters directly in the URL. By using asPath you are using the localized URL which means that the URL you will use will be fully localized.userRouter().pathname is conjunction with hydrateRouteParameters by providing localized parameters. By using pathname you are using the non-localized URL which means that the URL you will use might be a mix of non-localized segments plus the localized parameters. This can be useful in cases where you have nested dynamic routes.We provided several examples of on on to use dynamic routes in our dynamic route test pages.
The main challenge with dynamic routes, is that if the value of the parameter needs to be localized, we need to keep a relation between languages so that we can correctly switch languages. next-multilingual solves this problem with its getLocalizedRouteParameters API that creates a LocalizedRouteParameters object used as a page props. This can work both with getStaticProps and getServerSideProps .
getStaticProps First you need to tell Next.js which predefined paths will be valid by using getStaticPaths (all imports are added in the first example):
import { getCitiesMessages } from '@/messages/cities/citiesMessages'
import { GetStaticPaths } from 'next'
import { slugify } from 'next-multilingual/messages'
export const getStaticPaths : GetStaticPaths = async ( context ) => {
const paths : MultilingualStaticPath [ ] = [ ]
const { locales } = getStaticPathsLocales ( context )
locales . forEach ( ( locale ) => {
const citiesMessages = getCitiesMessages ( locale )
citiesMessages . getAll ( ) . forEach ( ( cityMessage ) => {
paths . push ( {
params : {
city : slugify ( cityMessage . format ( ) , locale ) ,
} ,
locale ,
} )
} )
} )
return {
paths ,
fallback : false ,
}
} Then you have to pre-compute the localized route parameters and return them as props using getStaticProps and getLocalizedRouteParameters :
export type CityPageProps = { localizedRouteParameters : LocalizedRouteParameters }
export const getStaticProps : GetStaticProps < CityPageProps > = async ( context ) => {
const localizedRouteParameters = getLocalizedRouteParameters (
context ,
{
city : getCitiesMessages ,
} ,
import . meta . url
)
return { props : { localizedRouteParameters } }
}If you are using a catch-all dynamic route, you will need to pass your parameters as an array, for each URL segment that you want to support. For example, if you want to support 2 levels:
const localizedRouteParameters = getLocalizedRouteParameters ( context , {
city : [ getCitiesMessages , getCitiesMessages ] ,
} ) Note that since we need to use the getMessages API instead of the useMessages hook, you will also need to export it in the message file:
export {
getMessages as getCitiesMessages ,
useMessages as useCitiesMessages ,
} from 'next-multilingual/messages'Finally you have to pass down your localized route parameters down to your language switcher component when you create your page:
const CityPage : NextPage < CityPageProps > = ( { localizedRouteParameters } ) => {
const messages = useMessages ( )
const title = getTitle ( messages )
const { query } = useRouter ( )
return (
< Layout title = { title } localizedRouteParameters = { localizedRouteParameters } >
< h1 > { query [ 'city' ] } < / h1>
< / Layout>
)
}
export default CityPage The only part missing now is the language switcher which needs to leverage the localized route parameters by using getLanguageSwitcherUrl :
import { normalizeLocale , setCookieLocale } from 'next-multilingual'
import Link from 'next-multilingual/link'
import { KeyValueObject } from 'next-multilingual/messages'
import { LocalizedRouteParameters , useRouter } from 'next-multilingual/router'
import { getLanguageSwitcherUrl } from 'next-multilingual/url'
import { ReactElement } from 'react'
// Locales don't need to be localized.
const localeStrings : KeyValueObject = {
'en-US' : 'English (United States)' ,
'fr-CA' : 'Français (Canada)' ,
}
type LanguageSwitcherProps = {
/** Route parameters, if the page is using a dynamic route. */
localizedRouteParameters ?: LocalizedRouteParameters
}
export const LanguageSwitcher : React . FC < LanguageSwitcherProps > = ( { localizedRouteParameters } ) => {
const router = useRouter ( )
const { pathname , locale : currentLocale , locales , defaultLocale , query } = useRouter ( )
const href = getLanguageSwitcherUrl ( router , localizedRouteParameters )
return (
< div id = "language-switcher" >
< ul >
{ locales
. filter ( ( locale ) => locale !== currentLocale )
. map ( ( locale ) => {
return (
< li key = { locale } >
< Link href = { href } locale = { locale } >
< a
onClick = { ( ) => {
setCookieLocale ( locale )
} }
lang = { normalizeLocale ( locale ) }
>
{ localeStrings [ normalizeLocale ( locale ) ] }
< / a>
< / Link>
< / li >
)
} ) }
< / ul>
< / div >
)
}Check out our fully working examples:
Our ideal translation process is one where you send the modified files to your localization vendor (while working in a branch), and get back the translated files, with the correct locale in the filenames. Once you get the files back you basically submit them back in your branch which means localization becomes an integral part of the development process. Basically, the idea is:
We don't have any "export/import" tool to help as at the time of writing this document.
next-multilingual ? ?️Why did we put so much effort into these details? Because our hypothesis is that it can have a major impact on:
More details can be found on the implementation and design decision in the individual README files of each API and in the documentation directory.