Next.js next-i18next is always routing to EN - reactjs

I have a simple project that supposed to work with English and Dutch(default). I have copied everything from the original example but somehow it doesn't work as expected.
Even though I have browserLanguageDetection: false, it is forcing me to /enendpoint.
I would like to show the NL text on / but currently I couldn't.
Could you please check the sandbox and tell me what is wrong here?
https://codesandbox.io/s/pensive-galileo-zifjm?file=/pages/index.js

There is solution in the docs. Here it is: https://nextjs.org/docs/advanced-features/i18n-routing
As I found out from the docs you should declare localeDetection: false then you should declare your own domain paths. It will work.
i18n: {
defaultLocale: 'en',
locales: ['en'],
localeDetection: false, // Important!
domains: [
{
domain: 'example.com', // <-
defaultLocale: 'en' // This locale will be appeared at the exact above domain.
},
{
// 2nd locale goes here in the same way.
}
]
}
I hope, it helps.

It is important to know that in Next.js, the first loading is always done on the server side. In i18n.js you have defined browserLanguageDetection: false but you have not defined serverLanguageDetection: false that's why you are always redirected to /en
In the index page, replace this line export default withTranslation('common')(IndexPage); with this one export default withTranslation(['common'])(IndexPage); to avoid this warning

Related

i18next/react: Trans displaying "undefined" in element

I'm getting my bearing with i18next, but Trans is offering me riddles when I try to work with a link. Everything is working well with t{} so far (I'm working in React – JSX):
Here is the code that almost works (other approaches I tried didn't work at all):
<p className="button"><Trans i18nkey="home.p3" components={{ MyLink: <a href='beispiele.html'>link</a> }}/>{t('home.p3')}</p>
JSON:
de:
{
(…)
"home": {
(…)
"p3": "Durchstöbern Sie unsere <5>Beispiele</5>.",
(…)
}
}
en:
{
(…)
"home": {
(…)
"p3": "View <MyLink>samples</MyLink> of our work.",
(…)
}
}
and this is how I initialize i18next:
i18next
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
debug: true,
fallbackLng: 'de', // language to use
resources: {
en: {
translation: common_en // 'translation' is our custom namespace
},
de: {
translation: common_de
},
},
});
The resulting text displayed: undefinedView samples of our work.
I've looked at the i18next documentation on using Trans, also trying to use <1></1> and similar to encapsulate the link. Each time "undefined" is displayed. I've gone through this tutorial, where it worked. And have been mirroring it as closely as possible. The Transelement is not being grasped, although there are no error messages.
I'd appreciate any tips on how I can further troubleshoot this. Many thanks!
ETA:
thanks to Ahmet's eagle eye one mistake has been found. I'm not correcting it above, in case someone else runs into this problem: it should be i18nKey.
Further digging showed I have to place the JSON files in to the public folder to have the links work. For those looking into this: use i18next-http-backend in your init (i18n.use(Backend)) in your setup so you can reach the folder
There is a typo in your Trans component. You need to change the i18nkey prop to i18nKey.
You can take a look at this sandbox for a live working example.

Gatsby V4: How to implement gatsby-plugin-react-i18next for client only routes

