Next.js Discord

Discord Forum

Error: Cannot find module './undefined.json'

Answered
Sun bear posted this in #help-forum
Open in Discord
Sun bearOP
According to the documentation (highlighted in the screenshot) I need to wrap my navbar with a wrapper but in their example of using next-intl they don't seem to be doing that (or maybe I've missed it).

Documentation source: https://next-intl-docs.vercel.app/docs/environments/server-client-components#missing-context

This seems a bit weird, I don't feel comfortable wrapping all my client components in wrappers just because I want to use translation inside them, because that adds alot of extra components to my project and it makes the workflow more complex.

Surely there has to be a better way.

Here is my code for my navigation bar:

// components/top-navigation-bar/top-navigation-bar.tsx

'use client';
import React from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import LanguageSelector from './language-selector';
import UserProfileButton from './user-profile-button';
import { useTranslations } from 'next-intl';
import HomeButton from './home-button';
import { unstable_setRequestLocale } from 'next-intl/server';

interface TopNavigationBarProps {
  lang: string;
}

const TopNavigationBar: React.FC<TopNavigationBarProps> = ({ lang }) => {
  const pathname = usePathname();
  const locale = pathname ? pathname.split('/')[1] : '';
  const t = useTranslations('navigation');

  // Set the request locale for proper translation
  unstable_setRequestLocale(locale);

  const baseTextStyle = {
    fontSize: '18px',
    fontWeight: '300',
    cursor: 'pointer',
    display: 'flex',
    alignItems: 'center',
    transition: 'color 0.2s ease-in-out',
  };
  const logoTextStyle = { ...baseTextStyle, marginLeft: '6px' };
  const buttonStyle = { ...baseTextStyle, marginLeft: '24px' };

  return (
//ui
  );
};

export default TopNavigationBar;

Let me know if you need more details please.
Answered by Ray
do you have liveshare
View full answer

127 Replies

Britannia Petite
depending on your needs, do you prefer full server side ? or client side ? if you want to use hooks to access translations inside client components you will need to provide the context
bear in mind that using the client hooks (and context provider) will increase the initial build size load by your user
you can still prop drill from server component to client component without using providers and client side lib
@Britannia Petite depending on your needs, do you prefer full server side ? or client side ? if you want to use hooks to access translations inside client components you will need to provide the context
Sun bearOP
I work with both server and client components, most of my components are client components, with the caveat being that I try keeping the actual pages on which those client components are used SSR. This is a pattern that can be seen across my project, it's not an isolated situation.

Basically, I try keeping things SSR as much as possible. What's the recommended way of doing it in this case ?
Sun bearOP
I have managed to solve that error, but got hit with another similar error and this one I can't seem to figure out what causes it
It complains about the path but I've tried 2 other paths with the help of the LLMs and still got the same error.
And here is my file structure
@Sun bear I have managed to solve that error, but got hit with another similar error and this one I can't seem to figure out what causes it
could you try this and see if it works?
const messages = await import("../../messages/en.json");
Sun bearOP
Holy, I was actually hopping for you to jump in and it happened. Universe has replied to me.
@Ray could you try this and see if it works? `const messages = await import("../../messages/en.json");`
Sun bearOP
This is the result Ray
@Sun bear This is the result Ray
you can't use that function in client component
Sun bearOP
// components/top-navigation-bar/top-navigation-bar.tsx

'use client';
import React from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import LanguageSelector from './language-selector';
import UserProfileButton from './user-profile-button';
import { useTranslations } from 'next-intl';
import HomeButton from './home-button';
import { unstable_setRequestLocale } from 'next-intl/server';

interface TopNavigationBarProps {
  lang: string;
}

