Closed mehmetnyarar closed 5 years ago
i think it can be fix by adding the preload key to the options object
module.exports = new NextI18Next({
preload: ['fr'],
otherLanguages: ['fr','en', 'es'],
browserLanguageDetection: true,
fallbackLng: 'fr',
debug: true
})
@oteka21 Please see the source.
Same issue here with latest versions. Site seems to render with:
lng: 'en',
as @truongtx9 proposed above. What's this ? Is this a bug or a non documented feature ?
@rdewolff As stated previously, that will break language detection.
Facing the same issue, there is a way to solve this without breaking the language detection?
+1
there is a way to solve this without breaking the language detection?
Yes, either await the promise returned by the i18next init
call, or use the callback.
@isaachinman
Yes, either await the promise returned by the i18next init call, or use the callback.
so do you know a solution or what is the state here? How can I help?
@StarpTech The working assumption is that it's a race condition on startup. The only way we can arrive at a non-breaking-change solution is if we can find a way to initialise an i18next instance synchronously.
If that helps, let me describe my solution to the problem.
In my case I've seen such errors when there were requests to non existing URLS(404) on /static/
.
And here's the logic:
next-i18next/middleware
next-i18next/middleware
adds another middleware i18next-express-middleware
i18next-express-middleware
checks ignoreRoutes option/static/
is ignored, so i18next-express-middleware
is not running at all - it just calls next()
function argument, so express.js server continuesi18next-express-middleware
didn't provide anything because /static/
is ignored route.So here is solution in my case - change ignoreRoutes to empty array:
const NextI18Next = require('next-i18next').default;
const { localeSubpaths } = require('next/config').default().publicRuntimeConfig;
const localeSubpathVariations = {
none: {},
foreign: {
fr: 'fr',
en: 'en',
},
all: {
en: 'en',
fr: 'fr',
},
};
module.exports = new NextI18Next({
defaultLanguage: 'ru',
otherLanguages: ['fr', 'en'],
localeSubpaths: localeSubpathVariations[localeSubpaths],
debug: true,
// initImmediate: true,
// load: 'all',
ignoreRoutes: [],
});
@isaachinman not sure if there's any race condition in i18next-express-middleware
(cuz there's no async and loadLanguages calls next()
only on callback), but please check my solution if it closes this issue
Setting ignoreRoutes
to an empty array is not a solution. That config option is there for a reason. For any users that use localeSubpaths
, their static
and _next
traffic would be erroneously redirected, breaking the entire app.
For anyone wishing to help on this issue: please take a deep dive before bumping or offering suggestions!
@isaachinman Not sure if it is of any help, but for me the problem seems to occur when I'm having a custom route, e.g.:
custom route:
router.get('/password-renew/:passwordResetSlug', helmet.noCache(), (req, res) => {
const actualPage = '/password-renew';
const queryParams = { ...req.query, passwordResetSlug: req.params.passwordResetSlug }
return app.render(req, res, actualPage, queryParams);
})
page:
class RenewPasswordPage extends Component {
static async getInitialProps(ctx) {
const namespacesRequired = ['public']
const passwordResetSlug = ctx.query.passwordResetSlug
return { namespacesRequired, passwordResetSlug }
}
render() {
// ...
}
}
export default withTranslation('public')(RenewPasswordPage)
Not sure if I'm helping but I caught this error from my side too and I temporary fix it by adding languages propriety to i18n object.
const languages = ['fr-FR', 'en-GB'];
const options = {
defaultLanguage: 'fr-FR',
otherLanguages: ['en-GB'],
...
};
const NextI18NextInstance = new NextI18Next(options);
NextI18NextInstance.i18n.languages = languages;
module.exports = NextI18NextInstance;
Using @jonathangiamp worked after adding the fallbackLng
config property.
Correct me if I'm wrong but if the root issue is really the way how we bootstrap i18n then we should release a breaking change to fix that correctly.
@StarpTech If and when it is determined that we cannot initialise an i18next instance synchronously, then yes, we'd need to release a breaking change.
This is a very good example of a use case where we definitely want to init an instance synchronously, as our application cannot serve any requests until it's ready.
@jamuhl Any ideas about what we might be doing wrong here? Any opinion about construction/initialisation? Funny that this issue has become so popular.
@isaachinman please add "bug" label
@isaachinman would be happy to help with this...but I do not get the issue
but why is that a problem in production...a server starts up and things will be ready on first request...or even delay start of server and start it inside the init callback...
for serverless add a middleware that asserts init is done before calling next should do the trick (just use the initialized event and flag on i18next.)
Looks like this might happen more often when you have a custom _error that uses t() or the hoc. Next will compile a _error page with no req, thus no i18n object that has the correct lang detected. I removed the custom _error in another project I’m working on and I have not seen the warning again.
Finally took some time to dig into this. The issue of awaiting the initialisation of the i18next instance is a very trivial one, and I can provide an easy, non-breaking way for users to do that if they want to. However, I think that that race condition is causing a very low percentage of the error reports we are seeing here.
The main problem is indeed with 404s, primarily in development. This is because a browser makes a request for a dev resource which used to exist, but now has been cleared by HMR. Eg:
http://localhost:3000/_next/static/webpack/f15dd305991bb90f87e1.hot-update.json
This request goes through the next-i18next
middleware first, and as far as we are concerned, this is a request for a static resource and has a statusCode
of 200 (has not been modified yet). The default behaviour here is to exclude static resources from i18next-express-middleware
, thus req.i18n
shouldn't exist on this request.
The request then gets passed to NextJs:
const handle = app.getRequestHandler()
server.get('*', (req, res) => handle(req, res))
At this point the request is determined to be a 404, and the status code is changed. At that point in time, NextJs wants to render an error page, but does so without a redirect (naturally), so the next-i18next
middleware never gets called again, and we do not have a chance to populate the i18n instance.
That NextJs logic can be found here.
(It's noteworthy that this code path is different than "normal", non-resource, 404s which next-i18next
handles just fine.)
The curious part is how react-i18next
ever gets to the point of calling hasLoadedNamespace
, as i18n.isInitialized
is a precondition of that call, and i18n
shouldn't exist on that req
at all. Still not sure about this, but it's relatively unimportant.
In general this is a bit of a chicken-and-egg problem to solve. The easy thing to do is to remove the passing of ignoreRoutes
to i18next-express-middleware
, seen here.
The actual redirect logic is protected by isI18nRoute
which uses the exact same
ignoreRoutes
array, so we actually don't have to worry about static resources being redirected when users have enabled localeSubpaths
.
However, this solution would mean that we are processing all our static resource requests through the i18next middleware, just on the off chance that one of them results in a 404. Perhaps this is actually the right thing to do? No idea if this has perf implications, but it probably does.
On a side note, I have no idea why the NextJs team have decided to return an HTML doc for a 404 on a JSON resource - that doesn't seem right to me. Not sure if that's configurable.
Apologies for a long post, but that's the entire story. We have all the information necessary to work on this, it's just a matter of discussing amongst ourselves what makes the most sense.
Thanks to OP and @isaachinman for taking time to check this issue.
Finally took some time to dig into this. The issue of awaiting the initialisation of the i18next instance is a very trivial one, and I can provide an easy, non-breaking way for users to do that if they want to. However, I think that that race condition is causing a very low percentage of the error reports we are seeing here.
What would be the quick-fix?
Thanks
There is no "quick-fix" in user land, it needs to happen within the source code.
I get this problem when I use public/static
path instead of static/locales
. Removing public folder and setting up localePath
to default value fixes the problem
My locales folder:
.
└── public
└── static
└── locales
├── ru
| └── common.json
└── kk
└── common.json
Instance:
const NextI18NextInstance = new NextI18Next({
localePath: 'public/static/locales',
preload: ['ru'],
defaultLanguage: 'ru',
otherLanguages: ['kk'],
localeSubpaths: {
ru: 'ru',
kk: 'kk'
}
});
@GraxMonzo
localePath: typeof window === 'undefined' ? 'public/static/locales' : 'static/locales'
Describe the bug
I get the the following error:
which appears only on the server (I mean in the output of the terminal, it doesn’t appear on the browser console).
Occurs in next-i18next version
"next": "^8.1.0", "i18next": "^17.0.6", "next-i18next": "^0.44.0",
Steps to reproduce
I followed every step described in the readme except
keySeparator
(because I have keys likeStatus.ONGOING
)Below is my configuration:
Expected behaviour
This doesn’t look like a critical error, though I’m wondering the cause.
Screenshots
OS (please complete the following information)
Additional context