I'm trying to implement client routes in Gatsby together with gatsby-plugin-react-i18next for two languages. I followed officel Gataby documentation and there is no client only path implementation explained.
Below is the code i implemeted.
gatsby-node.js
function langPrefix(page) {
return page.context.language === page.context.i18n.defaultLanguage &&
!page.context.i18n.generateDefaultLanguagePage
? ''
: `/${page.context.language}`
}
exports.onCreatePage = ({ page, actions }) => {
const { createPage } = actions
// Removing the ^ skips an optional /:lang prefix
if (page.path.match(/\/app/)) {
// adding lang if it's not the default page.
page.matchPath = `${langPrefix(page)}/app/*`
createPage(page)
}
}
Appjs
src/app/app.js
function App() {
return (
<>
<Router basepath="/:lang/app">
<PrivateRoute path="/accounthome" component={AccountHome} location=""/>
</Router>
<Router basepath="/app">
<PrivateRoute path="/accounthome" component={AccountHome} location=""/>
</Router>
</>)
}
export default App
Gatsby config
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
languages: ["en", "fr"],
defaultLanguage: `en-us`,
fallbackLanguage: `en-us`,
// if you are using Helmet, you must include siteUrl, and make sure you add http:https
siteUrl: `https://my.costco.com/`,
ns: langTranslationConfig,
// you can pass any i18next options
i18nextOptions: {
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
nsSeparator: false
},
pages: [
{
matchPath: '/:lang/app/accounthome',
getLanguageFromPath: true,
excludeLanguages: ['en-ca']
},
{
matchPath: '/preview',
languages: ['en']
}
]
}
}
Router path : http://localhost:8000/en-us/app/accounthome
When am accessing this rote in browser This code show Gatsby.js development 404 page not found. Any pointer what am missing and am not sure how to access the translation contents in client only route page example account home page. Do i need to write the graph query in account home page or i dont need to ?
I think your regex is leaking your code. I guess it should look like:
if (page.path.match(/^\/app/)) {
page.matchPath = `${langPrefix(page)}/app/*`
createPage(page)
}
Either way, check the created page list by accessing the 404 page in development mode. By default, there should be a list of all created pages. Check the paths there to see if you can spot any mistakes or trailing slash issues.
The problem here is that your page is not being generated properly, that's why it throws a 404, so checking the created pages may help you to spot the mistake or at least, a thread to pull.
After a few research I've seen that you are basing your approach in: Gatsby can't find client routes when using gatsby-plugin-react-i18next
In their case, the langPrefix function is only prefixing the language to the page slug if it's the default one:
function langPrefix(page) {
return page.context.language === page.context.i18n.defaultLanguage &&
!page.context.i18n.generateDefaultLanguagePage
? ''
: `/${page.context.language}`
}
In your case, I'm not sure the plugin supports en-us (it's en-US according to https://github.com/microapps/gatsby-plugin-react-i18next/issues/100) and I think that's the reason why there's a leak in your page creation. Try using en instead of en-us or directly looking for en-US paths.

Nextjs keep redirecting with double locale

We trying to redirect client if client's wish locale is not provided in the page.
So i added
redirect: !isPossibleLang
? {
destination: `/${locale}/main/${id}`,
statusCode: 301,
}
: undefined,
In the return of getStaticProps.
But next.js keep adding current language in the url.
like /ko/main/ID => /en/ko/main/ID
My next.config.js
module.exports = {
reactStrictMode: true,
i18n: {
locales: ['en', 'ko'],
defaultLocale: 'ko',
},
...
};
How to stop redirect with double locale ?
I advise you to include more code in the question, without giving readers undefined variables or without context. To help us better understand the problem and help you.
In my opinion you are passing unnecessarily the locale variable in the template string.
Maybe this is better like a comment but have no allow to comment yet.

lazy loading on i18n react questions

