dayjs icon indicating copy to clipboard operation
dayjs copied to clipboard

Setting the locale in the server context (SSR) does not work in production build

Open PatrickBauer opened this issue 1 year ago • 19 comments

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',

PatrickBauer avatar Jul 31 '24 15:07 PatrickBauer

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 😅

tcampbPPU avatar Jul 31 '24 19:07 tcampbPPU

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 🙏

PatrickBauer avatar Jul 31 '24 19:07 PatrickBauer

Same issue

The73756 avatar Aug 06 '24 05:08 The73756

Same issue, different locales between SSR and Client, hydration issue.

batjeciftci avatar Aug 18 '24 17:08 batjeciftci

Same issue

bell-101 avatar Sep 10 '24 13:09 bell-101

Any news on this ? Thank you.

cfab avatar Oct 14 '24 10:10 cfab

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

ReindDooyeweerd avatar Oct 24 '24 21:10 ReindDooyeweerd

Same issue, but in dev mode too. In ssr dayjs defaults to "en" locale even when explicitly set to another.

Trash0101 avatar Oct 30 '24 15:10 Trash0101

I can confirm this issue... very annoying and resulting in "Hydration completed but contains mismatches." errors in console in production builds!

simonmaass avatar Nov 13 '24 15:11 simonmaass

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

kofeinstyle avatar Nov 23 '24 16:11 kofeinstyle

(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"

gokhantaskan avatar Nov 29 '24 14:11 gokhantaskan

Got here because I have the same issue.

"dayjs-nuxt": "^2.1.11",

dpetrouk avatar Dec 05 '24 11:12 dpetrouk

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.

Trash0101 avatar Dec 05 '24 14:12 Trash0101

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()

dpetrouk avatar Dec 05 '24 15:12 dpetrouk

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",

Szlavicsek avatar Dec 09 '24 09:12 Szlavicsek

@acidjazz could this be included in the module?

simonmaass avatar Jan 27 '25 15:01 simonmaass

Same issue

waitstop avatar Jan 31 '25 08:01 waitstop

"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,
    );
  });
});

aloky avatar Jul 09 '25 12:07 aloky

Can confirm this error: in SSR the language is always "en", even in development mode, causing hydration issues. Using @aloky plugin works!

diogoterremoto avatar Jul 23 '25 17:07 diogoterremoto