Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use with nextjs not watching changes in json files on development #92

Closed
bryanltobing opened this issue Jul 19, 2022 · 16 comments
Closed
Labels

Comments

@bryanltobing
Copy link

bryanltobing commented Jul 19, 2022

🐛 Bug Report

I want to watch changes in the translation JSON files like reloadOnPrerender in next-18next does https://github.com/i18next/next-i18next#reloading-resources-in-development

But every time I make changes to JSON files it doesn't read the changes automatically. In order for the changes to be applied,
I need to:

  • shut down my development server
  • clear localStorage
    (if I didn't clear localStorage I will get a hydration error)
    Error: Text content does not match server-rendered HTML.
    See more info here: https://nextjs.org/docs/messages/react-hydration-error
  • run my dev server again, and it is really a hassle.

To Reproduce

I am following example from i18next-http-backend with nextjs https://github.com/i18next/i18next-http-backend/tree/master/example/next

this is my configuration

const path = require("path");
const HttpBackend = require("i18next-http-backend/cjs");
const ChainedBackend = require("i18next-chained-backend").default;
const LocalStorageBackend = require("i18next-localstorage-backend").default;

module.exports = {
  backend: {
    backendOptions: [{ expirationTime: 60 * 60 * 1000 }, {}], // 1 hour
    backends:
      typeof window !== "undefined" ? [LocalStorageBackend, HttpBackend] : [],
  },
  i18n: {
    defaultLocale: "en",
    locales: ["en", "id"],
    reloadOnPrerender: process.env.NODE_ENV === "development",
    localePath: path.resolve("./public/locales"),
  },
  serializeConfig: false,
  use: typeof window !== "undefined" ? [ChainedBackend] : [],
  react: {
    useSuspense: true,
  },
};

Expected behavior

Every time I make changes to JSON files and refresh the page the changes will apply, (check at runtime)
similar to reloadOnPrerender in next-i18next when using serverSideTranslations

Your Environment

  • runtime version: i.e. node v16.13.2
  • i18next version
"i18next-chained-backend": "^3.0.2",
"i18next-http-backend": "^1.4.1",
"i18next-localstorage-backend": "^3.1.3",
"next-i18next": "^11.0.0",
  • os: Windows
  • react, next version:
"next-i18next": "^11.0.0",
"next": "^12.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"

I also created a discussion in next-i18next i18next/next-i18next#1914

@adrai
Copy link
Member

adrai commented Jul 19, 2022

A couple of inputs:


Regarding localstorage during dev... you could change your config with something like:

const HttpBackend = require('i18next-http-backend/cjs')
const ChainedBackend= require('i18next-chained-backend').default
const LocalStorageBackend = require('i18next-localstorage-backend').default

const isBrowser = typeof window !== 'undefined'
const isDev = process.env.NODE_ENV === 'development'

module.exports = {
  debug: isDev,
  backend: isDev ? {} : {
    backendOptions: [{ expirationTime: 60 * 60 * 1000 }, {}], // 1 hour
    backends: isBrowser ? [LocalStorageBackend, HttpBackend]: [],
  },
  // react: { // used only for the lazy reload
  //   bindI18n: 'languageChanged loaded',
  //   useSuspense: false
  // },
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'de'],
  },
  serializeConfig: false,
  use: isBrowser ? [isDev ? HttpBackend : ChainedBackend] : [],
}

Regarding hot reload, you may check out i18next-hmr, I never used it in combination with next.js, maybe @felixmosh can help?


Regarding the hydration warning:

If client render and server renders outputs different html this may occur: #91

There's an alternative usage, you can try:
https://locize.com/blog/next-i18next/#alternative-usage
https://github.com/i18next/i18next-http-backend/tree/master/example/next#alternative-usage

@bryanltobing
Copy link
Author

bryanltobing commented Jul 19, 2022

Thank you for the response @adrai

@adrai
Copy link
Member

adrai commented Jul 19, 2022

So basically in the development, we are not saving the translation to the localStorage to prevent such errors?

yes

I haven't checked i18next-hmr yet. but is this really something that is not supported by default?

no

I have checked the alternative usage, but it doesn't apply to my case at all. because it still requires the use of getStaticProps. The reason I use the client-side translation for all my next.js pages in the first place is to prevent the use of serverSideTranslation

then you have to live with that warning, sorry (that's the nature of it)

@bryanltobing
Copy link
Author

bryanltobing commented Jul 19, 2022

Not sure if this is the right place to ask or related to this. But I'm curious how did you guys handle dynamic routes using next-i18next then, if in the case that we can't prefetch all our dynamic paths in getStaticPaths. I think this is common cases.

for example, if we have a page to list all users /users/[id].tsx, if we want to use serverSideTranslations we need to use getStaticProps, and because it is dynamic page we need to use getStaticPaths as well to list our ids, and locales.

if we fetch all user's ids from the backend I think it would be a very expensive request to make at build time, for example, if we have millions ids of users.

And also become a hassle to add fetch for every features users, transactions, orders, carts, etc

This has been asked many times. but there's no proper explanation for this I think for such common cases.
Instead of answering with a solution, people just provide a hack

This is why I switch to full client-side translation using next-i18next and i18next-http-backend

@adrai
Copy link
Member

adrai commented Jul 19, 2022

Sorry, but I've not such a use case like you describe. Mostly static stuff...
Also I'm relatively new to next.js i18next/next-i18next#1897
So, if you know of a way for an alternative approach, feel free to contribute to next-i18next with a PR.

@felixmosh
Copy link
Contributor

Regarding hot reload, you may check out i18next-hmr, example folder which contains an example setup for popular frameworks.

It works perfectly with next.js on a daily basis :]

