Hi Friends,
I am trying to integrate internationalization (i18n) for a Next.js 14 (app directory) project. However I get a lot of errors related to client and server components. Actually I followed the Next.js 14 documentation for internationalization.
At the moment I am not using an additional library for internationalization. All I am doing is pass down “lang” to the child component to use it there. Would you recommend to install an additional library?
At the moment I have a translation file (for German and English) and all I want to do is get the data and display it in the frontend. However I always get the error:
TypeError: Cannot read properties of undefined (reading ‘lang’)
I dont understand how “lang” can be undefined? The translation file is locally hosted in my application., so it should be always available. Btw: I am using TypeScript.
Furthermore there are different methods for client and server components. Here the method I am using for client components:
'use client';
import React, { useState, useEffect } from 'react';
import FaqData from '../../../../data/FaqData.json';
import { AiOutlinePlus, AiOutlineMinus } from 'react-icons/ai';
import { Locale } from '../../../../i18n.config';
import { getlocales } from '../../../actions';
import { FAQSectionTranslation } from '../../../../types';
export default function FaqSection({ lang = 'de' }: { lang: Locale }) {
const [activeQuestion, setActiveQuestion] = useState<number | null>(null);
const [faqSection, setFaqSection] = useState<FAQSectionTranslation | null>(
null
);
useEffect(() => {
console.log('Current language:', lang);
async function fetchData() {
try {
const data = await getlocales(lang);
setFaqSection(data.sections.faqSection);
} catch (error) {
console.error('Error fetching tools data:', error);
try {
const defaultData = await getlocales('de');
setFaqSection(defaultData.sections.faqSection);
} catch (defaultError) {
console.error('Error fetching default language data:', defaultError);
}
}
}
fetchData();
}, [lang]);
const toggleQuestion = (index: number) => {
setActiveQuestion(activeQuestion === index ? null : index);
};
return (
<div className="container" id="faq-section__container">
<div className="wrapper" id="faq-section__wrapper">
<h1 className="main-heading">{faqSection?.mainHeading}</h1>
<h4 className="sub-heading">{faqSection?.subHeading}</h4>
<div className="faq-container">
{FaqData.map((item, index) => (
<div key={index} className="faq-item">
<h5
className={`faq-question ${
activeQuestion === index ? 'active' : ''
}`}
onClick={() => toggleQuestion(index)}
>
{item.question[lang]}
<span className="faq-icon">
{activeQuestion === index ? (
<AiOutlineMinus />
) : (
<AiOutlinePlus />
)}
</span>
</h5>
<div
className={`faq-answer ${
activeQuestion === index ? 'active' : ''
}`}
>
<p>{item.answer[lang]}</p>
</div>
</div>
))}
</div>
</div>
</div>
);
}
This is the method I am using for server components:
import Image from 'next/image';
import Link from 'next/link';
import Button from '../Layout/BtnComponent';
import HardwareDataTable from '../Tables/HardwareDataTable';
import SoftwareDataTable from '../Tables/SoftwareDataTable';
import { Locale } from '../../../../i18n.config';
import { getlocales } from '../../../actions';
const ProductSection = async ({ lang }: { lang: Locale }) => {
const { sections } = await getlocales(lang);
return (
<>
<div className="container" id="product-section__container">
<div className="wrapper" id="product-section__wrapper">
<h1 className="main-heading">
{sections.productSection.mainHeading}
</h1>
<h4 className="sub-heading">{sections.productSection.subHeading}</h4>
<div className="product-section__grid">
{/* <div className="sticky-element">
<p>Test</p>
</div> */}
<div className="product-section__text">
<h3>{sections.productSection.speamBoxDetailsHeading}</h3>
<ul className="product-section__data-list">
<li>{sections.productSection.speamBoxDetails1}</li>
<li>{sections.productSection.speamBoxDetails2}</li>
<li>{sections.productSection.speamBoxDetails3}</li>
<li>{sections.productSection.speamBoxDetails4}</li>
<li>{sections.productSection.speamBoxDetails5}</li>
<li>{sections.productSection.speamBoxDetails6}</li>
<li>{sections.productSection.speamBoxDetails7}</li>
<li>{sections.productSection.speamBoxDetails8}</li>
<li>{sections.productSection.speamBoxDetails9}</li>
</ul>
<div className="download-btn__wrapper">
<Link
href="/pdfs/Box_Data_Sheet_DE.pdf"
passHref
target="_blank"
>
<Button
className="btn--primary"
variant="primary"
size="small"
type="button"
>
<Image
src="/icons/icon__download.svg"
alt="Download"
width={20}
height={20}
/>
{sections.productSection.btnDownloadDataSheet}
</Button>
</Link>
<Link
href="/pdfs/Box_Info_Sheet_DE.pdf"
passHref
target="_blank"
>
<Button
className="btn--primary"
variant="secondary"
size="small"
type="button"
>
<Image
src="/icons/icon__download.svg"
alt="Download"
width={20}
height={20}
/>
{sections.productSection.btnDownloadInfoSheet}
</Button>
</Link>
</div>
</div>
<div className="product-section__image-wrapper-wrapper">
<div className="product-section__image-wrapper">
<div className="product-section__image">
<Image
src="/images/speambox-connections.webp"
alt="Speambox"
layout="fill"
objectFit="contain"
/>
</div>
</div>
{/* <div className="product-section__image-wrapper">
<div className="product-section__image">
<Image
src="/images/speambox-connections-02.png"
alt="Speambox"
layout="fill"
objectFit="contain"
/>
</div>
</div> */}
</div>
</div>
<div className="data-table__wrapper">
<hr />
<HardwareDataTable lang={lang} />
<hr />
<SoftwareDataTable lang={lang} />
</div>
</div>
</div>
</>
);
};
export default ProductSection;
I get the following build error:
TypeError: Cannot read properties of undefined (reading 'lang')
> Export encountered errors on following paths:
/[lang]/agb/page: /de/agb
/[lang]/agb/page: /en/agb
/[lang]/danke/page: /de/danke
/[lang]/danke/page: /en/danke
/[lang]/datenschutz/page: /de/datenschutz
/[lang]/datenschutz/page: /en/datenschutz
/[lang]/impressum/page: /de/impressum
/[lang]/impressum/page: /en/impressum
/[lang]/page: /de
/[lang]/page: /en
Can anyone let me know what I am doing wrong? I would highly apprechiate if someone could guide me in the right direction or if someone can let me know another method to use i18n within Next.js 14
Actually I wanted to create a languageProvider
which will wrap all the components to pass doen the “lang” to the children. However I dont want the index page to be a client component and always when I wrap the components inside a languageProvider the entire page component will become a client component.
How can I fix this issue?
Thank you very much for answer!