i18next keeps saying missingKey but it looks fine? - storybook

I am trying to use i18next in our React app, the translation loaded just fine on the page and I was able to switch between the supported languages. But the console log would keeps on printing missingKey, something tells me that I'm doing something wrong... but I cannot pinpoint it. Could someone give me some clues?
The initialization was done like this:
const initOptions = {
fallbackLng: ['en'],
supportedLngs: ['en', 'fr'],
ns: ['common', 'dashboard'],
defaultNS: 'common',
react: {
useSuspense: false
},
debug: true,
interpolation: {
escapeValue: false
},
backend: {
backends: [
resourcesToBackend((language, namespace, callback) => {
console.debug('resourcesToBackend');
import(`./locales/${language}/${namespace}.json`)
.then((resources) => {
console.debug('then?', resources);
callback(null, resources)
})
.catch((error) => {
console.debug('catch?', error);
callback(error, null)
})
}),
HttpApi
]
}
}
i18n
.use(ChainedBackend)
.use(LanguageDetector)
.use(initReactI18next) // passes i18n down to react-i18next
.init(initOptions);
}
Then assets folder look something like this:
locales/
├─ en/
│ ├─ common.json
│ ├─ dashboard.json
├─ fr/
│ ├─ common.json
│ ├─ dashboard.json
The component using the translation is just a dummy component:
const Example = () => {
const { t } = useTranslation();
return (
<div className='container'>
<h1>{t('app_title')}</h1>
<hr />
<ul>
<li>{t('dashboard:item1')}</li>
<li>{t('dashboard:item2')}</li>
<li>{t('dashboard:item3')}</li>
</ul>
</div>
);
};

looks like you're not telling the useTranslation that you need the namespace 'dashboard' - so the hook does not assert it's loaded
https://react.i18next.com/latest/usetranslation-hook#loading-namespaces
const Example = () => {
const { t } = useTranslation('dashboard');
return (
<div className='container'>
<h1>{t('app_title')}</h1>
<hr />
<ul>
<li>{t('dashboard:item1')}</li>
<li>{t('dashboard:item2')}</li>
<li>{t('dashboard:item3')}</li>
</ul>
</div>
);
};

Related

NextJS ServerSideProps translation don't work properly in dynamic routes

Hi everyone I have a NextJS app ( main host ) inside a NX Project.
I have the need to translate the pages inside the app, and i'm using next-i18next package installed.
I have several dynamic pages like:
pages
|- projects
| |- index.js
| |- [id]
| | | - index.js
|
| index.js
| _app.js
And locally everything works just fine, but when I deploy to Vercel the translations inside the dynamic pages don't work.
I really don't understand why it's happening, one solution I've found was to transform all dynamic rendered pages into static ones, but this is not possible since new ids are generated during the usage of the application.
Packages I'm using:
"i18next": "^22.0.6",
"next": "13.0.0",
"next-i18next": "^13.0.0",
Code inside dynamic route:
export async function getServerSideProps({ locale }) {
return {
props: {
...(await ssrTranslations(locale, [
'projects',
'shared',
'newgateway-file',
'gatewaysummary',
])),
},
};
}
Next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'it', 'de', 'es', 'fr', 'ja'],
},
defaultNs: 'shared',
fallbackLng: { default: ['en'] },
localePath: 'apps/host/public/locales'
};
Next.config.js
const { withNx } = require('#nrwl/next/plugins/with-nx');
const { i18n } = require('./next-i18next.config');
/**
* #type {import('#nrwl/next/plugins/with-nx').WithNxOptions}
*
**/
const nextConfig = {
nx: {
// Set this to true if you would like to to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false,
},
reactStrictMode: true,
swcMinify: true,
i18n,
};
module.exports = withNx(nextConfig);

NEXT JS: Build exportPathMap for a dynamic page Route