@bryanltobing
Copy link
Author

bryanltobing commented Jul 19, 2022

Actually what I need here is not a hot reload. I just want the changes made to be applied at runtime (browser refresh) without the need to restart the server reloadOnPrerender does. not when saving files which I believe is what hmr does.

The browser is actually able to read the changes and apply them in page refresh, but I got this error when refreshing the page, and there's flickering between the old translation to the new translation

old translation

// common.json
{
  "button": {
     "register": "Register"
  }
}

new translation

// common.json
{
  "button": {
     "register": "Register Here"
  }
}
repro-i18next.mp4
next-dev.js?3515:24 Warning: Text content did not match. Server: "Register" Client: "Register Here"
    at button
    at eval 

when I restart the dev server it works fine.

I presume this is again because of the hydration things since I only use client-side translation.

@adrai
Copy link
Member

adrai commented Jul 19, 2022

I suspect you need to move the reloadOnPrerender option out of the i18n option in your config

i18n: {
    defaultLocale: "en",
    locales: ["en", "id"],
-    reloadOnPrerender: process.env.NODE_ENV === "development",
    localePath: path.resolve("./public/locales"),
  },
+reloadOnPrerender: process.env.NODE_ENV === "development",

@felixmosh
Copy link
Contributor

This is exactly the problem that i18next-hmr solves, when the translations are change, your browser (& server) will reflect the new translation (without reloading dev server or the browser state).

https://user-images.githubusercontent.com/9304194/71188474-b1f97100-2289-11ea-9363-257f8a2124b1.gif

@bryanltobing
Copy link
Author

I suspect you need to move the reloadOnPrerender option out of the i18n option in your config

i18n: {
    defaultLocale: "en",
    locales: ["en", "id"],
-    reloadOnPrerender: process.env.NODE_ENV === "development",
    localePath: path.resolve("./public/locales"),
  },
+reloadOnPrerender: process.env.NODE_ENV === "development",

I have always used it inside i18n obj and it still works in my static site, just tried to move it out, and still works. both work in my static site.

But in my case here for client-side translation, neither work

My current updated i18n configuration next-i18next.config.js

const path = require("path");
const HttpBackend = require("i18next-http-backend/cjs");
const ChainedBackend = require("i18next-chained-backend").default;
const LocalStorageBackend = require("i18next-localstorage-backend").default;

const isDev = process.env.NODE_ENV === "development";
const isBrowser = typeof window !== "undefined";

module.exports = {
  backend: isDev
    ? {}
    : {
        backendOptions: [{ expirationTime: 60 * 60 * 1000 }, {}], // 1 hour
        backends: isBrowser ? [LocalStorageBackend, HttpBackend] : [],
      },
  i18n: {
    defaultLocale: "en",
    locales: ["en", "id"],
    localePath: path.resolve("./public/locales"),
  },
  serializeConfig: false,
  use: isBrowser ? [isDev ? HttpBackend : ChainedBackend] : [],
  react: {
    useSuspense: true,
  },
  reloadOnPrerender: process.env.NODE_ENV === "development",
};

@bryanltobing
Copy link
Author

This is exactly the problem that i18next-hmr solves, when the translations are change, your browser (& server) will reflect the new translation (without reloading dev server or the browser state).

Question. Why is the example here https://github.com/felixmosh/i18next-hmr/blob/master/examples/next-with-next-i18next/pages/second-page.js using getInitialProps, is it just to prove that It works in client and server? or it's required? and not using useTranslation hooks and passing t in page props instead?

@felixmosh
Copy link
Contributor

Why is the example here

getInitialProps is not mandatory, for client side HMR you will need i18next-http-backend (this lib), it works with Webpack's HMR mechanisem.

@bryanltobing
Copy link
Author

getInitialProps is not mandatory, for client side HMR you will need i18next-http-backend (this lib), it works with Webpack's HMR mechanism.

I see that the example uses the very old version of next-i18next. is there any example using the current version ? i try to upgrade to the latest version and there are some breaking changes like next-i18next API that is not exported anymore

@felixmosh
Copy link
Contributor

felixmosh commented Jul 19, 2022

Check the new example of the latest next-i18next

@felixmosh
Copy link
Contributor

If you have any issue, I will be more than happy to help you, just open an issue on the i18next-hmr repo :]

@stale
Copy link

stale bot commented Aug 13, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Aug 13, 2022
@stale stale bot closed this as completed Sep 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants