Le moyen le plus simple de traduire vos applications Next.js (avec configuration des pages) .
Si vous utilisez next-i18next (répertoire de pages) en production et que vous souhaitez libérer des super pouvoirs, vous pouvez consulter cet article de blog.
Si vous utilisez Next.js 13/14 avec le répertoire d'applications, vous n'avez pas besoin de next-i18next, vous pouvez directement utiliser i18next et réagissez-i18next, comme décrit dans cet article de blog.
Bien que Next.js fournisse directement un routage internationalisé, il ne gère aucune gestion du contenu de traduction, ni la fonctionnalité de traduction elle-même. Tout ce que Next.js fait est de synchroniser vos paramètres régionaux et vos URL.
Pour compléter cela, next-i18next
fournit les fonctionnalités restantes – gestion du contenu de traduction et composants/hooks pour traduire vos composants React – tout en prenant entièrement en charge SSG/SSR, plusieurs espaces de noms, le fractionnement de codes, etc.
Alors que next-i18next
utilise i18next et réagir-i18next sous le capot, les utilisateurs de next-i18next
doivent simplement inclure leur contenu de traduction sous forme de fichiers JSON et n'ont pas à se soucier de grand-chose d'autre.
Une démo en direct est disponible ici. Cette application de démonstration est un exemple simple : ni plus, ni moins.
Facile à installer, facile à utiliser : l'installation ne prend que quelques étapes et la configuration est simple.
Aucune autre exigence : next-i18next
simplifie l'internationalisation de votre application Next.js sans dépendances supplémentaires.
Prêt pour la production : next-i18next
prend en charge la transmission des traductions et des options de configuration dans les pages en tant qu'accessoires avec la prise en charge SSG/SSR.
Votre fichier next-i18next.config.js
fournira la configuration pour next-i18next
. Après configuration, appWithTranslation
nous permet d'utiliser la fonction t
(traduire) dans nos composants via des hooks.
Ensuite, nous ajoutons serverSideTranslation
à getStaticProps ou getServerSideProps (selon votre cas) dans nos composants au niveau de la page.
Notre application Next.js est désormais entièrement traduisible !
yarn add next-i18next react-i18next i18next
Vous devez également avoir installé react
et next
.
Par défaut, next-i18next
s'attend à ce que vos traductions soient organisées comme telle :
.
└── public
└── locales
├── en
| └── common.json
└── de
└── common.json
Cette structure peut également être vue dans l’exemple simple.
Si vous souhaitez structurer vos traductions/espaces de noms de manière personnalisée, vous devrez transmettre les valeurs localePath
et localeStructure
modifiées dans la configuration d'initialisation.
Tout d’abord, créez un fichier next-i18next.config.js
à la racine de votre projet. La syntaxe de l'objet i18n
imbriqué provient directement de Next.js.
Cela indique next-i18next
quels sont votre defaultLocale
et les autres paramètres régionaux, afin qu'il puisse précharger les traductions sur le serveur :
next-i18next.config.js
/** @type {import('next-i18next').UserConfig} */
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
}
Maintenant, créez ou modifiez votre fichier next.config.js
, en passant l'objet i18n
dans votre fichier next.config.js
, pour activer le routage d'URL localisé :
next.config.js
const { i18n } = require ( './next-i18next.config' )
module . exports = {
i18n ,
}
Il existe trois fonctions exportées next-i18next
, que vous devrez utiliser pour traduire votre projet :
Il s'agit d'un HOC qui enveloppe votre _app
:
import { appWithTranslation } from 'next-i18next'
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp )
Le appWithTranslation
HOC est principalement responsable de l’ajout d’un I18nextProvider
.
Il s'agit d'une fonction asynchrone que vous devez inclure dans vos composants au niveau de la page, via getStaticProps
ou getServerSideProps
(selon votre cas d'utilisation) :
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
} ,
}
}
Notez que serverSideTranslations
doit être importé depuis next-i18next/serverSideTranslations
– il s'agit d'un module distinct qui contient du code spécifique à NodeJs.
Notez également que serverSideTranslations
n'est pas compatible avec getInitialProps
, car il ne peut s'exécuter que dans un environnement serveur, alors que getInitialProps
est appelé côté client lors de la navigation entre les pages.
Le serverSideTranslations
HOC est principalement responsable de la transmission des traductions et des options de configuration dans les pages, en tant qu'accessoires – vous devez l'ajouter à toute page contenant des traductions.
C'est le crochet que vous utiliserez réellement pour effectuer la traduction elle-même. Le hook useTranslation
provient de react-i18next
, mais doit être importé directement depuis next-i18next
.
N'utilisez PAS l'exportation useTranslation
de react-i18next
, mais utilisez UNIQUEMENT celle de next-i18next
!
import { useTranslation } from 'next-i18next'
export const Footer = ( ) => {
const { t } = useTranslation ( 'footer' )
return (
< footer >
< p > { t ( 'description' ) } < / p >
< / footer >
)
}
Par défaut, next-i18next
enverra tous vos espaces de noms au client à chaque demande initiale. Cela peut être une approche appropriée pour les petites applications avec moins de contenu, mais de nombreuses applications bénéficieront de la division des espaces de noms en fonction de l'itinéraire.
Pour ce faire, vous pouvez transmettre un tableau d'espaces de noms requis pour chaque page dans serverSideTranslations
. Vous pouvez voir cette approche dans examples/simple/pages/index.tsx. Passer un tableau vide d’espaces de noms requis n’enverra aucun espace de noms.
Remarque : useTranslation
fournit des espaces de noms au composant dans lequel vous l'utilisez. Cependant, serverSideTranslations
fournit le total des espaces de noms disponibles à l'ensemble de l'arborescence React et appartient au niveau de la page. Les deux sont nécessaires.
Par défaut, next-i18next
enverra uniquement les paramètres régionaux actifs au client à chaque requête. Cela permet de réduire la taille de la charge utile initiale envoyée au client. Cependant, dans certains cas, les traductions pour d'autres langues peuvent également être nécessaires au moment de l'exécution. Par exemple, lors de l'utilisation de getFixedT du hook useTranslation
.
Pour modifier le comportement et charger des paramètres régionaux supplémentaires, transmettez simplement un tableau de paramètres régionaux comme dernier argument à 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'])),
},
};
}
En conséquence, les traductions pour les locales no
et en
seront toujours chargées quelle que soit la langue actuelle.
Remarque : L'argument supplémentaire doit être ajouté à toutes les pages qui utilisent la fonction
getFixedT
.
Par défaut, next-i18next
ajoutera le defaultLocale
comme solution de secours. Pour changer cela, vous pouvez définir fallbackLng
. Toutes les valeurs prises en charge par i18next
( string
, array
, object
et function
) sont également prises en charge par next-i18next
.
De plus, nonExplicitSupportedLngs
peut être défini sur true
pour prendre en charge toutes les variantes d'un langage, sans qu'il soit nécessaire de fournir des fichiers JSON pour chacune d'elles. Notez que toutes les variantes doivent toujours être incluses dans locales
pour activer le routage dans next.js
.
Remarque :
fallbackLng
etnonExplicitSupportedLngs
peuvent être utilisés simultanément. Il n'y a qu'une seule exception : vous ne pouvez pas utiliser une fonction pourfallbackLng
lorsquenonExplicitSupportedLngs
esttrue
,
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
}
Sachez que l'utilisation fallbackLng
et nonExplicitSupportedLngs
peut facilement augmenter la taille initiale de la page.
Pour information : définir fallbackLng
sur false
ne sérialisera PAS votre langue de secours (généralement defaultLocale
). Cela réduira la taille du chargement initial de votre page.
Si vous devez modifier des options de configuration plus avancées, vous pouvez les transmettre via next-i18next.config.js
. Par exemple:
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
localePath :
typeof window === 'undefined'
? require ( 'path' ) . resolve ( './my-custom/path' )
: '/public/my-custom/path' ,
ns : [ 'common' ] ,
}
Certains plugins i18next
(que vous pouvez transmettre dans config.use
) ne sont pas sérialisables, car ils contiennent des fonctions et d'autres primitives JavaScript.
Vous pouvez rencontrer ce problème si votre cas d'utilisation est plus avancé. Vous verrez Next.js générer une erreur comme :
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.
Pour résoudre ce problème, vous devrez définir config.serializeConfig
sur false
et transmettre manuellement votre configuration dans 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
) ) ,
} ,
} )
Lors de l'utilisation sur des pages générées côté serveur avec getStaticPaths
et fallback: true
ou fallback: 'blocking'
, la configuration par défaut indiquée ci-dessus entraînera le démontage et le remontage de l'application à chaque chargement, entraînant diverses conséquences néfastes comme l'appel de chaque useEffect(() => {...}, [])
hook deux fois et légère dégradation des performances.
Cela est dû au fait que, pour ces pages, Next.js effectue un premier rendu avec serverSideProps
vides, puis un deuxième rendu avec les serverSideProps
qui incluent les traductions next-i18next
. Avec la configuration par défaut, l'instance i18n
est initialement undefined
lorsque serverSideProps
est empty
, provoquant le démontage-remontage.
Pour atténuer ce problème, vous pouvez procéder comme suit :
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
Cela fonctionnera tant que vous vous assurerez que, dans l'état de la page de secours, votre code côté client n'essaie pas d'afficher de traduction, sinon vous obtiendrez une erreur « incompatibilité serveur-client » de Next.js (en raison du (le fait que le serveur ait une traduction réelle dans son HTML alors que le HTML du client a la clé de traduction au même endroit).
C'est normal et très bien : vous ne devriez de toute façon pas afficher une clé de traduction à votre utilisateur !
Depuis la version 11.0.0, next-i18next prend également en charge le chargement des traductions côté client.
Dans certains cas d'utilisation, vous souhaiterez peut-être charger un fichier de traduction de manière dynamique sans avoir à utiliser serverSideTranslations
. Cela peut être particulièrement utile pour les composants chargés paresseux dont vous ne souhaitez pas ralentir les pages.
Plus d’informations à ce sujet peuvent être trouvées ici.
Étant donné que les ressources sont chargées une seule fois au démarrage du serveur, toutes les modifications apportées à vos fichiers JSON de traduction en cours de développement ne seront chargées qu'au redémarrage du serveur.
En production, cela ne pose généralement pas de problème, mais en développement, vous souhaiterez peut-être voir les mises à jour de vos fichiers JSON de traduction sans avoir à redémarrer votre serveur de développement à chaque fois. Pour ce faire, définissez l'option de configuration reloadOnPrerender
sur true
.
Cette option rechargera vos traductions chaque fois que serverSideTranslations
est appelé (dans getStaticProps
ou getServerSideProps
). Si vous utilisez serverSideTranslations
dans getServerSideProps
, il est recommandé de désactiver reloadOnPrerender
dans les environnements de production afin d'éviter de recharger les ressources à chaque appel du serveur.
Clé | Valeur par défaut | Note |
---|---|---|
defaultNS | 'common' | |
localePath | './public/locales' | Peut être une fonction, voir note ci-dessous. (peut également être nul, si vous transmettez l'option de ressources directement via la configuration, comme ici) |
localeExtension | 'json' | Ignoré si localePath est une fonction. |
localeStructure | '{{lng}}/{{ns}}' | Ignoré si localePath est une fonction. |
reloadOnPrerender | false | |
serializeConfig | true | |
use (pour les plugins) | [] | |
onPreInitI18next | undefined | c'est à dire (i18n) => i18n.on('failedLoading', handleFailedLoading) |
localePath
en tant que fonction est de la forme (locale: string, namespace: string, missing: boolean) => string
renvoyant le chemin complet, y compris le nom du fichier et l'extension. Lorsque missing
est vrai, renvoie le chemin de l'option addPath
de i18next-fs-backend
, lorsqu'il est faux, renvoie le chemin de l'option loadPath
. Plus d'informations sur le dépôt i18next-fs-backend
.
Si localePath est une fonction, assurez-vous de définir également l'option ns, car côté serveur, nous ne sommes alors pas en mesure de précharger les espaces de noms.
Toutes les autres options i18next et réagissent-i18next peuvent également être transmises.
Vous pouvez également transmettre les resources
directement en combinaison avec la définition localePath
sur null
.
Par défaut, i18next utilise {{
comme préfixe et }}
comme suffixe pour l'interpolation. Si vous souhaitez/devez remplacer ces paramètres d'interpolation, vous devez également spécifier un autre paramètre localeStructure
qui correspond à votre préfixe et suffixe personnalisés.
Par exemple, si vous souhaitez utiliser {
et }
la configuration ressemblerait à ceci :
{
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'nl' ] ,
} ,
interpolation : {
prefix : '{' ,
suffix : '}' ,
} ,
localeStructure : '{lng}/{ns}' ,
}
next-i18next.config.js
Si vous souhaitez modifier le chemin de configuration par défaut, vous pouvez définir la variable d'environnement I18NEXT_DEFAULT_CONFIG_PATH
.
Par exemple, dans le fichier .env
vous pouvez définir un chemin statique :
I18NEXT_DEFAULT_CONFIG_PATH=/path/to/project/apps/my-app/next-i18next.config.js
Ou vous pouvez utiliser une astuce pour le chemin dynamique et définir ce qui suit dans 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 ,
...
} ;
Cela signifie que le fichier de configuration i18n sera dans le même répertoire que next.config.js
et peu importe où se trouve votre répertoire de travail actuel. Cela aide par exemple pour nx
lorsque vous avez monorepo et démarrez votre application à partir de la racine du projet mais que l'application est dans apps/{appName}
.
Remarque Si votre configuration next-i18next.config.js
ne se trouve pas dans le même répertoire que next.config.js
, vous devez la copier manuellement (ou par script personnalisé).
Si vous envisagez d'ajouter progressivement next-i18next à votre projet, nous vous recommandons de transmettre votre next-i18next.config
à appWithTranslation
pour éviter tout problème.
c'est à dire
import nextI18nextConfig from '../../next-i18next.config' ;
//...
export default appWithTranslation ( MyApp , nextI18nextConfig ) ;
Voir le numéro 2259 pour plus d'informations.
Certains PaaS sans serveur peuvent ne pas être en mesure de localiser le chemin de vos traductions et nécessiter une configuration supplémentaire. Si vous rencontrez des problèmes de système de fichiers avec serverSideTranslations
, définissez config.localePath
pour utiliser path.resolve
. Un exemple peut être trouvé ici.
Pour le déploiement Docker, notez que si vous utilisez le Dockerfile
de la documentation Next.js, n'oubliez pas de copier next.config.js
et next-i18next.config.js
dans l'image Docker.
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js
Si vous choisissez d'utiliser un backend i18next différent du backend i18next-fs intégré, vous devrez vous assurer que les ressources de traduction sont chargées avant d'appeler la fonction t
. Étant donné que le suspense React n'est pas encore pris en charge pour SSR, cela peut être résolu de 2 manières différentes :
1) Préchargez les espaces de noms :
Définissez l'option ns
, comme dans cet exemple. Cela garantira que toutes les ressources de traduction sont chargées lors de l’initialisation.
2) Vérifiez le drapeau prêt :
Si vous ne pouvez pas ou ne voulez pas fournir le tableau ns
, les appels à la fonction t
entraîneront le chargement des espaces de noms à la volée. Cela signifie que vous devrez gérer l'état "pas prêt" en vérifiant ready === true
ou props.tReady === true
. Ne pas le faire entraînera le rendu de vos traductions avant leur chargement, ce qui entraînera l'appel de "save Missing" malgré les traductions réellement existantes (pas encore chargées). Cela peut être fait avec le hook useTranslation ou le withTranslation HOC.
Essayez-vous de générer une exportation HTML statique en exécutant next export
et obtenez cette erreur ?
Erreur : le support i18n n'est pas compatible avec la prochaine exportation. Voir ici pour plus d'informations sur le déploiement : https://nextjs.org/docs/deployment
Mais il existe un moyen de contourner ce problème à l'aide du détecteur de langue suivante. Consultez cet article de blog et cet exemple de projet.
Vous disposez de plusieurs façons d'utiliser la fonction t dans votre composant enfant :
t
via des accessoires aux enfantsuseTranslation
, comme dans cet exemple :next-i18next/examples/simple/components/Footer.tsx
Ligne 6 dans e6b5085
withTranslation
Et en général, vous devez toujours vous assurer que serverSideTranslations contient tous les espaces de noms dont vous avez besoin dans l'arborescence.
Merci à ces personnes merveilleuses (clé emoji) :
Rob Capellini | Alexandre Kachkaev ? ? | Mathias Wobbe ? | Lucas Féliciano ? ? | Ryan Leung | Nathan Friemel ? | Isaac Hinman ️️️️♿️ ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ?️ ? |
Adriano Raiano ️️️️♿️ ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ?️ ? | Félix Mosheev ? | Sébastien Vanvelthem ? ? |
Ce projet suit la spécification de tous les contributeurs. Les contributions de toute nature sont les bienvenues !
localisation en tant que service - locize.com
Besoin d'une gestion de traduction ? Vous souhaitez éditer vos traductions avec un éditeur InContext ? Utilisez l'original fourni par les responsables d'i18next !
En utilisant locize, vous soutenez directement l’avenir d’i18next et next-i18next.