next-i18next - Is it possible to change default language dynamically?

16.5k views Asked by At

I'm using next-i18next to handle internationalization of my next.js app.

Is it possible to change default language dynamically? For example based on the top level domain?

const defaultLanguage = topLevelDomain === "de" : "de" ? "it";

EDIT: I'm also using localeSubpaths so that's why I'm trying to investigate the topic.

3

There are 3 answers

1
yohanes On

For someone who use Nextjs v10.0.0 up as written here, we have to use the newest configurations.

next-i18next.config.js

module.exports = {
  i18n: {
    defaultLocale: 'it',
    locales: ['it', 'de'],
  },
}

next.config.js

const { i18n } = require('./next-i18next.config')

module.exports = {
  i18n,
}

And to change the language we have to use next/link and next/router:

import Link from 'next/link'
import { useRouter } from 'next/router'
import { Menu } from 'antd'
import { BorderOutlined, CheckSquareOutlined } from '@ant-design/icons'

.
.
.

export default function YourComponent() {
  .
  .
  const router = useRouter()

  const selectedLang = lang => {
    return router.locale === lang ? <CheckSquareOutlined /> : <BorderOutlined />
  }

  return (
    .
    .
    .
    <Menu onClick={handleLangMenuClick}>
      <Menu.Item key="it" icon={selectedLang('it')}>
        <Link href={router.pathname} locale="it" >
          <a>Italian</a>
        </Link>
      </Menu.Item>
      <Menu.Item key="en" icon={selectedLang('de')}>
        <Link href={router.pathname} locale="de" >
          <a>German</a>
        </Link>
      </Menu.Item>
    </Menu>
    .
    .
  )

.
.
}

But you have to bear in mind, that:

  1. At first render, the default language will always refer to the Accept- Language header sent by the browser. In other words, the default language will be based on your target user's browser language settings.

    Let say that Accept-Language header sent by the browser is as follows (both de and it exists):

    Accept-Language: de, de;q=0.9, it;q=0.8, en;q=0.7, *;q=0.5
    
    # Note: the `q` value may be differs, the bigger will get the most priority
    

    then the default language will be German, ignoring the configuration defaultLocale at next-i18next.config.js.

  2. If both de and it not listed in Accept-Language for example:

    Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, cn;q=0.7, *;q=0.5
    

    then the default language will be Italian following the configuration we made.

  3. For development purposes, we can change the browser language settings (I use google chrome) at chrome://settings/?search=language and order the languages based on your preference.

  4. We can set the default language for the next render by programmatically add NEXT_LOCALE cookies to the target user's browser, based on their selection. Example:

    import cookie from 'react-cookies'
    .
    .
    .  
    
    export default function YourComponent() {
      .
      .
    
      setDefaultLang = (lang) => {
         cookie.save('NEXT_LOCALE', lang)
      }
      .
      .
      .
    }
    
  5. Always check the documentation to get the newest update.

1
Yvan Njomkam On

Migration from next-i18next v7 to v8 is explain through this articles https://github.com/isaachinman/next-i18next/issues/1040

var languages = [
  ['English', 'en'],
  ['French', 'fr']
]

export default function YourComponent() {
  const router = useRouter();

  const handleLocaleChange = (data)=>{
    router.replace(router.pathname, router.pathname, { locale: data })
  }
  return (
    <Menu onClick={handleLangMenuClick}>
      {languages.map((row, index) => (
      <Menu.Item key="en" onClick={(row[1]) =>handleLocaleChange(row[1])}>
          <a>{row[0]}</a>
      </Menu.Item>      
      )}

    </Menu>
   )
}

0
Azizbek Savkimov On

Of course, you can change. You should disable localeDetection and it will work fine:

next-i18next.config.js

const path = require('path');

module.exports = {
  i18n: {
    locales: ['ru', 'uz', 'en'],
    defaultLocale: 'ru',
    localeDetection: false,
  },
  localePath: path.resolve('./public/locales'),
};