const TopNavigationBar: React.FC<TopNavigationBarProps> = ({ lang }) => {
  const pathname = usePathname();
  const locale = pathname ? pathname.split('/')[1] : '';
  const t = useTranslations('navigation');

  // Set the request locale for proper translation
  unstable_setRequestLocale(locale);

  const baseTextStyle = {
    fontSize: '18px',
    fontWeight: '300',
    cursor: 'pointer',
    display: 'flex',
    alignItems: 'center',
    transition: 'color 0.2s ease-in-out',
  };
  const logoTextStyle = { ...baseTextStyle, marginLeft: '6px' };
  const buttonStyle = { ...baseTextStyle, marginLeft: '24px' };
@Ray you can't use that function in client component
Sun bearOP
Then how I can translate the stuff inside it ?
@Sun bear Then how I can translate the stuff inside it ?
from their doc, I think you should use it on layout or page?
Sun bearOP
Oh, so only in the layout page ?
yeah try using it on app/[locale]/layout.tsx
Sun bearOP
Okay, let me try that, thank you very much. This is a miracle, I can't believe you actually showed up. I actually wanted to say "man if only Ray was here this would be solved by now" and you actually showed up. So surreal.
Like that's what I was thinking like 20 minutes ago lol
@Sun bear Okay, let me try that, thank you very much. This is a miracle, I can't believe you actually showed up. I actually wanted to say "man if only Ray was here this would be solved by now" and you actually showed up. So surreal.
and change
const messages = await import("../../messages/${locale}.json")

to
import fs from 'fs/promises'

  const messages = await fs
    .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8")
    .then(JSON.parse);
because import doesn't work with dynamic variable
so use fs.readFile instead but you have to use it on server
btw, do you really need to read the json yourself?
I think next-intl does it for you?
@Ray btw, do you really need to read the json yourself?
Sun bearOP
Hmm I don't know
If it does that automatically I guess I don't
I'm not familiar with how it works, I have never used it before 😄
where do you use the messages?
I think you just need to call unstable_setRequestLocale on the layout and it will do the work for you
@Ray I think you just need to call `unstable_setRequestLocale` on the layout and it will do the work for you
Sun bearOP
// src/app/[locale]/layout.tsx

import '../globals.css';
import { ThemeProvider } from "@/components/theme-provider";
import { PropsWithChildren } from 'react';
import { SvgGradients } from '@/components/svg-gradient';
import fontVariables from '@/components/fonts';
import { createClient } from '@/utilities/supabase/server';
import SessionProvider from '@/components/providers';
import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar';
import { NextIntlClientProvider } from 'next-intl';
import fs from 'fs/promises';

const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com";

export const metadata = {
  metadataBase: new URL(defaultUrl),
  title: 'Next.js and Supabase Starter Kit',
  description: 'The fastest way to build apps with Next.js and Supabase',
};

export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) {
  const supabase = createClient();
  const { data: { session } } = await supabase.auth.getSession();

  const messages = await fs
    .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8")
    .then(JSON.parse);

  return (
    <html lang={locale} className={fontVariables} suppressHydrationWarning>
      <body className="font-roboto h-[100svh]">
        <SessionProvider session={session}>
          <SvgGradients />
          <NextIntlClientProvider locale={locale} messages={messages}>
            <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
              <main className="flex flex-col flex-grow items-center h-full">
                <TopNavigationBar lang={locale} />
                {children}
              </main>
            </ThemeProvider>
          </NextIntlClientProvider>
        </SessionProvider>
      </body>
    </html>
  );
}

export function generateStaticParams() {
  return ['en', 'ro'].map((locale) => ({ lang: locale }));
}

Like this ?
@Ray where do you use the messages?
Sun bearOP
I don't understand this question. As far as I'm aware the messages is just basically the dictionary used for storing the translations, the translations will be used almost everywhere across the website.
@Sun bear js // src/app/[locale]/layout.tsx import '../globals.css'; import { ThemeProvider } from "@/components/theme-provider"; import { PropsWithChildren } from 'react'; import { SvgGradients } from '@/components/svg-gradient'; import fontVariables from '@/components/fonts'; import { createClient } from '@/utilities/supabase/server'; import SessionProvider from '@/components/providers'; import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar'; import { NextIntlClientProvider } from 'next-intl'; import fs from 'fs/promises'; const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com"; export const metadata = { metadataBase: new URL(defaultUrl), title: 'Next.js and Supabase Starter Kit', description: 'The fastest way to build apps with Next.js and Supabase', }; export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) { const supabase = createClient(); const { data: { session } } = await supabase.auth.getSession(); const messages = await fs .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8") .then(JSON.parse); return ( <html lang={locale} className={fontVariables} suppressHydrationWarning> <body className="font-roboto h-[100svh]"> <SessionProvider session={session}> <SvgGradients /> <NextIntlClientProvider locale={locale} messages={messages}> <ThemeProvider attribute="class" defaultTheme="system" enableSystem> <main className="flex flex-col flex-grow items-center h-full"> <TopNavigationBar lang={locale} /> {children} </main> </ThemeProvider> </NextIntlClientProvider> </SessionProvider> </body> </html> ); } export function generateStaticParams() { return ['en', 'ro'].map((locale) => ({ lang: locale })); } Like this ?
change to
import {NextIntlClientProvider, useMessages} from 'next-intl';

 const messages = useMessages();
how does src/i18n.ts look like?
@Ray change to ts import {NextIntlClientProvider, useMessages} from 'next-intl'; const messages = useMessages();
Sun bearOP
@Sun bear Click to see attachment
<NextIntlClientProvider locale={locale} messages={messages}>
@Ray how does `src/i18n.ts` look like?
Sun bearOP
// src/i18n.ts

import { notFound } from 'next/navigation';
import { getRequestConfig } from 'next-intl/server';

// Can be imported from a shared config
const locales = ['en', 'ro'];

export default getRequestConfig(async ({ locale }) => {
  // Validate that the incoming `locale` parameter is valid
  if (!locales.includes(locale as any)) notFound();

  return {
    messages: (await import(`./messages/${locale}.json`)).default
  };
});
Sun bearOP
// src/app/[locale]/layout.tsx

import '../globals.css';
import { ThemeProvider } from "@/components/theme-provider";
import { PropsWithChildren } from 'react';
import { SvgGradients } from '@/components/svg-gradient';
import fontVariables from '@/components/fonts';
import { createClient } from '@/utilities/supabase/server';
import SessionProvider from '@/components/providers';
import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar';
import {NextIntlClientProvider, useMessages} from 'next-intl';
import { unstable_setRequestLocale } from 'next-intl/server';

const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com";

export const metadata = {
  metadataBase: new URL(defaultUrl),
  title: 'Next.js and Supabase Starter Kit',
  description: 'The fastest way to build apps with Next.js and Supabase',
};

export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) {
  const supabase = createClient();
  const { data: { session } } = await supabase.auth.getSession();

  const messages = useMessages();

  unstable_setRequestLocale(locale);

  return (
    <html lang={locale} className={fontVariables} suppressHydrationWarning>
      <body className="font-roboto h-[100svh]">
        <SessionProvider session={session}>
          <SvgGradients />
          <NextIntlClientProvider locale={locale} messages={messages.default}>
            <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
              <main className="flex flex-col flex-grow items-center h-full">
                <TopNavigationBar lang={locale} />
                {children}
              </main>
            </ThemeProvider>
          </NextIntlClientProvider>
        </SessionProvider>
      </body>
    </html>
  );
}

export function generateStaticParams() {
  return ['en', 'ro'].map((locale) => ({ lang: locale }));
}
In regards with the layout this is how it looks now
@Sun bear js // src/app/[locale]/layout.tsx import '../globals.css'; import { ThemeProvider } from "@/components/theme-provider"; import { PropsWithChildren } from 'react'; import { SvgGradients } from '@/components/svg-gradient'; import fontVariables from '@/components/fonts'; import { createClient } from '@/utilities/supabase/server'; import SessionProvider from '@/components/providers'; import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar'; import {NextIntlClientProvider, useMessages} from 'next-intl'; import { unstable_setRequestLocale } from 'next-intl/server'; const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com"; export const metadata = { metadataBase: new URL(defaultUrl), title: 'Next.js and Supabase Starter Kit', description: 'The fastest way to build apps with Next.js and Supabase', }; export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) { const supabase = createClient(); const { data: { session } } = await supabase.auth.getSession(); const messages = useMessages(); unstable_setRequestLocale(locale); return ( <html lang={locale} className={fontVariables} suppressHydrationWarning> <body className="font-roboto h-[100svh]"> <SessionProvider session={session}> <SvgGradients /> <NextIntlClientProvider locale={locale} messages={messages.default}> <ThemeProvider attribute="class" defaultTheme="system" enableSystem> <main className="flex flex-col flex-grow items-center h-full"> <TopNavigationBar lang={locale} /> {children} </main> </ThemeProvider> </NextIntlClientProvider> </SessionProvider> </body> </html> ); } export function generateStaticParams() { return ['en', 'ro'].map((locale) => ({ lang: locale })); }
<NextIntlClientProvider locale={locale} messages={messages}>
remove .default
Sun bearOP
That solved it!
is it working now?
Sun bearOP
Of course not
lol
Welcome to my world xD
@Sun bear Click to see attachment
change back to
import fs from 'fs/promises'

  const messages = await fs
    .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8")
    .then(JSON.parse);
Sun bearOP
// src/app/[locale]/layout.tsx

import '../globals.css';
import { ThemeProvider } from "@/components/theme-provider";
import { PropsWithChildren } from 'react';
import { SvgGradients } from '@/components/svg-gradient';
import fontVariables from '@/components/fonts';
import { createClient } from '@/utilities/supabase/server';
import SessionProvider from '@/components/providers';
import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar';
import { NextIntlClientProvider } from 'next-intl';
import { unstable_setRequestLocale } from 'next-intl/server';
import fs from 'fs/promises';

const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com";

export const metadata = {
  metadataBase: new URL(defaultUrl),
  title: '',
  description: '-',
};

export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) {
  const supabase = createClient();
  const { data: { session } } = await supabase.auth.getSession();

  const messages = await fs
    .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8")
    .then(JSON.parse);

  unstable_setRequestLocale(locale);

  return (
    <html lang={locale} className={fontVariables} suppressHydrationWarning>
      <body className="font-roboto h-[100svh]">
        <SessionProvider session={session}>
          <SvgGradients />
          <NextIntlClientProvider locale={locale} messages={messages}>
            <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
              <main className="flex flex-col flex-grow items-center h-full">
                <TopNavigationBar lang={locale} />
                {children}
              </main>
            </ThemeProvider>
          </NextIntlClientProvider>
        </SessionProvider>
      </body>
    </html>
  );
}

