☝️Toàn bộ giải thích sử dụng chatgpt Triển khai client, server (part 3)
The TypeScript error you're encountering indicates a mismatch between the expected type for getServerSideProps and the actual type defined in your pages/[lang]/new-page.tsx. Specifically:
The error occurs because the
langprop in the return value ofgetServerSidePropsis typed asstring | string[], but theNewPagePropsinterface expectslangto be strictly astring.In Next.js Pages Router,
context.params.langcan be astringorstring[](if the dynamic route supports multiple segments, e.g.,pages/[...lang].tsx), but yourNewPagePropsinterface and page logic assumelangis always astring.
This is likely caused by:
The dynamic route
[lang]being interpreted by TypeScript as potentially returningstring | string[]forcontext.params.lang.The
NewPagePropsinterface not aligning with the return type ofgetServerSideProps.
Let’s fix the error by:
Ensuring
langis always astringingetServerSideProps.Updating the
NewPagePropsinterface to match the props returned.Maintaining compatibility with your i18n setup and
ClientComponent.
Solution
1. Fix pages/[lang]/new-page.tsx
Update pages/[lang]/new-page.tsx to explicitly handle context.params.lang as a string and ensure the NewPageProps interface matches the props returned by getServerSideProps.
import ClientComponent from '@/src/components/ClientComponent';
import LanguageSwitcher from '@/src/components/LanguageSwitcher';
import initI18next from '@/src/lib/i18n/server';
import { fallbackLng, languages } from '@/src/lib/i18n/settings';
import { GetServerSideProps } from 'next';
interface NewPageProps {
lang: string;
serverTranslation: string;
}
export default function NewPage({ lang, serverTranslation }: NewPageProps) {
console.log('NewPage Server: lang=', lang, 'serverTranslation=', serverTranslation);
return (
<>
<header className="flex justify-end p-4">
<LanguageSwitcher />
</header>
<ClientComponent lang={lang} />
<h1>{serverTranslation}</h1>
</>
);
}
export const getServerSideProps: GetServerSideProps<NewPageProps> = async (context) => {
// Ensure lang is a string
const langParam = Array.isArray(context.params?.lang)
? context.params.lang[0] // Take first element if array
: context.params?.lang || fallbackLng;
const lang = languages.includes(langParam) ? langParam : fallbackLng;
const i18n = await initI18next(lang, 'common');
const t = i18n.getFixedT(lang, 'common');
const serverTranslation = t('hello');
console.log('NewPage getServerSideProps: lang=', lang, 't(hello)=', serverTranslation);
return {
props: {
lang,
serverTranslation,
},
};
};Changes:
Handle
langParam:Check if
context.params?.langis an array (string[]) usingArray.isArray. If it is, take the first element (lang[0]). If not, use the string value or fall back tofallbackLng.This ensures
langis always astring, resolving thestring | string[]type mismatch.
Type Safety:
The
NewPagePropsinterface defineslang: string, which matches thelangprop returned bygetServerSideProps.
Validation:
Validates
langagainstlanguages(['en', 'vi']) to ensure only supported languages are used.
Logging:
Kept logging to debug
langand translations.
2. Verify Route Structure
Ensure the file is correctly placed in pages/[lang]/new-page.tsx (not pages/[...lang]/new-page.tsx):
pages/[lang]/new-page.tsxexpects a singlelangsegment (e.g.,/en/new-page,/vi/new-page).If you accidentally used
pages/[...lang]/new-page.tsx(catch-all route),context.params.langwould be astring[], causing the type error. Rename the folder to[lang]if needed.
Check:
Confirm the file path:
pages/[lang]/new-page.tsx.Run
ls pagesto verify the directory structure.
3. Verify ClientComponent
Ensure src/components/ClientComponent.tsx handles lang correctly and is synchronous:
'use client';
import { useEffect, useState } from 'react';
import i18n from '@/src/lib/i18n/client';
import { useTranslation } from 'react-i18next';
import { fallbackLng } from '@/src/lib/i18n/settings';
export default function ClientComponent({ lang = fallbackLng }: { lang?: string }) {
const { t } = useTranslation('common');
const [isLanguageReady, setIsLanguageReady] = useState(i18n.language === lang);
useEffect(() => {
console.log('ClientComponent: lang=', lang, 'i18n.language=', i18n.language);
if (i18n.language !== lang) {
i18n.services.languageDetector?.cache?.clear?.();
i18n.changeLanguage(lang, (err) => {
if (err) console.error(`Failed to change language to ${lang}`, err);
i18n.loadNamespaces('common', (err) => {
if (err) console.error(`Failed to load namespace 'common' for ${lang}`, err);
setIsLanguageReady(true);
});
});
} else {
setIsLanguageReady(true);
}
}, [lang]);
console.log('ClientComponent rendering: t(hello)=', t('hello'));
return isLanguageReady ? <p>{t('hello')}</p> : null;
}Checks:
Synchronous: Not
async, avoiding the async Client Component error.Fallback
lang: Defaults tofallbackLngto preventTypeError: Cannot read properties of undefined (reading 'lang').Language Sync: Ensures translations are correct.
4. Verify client.ts
Ensure src/lib/i18n/client.ts is unchanged and supports client-side translations:
'use client';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import resourcesToBackend from 'i18next-resources-to-backend';
import { getOptions } from './settings';
if (!i18n.isInitialized) {
i18n
.use(initReactI18next)
.use(LanguageDetector)
.use(
resourcesToBackend(async (lang: string, namespace: string) => {
try {
console.log(`Loading translation: ${lang}/${namespace}`);
const module = await import(`@/src/locales/${lang}/${namespace}.json`);
return module.default;
} catch (error) {
console.error(`Failed to load translation for ${lang}/${namespace}`, error);
return {};
}
})
)
.init({
...getOptions(),
detection: {
order: ['path'],
caches: [],
lookupFromPathIndex: 0,
},
ns: ['common'],
defaultNS: 'common',
});
i18n.on('languageChanged', (lng) => {
console.log('Language changed to:', lng, 'Resources:', i18n.services.resourceStore.data);
});
}
export default i18n;5. Verify LanguageSwitcher
Ensure src/components/LanguageSwitcher.tsx works in the Pages Router:
'use client';
import { usePathname, useRouter } from 'next/navigation';
import { useTransition } from 'react';
const locales = ['en', 'vi'];
export default function LanguageSwitcher() {
const router = useRouter();
const pathname = usePathname();
const [isPending, startTransition] = useTransition();
const currentLang = pathname ? pathname.split('/')[1] : 'en';
const otherLang = locales.find((lng) => lng !== currentLang) || 'en';
const switchLang = () => {
if (!pathname) return;
const segments = pathname.split('/');
segments[1] = otherLang;
const newPath = segments.join('/');
console.log('LanguageSwitcher: Switching to:', newPath);
startTransition(() => {
router.push(newPath, { scroll: false });
});
};
return (
<button
onClick={switchLang}
disabled={isPending}
className="px-4 py-2 rounded border bg-gray-100 hover:bg-gray-200 text-sm"
>
{otherLang.toUpperCase()}
</button>
);
}6. Handle Turbopack HMR
If Turbopack HMR issues persist (from your previous errors), disable Turbopack:
Update next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
enabled: false,
},
},
};
export default nextConfig;Alternative: Preload translations in src/lib/i18n/client.ts (as shown previously) to avoid dynamic import issues.
7. Test the Page
Clear Cache:
Run
rm -rf .nextand restart the server (npm run dev).
Test Navigation:
Visit
http://localhost:3000/en/new-page:Expect
<h1>and<ClientComponent>to showHello Eng.Check logs:
NewPage getServerSideProps: lang= en t(hello)= Hello Eng NewPage Server: lang= en serverTranslation= Hello Eng ClientComponent: lang= en i18n.language= en ClientComponent rendering: t(hello)= Hello Eng
Visit
http://localhost:3000/vi/new-page:Expect
<h1>and<ClientComponent>to showXin chào Việt Nam.
Test Language Switching:
Start at
/en/new-page, switch to/vi/new-page, then back to/en/new-page.Verify no TypeScript errors or runtime issues.
Test Production Build:
Run
npm run build && npm run start.
8. Debugging Tips
If the TypeScript error persists or other issues arise:
Check Route Name:
Ensure the file is
pages/[lang]/new-page.tsx, notpages/[...lang]/new-page.tsx.
Log
context.params:Add logging in
getServerSideProps:console.log('NewPage getServerSideProps: context.params=', context.params);
Test Static
lang:Temporarily hardcode
lang:export default function NewPage() { return ( <> <LanguageSwitcher /> <ClientComponent lang="vi" /> </> ); }
Check TypeScript Config:
Ensure
tsconfig.jsonis configured for Next.js:{ "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] }
Disable Turbopack:
If HMR issues occur, disable Turbopack as shown above.
9. Expected Outcome
The TypeScript error is resolved by ensuring
langis astringingetServerSideProps./en/new-pageand/vi/new-pagerender correctly withClientComponent.Language switching works without errors.
10. If Issues Persist
Please provide:
Full console logs and error stack trace.
Confirmation that the file is
pages/[lang]/new-page.tsx.The exact URL where the issue occurs (e.g.,
/en/new-page).The Next.js version (
next --version).Contents of
tsconfig.jsonif TypeScript issues persist.
Let me know how it goes or if you need further clarification!
Last updated
Was this helpful?