I wanted to build a static export for my NEXT project that looks like following:
- pages
---- index.tsx
---- [pageRoute].tsx
Now I want to statically generate routeId for home page that I have handled as shown below:
import { useRouter } from 'next/router';
import React from 'react';
import { PAGE_ROUTES } from '../constants/config';
import Home from './Home/Home';
type Props = {};
export default function Base({}: Props) {
const router = useRouter();
const route = router.query.pageRoute as string;
let RenderComponent = <div>404: Page Not Found</div>;
switch (route) {
case PAGE_ROUTES.HOME: {
RenderComponent = <Home />;
break;
}
default: {
}
}
return (
<div className='flex flex-col items-center max-w-sm mx-auto'>
{RenderComponent}
</div>
);
}
I am not sure what do I specify in exportPathMaps in next.config.js in order to create static export of home page:
/** #type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
// how do I add configuration for '/home': {page: '/[pageRoute]',query:{pageRoute:'home'}}
};
},
};
when I do this:
'/home': { page: '/[pageRoute]', query: { pageRoute: 'home' } },
It throws error saying:
Error: you provided query values for /home which is an auto-exported page. These can not be applied since the page can no longer be re-rendered on the server. To disable auto-export for this page addgetInitia
lProps
In order to statically pre-render dynamic paths, you should return them from getStaticPaths:
import { useRouter } from 'next/router';
import React from 'react';
import { PAGE_ROUTES } from '../constants/config';
import Home from './Home/Home';
import type { GetStaticPaths } from 'next'
export const getStaticPaths: GetStaticPaths = async () => {
const paths = Object.values(PAGE_ROUTES)
.map(route => [{ params: { pageRoute: route } }])
return {
paths,
fallback: false, // meaning any path not returned by `getStaticPaths` will result in a 404 page
}
}
type Props = {};
export default function Base({}: Props) {
return (
<div className='flex flex-col items-center max-w-sm mx-auto'>
<Home />
</div>
);
}
And, as #juliomalves said, in that case you don't need exportPathMap in next.config.js.
For custom 404 page create 404.tsx in /pages
More about getStaticPaths - https://nextjs.org/docs/api-reference/data-fetching/get-static-paths
fallback: false - https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-false

Remove language from URL in Next JS dynamic routes

I have a website in NextJS with next-i18next, and every page must be translated except for the legal pages.
These legal pages are in markdown, and I have dynamic routing enabled thanks to a [legal].js page and the getStaticPaths and getStaticProps in it.
The problem is that by building my website, my legal pages are prefixed with the language (here en). I would like to remove it as I don't want these pages to be translated.
What am I doing wrong here?
Thanks a lot 🙏
Folder structure:
pages
|- index.js
|- [legal].js
|- privacy-policy.mdx
next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en'],
fallbackLng: 'en',
defaultNS: ['homepage', 'header', 'footer'],
localeDetection: false,
},
}
[legal].js
import matter from 'gray-matter'
import ReactMarkdown from 'react-markdown'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import glob from 'glob'
const LegalPage = ({ markdownBody }) => (
<ReactMarkdown>{markdownBody}</ReactMarkdown>
)
export async function getStaticProps({ locale, params }) {
const { legal } = params
const content = await import(`./${legal}.mdx`)
const data = matter(content.default)
return {
props: {
...(await serverSideTranslations(locale, ['header', 'footer'])),
markdownBody: data.content,
},
}
}
export async function getStaticPaths() {
const blogs = glob.sync('src/pages/**/*.mdx')
const blogSlugs = blogs.map(file => {
const parts = file.split('/')
return parts[parts.length - 1].replace('.mdx', '')
})
const paths = blogSlugs.map(slug => ({
params: { legal: slug },
}))
return {
paths,
fallback: false,
}
}
export default LegalPage
build output:
All static HTML files should be created in separate folders for each locale.
Your default locale can be omitted in the URL, and the following URLs are equivalent:
example.com/my-first-blog
example.com/en/my-first-blog
🎈 As a solution, you can setup app i18n base on domain:
module.exports = {
i18n: {
locales: ['en'],
defaultLocale: 'en',
domains: [
{
domain: 'example.com',
defaultLocale: 'en',
},
]
}
}

next js dynamic page routing working in localhost but giving file not found error in production

