How can I get the initial locale to set default according to the user location?
I'm looking for something like this:
```
import { defaultLocale } from './config'
import { Locale, isLocale } from './types'
export function getInitialLocale(): Locale {
// preference from the previous session
const localSetting = localStorage.getItem('locale')
if (localSetting && isLocale(localSetting)) {
return localSetting
}
// the language setting of the browser
const [browserSetting] = navigator.language.split('-')
if (isLocale(browserSetting)) {
return browserSetting
}
return defaultLocale
}
There isn't a solid solution for this.
If you are using a custom server, you can set the defaultLanguage as a function like this, and setting the defaultLanguage, for example from the Accept-Language header:
For SSG/SSR without a custom server, you can use an API route /api/detectLanguage for language detection together with rewrites.
So /about is rewritten to /api/detectLanguage where you can detect the language from the headers, and then redirect to /[lang]/about.
However, rewrites doesn't work on next export, so for fully static sites you could use a catch-all and checking the language on client-side and doing the redirect on client-side. Or another alternative is to add a useEffect on _app.js to check the language from the pathname and redirect to the user language in case that the pathname doesn't have any language.
Do you have an example for useEffect on _app.js?
Something like this:
import React, { useEffect } from 'react'
import { useRouter } from 'next/router'
import config from '../i18n.json'
function useLanguageDetection() {
const router = useRouter()
useEffect(() => {
const [, langQuery] = router.asPath.split('/')
if (config.allLanguages.some((l) => l === langQuery)) return
const navLang = navigator.language || navigator.userLanguage || ''
const userLang = navLang.split('-')[0]
function getLangRoute(lang) {
return {
pathname: `/${lang}${router.pathname}`,
query: router.query,
asPath: `/${lang}${router.asPath}`,
}
}
if (config.allLanguages.some((l) => l === userLang)) {
router.replace(getLangRoute(userLang))
return
}
router.replace(getLangRoute(config.defaultLanguage))
}, [])
}
export default function MyApp({ Component, pageProps }) {
useLanguageDetection()
return <Component {...pageProps} />
}
Something like this:
import React, { useEffect } from 'react' import { useRouter } from 'next/router' import config from '../i18n.json' function useLanguageDetection() { const router = useRouter() useEffect(() => { const [, langQuery] = router.asPath.split('/') if (config.allLanguages.some((l) => l === langQuery)) return const navLang = navigator.language || navigator.userLanguage || '' const userLang = navLang.split('-')[0] function getLangRoute(lang) { return { pathname: `/${lang}${router.pathname}`, query: router.query, asPath: `/${lang}${router.asPath}`, } } if (config.allLanguages.some((l) => l === userLang)) { router.replace(getLangRoute(userLang)) return } router.replace(getLangRoute(config.defaultLanguage)) }, []) } export default function MyApp({ Component, pageProps }) { useLanguageDetection() return <Component {...pageProps} /> }
That works great, but when it redirect a dymic route, it fail, for example
-courses
-[lang]
[...all].js
When i go to /courses/it/Aprender-Italiano it redirects to /es/courses/[lang]/[...all]. Is there a way to fix it?
Note: es is the user lang
any update?
Someone has achieved this?
I'm doing like this
import { defaultLanguage, allLanguages } from 'i18n.json';
import Cookie from 'js-cookie';
import { useRouter } from 'next/router';
function useLanguageDetection() {
const router = useRouter()
useEffect(() => {
const navLang = navigator.language || navigator['userLanguage'] || ''
const userLang = locales[0]
function handleChange(lng) {
const regex = new RegExp(`^/(${allLanguages.join('|')})`)
const path = router.asPath.replace(regex, '')
router.replace(`/${lng}${path}`)
}
let lang = Cookie.get("lang")
if (!lang) {
const isLang = allLanguages.some((l) => l === userLang);
lang = isLang ? userLang : defaultLanguage;
Cookie.set("lang", lang);
}
handleChange(lang)
}, [])
}
What do you think?
The only thing I want to improve is for the root. I have "defaultLanguage": "en", "defaultLangRedirect": "lang-path" in my config so when you go with aw french browser to mysite.com it redirect to mysite.com/en then mysite.com/fr
For anyone whos is suffering with this code and dynamic routes, theres one mistake in function "getLangRoute". You can see one warning in your console saying that "asPath" is an unkown key. I dont know why, because asPath appears on official Next.js documentation.
TL;DR
This is my current code for automatic language detection that fixs wrong redirection with dynamic routes.
_app.js
import React, { useEffect } from 'react';
import AppProvider from '../hooks';
import { useRouter } from 'next/router';
import config from '../i18n.json';
function useLanguageDetection() {
const router = useRouter();
useEffect(() => {
const [, langQuery] = router.asPath.split('/');
if (config.allLanguages.some((l) => l === langQuery)) return;
const navLang = navigator.language || navigator.userLanguage || '';
const userLang = navLang.split('-')[0];
//avoid useless redirect if user use default language
if (userLang === 'en') {
return;
}
function getLangRoute(lang) {
return {
pathname: `/${lang}${router.asPath}`,
};
}
if (config.allLanguages.some((l) => l === userLang)) {
router.replace(getLangRoute(userLang));
return;
}
router.replace(getLangRoute(config.defaultLanguage));
}, []);
}
const MyApp = ({ Component, pageProps }) => {
useLanguageDetection();
return (
<AppProvider>
<Component {...pageProps} />
</AppProvider>
);
};
export default MyApp;
Most helpful comment
Something like this: