<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ikram Ul Haq</title>
    <description>The latest articles on DEV Community by Ikram Ul Haq (@ikramdeveloper).</description>
    <link>https://dev.to/ikramdeveloper</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F862423%2F40249de8-b11a-4b84-af61-649975bb92ba.png</url>
      <title>DEV Community: Ikram Ul Haq</title>
      <link>https://dev.to/ikramdeveloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ikramdeveloper"/>
    <language>en</language>
    <item>
      <title>The answer was somewhere in a one-hour video. That's the whole reason I built this.</title>
      <dc:creator>Ikram Ul Haq</dc:creator>
      <pubDate>Mon, 07 Sep 2026 05:33:36 +0000</pubDate>
      <link>https://dev.to/ikramdeveloper/the-answer-was-somewhere-in-a-one-hour-video-thats-the-whole-reason-i-built-this-i5l</link>
      <guid>https://dev.to/ikramdeveloper/the-answer-was-somewhere-in-a-one-hour-video-thats-the-whole-reason-i-built-this-i5l</guid>
      <description>&lt;p&gt;I didn't set out to build a product. I built this for myself, and the reason is small and specific.&lt;/p&gt;

&lt;p&gt;Other AI tools have gotten dramatically better over the last couple of years, and the complaint isn't that they won't stick to one source. Ask one to answer only from a particular website and it mostly will — that site's pages are indexed, and it can reach them.&lt;/p&gt;

&lt;p&gt;The problem starts where the index stops.&lt;/p&gt;

&lt;p&gt;Think of a site with a thousand PDFs on it — a research library, a manuals archive, years of annual reports. A general AI tool can find the page that lists those files. It can't read across them. Some are indexed shallowly, many aren't indexed at all, and the scanned ones have no text in them to index in the first place. You can upload one PDF into a chat and ask about it — I do that all the time — but that's one file, in one conversation, for me. It isn't a searchable body of knowledge, and nobody else can use it.&lt;/p&gt;

&lt;p&gt;Video is worse. One channel I follow has hundreds of videos, plenty of them over an hour long. The answer I wanted was somewhere around minute 43 of a video whose title and description never mention it. The title, description, and chapter markers get indexed. What's actually said at minute 43 doesn't — not in any way a general tool can search. So you either remember roughly where it was, or you scrub through and hope.&lt;/p&gt;

&lt;p&gt;So I built a small thing for myself: point it at the videos and documents I trust, ask a question, get an answer with the exact timestamp or the exact page. I shared it with a few friends and they used it more than I expected. No revenue, no customers, no plan — just a tool that solved my own problem.&lt;/p&gt;

&lt;p&gt;The realization came later and was obvious in hindsight: that gap isn't mine, it's structural. General AI tools are excellent at everything the index can reach and blind to everything it can't — and the moment knowledge lives in a pile of documents or hours of video, it can't. Which means anyone sitting on a body of content has this exact problem pointed at their own audience: a business with its documentation, a non-profit with material to distribute, an academy with recorded lectures, a creator with a back catalogue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually under the hood
&lt;/h2&gt;

&lt;p&gt;Content gets chunked and embedded with &lt;code&gt;BAAI/bge-m3&lt;/code&gt;, stored in a &lt;strong&gt;separate vector collection per tenant&lt;/strong&gt; — no shared index across customers. At query time, it's retrieved and reranked, then the top passages are passed as context to a generation model, with a fallback chain across providers so one outage doesn't take the whole thing down.&lt;/p&gt;

&lt;p&gt;Documents that are scanned rather than text-based go through an OCR cascade rather than silently returning nothing. Video transcripts come from captions where they exist and speech-to-text where they don't. Every tenant gets its own database, not just its own rows in a shared one.&lt;/p&gt;

&lt;p&gt;The part I care most about: answers are confined to that tenant's content and always attributable. If it can't find support in the material, it says so rather than filling the gap. Citations point at the specific page or the specific moment, not just "somewhere in this document."&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this just a wrapper around a model?
&lt;/h2&gt;

&lt;p&gt;Worth answering directly rather than dodging it: the generation model is one component, and it's swappable. The retrieval, the per-tenant isolation, citation-to-exact-page-or-timestamp, the OCR and transcription cascades, and the branding/domain/billing layer on top are the actual product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it ended up
&lt;/h2&gt;

&lt;p&gt;About two months of evenings and weekends around a full-time software job — six years as an engineer — from the thing I built for myself to the thing anyone can sign up for. Multi-tenant, so you bring your own PDFs, DOCX files, or a YouTube channel, and it comes with an embeddable widget so you're not sending people to a separate site to ask a question.&lt;/p&gt;

&lt;p&gt;The result is your own branded AI, on your own domain, trained only on your content, answering only from it, citing the exact page of a document or the exact moment in a video. It's live at &lt;a href="https://ultranivo.com/?utm_source=devto&amp;amp;utm_medium=community" rel="noopener noreferrer"&gt;ultranivo.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy to answer anything — the retrieval setup, the multi-tenant design, the OCR/transcription cascades, or what I'd do differently.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>showdev</category>
      <category>buildinpublic</category>
      <category>webdev</category>
    </item>
    <item>
      <title>HTTP 500 on AWS Amplify After Deployment — Solved by a Monorepo Dependency Mismatch</title>
      <dc:creator>Ikram Ul Haq</dc:creator>
      <pubDate>Thu, 12 Mar 2026 16:20:16 +0000</pubDate>
      <link>https://dev.to/ikramdeveloper/http-500-on-aws-amplify-after-deployment-solved-by-a-monorepo-dependency-mismatch-4gfo</link>
      <guid>https://dev.to/ikramdeveloper/http-500-on-aws-amplify-after-deployment-solved-by-a-monorepo-dependency-mismatch-4gfo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I used Claude Code to investigate this issue. What could have taken a day of back-and-forth debugging was resolved in a focused session — pinpointing the root cause, testing fixes, and ruling out dead ends systematically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;After a successful deployment on AWS Amplify, the app was returning HTTP 500 with no build failure, no warning — just a blank page. CloudWatch logs showed this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;ln: failed to create symbolic link '/tmp/app/node_modules/node_modules': Read-only file system
ln: failed to create symbolic link '/tmp/app/public/public': Read-only file system
ln: failed to create symbolic link '/tmp/app/.next/static/static': Read-only file system
ln: failed to create symbolic link '/tmp/app/.next/server/chunks/chunks': Read-only file system
INIT_REPORT Init Duration: 767.95 ms   Phase: invoke   Status: error   Error Type: Runtime.ExitError
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deployment was marked successful. The app was dead on arrival.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Next.js · pnpm monorepo · AWS Amplify SSR&lt;/p&gt;




&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;This is a pnpm monorepo with two apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app-1&lt;/code&gt; — already deployed and working on Amplify&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app-2&lt;/code&gt; — newly added to the monorepo, deployed in the same commit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both apps share the root &lt;code&gt;node_modules&lt;/code&gt; via pnpm hoisting.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Tried (All Failed)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;output: 'standalone'&lt;/code&gt; in &lt;code&gt;next.config.mjs&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The idea was to bundle all dependencies into &lt;code&gt;.next/standalone&lt;/code&gt; to avoid symlink resolution issues at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.mjs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same symlink errors in CloudWatch. Didn't help.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Scoped install in Amplify build spec
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;preBuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm install --filter app-1...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The intent was to install only &lt;code&gt;app-1&lt;/code&gt;'s dependency tree to avoid &lt;code&gt;app-2&lt;/code&gt;'s deps affecting the hoisting layout. Same error.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Removed &lt;code&gt;node_modules&lt;/code&gt; from Amplify cache
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.next/cache/**/*'&lt;/span&gt;
    &lt;span class="c1"&gt;# removed: node_modules/**/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ruled out stale cached &lt;code&gt;node_modules&lt;/code&gt;. Same error.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. &lt;code&gt;pnpm.overrides&lt;/code&gt; to force a single React version
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"pnpm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^19.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^19.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was an attempt to eliminate the version conflict at the root. Same symlink error on Amplify.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Redeployed the last known-working commit
&lt;/h3&gt;

&lt;p&gt;Redeploying the commit before &lt;code&gt;app-2&lt;/code&gt; was added worked perfectly. This confirmed the issue was introduced entirely by &lt;code&gt;app-2&lt;/code&gt; being part of the monorepo — not an Amplify infrastructure issue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At this point we also found similar reports on the Amplify GitHub repo (&lt;a href="https://github.com/aws-amplify/amplify-hosting/issues/3793" rel="noopener noreferrer"&gt;#3793&lt;/a&gt;, &lt;a href="https://github.com/aws-amplify/amplify-hosting/issues/4079" rel="noopener noreferrer"&gt;#4079&lt;/a&gt;) with identical log output. Those were intermittent platform-side issues. Ours was consistent and reproducible — which pointed back to our code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Twist: A Local Build Failure Along the Way
&lt;/h2&gt;

&lt;p&gt;While trying &lt;code&gt;pnpm.overrides&lt;/code&gt;, the local build started failing with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot read properties of null (reading 'useContext')
Cannot read properties of null (reading 'useRef')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Occurring during prerendering of &lt;code&gt;/404&lt;/code&gt; and &lt;code&gt;/500&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt; pnpm was hoisting &lt;code&gt;react@19.2.3&lt;/code&gt; at root but &lt;code&gt;react-dom@18.3.1&lt;/code&gt; at root (pulled in by a transitive dependency from &lt;code&gt;app-2&lt;/code&gt;). Two incompatible React instances in the same &lt;code&gt;node_modules&lt;/code&gt; — classic split brain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; After removing the overrides, regenerating &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; from scratch cleaned up the hoisting and resolved the local build. This was a separate issue from the Amplify problem but surfaced during the same investigation.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Actual Root Cause
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;app-1&lt;/code&gt; and &lt;code&gt;app-2&lt;/code&gt; had different versions of React and Next.js:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;app-1&lt;/th&gt;
&lt;th&gt;app-2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;next&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;15.1.11&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;16.1.4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;react&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^19.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;19.2.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;react-dom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^19.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;19.2.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The version mismatch in Next.js was enough for pnpm to create a conflicting &lt;code&gt;node_modules&lt;/code&gt; layout across the two apps — which Amplify's Lambda runtime couldn't handle at bootstrap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Downgraded &lt;code&gt;app-2&lt;/code&gt;'s Next.js from &lt;code&gt;16.1.4&lt;/code&gt; to &lt;code&gt;15.1.11&lt;/code&gt; and aligned React/react-dom versions to match &lt;code&gt;app-1&lt;/code&gt;. Clean layout, no symlink failures, app running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why It Didn't Fail Locally or on Vercel
&lt;/h2&gt;

&lt;p&gt;To rule out our own code, we deployed the same commit to Vercel — it worked fine. Ran it locally — worked fine. Only Amplify was breaking.&lt;/p&gt;

&lt;p&gt;That's because Node.js and Vercel are both flexible with how they resolve modules at runtime. Amplify's Lambda compute is not — it expects a specific &lt;code&gt;node_modules&lt;/code&gt; layout and breaks silently at the build level but loudly at runtime when that layout doesn't match. - According to Claude 😊&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;If you're running a pnpm monorepo on Amplify SSR and seeing &lt;code&gt;Read-only file system&lt;/code&gt; symlink errors in CloudWatch with a successful build — &lt;strong&gt;check your dependency versions across all apps before debugging Amplify's infrastructure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep React and Next.js versions consistent across all apps in the monorepo. pnpm's hoisting is sensitive to version conflicts, and Amplify's runtime is sensitive to pnpm's hoisting layout.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Added a comment on the related GitHub issue here: &lt;a href="https://github.com/aws-amplify/amplify-hosting/issues/4079" rel="noopener noreferrer"&gt;aws-amplify/amplify-hosting#4079&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>nextjs</category>
      <category>pnpm</category>
      <category>devops</category>
    </item>
    <item>
      <title>i18n with NextJS output export</title>
      <dc:creator>Ikram Ul Haq</dc:creator>
      <pubDate>Tue, 06 Feb 2024 20:44:52 +0000</pubDate>
      <link>https://dev.to/ikramdeveloper/i18n-with-nextjs-output-export-1pbc</link>
      <guid>https://dev.to/ikramdeveloper/i18n-with-nextjs-output-export-1pbc</guid>
      <description>&lt;p&gt;In this post, I'll guide you through the process of setting up &lt;strong&gt;internationalization (i18n)&lt;/strong&gt; in a &lt;strong&gt;Next.js&lt;/strong&gt; project. We'll explore how to integrate i18n with the page router and address the export output option, overcoming challenges where Next.js doesn't provide direct assistance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibnkrkunwwn87o4l9exo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibnkrkunwwn87o4l9exo.png" alt="Next.js does not support i18n with output export" width="667" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To begin, let's initialize a Next.js v14 project with TypeScript. Alternatively, you can opt for JavaScript; either choice works seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing NextJS Project
&lt;/h2&gt;

&lt;p&gt;Execute the following command to set up your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`npx create-next-app@latest`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the setup, you'll encounter several questions; respond based on your preferences. In my case, I opted for the page router and specified the src directory with TypeScript.&lt;/p&gt;

&lt;p&gt;Afterward, include the &lt;code&gt;output: "export"&lt;/code&gt; in the next.config.js file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffwmsy8pp3fiq4csz80d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffwmsy8pp3fiq4csz80d.png" alt="next configuration with output: " width="799" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, remove the &lt;code&gt;api&lt;/code&gt; folder from the &lt;code&gt;pages&lt;/code&gt; directory, as it's incompatible with the &lt;code&gt;output: "export"&lt;/code&gt; configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and Configuring i18n
&lt;/h2&gt;

&lt;p&gt;For internationalization, we'll be utilizing the &lt;a href="https://www.npmjs.com/package/next-translate" rel="noopener noreferrer"&gt;next-translate&lt;/a&gt; package. Although it doesn't inherently support output: export, don't fret – that's where our assistance comes in.&lt;/p&gt;

&lt;p&gt;Begin by installing the &lt;code&gt;next-translate&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`npm i next-translate`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate a file named &lt;code&gt;i18n.ts&lt;/code&gt; or &lt;code&gt;.js&lt;/code&gt; at the project's root level, and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { I18nConfig } from "next-translate";

export const i18nConfig = {
  locales: ["en", "es"],
  defaultLocale: "en",
  loader: false,
  pages: {
    "*": ["common"],
  },
  defaultNS: "common",
} satisfies I18nConfig;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've established the fundamental configuration for i18n. Feel free to customize it based on your specific needs.&lt;/p&gt;

&lt;p&gt;Now, establish a &lt;code&gt;locales&lt;/code&gt; folder at the project's root level. This folder will house translation files for each language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd3m1r3xvj6jfr9tq1o5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd3m1r3xvj6jfr9tq1o5.png" alt="locales folder structure" width="656" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;code&gt;_app.ts&lt;/code&gt; file within the &lt;code&gt;pages&lt;/code&gt; directory, and envelop the &lt;code&gt;Component&lt;/code&gt; with &lt;code&gt;I18nProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "@/styles/globals.css";
import type { AppProps } from "next/app";
import I18nProvider from "next-translate/I18nProvider";
import { i18nConfig } from "../../i18n";
import commonES from "../../locales/es/common.json";
import commonEN from "../../locales/en/common.json";

const App = ({ Component, pageProps, router }: AppProps) =&amp;gt; {
  const lang = i18nConfig.locales.includes(router.query.locale as string)
    ? String(router.query.locale)
    : i18nConfig.defaultLocale;

  return (
    &amp;lt;I18nProvider
      lang={lang}
      namespaces={{ common: lang === "es" ? commonES : commonEN }}
    &amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/I18nProvider&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We enclosed the &lt;code&gt;Component&lt;/code&gt; with &lt;code&gt;I18nProvider&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Detected the language from the route and passed it as a prop to &lt;code&gt;I18nProvider&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Defined the namespace file based on the current language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, generate a custom hook named &lt;code&gt;useI18n.ts&lt;/code&gt; in the &lt;code&gt;src/hooks&lt;/code&gt; directory and insert the code there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import useTranslation from "next-translate/useTranslation";
import { i18nConfig } from "../../i18n";

interface IUseI18n {
  namespace?: string;
}

export const useI18n = ({ namespace }: IUseI18n = {}) =&amp;gt; {
  const { t } = useTranslation(namespace ? namespace : i18nConfig.defaultNS);

  return { t };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook will supply us with translations based on the provided namespace or the default namespace.&lt;/p&gt;

&lt;p&gt;Now, proceed to the &lt;code&gt;index.tsx&lt;/code&gt; file in the &lt;code&gt;pages&lt;/code&gt; directory and include the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useI18n } from "@/hooks/useI18n";

export default function Home() {
  const { t } = useI18n();
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{t("greeting")}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will display something similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0x5w90losm7f8ozuzas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0x5w90losm7f8ozuzas.png" alt="Hello World" width="273" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hurrah! We've successfully configured i18n in our project. However, the language detection aspect is still pending. Let's implement that part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language Detection
&lt;/h2&gt;

&lt;p&gt;As observed earlier, we were fetching the locale value from &lt;code&gt;router.query&lt;/code&gt;. To proceed, establish a folder named &lt;code&gt;[locale]&lt;/code&gt; within the &lt;code&gt;pages&lt;/code&gt; directory. Note that all our route files will be contained within this folder. Create an &lt;code&gt;index.tsx&lt;/code&gt; file in the &lt;code&gt;[locale]&lt;/code&gt; folder and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useI18n } from "@/hooks/useI18n";

const Home = () =&amp;gt; {
  const { t } = useI18n();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{t("greeting")}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Home;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, visiting &lt;code&gt;localhost:3000/en&lt;/code&gt; will display content in English, and changing it to &lt;code&gt;localhost:3000/es&lt;/code&gt; will show content in Spanish. This functionality also seamlessly integrates with dynamic routes.&lt;/p&gt;

&lt;p&gt;The structure of your &lt;code&gt;pages&lt;/code&gt; folder will resemble this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39yib43wqcbuoymyrt4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39yib43wqcbuoymyrt4q.png" alt="Pages folder structure with locale folder" width="268" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's implement language detection using &lt;a href="https://www.npmjs.com/package/next-language-detector" rel="noopener noreferrer"&gt;next-language-detector&lt;/a&gt; to cache our chosen language.&lt;/p&gt;

&lt;p&gt;Begin by installing &lt;code&gt;next-language-detector&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i next-language-detector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a folder named &lt;code&gt;lib&lt;/code&gt; in the &lt;code&gt;src&lt;/code&gt; directory, and within it, generate a file named &lt;code&gt;languageDetector.ts&lt;/code&gt;. Open the file and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import nextLanguageDetector from "next-language-detector";
import { i18nConfig } from "../../i18n";

export const languageDetector = nextLanguageDetector({
  supportedLngs: i18nConfig.locales,
  fallbackLng: i18nConfig.defaultLocale,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate another file named &lt;code&gt;redirect.tsx&lt;/code&gt; in the same &lt;code&gt;lib&lt;/code&gt; folder and insert the following code there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRouter } from "next/router";
import { useEffect } from "react";
import { languageDetector } from "./languageDetector";

export const useRedirect = (to?: string) =&amp;gt; {
  const router = useRouter();
  const redirectPath = to || router.asPath;

  // language detection
  useEffect(() =&amp;gt; {
    const detectedLng = languageDetector.detect();
    if (redirectPath.startsWith("/" + detectedLng) &amp;amp;&amp;amp; router.route === "/404") {
      // prevent endless loop
      router.replace("/" + detectedLng + router.route);
      return;
    }

    if (detectedLng &amp;amp;&amp;amp; languageDetector.cache) {
      languageDetector.cache(detectedLng);
    }
    router.replace("/" + detectedLng + redirectPath);
  });

  return &amp;lt;&amp;gt;&amp;lt;/&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open the &lt;code&gt;index.tsx&lt;/code&gt; file in the &lt;code&gt;pages&lt;/code&gt; directory (outside the &lt;code&gt;[locale]&lt;/code&gt; folder) and replace the existing code with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRedirect } from "@/lib/redirect";

const Redirect = () =&amp;gt; {
  useRedirect();
  return &amp;lt;&amp;gt;&amp;lt;/&amp;gt;;
};

export default Redirect;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If anyone attempts to access the home page without specifying a locale, they will now be redirected to the locale page.&lt;/p&gt;

&lt;p&gt;However, creating a redirection page for all routes within the &lt;code&gt;[locale]&lt;/code&gt; folder may not be the most efficient practice. To address this, let's create a language wrapper that redirects to the route with the language if a user tries to access a page without specifying a language.&lt;/p&gt;

&lt;p&gt;Start by creating a folder named &lt;code&gt;wrappers&lt;/code&gt; inside the &lt;code&gt;src&lt;/code&gt; directory. Within this folder, generate a file named &lt;code&gt;LanguageWrapper.tsx&lt;/code&gt; and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ReactNode, useEffect } from "react";
import { useRouter } from "next/router";
import { languageDetector } from "@/lib/languageDetector";
import { i18nConfig } from "../../i18n";

interface LanguageWrapperProps {
  children: ReactNode;
}

export const LanguageWrapper = ({ children }: LanguageWrapperProps) =&amp;gt; {
  const router = useRouter();
  const detectedLng = languageDetector.detect();

  useEffect(() =&amp;gt; {
    const {
      query: { locale },
      asPath,
      isReady,
    } = router;

    // Check if the current route has accurate locale
    if (isReady &amp;amp;&amp;amp; !i18nConfig.locales.includes(String(locale))) {
      if (asPath.startsWith("/" + detectedLng) &amp;amp;&amp;amp; router.route === "/404") {
        return;
      }

      if (detectedLng &amp;amp;&amp;amp; languageDetector.cache) {
        languageDetector.cache(detectedLng);
      }
      router.replace("/" + detectedLng + asPath);
    }
  }, [router, detectedLng]);

  return (router.query.locale &amp;amp;&amp;amp;
    i18nConfig.locales.includes(String(router.query.locale))) ||
    router.asPath.includes(detectedLng ?? i18nConfig.defaultLocale) ? (
    &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;
  ) : (
    &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add the LanguageWrapper in your _app.tsx file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29bc07vta3ak6cnooiig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29bc07vta3ak6cnooiig.png" alt="_app.tsx file with LanguageWrapper" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're almost done, just a few touches left. Let's create a component named &lt;code&gt;Link.tsx&lt;/code&gt; in the &lt;code&gt;src/components/_shared&lt;/code&gt; directory and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ReactNode } from "react";
import NextLink from "next/link";
import { useRouter } from "next/router";

interface LinkProps {
  children: ReactNode;
  skipLocaleHandling?: boolean;
  locale?: string;
  href: string;
  target?: string;
}

export const Link = ({
  children,
  skipLocaleHandling,
  target,
  ...rest
}: LinkProps) =&amp;gt; {
  const router = useRouter();
  const locale = rest.locale || (router.query.locale as string) || "";

  let href = rest.href || router.asPath;
  if (href.indexOf("http") === 0) skipLocaleHandling = true;
  if (locale &amp;amp;&amp;amp; !skipLocaleHandling) {
    href = href
      ? `/${locale}${href}`
      : router.pathname.replace("[locale]", locale);
  }

  return (
    &amp;lt;NextLink href={href} target={target}&amp;gt;
      {children}
    &amp;lt;/NextLink&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will utilize this &lt;code&gt;Link&lt;/code&gt; component throughout our project instead of next/link component.&lt;/p&gt;

&lt;p&gt;Now, create a file named &lt;code&gt;useRouteRedirect.ts&lt;/code&gt; in the &lt;code&gt;hooks&lt;/code&gt; folder and insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRouter } from "next/router";
import { i18nConfig } from "../../i18n";
import { languageDetector } from "@/lib/languageDetector";

export const useRouteRedirect = () =&amp;gt; {
  const router = useRouter();

  const redirect = (to: string, replace?: boolean) =&amp;gt; {
    const detectedLng = i18nConfig.locales.includes(String(router.query.locale))
      ? String(router.query.locale)
      : languageDetector.detect();
    if (to.startsWith("/" + detectedLng) &amp;amp;&amp;amp; router.route === "/404") {
      // prevent endless loop
      router.replace("/" + detectedLng + router.route);
      return;
    }

    if (detectedLng &amp;amp;&amp;amp; languageDetector.cache) {
      languageDetector.cache(detectedLng);
    }
    if (replace) {
      router.replace("/" + detectedLng + to);
    } else {
      router.push("/" + detectedLng + to);
    }
  };

  return { redirect };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use this custom hook instead of &lt;code&gt;router.push&lt;/code&gt; and &lt;code&gt;router.replace&lt;/code&gt; as illustrated below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fence2oltrv1xrk67ig8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fence2oltrv1xrk67ig8v.png" alt="Usage of useRouteRedirect hook" width="799" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, create a &lt;code&gt;LanguageSwitcher.tsx&lt;/code&gt; component in the &lt;code&gt;src/components&lt;/code&gt; directory to switch to a specific language with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { languageDetector } from "@/lib/languageDetector";
import { useRouter } from "next/router";
import Link from "next/link";

interface LanguageSwitcherProps {
  locale: string;
  href?: string;
  asPath?: string;
}

export const LanguageSwitcher = ({
  locale,
  ...rest
}: LanguageSwitcherProps) =&amp;gt; {
  const router = useRouter();

  let href = rest.href || router.asPath;
  let pName = router.pathname;
  Object.keys(router.query).forEach((k) =&amp;gt; {
    if (k === "locale") {
      pName = pName.replace(`[${k}]`, locale);
      return;
    }
    pName = pName.replace(`[${k}]`, String(router.query[k]));
  });
  if (locale) {
    href = rest.href ? `/${locale}${rest.href}` : pName;
  }

  return (
    &amp;lt;Link
      href={href}
      onClick={() =&amp;gt;
        languageDetector.cache ? languageDetector.cache(locale) : {}
      }
    &amp;gt;
      &amp;lt;button style={{ fontSize: "small" }}&amp;gt;{locale}&amp;lt;/button&amp;gt;
    &amp;lt;/Link&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You have successfully implemented i18n in your Next.js project with &lt;code&gt;output: export&lt;/code&gt;. Keep in mind that if you want to load translations from different namespaces, like the 'dynamic' namespace, you'll need to define the namespaces and their translation files in &lt;code&gt;_app.tsx&lt;/code&gt; within the &lt;code&gt;I18nProvider&lt;/code&gt; component:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw68zgdlq0mmqsfdawaax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw68zgdlq0mmqsfdawaax.png" alt="Loading namespace files according to the current language" width="800" height="780"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before testing it after creating a build, first, create a &lt;code&gt;404.tsx&lt;/code&gt; file in the &lt;code&gt;pages&lt;/code&gt; directory with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FC, useEffect, useState } from "react";
import { NextRouter, useRouter } from "next/router";
import { getRouteRegex } from "next/dist/shared/lib/router/utils/route-regex";
import { getClientBuildManifest } from "next/dist/client/route-loader";
import { parseRelativeUrl } from "next/dist/shared/lib/router/utils/parse-relative-url";
import { isDynamicRoute } from "next/dist/shared/lib/router/utils/is-dynamic";
import { removeTrailingSlash } from "next/dist/shared/lib/router/utils/remove-trailing-slash";
import { Link } from "@/components/_shared/Link";

async function getPageList() {
  if (process.env.NODE_ENV === "production") {
    const { sortedPages } = await getClientBuildManifest();
    return sortedPages;
  } else {
    if (typeof window !== "undefined" &amp;amp;&amp;amp; window.__BUILD_MANIFEST?.sortedPages) {
      console.log(window.__BUILD_MANIFEST.sortedPages);
      return window.__BUILD_MANIFEST.sortedPages;
    }
  }
  return [];
}

async function getDoesLocationMatchPage(location: string) {
  const pages = await getPageList();

  let parsed = parseRelativeUrl(location);
  let { pathname } = parsed;
  return pathMatchesPage(pathname, pages);
}

function pathMatchesPage(pathname: string, pages: string[]) {
  const cleanPathname = removeTrailingSlash(pathname);

  if (pages.includes(cleanPathname)) {
    return true;
  }

  const page = pages.find(
    (page) =&amp;gt; isDynamicRoute(page) &amp;amp;&amp;amp; getRouteRegex(page).re.test(cleanPathname)
  );

  if (page) {
    return true;
  }
  return false;
}

/**
 * If both asPath and pathname are equal then it means that we
 * are on the correct route it still doesnt exist
 */
function doesNeedsProcessing(router: NextRouter) {
  const status = router.pathname !== router.asPath;
  console.log("Does Needs Processing", router.asPath, status);
  return status;
}

const Custom404 = () =&amp;gt; {
  const router = useRouter();

  const [isNotFound, setIsNotFound] = useState(false);

  const processLocationAndRedirect = async (router: NextRouter) =&amp;gt; {
    if (doesNeedsProcessing(router)) {
      const targetIsValidPage = await getDoesLocationMatchPage(router.asPath);
      if (targetIsValidPage) {
        await router.replace(router.asPath);
        return;
      }
    }
    setIsNotFound(true);
  };

  useEffect(() =&amp;gt; {
    if (router.isReady) {
      processLocationAndRedirect(router);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [router.isReady]);

  if (!isNotFound) return null;

  return (
    &amp;lt;div className="fixed inset-0 flex justify-center items-center"&amp;gt;
      &amp;lt;div className="flex flex-col gap-10"&amp;gt;
        &amp;lt;h1&amp;gt;Custom 404 - Page Not Found&amp;lt;/h1&amp;gt;
        &amp;lt;Link href="/"&amp;gt;
          &amp;lt;button&amp;gt;Go to Home Page&amp;lt;/button&amp;gt;
        &amp;lt;/Link&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Custom404;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To resolve page not found errors for dynamic routes, the inclusion of a &lt;code&gt;404.tsx&lt;/code&gt; file in the &lt;code&gt;pages&lt;/code&gt; directory is essential.&lt;/p&gt;

&lt;p&gt;Additionally, add the following command to your &lt;code&gt;package.json&lt;/code&gt; file to execute the code after creating the build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serve out/ -p 3000"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure the &lt;code&gt;serve&lt;/code&gt; package is installed if it's not already present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running &lt;code&gt;npm run build&lt;/code&gt; and then &lt;code&gt;npm run preview&lt;/code&gt;, you can access your project on port 3000.&lt;/p&gt;

&lt;p&gt;The complete code can be found on &lt;a href="https://github.com/ikramdeveloper/i18n-nextjs-output-export" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Some tweaks have been added there, so make sure to check it out.&lt;/p&gt;

&lt;p&gt;Feel free to comment if anything is missing or if you encounter any errors. I'm here to assist you. Thanks!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>i18n</category>
      <category>internationalization</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
