dayjs
dayjs copied to clipboard
Setting the locale in the server context (SSR) does not work in production build
We have a very simple code that works perfectly on client side, but fails on the server side on a production build. This does not happen when using the dev server though.
Code
export default defineNuxtRouteMiddleware(() => {
const { locale } = useNuxtApp().$i18n;
const dayjs = useDayjs();
if (locale.value !== dayjs.locale()) {
console.log("Setting dayjs locale to", locale.value);
dayjs.locale(locale.value);
console.log("Dayjs locale is now set to", dayjs.locale());
}
});
Output
Setting dayjs locale to de
Dayjs locale is now set to en
Here I'd expect the server to put out "de" twice, but setting the locale simply does nothing.
Config
locales: i18nConfig.locales,
plugins: ["localeData", "localizedFormat", "utc", "customParseFormat"],
defaultLocale: 'en',
does the console say anything about hydration miss match issues? also i wouldn't full trust the dev server without giving it a build first 😅
Like I said it's not happening in the dev server but only in the production build. I can see the backend content being rendered in the page source in the English locale, but being overridden on the client once hydration happens.
But client side and hydration are not important here, I can't get the server to render any non-en locale dates when using the built prod server version. I can't even get it so switch to a different locale, as reading after setting the locale immediately returns the default locale again. In the dev server and client side, this works without any issues 🙏
Same issue
Same issue, different locales between SSR and Client, hydration issue.
Same issue
Any news on this ? Thank you.
Seems to be an issue i'm having also on a side project i'm building, https://huishistorie.nl/amersfoort/3822cg/bombardonstraat/132
As soon as i change stuff like this:
{{ $dayjs(homeDataStore.homeData.energy.expiry_date).format("D MMMM YYYY") }}
To:
{{ homeDataStore.homeData.energy.expiry_date }}
From the template my hydration error on the frontend disappears. Haven't seen it in dev builds as mentioned above by @PatrickBauer
Same issue, but in dev mode too. In ssr dayjs defaults to "en" locale even when explicitly set to another.
I can confirm this issue... very annoying and resulting in "Hydration completed but contains mismatches." errors in console in production builds!
Same issue with defaultTimezone. SSR does not use it (maybe and client ). In ssr dayjs using server timezone and after that I see hydration error because I have another timezone
(Updated) I created a plugin.
export default defineNuxtPlugin({
name: "locale",
hooks: {
"app:created": () => {
const nuxtApp = useNuxtApp();
const dayjs = nuxtApp.$dayjs;
const i18n = nuxtApp.$i18n;
dayjs.locale(i18n.locale.value);
},
"i18n:beforeLocaleSwitch": ({ newLocale }) => {
const nuxtApp = useNuxtApp();
const dayjs = nuxtApp.$dayjs;
dayjs.locale(newLocale);
},
},
});
Both the server and the client are configured correctly. However, it didn't work with the "i18n:localeSwitched" hook, which might be an issue with the dayjs plugin.
"@nuxtjs/i18n": "^9.1.0",
"dayjs": "^1.11.13",
"dayjs-nuxt": "^2.1.11"
Got here because I have the same issue.
"dayjs-nuxt": "^2.1.11",
The core issue is that all locales except "en" do not exist when called during SSR, despite being set in the configuration files. My temporary solution involves extracting locale configurations directly from the Day.js source, storing them in separate files within my application, and passing them as arguments to dayjs.locale(). Once the page finishes loading, I swap these temporary locales with the actual ones.
This approach does have potential discrepancies if locales are updated or dayjs configurations change significantly. However, as long as you stick to the same Day.js version, this method works reliably. To avoid conflicts with standard locales, name the temporary locales distinctly, such as frSSR instead of just fr.
To make locale config available dayjs requires import with side-effects (like import 'dayjs/locale/ru.js'). After that dayjs.Ls.ru with locale config becomes available.
It seems that imports without binding to a variable are lost on nuxt build.
Current workaround for my case:
./composables/dayjs.ts:
import dayjs from 'dayjs'
import locale from 'dayjs/locale/ru'
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)
dayjs.locale('ru', locale)
export function useDayjs()
{
return dayjs
}
To use:
const dayjs = useDayjs()
Thank you @Trash0101 and @dpetrouk for sharing your solutions.
For anyone having an internationalized site, I'd suggest creating an i18n plugin and adding the workaround like this:
import locale_hu from 'dayjs/locale/hu';
import locale_en from 'dayjs/locale/en';
export default defineNuxtPlugin((nuxtApp) => {
const localeFiles = {
hu: locale_hu,
en: locale_en,
};
nuxtApp.hook('app:created', () => {
nuxtApp.$dayjs.locale(nuxtApp.$i18n.locale.value, localeFiles[nuxtApp.$i18n.locale.value]);
});
nuxtApp.hook('i18n:beforeLocaleSwitch', ({ oldLocale, newLocale, initialSetup, context }) => {});
nuxtApp.hook('i18n:localeSwitched', ({ oldLocale, newLocale }) => {
nuxtApp.$dayjs.locale(newLocale);
// change locale of other dependencies
});
});
"dayjs-nuxt": "^2.1.11",
@acidjazz could this be included in the module?
Same issue
"dayjs-nuxt": "^2.1.11",
export default defineNuxtPlugin(({ hook }) => {
const locales = {
en: () => import('dayjs/locale/en'),
ru: () => import('dayjs/locale/ru'),
ky: () => import('dayjs/locale/ky'),
};
const { $i18n, $dayjs } = useNuxtApp();
hook('app:created', async () => {
const localeModule = await locales[$i18n.locale.value || 'en']();
$dayjs.locale(
$i18n.locale.value,
localeModule.default,
);
});
});
Can confirm this error: in SSR the language is always "en", even in development mode, causing hydration issues. Using @aloky plugin works!