export function generateStaticParams() {
  return ['en', 'ro'].map((locale) => ({ lang: locale }));
}
Like this ?
@Sun bear js // src/app/[locale]/layout.tsx import '../globals.css'; import { ThemeProvider } from "@/components/theme-provider"; import { PropsWithChildren } from 'react'; import { SvgGradients } from '@/components/svg-gradient'; import fontVariables from '@/components/fonts'; import { createClient } from '@/utilities/supabase/server'; import SessionProvider from '@/components/providers'; import TopNavigationBar from '@/components/top-navigation-bar/top-navigation-bar'; import { NextIntlClientProvider } from 'next-intl'; import { unstable_setRequestLocale } from 'next-intl/server'; import fs from 'fs/promises'; const defaultUrl = process.env.NODE_ENV === "production" ? `https://${process.env.VERCEL_URL}` : "https://www.jobsbringer.com"; export const metadata = { metadataBase: new URL(defaultUrl), title: '', description: '-', }; export default async function RootLayout({ children, params: { lang: locale } }: PropsWithChildren<{ params: { lang: string } }>) { const supabase = createClient(); const { data: { session } } = await supabase.auth.getSession(); const messages = await fs .readFile(process.cwd() + `/messages/${locale}.json`, "utf-8") .then(JSON.parse); unstable_setRequestLocale(locale); return ( <html lang={locale} className={fontVariables} suppressHydrationWarning> <body className="font-roboto h-[100svh]"> <SessionProvider session={session}> <SvgGradients /> <NextIntlClientProvider locale={locale} messages={messages}> <ThemeProvider attribute="class" defaultTheme="system" enableSystem> <main className="flex flex-col flex-grow items-center h-full"> <TopNavigationBar lang={locale} /> {children} </main> </ThemeProvider> </NextIntlClientProvider> </SessionProvider> </body> </html> ); } export function generateStaticParams() { return ['en', 'ro'].map((locale) => ({ lang: locale })); }
yes
Sun bearOP
@Sun bear Click to see attachment
export default async function RootLayout({ children, params: { locale } }
@Ray `export default async function RootLayout({ children, params: { locale } }`
Sun bearOP
@Sun bear Click to see attachment
change lang: string to locale: string
Sun bearOP
Should I restart my server ?
Maybe it's stuck or something
@Sun bear Should I restart my server ?
no the path is wrong
  const messages = await fs
    .readFile(process.cwd() + `/src/messages/${locale}.json`, "utf-8")
    .then(JSON.parse);
i noticed that you have src folder
Sun bearOP
Yup
This is my structure
Sun bearOP
Success 😮
Now
@Sun bear Success 😮
try change back to this
const messages = await import(`../../messages/${locale}.json`)

<NextIntlClientProvider locale={locale} messages={messages.default}>
Sun bearOP
there is 2 more files I need help with, my language selector which still uses the old code from how i've done localization before and my middleware.
Website still loads
yes then keep it
Sun bearOP
However I am noticing some issues in the terminal
Not sure what they mean
As in the green ones
how does your messages/en.json look like
what is that lol
oh I can see it now
Sun bearOP
It's the old way I was doing translation
Do I need to update the format of that file ?
change Index.title to pages.home.title
@Sun bear Click to see attachment
I think you are using t("Index.title") here?
Sun bearOP
Ohhh actually that's a placeholder, hold on.
I forgot we need to update that page too
//src/app/[locale]/page.tsx

import { Locale } from '@/i18n.config'
import { getDictionary } from '../translation/dictionary';

export default async function Index({
  params: { lang }
}: {
  params: { lang: Locale }
}) {

  const { page } = await getDictionary(lang)

  return (
    <div className="flex-1 w-full h-full flex justify-center items-center">

      <main className="animate-in opacity-0 flex justify-center items-center h-full w-full">
        <h2 className="font-bold text-4xl text-center m-0">{page.home.title}</h2>
      </main>

      <footer className="absolute bottom-0 w-full p-8 flex justify-center text-center text-xs">
      </footer>
    </div>
  )
}

This is how I currently have it, as you can see it's not using next-intl
It's using my old localization system
How can I update it to use what we've done, if you don't mind showing me ?
Then we only need to update my language selector and my middleware, I hope I can solve the rest by myself.
@Sun bear How can I update it to use what we've done, if you don't mind showing me ?
//src/app/[locale]/page.tsx

import {useTranslations} from 'next-intl';

export default async function Index({
  params: { locale }
}: {
  params: { locale }
}) {

  const t = useTranslations('page.home')

  return (
    <div className="flex-1 w-full h-full flex justify-center items-center">

      <main className="animate-in opacity-0 flex justify-center items-center h-full w-full">
        <h2 className="font-bold text-4xl text-center m-0">{t('title')}</h2>
      </main>

      <footer className="absolute bottom-0 w-full p-8 flex justify-center text-center text-xs">
      </footer>
    </div>
  )
}
@Sun bear Click to see attachment
import {getTranslations} from 'next-intl/server';

export default async function Index({
  params: { locale }
}: {
  params: { locale: string }
}) {

  const t = getTranslations('page.home')

  return (
    <div className="flex-1 w-full h-full flex justify-center items-center">

      <main className="animate-in opacity-0 flex justify-center items-center h-full w-full">
        <h2 className="font-bold text-4xl text-center m-0">{t('title')}</h2>
      </main>

      <footer className="absolute bottom-0 w-full p-8 flex justify-center text-center text-xs">
      </footer>
    </div>
  )
}
@Sun bear Click to see attachment
const t = await getTranslations('page.home')
@Sun bear Click to see attachment
do you have liveshare
Answer
@Ray do you have liveshare
Sun bearOP
I can get it if that would help
Huh, my website looks different 😕
I think something is messed up in next config
or something
what is different?
Sun bearOP
It no longer has dark mode
and uhhh I don't have a screensot to show you
But the text looked different too it was centred in the middle
nav bar looks the same but the index page looks different from how i had it before
Can you see my session ?
I'm not sure if it works
can you start it?
Sun bearOP
I have written in the chat
can you see ?
Sun bearOP
I can see but I want to be able to see the page too
Sun bearOP
I am using github
for the sharing
So what do I have to do ?
Sun bearOP
@Sun bear Click to see attachment
share server
Sun bearOP
@Ray
Sun bearOP
@Ray Found it, here is how it looked before we updated it.
Just for you to make an idea. That is the home page.