This is part of my next js project. This website is running perfectly on localhost but when i deploy it on vercel, the /blogs/book/chapter page is giving me file not found enter image description here500 error.
Hosted Page - Website
Source Code - GitHub
Dynamic Routing Folder Structure
Page Structure
chapter.js
import fs from "fs";
import path from "path";
import Head from "next/head";
import DefaultErrorPage from "next/error";
import { useRouter } from "next/router";
import matter from "gray-matter";
import { marked } from "marked";
import styles from "../../../../styles/blog/Chapter.module.css";
import { capitalise } from "../../../../components/blog/Capitalise";
import BlogPostBottom from "../../../../components/blog/BlogPostBottom";
export default function Chapter({ book, chapter, frontmatter, content }) {
// Destructuring
const { description } = frontmatter;
// Router Variable
const router = useRouter();
// If fallback then show this
if (router.isFallback) {
// if (router.isFallback || !book || !chapter || !content) {
return <div>Loading...</div>;
}
if (!book || !chapter || !content || !frontmatter) {
return (
<div>
<DefaultErrorPage statusCode={404} />
</div>
);
}
return (
<div className={styles.bookChapter}>
<Head>
<title>{`${capitalise(chapter)} | ${capitalise(
book
)} | Blog | Manav Goyal`}</title>
<meta
name="description"
content={`Read Blog about this book ${book} covering chapter ${chapter} of topics ${description}`}
/>
</Head>
<h1>{`${capitalise(chapter)} - ${capitalise(book)}`}</h1>
<section
className={styles.bookChapterContent}
dangerouslySetInnerHTML={{ __html: marked(content) }}
></section>
<BlogPostBottom slug={`/blog/${book}`} />
</div>
);
}
export async function getStaticPaths() {
return {
paths: [{ params: { book: "css", chapter: "bootstrap" } }],
// paths: [],
fallback: true,
};
}
// Web crawlers, won't be served a fallback and instead the path will behave as in fallback: 'blocking'
// fallback: true is not supported when using `next export`
export async function getStaticProps({ params }) {
const { book, chapter } = params;
let chapterPost = null;
try {
chapterPost = await fs.promises.readFile(
path.join(`posts/${book}/${chapter}.md`),
"utf-8"
);
} catch (err) {}
const { data: frontmatter, content } = matter(chapterPost);
return {
props: {
book,
chapter,
frontmatter,
content,
},
// redirect: {
// destination: `/blog/${book}`,
// permanent: false,
// },
// revalidate: 1,
};
}
Chapter.defaultProps = {
book: "css",
chapter: "bootstrap",
frontmatter: { description: "CSS", id: "1" },
content: "Error",
};
Posts Folder Structure
Posts Folder Structure
Error
Console
Vercel Function Log

Next.js route mismatch in prod build but not in dev

I'm using Next.js and trying to implement incremental static regeneration. My pages structure is:
pages
- [primary]
- article
- [...slug.js]
and my [...slug.js]
import Head from 'next/head'
export default function Article({ post }) {
if (!post) {
return 'loading'
}
const data = post[0];
return (
<div className="container mx-auto pt-6">
<Head>
<title>{`${data.title.rendered}`}</title
</Head>
<main>
<div>{data.content.rendered}</div>
</main>
</div >
)
}
export async function getStaticPaths() {
return {
paths: [{ params: { primary: '', slug: [] } }],
fallback: true,
};
}
export async function getStaticProps({ params }) {
const slug = params.slug[0];
const res = await fetch(`https://.../?slug=${slug}`)
const post = await res.json()
return {
props: { post },
revalidate: 1,
}
}
This works locally when I pass route like: localhost:3000/dance/article/lots-of-dancers-dance-in-unison, it correctly passes the slug and I can query the CMS no problem. But when I run build I get:
Error: Requested and resolved page mismatch: //article /article at normalizePagePath
This is because the static path you are providing for primary is '' (empty).
For empty string value for primary, the static path becomes //article which resolves to /article. This is what the error says.
Though this works in development, it will give the said error in Prod build.
Add a value to the path and it should work!
paths: [{ params: { primary: 'abc', slug: [] } }],

Resources