I am working in a project where we are using modules with lazy loading to separate it, now we would like to separate also the translations into the different modules, so only the translations that belogn to that module get loaded.
currently we have the translations as it follows:
translations
--en
--de
--it
--sp
we would like to have sth like this now:
translations
--en
|--moduleA
|--moduleB
|--moduleC
--it
|--moduleA
|--moduleB
|--moduleC
etc,
I have been throug the documentation and tried the 'useTranslation (hook)' and 'withTranslation', both dont seem to work since they load all the translations in the specified ns anyway and after take what is received when calling i18n, I also hada look at the i18next-http-backend but the documentation do not specify how to use it very clearly.
basically I am missing some information about how to use it, but as per my findings seems the only posible solution, am I wrong?.
after installing the dependancy I have my i18n as followns:
import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import moment from 'moment'
import HttpApi from 'i18next-http-backend'
import request from 'superagent'
import {EN} from './translations/eng'
import {test} from './translations/test'
i18n
.use(LanguageDetector)
.use(HttpApi)
.init({
backend: options,
resources: {
en: {
translations: EN,
translations2: test,
},
},
fallbackLng: 'en',
ns: ['translations', 'translations2'],
defaultNS: 'translations',
keySeparator: false,
interpolation: {
escapeValue: false,
formatSeparator: ',',
format: function(value, formatting) {
if (value instanceof Date) return moment(value).format(formatting)
return value.toString()
},
},
react: {
wait: true,
},
})
the backend key is expecting some options information:
const options = {
loadPath: 'path to file',
addPath: 'path to file',
allowMultiLoading: false,
parse: function(data) {
return data.replace(/a/g, '')
},
parsePayload: function(namespace, key, fallbackValue) {
return {key}
},
request: function(options, url, payload, callback) {},
}
But I am not really sure about the way how to use it,I wanted to know if someone has experience with this and if someone can recomend any guide or documentation that might help me.
thanks
I think you may be looking for Namespaces:
Namespaces are a feature in i18next internationalization framework which allows you to separate translations that get loaded into multiple files.
While in a smaller project it might be reasonable to just put everything in one file you might get at a point where you want to break translations into multiple files. Reasons might be:
You start losing the overview having more than 300 segments in a file
Not every translation needs to be loaded on the first page, speed up load time

React i18next Backend-Path different in local and production environment

I'm using a react app with react-i18next and loading the translation with i18next-xhr-backend
i18n
.use(Backend)
.use(initReactI18next) // passes i18n down to react-i18next
.init({
lng: "de",
backend: {
loadPath: '/static/locales/{{lng}}/{{ns}}.json'
}
});
If I run it locally my app is served over http://localhost:3000/
and the translation file is also loading nicely (src is located in public/statuc/locales/ ) http://localhost:3000/static/locales/de/translation.json
I'm now facing the issue that in production the app is not served from root, instead the builded files are served over a subfolder. Because of that I changed my packages.json and added homepage
{
"name": "myapp",
"version": "0.1.0",
"homepage": "/static/app/",
...
}
After building the application and deploying it on prod, it still loads correctly, but the translation files are not found.
http://production.tld/static/app/index.html
react app files are loaded correctly http://production.tld/static/app/static/js/main*.js
but the translation file is still fetched by http://production.tld/static/locales/de/translation.json which is not available anymore (instead http://production.tld/static/app/static/locales/de/translation.json would be correct)
I could fix it by changing the i18n config
backend: {
loadPath: '/static/app/static(locales/{{lng}}/{{ns}}.json'
}
then it works in production, but not locally anymore :-/
I'm not sure how to avoid this situation ?
You can pass loadPath as function.
backend: {
loadPath: () => {
// check the domain
const host = window.location.host;
return (host === 'production.ltd' ? '/static/app':'') + '/static/app/static/locales/{{lng}}/{{ns}}.json';
},
},
Another solution would be to work with environment variables. Only the condition would be different and without a function, the idea is like #felixmosh's solution.
An example with create-react-app, here you can use the environment variable 'NODE_ENV' for the condition.
i18n.use(XHR)
.use(initReactI18next)
.init({
backend: {
loadPath:
process.env.NODE_ENV !== "production"
? `./locales/{{lng}}/{{ns}}.json`
: ` /static/app/static/locales/{{lng}}/{{ns}}.json`,
},
lng: "de",
fallbackLng: "de",
load: "languageOnly",
debug: true,
react: {
transSupportBasicHtmlNodes: true,
transKeepBasicHtmlNodesFor: ["br", "strong", "i", "sub", "sup", "li"],
},
});
Here the documentation of create-react-app
https://create-react-app.dev/docs/adding-custom-environment-variables
Here's a follow-along question that may deserve its own top-level question:
it appears that if your locales directories have dashes in the name (e.g. locales/en-us/translation.json), then things don't work. How are we supposed to get around that? I stumbled on this answer because I thought perhaps I could do something along the lines of:
loadPath: (lng, ns) => { return `/locales/{{lng.replace(/-/g,'')/{{ns}}.json` }
But during my initial testing, that didn't work.

Resources