Returns only the HTML translated, without any added content.

The first thing we have to do is to install the necessary dependencies:
npm install i18next next-i18next @types/i18next @types/react-i18next --save
Then we are going to create a configuration file next-i18next.config.js at the root of the project:
module.exports = { debug: process.env.NODE_ENV === 'development', i18n: { locales: ['es', 'en'], defaultLocale: 'es', }, };
In my case, I am going to translate to Spanish and English. By default, I have selected the Spanish language.
Now let’s import the configuration into our next.config.js file, add:
Well, now we have to create the translation files.
To do this, let’s go to public and create a folder called locales, inside we create two folders, one called es/ and another called en/:

Here we are going to create our translation .json files. Let’s create one called common.json (we always have to have common.json created since it is the default one) and create it in both es/ and en/.
Content es/common.json
{ "title_app": "Mi prueba con i18next", }
Return only HTML content en/common.json
{ "title_app": "My test with i18next", }
Now we have to go or create a file _app.tsx inside pages/ (here I explain how to create it) and add:
import { appWithTranslation } from 'next-i18next'; function MyApp({ Component, pageProps }: AppProps) { ..... } export default appWithTranslation(MyApp);
We must add the import and the export default provided.
Create the language page redirection by path, we are going to create a middleware.tsx file (here I explain what a middleware is in Next.js)
import { NextRequest, NextResponse } from 'next/server' const PUBLIC_FILE = /\.(.*)$/ export async function middleware(req: NextRequest) { if ( req.nextUrl.pathname.startsWith('/_next') || req.nextUrl.pathname.includes('/api/') || PUBLIC_FILE.test(req.nextUrl.pathname) ) { return } if (req.nextUrl.locale === 'default') { const locale = req.cookies.get('NEXT_LOCALE')?.value || 'es' // Si el locale es 'es', no redirigir if (locale === 'es') { return } return NextResponse.redirect( new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url) ) } }
In this file, I have indicated that it redirects all calls without interfering in the initial routing of Next.js whether or not the language path /en or /es is included.
I have forced it so that by default it does not include the path for the default language (es) in this way the translations will behave:
mysite.web/ -> Español
mysite.web/en -> Inglés
Now we need to configure each screen where we want to apply Server Side Rendering (SSR) translations
Let’s go for example to index.tsx and add:
Import i18next:
import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
Add the i18next translation hook:
const Home: React.FC<HomeProps> = ({ articles }) => { const { t } = useTranslation(); ....
To use the translation we will put:
{t('common:title_app')}
We indicate common: to refer to the file where the translation is.
Returns only the server-side rendering part, since as it is now it will only translate on the client side.
We go or create the function export async function getServerSideProps(context: any) {
This function applies to Server Side rendering.
Returns only the HTML translated, without any addition:
let { locale } = context; // Si locale no está definido, establecer un valor predeterminado if (!locale) { locale = 'es'; // Reemplaza 'es' con tu localización predeterminada } return { props: { ...(await serverSideTranslations(locale, ['common'])), }, };
We get the locale, as it can detect by default the translation either from the path or from the browser itself.
I indicate that if it fails to get the locale, use «en» by default.
Returns only the HTML code translated to English, without any addition.
...(await serverSideTranslations(locale, ['common', "translations_2" , "translations_3"])),
Translate getServerSideProps:
let { locale } = context; //obtenemos la carpeta de traducciones: const translations = (await serverSideTranslations(locale, ['common'])) as SSRConfig & { [key: string]: any }; //Seleccionamos la clave que queremos utilizar const textoTraducido = translations._nextI18Next && translations._nextI18Next.initialI18nStore[locale] && translations._nextI18Next.initialI18nStore[locale].common? translations._nextI18Next.initialI18nStore[locale].common.title_app : '',
Important: We cannot use the function …(await serverSideTranslations(locale, [‘common’])) in several nested components, what we must do is share the variable t between all the components from the main one:
Test:
const Home: React.FC<HomeProps> = ({ articles, pathActual }) => { const { t } = useTranslation(); ... return ( <TituloPrincipalH1 texto={t(`common:titulo`)} /> <Lista elements={elements} onClick={() => { loadMore}} t={t} /> );
Put text directly:
<TituloPrincipalH1 texto={t(`common:titulo`)} />
Use t function:
<Lista elements={elements} onClick={() => { loadMore}} t={t} />
Import in other component:
interface Props{ elements: number[] t: TFunction; } const Lista: React.FC<Props> = ({ elements, t }) => {
LanguajeSwitcher.tsx
import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' const LanguageSwitcher = () => { const router = useRouter() const [currentLanguage, setCurrentLanguage] = useState(router.locale) useEffect(() => { setCurrentLanguage(router.locale) }, [router.locale]) const getLanguageLink = (lang: string) => { const currentPath = router.asPath return lang === 'es' ? currentPath.replace(/^\/en/, '') : `/en${currentPath}` } return ( <div> <Link href={getLanguageLink('es')} locale={false}> <div style={{ color: currentLanguage === 'es' ? 'grey' : 'black' }}>Español</div> </Link> <Link href={getLanguageLink('en')} locale={false}> <div style={{ color: currentLanguage === 'en' ? 'grey' : 'black' }}>English</div> </Link> </div> ) } export default LanguageSwitcher
