Karena pergeseran fokus dan prioritas, kami tidak dapat lagi mempertahankan paket ini. Ini tidak akan menerima pembaruan, perbaikan bug, atau fitur baru dan mungkin menjadi tidak kompatibel dari waktu ke waktu. Kami merekomendasikan untuk beralih ke paket yang mendukung direktori aplikasi selanjutnya. JS terbaru.
next-multilingual adalah solusi ujung ke ujung untuk selanjutnya. Aplikasi ✱ yang membutuhkan banyak bahasa.
Lihat aplikasi demo kami!
✱ next-multilingual hanya berfungsi dengan? direktori pages . Kami masih menyetrika solusi kami untuk mendukung yang baru? Direktori app karena internasionalisasi tidak lagi menjadi bagian dari konfigurasi Next.js.
npm install next-multilingual
useMessages yang kuat yang mendukung ICU MessageFormat dan injeksi JSX di luar kotak./en-us/contact-us untuk AS Inggris dan /fr-ca/nous-joindre untuk bahasa Prancis Kanada) ✱ . ✱ Siput lokal Anda yang default harus cocok dengan sistem file direktori pages (misalnya, siput untuk "tentang kita" harus berada di direktori about-us ). Jika lokasi default yang Anda perlukan menggunakan karakter di luar yang didukung oleh sistem file, itu belum diuji dan kemungkinan tidak akan berfungsi. Permintaan tarik dipersilakan?
next-multilingual telah berupaya keras untuk menambahkan TSDOC ke semua API-nya. Silakan periksa langsung di IDE Anda jika Anda tidak yakin bagaimana menggunakan API tertentu yang disediakan dalam contoh kami.
Juga, memiliki pendapat tentang "praktik terbaik" bukanlah tugas yang mudah. Inilah sebabnya kami mendokumentasikan keputusan desain kami dalam dokumen khusus yang dapat dikonsultasikan di sini. Jika Anda merasa bahwa beberapa API kami tidak menawarkan apa yang Anda harapkan, pastikan untuk berkonsultasi dengan dokumen ini sebelum membuka masalah.
Bagi mereka yang lebih suka melompat langsung ke dalam aksi, lihat di Direktori example untuk implementasi ujung-ke-ujung dari next-multilingual . Untuk sisanya, bagian di bawah ini akan memberikan panduan konfigurasi yang lengkap, langkah demi langkah,.
Ada banyak opsi untuk dikonfigurasi di Next.js untuk mencapai tujuan kami. next-multilingual kebanyakan peduli tentang:
Kami menawarkan dua API untuk menyederhanakan langkah ini:
getConfig (konfigurasi sederhana) Fungsi ini akan menghasilkan konfigurasi Next.js yang akan memenuhi sebagian besar kasus penggunaan. getConfig mengambil argumen berikut:
applicationId - Pengidentifikasi aplikasi unik yang akan digunakan sebagai awalan kunci pesan.locales - Lokal aplikasi Anda.defaultLocale - Lokal default aplikasi Anda (itu juga harus dimasukkan dalam locales )❗ Hanya BCP 47 Tag Bahasa yang Mengikuti
language- Formatcountryditerima. Untuk detail lebih lanjut tentang alasannya, lihat dokumen keputusan desain.
options (Opsional) - Opsi Bagian dari objek konfigurasi Next.js. getConfig akan mengembalikan objek konfigurasi Next.js.
Untuk menggunakannya, cukup tambahkan kode berikut di next.config.js aplikasi Anda:
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 Tidak semua opsi konfigurasi tidak didukung oleh getConfig . Jika Anda pernah menggunakannya, pesan kesalahan akan mengarahkan Anda langsung ke bagian berikutnya: Config Config.
Config (canggih) Jika Anda memiliki kebutuhan yang lebih maju, Anda dapat menggunakan objek Config secara langsung dan memasukkan konfigurasi yang diperlukan oleh next-multilingual secara langsung di selanjutnya yang next.config.js . Argumen Config hampir identik dengan getConfig (minus options ) - Periksa IDE Anda (TSDOC) untuk detailnya. Berikut adalah contoh bagaimana itu dapat digunakan:
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 ,
}Jika Anda perlu menyesuaikan konfigurasi webpack Anda sendiri, kami sarankan untuk memperluas penangan kami seperti ini:
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
} Atau langsung di 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 melakukan 2 hal yang memanfaatkan kemampuan perutean saat ini: JS saat ini:
next-multilingual/config juga menangani konfigurasi webpack khusus yang diperlukan untuk rendering sisi server URL lokal menggunakan next-multilingual/link/ssr untuk komponen Link dan next-multilingual/head/ssr untuk tautan kanonik dan alternatif di komponen Head .
Untuk detail lebih lanjut tentang implementasi seperti mengapa kami menggunakan karakter UTF-8, lihat dokumen keputusan desain.
next-multilingual/messages/babel-plugin Untuk menampilkan pesan yang terlokalisasi dengan hook useMessages() , kita perlu mengonfigurasi plugin Babel Kustom kami yang secara otomatis akan menyuntikkan string ke halaman dan komponen. Cara yang disarankan untuk melakukan ini adalah dengan memasukkan .babelrc di dasar aplikasi Anda:
{
"presets" : [ " next/babel " ],
"plugins" : [ " next-multilingual/messages/babel-plugin " ]
} Jika Anda tidak mengonfigurasi plugin, Anda akan mendapatkan kesalahan saat mencoba menggunakan useMessages .
App khusus ( _app.tsx ) Kita perlu membuat App khusus dengan menambahkan _app.tsx di direktori pages :
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 ExampleAppIni pada dasarnya melakukan dua hal, seperti yang disebutkan dalam komentar:
/ ). Jika Anda tidak ingin menggunakan Deteksi Lokal next-multilingual , Anda dapat menggunakan useActualLocale(false) sebagai gantinya.Document khusus ( _document.tsx ) Kami juga perlu membuat Document khusus dengan menambahkan _document.tsx di direktori pages :
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 Ini hanya melayani 1 Tujuan: Menampilkan lokasi sisi server yang benar di tag <html> . Karena kami menggunakan lokasi default "palsu", penting untuk menjaga markup SSR yang benar, terutama saat menyelesaikan lokal yang dinamis di / .
next-multilingual/head menyediakan komponen <Head> yang secara otomatis membuat tautan kanonik dan tautan alternatif di header. Ini adalah sesuatu yang tidak disediakan di luar kotak oleh Next.js.
NEXT_PUBLIC_ORIGIN Sesuai Google, tautan alternatif harus sepenuhnya memenuhi syarat, termasuk metode transportasi (http/https). Karena Next.js tidak tahu URL mana yang digunakan pada waktu pembangunan, kita perlu menentukan URL absolut yang akan digunakan, dalam variabel lingkungan. Misalnya, untuk lingkungan pengembangan, buat file .env.development di root aplikasi Anda dengan variabel berikut (sesuaikan berdasarkan pengaturan Anda):
NEXT_PUBLIC_ORIGIN =http://localhost:3000 Terlepas dari lingkungannya, next-multilingual akan mencari variabel yang disebut NEXT_PUBLIC_ORIGIN untuk menghasilkan URL yang sepenuhnya memenuhi syarat. Jika Anda menggunakan basePath Next.js, itu akan ditambahkan secara otomatis ke URL dasar.
NEXT_PUBLIC_ORIGIN hanya akan menerima domain yang memenuhi syarat (misalnya, http://example.com ), tanpa jalur apa pun.
next-multilingual ? Sekarang semuanya telah dikonfigurasi, kita dapat fokus menggunakan next-multilingual !
Untuk mendapatkan next-multilingual untuk bekerja seperti yang dirancang, kami harus menemukan solusi untuk 2 masalah:
undefined undefined Karena situs pendukung selanjutnya.next-multilingual harus membuat lokal default yang tidak pernah kami gunakan. Ini berarti bahwa untuk mengakses informasi lokal yang relevan, kami tidak dapat mengandalkan API Next.js.Kami membuat API berikut untuk memungkinkan nilai lokal yang konsisten di seluruh aplikasi Anda:
useRouter Ini adalah pembungkus sederhana di atas useRouter Next.js yang keduanya menyediakan lokal yang benar tetapi juga tidak pernah kembali undefined .
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 : { } }
}
️ Perhatikan bahwa sementara kami merekomendasikan penggunaan deteksi lokal pintar untuk secara dinamis membuat beranda, ini sepenuhnya opsional. Dengan menggunakan konfigurasi lanjutan denganlocaleDetection: true, Anda akan mengembalikan perilaku Default Next.js tanpa perlu menggunakangetServerSideProps.
Berandanya sedikit lebih kompleks daripada halaman lain, karena kita perlu menerapkan deteksi lokal yang dinamis (dan tampilan) karena alasan berikut:
/ dapat memiliki dampak negatif pada SEO dan bukan pengalaman pengguna terbaik.next-multilingual dilengkapi dengan API getPreferredLocale yang menawarkan deteksi otomatis yang lebih cerdas daripada implementasi Default Next.js.Anda dapat menemukan implementasi lengkap dalam contoh, tetapi di sini adalah versi yang dilucuti:
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 ) ,
} ,
}
}Singkatnya, inilah yang terjadi:
next-multilingual .useResolvedLocale untuk membuat dinamika ini di seluruh aplikasi. Setiap kali Anda membuat file tsx , ts , jsx atau js (dapat dikompilasi) dan bahwa Anda memerlukan pesan yang terlokalisasi, Anda dapat membuat file pesan di daerah yang didukung yang hanya dapat digunakan oleh file -file ini. Sama seperti modul CSS, idenya adalah Anda dapat memiliki file pesan yang terkait dengan ruang lingkup lokal file lain. Ini memiliki manfaat membuat pesan lebih modular dan juga menghindari berbagi pesan di berbagai konteks (lebih detail dalam dokumen keputusan desain tentang mengapa ini buruk).
File pesan memiliki 2 kasus penggunaan utama:
pages Anda, Anda dapat menentukan segmen URL lokal (bagian dari URL di antara / atau di ujung jalur) menggunakan pengidentifikasi kunci slug . Rincian lebih lanjut tentang cara melakukan ini di bawah ini.useMessages . Bayangkan CSS tetapi untuk string yang dapat dilokalkan.Untuk meringkas:
Membuat dan mengelola file -file itu sesederhana membuat lembar gaya, tetapi berikut adalah detail penting:
.properties . Ya, Anda mungkin bertanya -tanya mengapa, tetapi ada alasan bagus yang didokumentasikan dalam dokumen keputusan desain.UTF-8 . Tidak melakukannya akan menggantikan karakter non-Latin dengan �.properties , kami mengikuti konvensi penamaan yang ketat: <PageFilename>.<locale>.properties<applicationId>.<context>.<id> Di mana:next-multilingual/configaboutUsPage atau footerComponent bisa menjadi contoh konteks yang baik. Setiap file hanya dapat berisi 1 konteks dan konteks tidak boleh digunakan di banyak file karena ini dapat menyebabkan "tabrakan kunci" (kunci non-unik).. dan hanya dapat berisi antara 1 hingga 50 karakter alfanumerik - kami sarankan menggunakan Camel Case untuk keterbacaan.slug .title .getTitle yang disediakan di next-multilingual/messages untuk secara otomatis mundur antara title dan kunci slug .useMessages .Juga, pastikan untuk memeriksa log konsol Anda untuk peringatan tentang masalah potensial dengan pesan Anda. Mungkin sulit untuk terbiasa dengan cara kerjanya terlebih dahulu, tetapi kami mencoba membuatnya mudah untuk mendeteksi dan memperbaiki masalah. Perhatikan bahwa log-log tersebut hanya akan ditampilkan di lingkungan non-produksi.
Tidak jarang membutuhkan pesan terlokalisasi sementara tidak dapat menggunakan kait. Contohnya adalah saat menggunakan salah satu fitur inti Next.js adalah dukungan API builtin -nya. Dalam konteks itu, alih -alih menggunakan useMessage kita dapat dengan mudah menggunakan getMessages sambil menentukan argumen locale .
Seperti yang disebutkan sebelumnya, ada satu kunci khusus untuk pages , di mana id slug . Tidak seperti siput tradisional yang terlihat seperti this-is-a-page , kami meminta Anda untuk menulis siput sebagai kalimat yang normal dan dapat dibaca manusia, sehingga dapat diterjemahkan seperti string lainnya. Ini menghindari memiliki proses khusus untuk siput yang bisa mahal dan rumit untuk dikelola dalam berbagai bahasa.
Pada dasarnya, slug adalah "deskripsi pendek" yang dapat dibaca manusia dari halaman Anda, dan mewakili segmen (bagian antara / atau di ujung jalan) URL. Saat digunakan sebagai segmen URL, transformasi berikut diterapkan:
- Misalnya, About Us akan menjadi about-us .
Untuk beranda, URL akan selalu / yang berarti bahwa kunci slug tidak akan digunakan untuk membuat segmen URL lokal.
Jangan lupa, siput harus ditulis sebagai deskripsi pendek yang normal, yang berarti melewatkan kata -kata agar lebih pendek untuk SEO tidak dianjurkan. Alasan utama untuk ini, adalah bahwa jika Anda menulis "sekelompok kata kunci", seorang ahli bahasa yang tidak terbiasa dengan SEO mungkin mengalami kesulitan menerjemahkan pesan itu. Memiliki spesialis SEO dalam banyak bahasa juga akan sangat mahal dan sulit untuk diukur. Dalam skenario yang ideal, halaman SEO khusus pasar mungkin harus ditulis dan dioptimalkan dalam bahasa asli, tetapi ini bukan lagi bagian dari proses penerjemahan. Fokus next-multilingual adalah solusi yang mudah dan ramping untuk melokalisasi URL dalam banyak bahasa.
Kunci slug juga akan digunakan sebagai fallback dari kunci title saat menggunakan API getTitle yang disediakan dalam next-multilingual/messages . API ini memudahkan untuk menyesuaikan judul ketika siput terasa tidak cukup.
️ Perhatikan bahwa mengubah nilaislugberarti URL akan berubah. Karena perubahan itu terjadi dinext.config.js, seperti perubahan konfigurasi Next.js, server harus dimulai kembali untuk melihat perubahan yang berlaku. Hal yang sama berlaku jika Anda mengubah struktur folder karena konfigurasi yang mendasarinya bergantung pada ini.
Jika Anda ingin memiliki direktori tanpa halaman apa pun, Anda masih dapat melokalkannya dengan membuat index.<locale>.properties (di mana locale adalah tempat yang Anda dukung). Meskipun opsi ini didukung, kami tidak merekomendasikan menggunakannya karena ini akan membuat jalur URL lebih lama yang bertentangan dengan praktik terbaik SEO.
Secara default, next-multilingual akan mengecualikan beberapa file seperti halaman kesalahan khusus, atau rute API apa pun di bawah direktori /api . Anda selalu dapat menggunakan kunci slug saat menggunakan pesan untuk file -file ini, tetapi mereka tidak akan digunakan untuk membuat URL lokal.
Anda selalu dapat melihat contoh untuk melihat file pesan beraksi, tetapi berikut adalah sampel yang dapat digunakan di beranda:
# Homepage title
exampleApp.homepage.title = Homepage
# Homepage headline
exampleApp.homepage.headline = Welcome to the homepage Sekarang kami belajar cara membuat beranda dan beberapa detail tentang cara kerja, kami dapat dengan mudah membuat halaman lain. Kami membuat banyak halaman dalam contoh, tetapi di sini adalah contoh bagaimana about-us.jsx bisa terlihat seperti:
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 Dan tentu saja Anda akan memiliki file pesan ini 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 hadir dengan komponen <Link> sendiri yang memungkinkan untuk sisi klien dan rendering sisi server URL lokal. Penggunaannya sederhana, berfungsi persis seperti Next.js ' <Link> .
Satu -satunya hal penting yang perlu diingat adalah bahwa atribut href harus selalu berisi url berikutnya.js. Artinya, struktur file di bawah folder pages harus apa yang digunakan dan bukan versi yang terlokalisasi.
Dengan kata lain, struktur file dianggap sebagai representasi URL "non-terlokalisasi", dan <Link> akan menangani penggantian URL dengan versi lokal (dari file pesan), jika mereka berbeda dari struktur.
API tersedia di bawah next-multilingual/link dan Anda dapat menggunakannya seperti ini:
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 Masing -masing tautan ini akan dilokalisasi secara otomatis ketika kunci slug ditentukan dalam file pesan halaman itu. Misalnya, dalam bahasa Inggris AS, jalur URL "Hubungi Kami" akan /en-us/contact-us sementara dalam bahasa Prancis Kanada itu akan menjadi /fr-ca/nous-joindre .
Karena data untuk pemetaan ini tidak segera tersedia selama rendering, next-multilingual/link/ssr akan mengurus rendering sisi server (SSR). Dengan menggunakan getConfig next-multilingual/config , konfigurasi webpack akan ditambahkan secara otomatis. Jika Anda menggunakan metode Config canggih, ini menjelaskan mengapa konfigurasi webpack khusus diperlukan dalam contoh yang disediakan sebelumnya.
Tidak semua URL lokal menggunakan komponen <Link> dan ini juga mengapa Next.js memiliki metode router.push yang dapat digunakan oleh banyak kasus penggunaan lainnya. next-multilingual dapat mendukung kasus penggunaan ini dengan hook useLocalizedUrl yang akan mengembalikan URL lokal, dapat digunakan oleh komponen apa pun. Berikut adalah contoh tentang bagaimana hal itu dapat dimanfaatkan:
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 Jika Anda lebih suka mendefinisikan URL inline Anda daripada di bagian atas komponen, atau jika Anda perlu melakukan manipulasi URL yang lebih maju, Anda juga dapat menggunakan hook useGetLocalizedUrl yang mengembalikan fungsi untuk mendapatkan URL:
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 TestsHati-hati, jika Anda ingin menggunakan nilai string URL di dalam elemen bereaksi, Anda akan memiliki kesalahan karena URL berbeda antara pra-rendering dan browser. Alasan untuk ini adalah bahwa pada klien, pada render pertama, Next.js tidak memiliki akses ke data penulisan ulang, dan karenanya menggunakan jalur URL "semi-terlokalisasi" (EG
/fr-ca/about-us). Karena ini adalah perilaku asli Next.js, cara paling sederhana untuk mengatasi hal ini untuk saat ini adalah dengan menambahkansuppressHydrationWarning={true}ke elemen Anda. Untuk mengatasi hal ini,useGetLocalizedUrljuga mengembalikan propertiisLoadingyang dapat digunakan untuk melacak ketika URL lokal tersedia untuk digunakan pada klien.
Anda mungkin mengalami situasi di mana Anda juga perlu mendapatkan URL lokal tetapi menggunakan pengait bukanlah suatu pilihan. Di sinilah getLocalizedUrl di next-multilingual/url masuk. Ini bertindak sama dengan useLocalizedUrl tetapi argumen locale wajib.
Bayangkan menggunakan API berikutnya next-multilingual Berikut adalah contoh bagaimana itu dapat digunakan:
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 Membuat komponen sama dengan halaman tetapi mereka tinggal di luar direktori pages . Juga, kunci slug (jika digunakan) tidak akan berdampak pada URL. Kami memiliki beberapa contoh komponen yang harus jelas tetapi di sini adalah contoh komponen Footer.tsx :
import { useMessages } from 'next-multilingual/messages'
const Footer : React . FC = ( ) => {
const messages = useMessages ( )
return < footer > { messages . format ( 'footerMessage' ) } </ footer >
}
export default FooterDan file pesannya:
# This is the message in the footer at the bottom of pages
exampleApp.footerComponent.footerMessage = © FooterPastikan juga untuk melihat contoh komponen switcher bahasa yang merupakan suatu keharusan di semua aplikasi multibahasa.
Kami sudah jelas bahwa berbagi pesan adalah praktik yang buruk sejak awal, jadi apa yang kita bicarakan di sini? Bahkan, berbagi pesan dengan sendirinya tidak buruk. Yang dapat menyebabkan masalah adalah ketika Anda berbagi pesan dalam konteks yang berbeda. Misalnya, Anda mungkin tergoda untuk membuat file pesan bersama Button.ts berisi yesButton , tombol noButton - tetapi ini akan salah. Dalam banyak bahasa kata -kata sederhana seperti "ya" dan "tidak" dapat memiliki ejaan yang berbeda tergantung pada konteksnya, bahkan jika itu sebuah tombol.
Kapan bagus untuk berbagi pesan? Untuk daftar item.
Misalnya, untuk menjaga proses lokalisasi Anda tetap sederhana, Anda ingin menghindari menyimpan string yang dapat dilokalkan di database Anda (lebih detail tentang mengapa dalam dokumen keputusan desain). Dalam database Anda, Anda akan mengidentifikasi konteksnya menggunakan pengidentifikasi unik dan Anda akan menyimpan pesan Anda dalam file pesan bersama, di mana pengidentifikasi kunci Anda akan cocok dengan yang dari database.
Untuk mengilustrasikan ini, kami membuat satu contoh menggunakan buah -buahan. Yang perlu Anda lakukan, adalah membuat kait yang memanggil useMessages seperti ini:
export { useMessages as useFruitsMessages } from 'next-multilingual/messages'❗ Jika Anda perlu mengakses pesan di luar kait, Anda juga perlu mengekspor
getMessages.
Tentu saja, Anda akan memiliki file pesan di direktori yang sama:
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 = LemonDan untuk menggunakannya, impor sederhana kait ini dari mana saja Anda mungkin membutuhkan nilai -nilai ini:
import { useFruitsMessages } from '../messages/useFruitsMessages'
const FruitList : React . FC ( ) => {
const fruitsMessages = useFruitsMessages ( )
return (
< >
{ fruitsMessages
. getAll ( )
. map ( ( message ) => message . format ( ) )
. join ( ', ' ) }
</ >
)
}
export default FruitListAnda juga dapat memanggil pesan individual seperti ini:
fruitsMessages . format ( 'banana' )Gagasan untuk membagikan daftar item tersebut adalah Anda dapat memiliki pengalaman yang konsisten di berbagai komponen. Bayangkan dropdown dengan daftar buah di satu halaman, dan di halaman lain input lengkap otomatis. Tetapi bagian yang penting untuk diingat adalah bahwa daftar tersebut harus selalu digunakan dalam konteks yang sama, bukan untuk menggunakan kembali beberapa pesan dalam konteks yang berbeda.
Menggunakan placeholder dalam pesan adalah fungsi kritis karena tidak semua pesan berisi teks statis. next-multilingual mendukung sintaks ICU MessageFormat di luar kotak yang berarti Anda dapat menggunakan pesan berikut:
exampleApp.homepage.welcome = Hello {name}!Dan menyuntikkan kembali nilai menggunakan:
messages . format ( 'welcome' , { name : 'John Doe' } ) format Ada beberapa aturan sederhana yang perlu diingat saat menggunakan format :
values saat memformat pesan, itu hanya akan menghasilkan pesan sebagai teks statis.values saat memformat pesan, Anda harus menyertakan nilai semua placeholder menggunakan sintaks {placeholder} dalam pesan Anda. Kalau tidak, pesan tidak akan ditampilkan.values yang tidak ada dalam pesan Anda, mereka akan diabaikan secara diam -diam. Salah satu manfaat utama ICU MessageFormat adalah menggunakan alat dan standar Unicode untuk memungkinkan aplikasi menjadi fasih berbahasa sebagian besar bahasa. Banyak insinyur mungkin percaya bahwa dengan memiliki 2 pesan, satu untuk tunggal dan satu untuk jamak sudah cukup fasih dalam semua bahasa. Faktanya, Unicode mendokumentasikan aturan jamak lebih dari 200 bahasa dan beberapa bahasa seperti Arab dapat memiliki hingga 6 bentuk jamak.
Untuk memastikan bahwa kalimat Anda akan tetap fasih dalam semua bahasa, Anda dapat menggunakan pesan berikut:
exampleApp.homepage.mfPlural = {count, plural, =0 {No candy left.} one {Got # candy left.} other {Got # candies left.}}Dan bentuk jamak yang benar akan dipetik, menggunakan kategori jamak yang benar yang ditentukan oleh Unicode:
messages . format ( 'mfPlural' , { count } )Ada banyak yang harus dipelajari tentang topik ini. Pastikan untuk membaca dokumentasi Unicode dan cobalah sintaksnya sendiri untuk lebih terbiasa dengan kemampuan I18N yang kurang hyped ini.
Dalam peristiwa langka di mana Anda perlu menggunakan kedua placeholder menggunakan sintaks {placeholder} dan juga menampilkan karakter { dan } dalam sebuah pesan, Anda harus menggantinya dengan { (untuk { ) dan } (untuk } ) entitas html yang dikenali oleh alat terjemahan seperti ini:
exampleApp.debuggingPage.variableInfo = Your variable contains the following values: & # x7b;{values}} Jika Anda memiliki pesan tanpa nilai (placeholder), melarikan diri dari { dan } dengan entitas HTML tidak diperlukan dan akan menampilkan entitas sebagai teks statis.
Ini adalah situasi yang sangat umum yang perlu kita miliki inline HTML, di dalam satu pesan. Salah satu cara untuk melakukan ini adalah:
# Bad example, do not ever do this!
exampleApp.homepage.createAccount1 = Please
exampleApp.homepage.createAccount2 = create your account
exampleApp.homepage.createAccount3 = today for free.Kemudian:
< div >
{ messages . format ( 'createAccount1' ) }
< Link href = "/sign-up" > { messages . format ( 'createAccount2' ) } </ Link >
{ messages . format ( 'createAccount3' ) }
</ div >Ada 2 masalah dengan pendekatan ini:
Ini sebenarnya adalah anti-pola yang disebut gabungan dan harus selalu dihindari. Ini adalah cara yang benar untuk melakukan ini, menggunakan formatJsx :
exampleApp.homepage.createAccount = Please <link>create your account</link> today for free.Kemudian:
< div > { messages . formatJsx ( 'createAccount' , { link : < Link href = "/sign-up" > </ Link > } ) } </ div > formatJsx formatJsx mendukung placeholder dan elemen JSX sebagai values yang berarti Anda dapat memperoleh manfaat dari fitur format standar (misalnya, bentuk jamak) sambil menyuntikkan elemen JSX.
Ada beberapa aturan sederhana yang perlu diingat saat menggunakan format :
formatJsx .<link> XML, elemen JSX perlu disediakan menggunakan link: <Link href="/"></Link> .<i> berkali -kali dalam sebuah kalimat, Anda perlu membuat tag unik seperti <i1> , <i2> , dll. Dan lulus nilainya dalam argumen sebagai elemen JSX.Hello <name>{name}</name> ) tidak didukung..properties .<Link href="/contact-us><a id="test"></a></Link> valid tetapi <div><span1></span1><span2></span2></div> tidak valid. Sebaliknya Anda harus menggunakan markup XML tingkat yang sama dalam file .properties dan bukan sebagai argumen JSX. > < Saat menggunakan formatJsx , Anda masih perlu melarikan diri dari kurung keriting jika Anda ingin menampilkannya sebagai teks. Selain itu, karena kami akan menggunakan XML dalam pesan formatJsx , aturan > akan berlaku untuk < yang digunakan untuk mengidentifikasi tag.
Dalam peristiwa langka di mana Anda perlu menyuntikkan JSX dalam pesan menggunakan sintaks <element></element> (xml) dan juga menampilkan karakter < dalam pesan, Anda perlu menggantinya dengan > < (untuk < ) dan > (untuk > ) entitas html yang diakui oleh alat terjemahan seperti ini:
exampleApp.statsPage.targetAchieved = You achieved your weekly target (& # x3c;5) and are eligible for a <link>reward</link>.Anchor Links adalah tautan yang membawa Anda ke tempat tertentu dalam dokumen daripada bagian atasnya.
Salah satu fitur inti next-multilingual adalah mendukung URL lokal. Desain kami telah dibangun menggunakan kalimat normal yang mudah dilokalisasi dan kemudian diubah menjadi siput ramah SEO. Kita dapat menggunakan fungsi yang sama untuk membersihkan tautan jangkar, sehingga alih-alih memiliki /fr-ca/nous-joindre#our-team yang dapat Anda miliki /fr-ca/nous-joindre#notre-équipe .
Ada dua jenis tautan jangkar:
Jika tautan jangkar ada di halaman yang sama, dan tidak dirujuk pada halaman lain, Anda dapat menambahkannya di asosiasi file .properties dengan halaman seperti ini:
# 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... Dan kemudian halaman dapat menggunakan fungsi slugify untuk menautkan ke pengidentifikasi unik yang terkait dengan elemen yang ingin Anda arahkan ke fragmen URL ke:
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 Juga umum untuk menggunakan tautan jangkar di seluruh halaman, sehingga ketika Anda mengklik tautan, browser Anda akan secara langsung menampilkan konten yang relevan di halaman itu. Untuk melakukan ini, Anda perlu membuat pesan halaman Anda tersedia untuk halaman lain dengan menambahkan ekspor sederhana ini yang akan bertindak seperti "Pesan Bersama":
export const useLongPageMessages = useMessagesDan kemudian Anda dapat menggunakan kait ini dari halaman lain seperti ini:
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 AnchorLinksPola ini juga berfungsi untuk komponen. Manfaat dari melakukan ini adalah bahwa jika Anda menghapus, atau refactor halaman, tautan jangkar yang terkait dengannya akan selalu tetap dengan halaman.
Anda dapat membuat komponen pesan bersama terpisah hanya untuk tautan jangkar tetapi ini akan merusak prinsip kedekatan.
Contoh lengkap tautan jangkar dapat ditemukan di aplikasi contoh.
Salah satu fitur yang hilang dari Next.js adalah mengelola tag HTML penting yang digunakan untuk SEO. Kami menambahkan komponen <Head> untuk menangani dua tag yang sangat penting yang hidup di html <head> :
<link rel=canonical> ): Ini memberi tahu mesin pencari bahwa sumber kebenaran untuk halaman yang dijelajahi adalah URL ini. Sangat penting untuk menghindari dihukum karena konten duplikat, terutama karena URL tidak sensitif, tetapi Google memperlakukannya sebagai case-sensitive.<link rel=alternate> ): Ini memberi tahu mesin pencari bahwa halaman yang dijelajahi juga tersedia dalam bahasa lain dan memfasilitasi merangkak situs. API tersedia di bawah next-multilingual/head dan Anda dapat mengimpornya seperti ini:
import Head from 'next-multilingual/head' Sama seperti <Link> , <Head> dimaksudkan untuk menjadi pengganti drop-in untuk komponen Next.js ' <Head> . Dalam contoh kami, kami menggunakannya di komponen tata letak, seperti ini:
< Head >
< title > { title } </ title >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" > </ meta >
</ Head > Yang dilakukannya adalah memasukkan tautan kanonik dan alternatif sehingga mesin pencari dapat merayapi aplikasi Anda dengan lebih baik. Misalnya, jika Anda berada di halaman /en-us/about-us , HTML berikut akan ditambahkan secara otomatis di bawah tag HTML <head> Anda:
< 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 " /> Untuk mendapatkan manfaat penuh dari markup SEO, <Head> harus dimasukkan pada semua halaman. Ada beberapa cara untuk mencapai ini, tetapi dalam contoh, kami membuat komponen <Layout> yang digunakan pada semua halaman.
Seperti kebanyakan situs, Anda akan ingin memanfaatkan kemampuan halaman kesalahan kustom Next.js. Dengan useMessages() , semudah membuat halaman lain. Misalnya, untuk kesalahan 404 , Anda dapat membuat 404.tsx Anda:
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 Dan tentu saja, pesan Anda, misalnya 404.en-US.properties :
# Page title
exampleApp.pageNotFoundError.title = 404 - Page Not Found
# Go back link text
exampleApp.pageNotFoundError.goBack = Go back homeAPI sering perlu dilokalisasi. Berikut adalah contoh "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' ) } )
} Ini sangat mirip dengan API yang diimplementasikan dalam aplikasi contoh. Kami menggunakan header http Accept-Language untuk memberi tahu API di mana lokasi yang kami inginkan. Berbeda dengan hook useMessages yang memiliki konteks lokal saat ini, kita perlu memberi tahu getMessages di mana lokal untuk mengembalikan pesan.
File pesan berperilaku persis sama dengan dengan useMessages Anda hanya perlu membuat satu di sebelah file rute API, dalam kasus kami hello.en-US.properties :
# API message
exampleApp.helloApi.message = Hello, from API.Anda dapat menerapkan ini di halaman apa pun, sama seperti panggilan API berbasis reaksi lainnya, seperti ini:
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 tidak wajib tetapi konvensi ISO 3166 yang direkomendasikan. Karena Next.js menggunakan lokal sebagai awalan URL, mereka lebih rendah dalam konfigurasi dan dapat dinormalisasi ulang sesuai kebutuhan.
❗ Rute dinamis kompleks dan melokalkannya menambah lebih banyak kompleksitas. Pastikan Anda terbiasa dengan cara kerja fitur selanjutnya.js ini sebelum mencoba menambahkan lokalisasi.
Rute dinamis sangat umum dan didukung di luar kotak oleh Next.js. Sejak versi 3.0, next-multilingual memberikan dukungan yang sama seperti Next.js dalam hal rute dinamis. Untuk membuat rute dinamis bekerja dengan next-multilingual kami memiliki beberapa pola untuk diikuti:
href <Link> dan useLocalizedUrl / useGetLocalizedUrl / getLocalizedUrl argumen url hanya menerima URL string.<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.