<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Ayantunji Timilehin - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Ayantunji Timilehin - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:47:50 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/timmy471/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Next.js Web Apps for Better Performance ]]>
                </title>
                <description>
                    <![CDATA[ As engineers, we often get so carried away with other aspects of development that we overlook how users perceive and interact with our applications. This oversight can result in users leaving the app almost as soon as they arrive, leading to higher b... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/optimize-nextjs-web-apps-for-better-performance/</link>
                <guid isPermaLink="false">6776a323218b455d646035b2</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Performance Optimization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ optimization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayantunji Timilehin ]]>
                </dc:creator>
                <pubDate>Thu, 02 Jan 2025 14:30:59 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735828217839/b65374be-d891-4f19-a359-f84f2ac8f3b9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As engineers, we often get so carried away with other aspects of development that we overlook how users perceive and interact with our applications. This oversight can result in users leaving the app almost as soon as they arrive, leading to higher bounce rates and minimal engagement.</p>
<p>At its core, every business thrives on delivering value to its users. When users are unable to access this value due to poor performance, it ultimately impacts the business's success. Slow load times, among other factors, frustrate users and drive them away before they even get a chance to engage.</p>
<p>Optimizing performance is more than just a technical detail – it’s also a critical part of creating a successful application. Without it, even the best features can go unnoticed if users don’t stick around long enough to see them.</p>
<p>In this article, we’ll explore key approaches to optimize your Next.js application, making it faster and more efficient.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-building-a-performant-app">Building a Performant Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-your-applications">How to Optimize Your Applications</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-techniques-to-optimize-performance">Key Techniques To Optimize Performance</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-using-the-nextjs-image-component">Using The Next.js Image Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-optimizing-third-party-scripts-with-the-nextjs-script-component">Optimizing Third-Party Scripts with the Next.js Script Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-remove-unused-packagesdependencies">Remove Unused Packages/Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-caching-and-incremental-static-regeneration-isr">Caching and Incremental Static Regeneration (ISR)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-caching-frequently-used-content">Caching Frequently Used Content</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-font-optimization-with-nextfont">Font Optimization With next/font</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-lazy-loading-and-code-splitting">Lazy Loading And Code Splitting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lazy-loading-in-nextjs">Lazy Loading in Next.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-code-splitting">Code Splitting</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-building-a-performant-application">Building a Performant Application</h2>
<p>Making your apps more performant means striking the right balance between speed, responsiveness, and efficient use of resources. You should strive to create an application that delivers value and keeps users satisfied.</p>
<p>Building a performant app is about making sure the app feels smooth and intuitive so that there are no frustrating lags when a user clicks buttons, scrolls, or navigates around. You’ll also want to make sure that data loads or updates without unnecessary delays.</p>
<h2 id="heading-how-to-optimize-your-applications">How to Optimize Your Applications</h2>
<p>The first step in optimizing your application is identifying problem areas. A number of tools and packages can help you analyze your application's performance effectively. Here's how you can use them:</p>
<h3 id="heading-using-npm-run-build">Using <code>npm run build</code></h3>
<p>When you run <code>npm run build</code>, Next.js creates a production-ready version of your application and gives a detailed breakdown of your pages. This includes:</p>
<ul>
<li><p><strong>Size</strong>: The size of the JavaScript files for each route. Highlighting any routes that are too large and could slow things down. Smaller page sizes generally result in faster load times while large pages might take longer to download, especially for users with slower network connections.</p>
</li>
<li><p><strong>First Load Js</strong>: This column provides information about the total amount of JavaScript the browser needs to download and execute to fully render the page for the first time. Large <strong>First Load JS</strong> values</p>
<p>  cause Slower Time-to-Interactive (TTI).</p>
</li>
</ul>
<p>Running this command produces an analysis like below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734639730677/cfd1f858-a9df-4e6c-af28-454857309156.png" alt="Example result of running npm run build" class="image--center mx-auto" width="984" height="300" loading="lazy"></p>
<h3 id="heading-using-nextbundle-analyzer">Using <code>@next/bundle-analyzer</code></h3>
<p>The <a target="_blank" href="https://www.npmjs.com/package/@next/bundle-analyzer">bundle analyzer</a> is a package provided by Next.js to analyze the size of JavaScript bundles by providing a visual representation of the application’s module and dependencies. Here’s how to use the package:</p>
<p>First, install the package by running this command:</p>
<pre><code class="lang-bash">npm install @next/bundle-analyzer
</code></pre>
<p>Or you can use yarn:</p>
<pre><code class="lang-bash">yarn add @next/bundle-analyzer
</code></pre>
<p>Then add the <code>@next/bundle-analyzer</code> configuration to your <code>next.config.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> withBundleAnalyzer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@next/bundle-analyzer'</span>)({
  <span class="hljs-attr">enabled</span>: process.env.ANALYZE === <span class="hljs-string">'true'</span>,
});

<span class="hljs-built_in">module</span>.exports = withBundleAnalyzer({
  <span class="hljs-comment">// other Next.js config options here</span>
});
</code></pre>
<p>To analyze your application bundles while generating a production build, run the following command:</p>
<pre><code class="lang-bash">ANALYZE=<span class="hljs-literal">true</span> npm run build
</code></pre>
<p>For a step-by-step guide on how to use the bundle analyzer effectively, check out this detailed <a target="_blank" href="https://www.youtube.com/watch?v=EIGmcxwbbZw">video tutorial</a></p>
<h3 id="heading-browser-tools">Browser tools</h3>
<p>Finally, modern browsers, including Google Chrome, Firefox, and Edge, offer powerful tools to analyze and improve your application's performance. Features like the Performance Tab help you record and visualize how your application runs, pinpointing issues like slow rendering or long tasks.</p>
<p>You can also use tools like Lighthouse (available in Chrome and Edge) to generate automated audits, highlighting problems such as large assets and unoptimized resources.</p>
<p>To access the <strong>Lighthouse</strong> and <strong>Performance</strong> tabs:</p>
<ol>
<li><p>Open your browser's developer tools by right-clicking anywhere on the browser and selecting the <strong>Inspect</strong> option or pressing <strong>Command + Option + I</strong> (on Mac) or <strong>Ctrl + Shift + I</strong> (on Windows).</p>
</li>
<li><p>Look at the top menu in the developer tools.</p>
</li>
<li><p>If you don’t see the <strong>Lighthouse</strong> or <strong>Performance</strong> tabs right away, click the <strong>double right arrow (&gt;&gt;)</strong> to reveal hidden tabs.</p>
</li>
<li><p>Select the desired tab to start analyzing performance or generating a Lighthouse report.</p>
</li>
</ol>
<p>Here is an example of a generated audit in the Performance tab on Chrome</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735616911745/e5f09934-df99-40fc-b194-a292a21a4517.png" alt="image of the performance tab on chrome browser" class="image--center mx-auto" width="1130" height="966" loading="lazy"></p>
<p>Here’s another image showing the generated audit by lighthouse</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735617075187/dfde608b-eeb7-443d-81c6-56ff2a6dd92b.png" alt="dfde608b-eeb7-443d-81c6-56ff2a6dd92b" class="image--center mx-auto" width="1124" height="1522" loading="lazy"></p>
<h2 id="heading-key-techniques-to-optimize-performance">Key Techniques to Optimize Performance</h2>
<h3 id="heading-1-using-the-nextjs-image-component">1.) Using The Next.js <code>Image</code> Component</h3>
<p>Images often account for the largest portion of page weight, directly affecting load times and user experience. Large images slow down rendering and ultimately, increase bandwidth usage.</p>
<p>Next.js has a built-in <code>Image</code> component that automatically optimizes images, making it very useful for web performance. It takes care of resizing, lazy loading, and format optimization, so images are served in the most performant format (like .WebP) when the browser supports it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">"/house.jpg"</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">"House Image"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">{700}</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">{500}</span>
      <span class="hljs-attr">priority</span>=<span class="hljs-string">{false}</span> // <span class="hljs-attr">Lazy</span> <span class="hljs-attr">loads</span> <span class="hljs-attr">the</span> <span class="hljs-attr">image</span> <span class="hljs-attr">by</span> <span class="hljs-attr">default</span>
    /&gt;</span></span>
</code></pre>
<p>In the snippet above,</p>
<ul>
<li><p><code>src="/house.jpg"</code>: This points to the image file's location, which is in the <code>public</code> folder. Images in the <code>/public</code> directory are served statically, so you don’t need extra configuration.</p>
</li>
<li><p><code>alt="House Image"</code>: The <code>alt</code> text (just like in the native HTML <code>image</code> element) provides a description of the image, which is great for accessibility (like screen readers) and also helps with SEO.</p>
</li>
<li><p><code>width &amp; heigh</code>t: By explicitly setting the width and height, Next.js can calculate the space the image will occupy on the page before it loads. This prevents the page layout from shifting as the image loads, which improves user experience and boosts performance metrics like <a target="_blank" href="https://blog.hubspot.com/marketing/cumulative-layout-shift">Cumulative Layout Shift</a> (as shown in the image above).</p>
</li>
<li><p><code>priority={false}</code>: This ensures the image will only load when it's near the user's viewport conserving the bandwidth and improving page load times for non-critical images. However, for important images that should load immediately (like those visible as soon as the page opens), you can set <code>priority={true}</code> to bypass lazy loading and ensure the image loads as quickly as possible.</p>
</li>
</ul>
<p>One of the key advantages of the Next.js <code>Image</code> component is its built-in <strong>lazy loading</strong> feature. This means that images won’t be loaded until they are actually needed (when they enter the viewport). By only loading images that are about to be viewed, performance is improved and pages can load faster, even with many high-quality images.</p>
<h3 id="heading-2-optimizing-third-party-scripts-with-the-nextjs-script-component">2.) Optimizing Third-Party Scripts with the Next.js Script Component</h3>
<p>Third-party scripts, such as analytics tools or advertising networks, can heavily affect your application's performance if not properly managed. Next.js has a <strong>Script</strong> component that makes it easy to load scripts efficiently, giving you control over how and when they load.</p>
<p>The <code>Script</code> component allows you to define a <strong>loading strategy</strong> for scripts, determining when and how they are fetched and executed. By prioritizing or deferring scripts based on their importance, you can improve the overall performance and user experience of your application.</p>
<ul>
<li><p><code>beforeInteractive</code><strong>:</strong> Use this strategy for scripts that must load before the page becomes interactive, like essential analytics or monitoring tools.</p>
</li>
<li><p><code>afterInteractive</code>: When you use this strategy, the script loads after the page becomes interactive, which is the default behavior. This is ideal for scripts that add functionality but aren’t essential for initial rendering.</p>
</li>
<li><p><code>lazyOnload</code>: Defers loading the script until all other page resources have finished loading. This is perfect for non-essential scripts like ads or social media widgets.</p>
</li>
</ul>
<pre><code class="lang-javascript">&lt;Script src=<span class="hljs-string">"https://example.com/non-essential.js"</span> strategy=<span class="hljs-string">"lazyOnload"</span> /&gt; <span class="hljs-comment">//Pass the strategy as a prop to the component</span>
</code></pre>
<p>By leveraging the Next.js <code>Script</code> component, you can prevent scripts from blocking critical rendering, reducing load times and improve <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Time_to_interactive">Time to Interactive</a> (TTI).</p>
<h3 id="heading-3-remove-unused-packagesdependencies">3.) Remove Unused Packages/Dependencies</h3>
<p>Over time, as you build and maintain your project, unused dependencies can pile up in your codebase. These unnecessary packages increase the size of your project, slow down installation times, and make the code harder to maintain. Cleaning up these unused dependencies is essential for optimizing your application's performance and keeping your codebase clean.</p>
<p>The <a target="_blank" href="https://www.npmjs.com/package/depcheck">depcheck</a> tool is a great way to identify and remove unused dependencies from your project. It analyzes your <code>package.json</code> and the project files to find unused dependencies, unused devDependencies, and missing dependencies.</p>
<p>You can run a <code>depcheck</code> like this:</p>
<pre><code class="lang-bash">npx depcheck
</code></pre>
<p>After identifying the unused dependencies, you can remove them by running:</p>
<pre><code class="lang-bash">npm uninstall &lt;package-name&gt;
</code></pre>
<p>or with yarn:</p>
<pre><code class="lang-bash">yarn remove &lt;package-name&gt;
</code></pre>
<p>Regularly running <code>depcheck</code> is a simple yet effective way to keep your project clean and efficient.</p>
<h3 id="heading-4-caching-and-incremental-static-regeneration-isr">4.) Caching and Incremental Static Regeneration (ISR)</h3>
<p>When you find yourself running the same calculations or database queries repeatedly, you should consider caching. It’s a simple yet powerful way to boost your web application's performance, especially for content that doesn’t change often. By storing frequently accessed data in a cache, you can avoid unnecessary processing and speed up load times.</p>
<p>In Next.js, you can take this a step further with Incremental Static Regeneration (ISR), which lets you serve static content instantly while keeping it fresh behind the scenes.</p>
<p><strong>Incremental Static Regeneration (ISR)</strong> in Next.js lets you update static pages without rebuilding the whole site. Here's how it works:</p>
<ol>
<li><p><strong>Build time generation</strong>: ISR generates pages when the site is built.</p>
</li>
<li><p><strong>Caching</strong>: It stores the pages so they load quickly when users visit.</p>
</li>
<li><p><strong>Background updates</strong>: When content changes, ISR updates the pages behind the scenes without affecting users.</p>
</li>
<li><p><strong>Dynamic updates</strong>: It combines the fast loading of static pages with the ability to update content regularly.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { data },
    <span class="hljs-comment">//regenerate the page every 20 seconds.</span>
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">20</span>,
  };
}

<span class="hljs-comment">//pre-render the page as static content</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyPage</span>(<span class="hljs-params">{ data }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyPage;
</code></pre>
<h3 id="heading-caching-frequently-used-content">Caching Frequently Used Content</h3>
<p>For websites with pages that get a lot of visitors, like product listings or blog posts, it's important to keep the content fast and up-to-date.</p>
<p>Caching helps achieve this by saving a copy of the page so it doesn't need to be created from scratch each time someone visits. The browser or server will store this cached page for a set amount of time, which is controlled by caching headers. Meanwhile, ISR (Incremental Static Regeneration) ensures that the page can be updated in the background when necessary, without needing to rebuild the entire site.</p>
<p>In applications with lots of data, caching can also speed up the process by storing API responses. This way, when users request the same data again, they can get it quickly from the cache instead of waiting for it to be fetched anew. Tools like Vercel and Content Delivery Networks (CDNs) help by storing these cached pages in multiple locations around the world, so visitors can access them faster.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { data },
    <span class="hljs-comment">// Regenerate page at most once every 30 seconds</span>
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">30</span>,
    <span class="hljs-comment">// Cache for 1 hour at the CDN level</span>
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'public, max-age=3600, must-revalidate'</span>,
    },
  };
}
</code></pre>
<p>Here, the page regenerates every 30 seconds and is cached at the CDN level for one hour. The <code>Cache-Control</code> header tells the CDN and browser to cache the page for 1 hour and revalidate it afterward.</p>
<p>For a deeper dive into caching and its role in web performance, check out this insightful <a target="_blank" href="https://www.freecodecamp.org/news/caching-vs-content-delivery-network/">freeCodeCamp article on Caching vs. Content Delivery Networks</a>.</p>
<h3 id="heading-5-font-optimization-with-nextfont">5.) Font Optimization With <code>next/font</code></h3>
<p>The <code>next/font</code> module in Next.js automatically handles font loading for improved performance, so you don’t need to manually configure or use extra libraries. It loads only the essential parts of the font, which results in faster page load times.</p>
<p>To further reduce the font file size, you can provide the <code>subsets</code> array which ensures fewer bytes are transferred and pages load quickly.</p>
<p>Here’s how it works:</p>
<ul>
<li><p><strong>Automatic font loading</strong>: The module optimizes font loading automatically, making sure fonts are served in the most efficient way, improving performance without extra effort.</p>
</li>
<li><p><strong>Subsetting fonts</strong>: You can specify the exact font characters needed for your app.</p>
</li>
<li><p><strong>Font display strategy</strong>: The font-display strategy determines how text is shown to the user while fonts are loading. Next.js typically uses the <code>swap</code> strategy by default, but you can manually configure it if necessary. The most common strategies are <code>swap</code> <code>fallback</code> <code>optional</code> and <code>block</code>.</p>
</li>
<li><pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>

  <span class="hljs-keyword">const</span> inter = Inter({
    <span class="hljs-attr">subsets</span>: [<span class="hljs-string">'latin'</span>, <span class="hljs-string">'latin-ext'</span>], <span class="hljs-comment">// Load only the Latin and extended Latin subsets</span>
    <span class="hljs-attr">weight</span>: <span class="hljs-string">'400'</span>, <span class="hljs-comment">// Choose the specific weight you need</span>
    <span class="hljs-attr">style</span>: <span class="hljs-string">'normal'</span>, <span class="hljs-comment">// Specify the style if needed</span>
  })

  <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{inter.className}</span>&gt;</span>Hello World<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  }
</code></pre>
</li>
</ul>
<p>The snippet above uses the Next.js built-in tool for Google Fonts. Instead of adding the font link in your HTML or using a third-party library, you can import it directly like this for ease and efficiency.s</p>
<ul>
<li><p><strong>subsets:</strong> Tells the app to load only the characters needed. Skipping other character sets like Cyrillic (used in Russian) or Greek, avoids downloading extra, unnecessary data, which keeps your app lightweight and faster to load.</p>
</li>
<li><p><strong>weight:</strong> Instead of loading all font weights (e.g., Bold, Light), you only bring in Regular (400). This reduces the overall size.</p>
</li>
<li><p><strong>style:</strong> Stick with the standard style (no fancy italics). This also trims down what’s downloaded.</p>
</li>
</ul>
<h3 id="heading-6-lazy-loading-and-code-splitting">6.) Lazy Loading and Code Splitting</h3>
<p>When building web apps, you want to make sure your users don’t wait too long for your pages to load. A big part of this involves reducing how much JavaScript is loaded when the page first opens. Two techniques that help with this are <strong>lazy loading</strong> and <strong>code splitting</strong>, both of which Next.js makes easy to use.</p>
<h4 id="heading-lazy-loading-in-nextjs">Lazy Loading in Next.js</h4>
<p>Think of lazy loading like waiting to download a movie only when you decide to watch it. Imagine you have a large component like a chart or a map that users only see after interacting with a page. Instead of loading it upfront, you can tell Next.js to load it only when it’s needed using <code>next/dynamic</code>.</p>
<h4 id="heading-code-splitting-in-nextjs">Code Splitting in Next.js</h4>
<p>Code splitting breaks your JavaScript into smaller pieces (called bundles), so users only load what’s necessary. For example, if a user visits your homepage, there’s no need to load JavaScript for other pages like "About Us" or "Dashboard". It typically happens during the build process or dynamically at runtime.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>

<span class="hljs-comment">// Load HeavyComponent only when it’s rendered</span>
<span class="hljs-keyword">const</span> HeavyComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./HeavyComponent'</span>), { <span class="hljs-attr">ssr</span>: <span class="hljs-literal">false</span> })

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome Home!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">HeavyComponent</span> /&gt;</span> {/* This loads only when rendered */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>In the above code, <code>dynamic</code> dynamically imports the component only when needed. <code>ssr: false</code> disables server-side rendering for the component, which can save resources if the component doesn’t need to be pre-rendered.</p>
<p>Next.js automatically splits code by page, meaning each page only loads the necessary JavaScript when accessed, improving load times. For more granular control, <code>next/dynamic</code> allows you to dynamically import specific components, ensuring they are loaded lazily only when needed. While Next.js handles page-level code splitting by default, using <code>next/dynamic</code> gives you the flexibility to apply component-level splitting, optimizing resource loading and enhancing performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating a high-performance application is a very important aspect of any business. A faster and more efficient application enhances user engagement, lowers bounce rates, and boosts SEO rankings, which all contribute to business growth and customer satisfaction.</p>
<p>By utilizing these techniques we discussed in this guide, you can provide a smooth user experience while maintaining optimal efficiency behind the scenes.</p>
<p>Remember, every second saved in load time translates to happier users and, ultimately, better business outcomes.</p>
<p>Thank you for reading!</p>
<p>Want to connect with me?</p>
<ul>
<li><p>Twitter / X: <a target="_blank" href="https://x.com/Timi471">@timi471</a></p>
</li>
<li><p>Linkedin: <a target="_blank" href="https://www.linkedin.com/in/timilehin-micheal/">Ayantunji Timilehin</a></p>
</li>
<li><p>Email: ayantunjitimilehin@gmail.com</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://nextjs.org/docs/pages/building-your-application/optimizing">Next.Js Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/caching-vs-content-delivery-network/">Caching-vs-content-delivery-network</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=EIGmcxwbbZw">Using next/bundle-analyzer</a></p>
</li>
<li><p><a target="_blank" href="https://blog.hubspot.com/marketing/cumulative-layout-shift">Cumulative layout shift</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Multilingual Apps with i18n in React ]]>
                </title>
                <description>
                    <![CDATA[ I recently worked on an exciting project that involved creating a website capable of switching between languages to appeal to a broader audience. This made me understand the concept of "localization" better, which typically entails adapting content t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-multilingual-apps-with-i18n-in-react/</link>
                <guid isPermaLink="false">6750aec5bb4ed9c12f206d7d</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ localization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayantunji Timilehin ]]>
                </dc:creator>
                <pubDate>Wed, 04 Dec 2024 19:34:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733137904769/d29dd9ea-5794-4fbe-ac1c-066f6a216cb2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I recently worked on an exciting project that involved creating a website capable of switching between languages to appeal to a broader audience. This made me understand the concept of "localization" better, which typically entails adapting content to make it relevant, accessible, and relatable for users in different languages and regions.</p>
<p>Localization isn’t just about translating words, it’s about creating an experience that makes users feel at home, no matter their language. For example, global platforms like Amazon make language switching so seamless that it feels almost magical. Beyond enhancing user experience, this feature plays a crucial role in boosting businesses by reaching a wider audience and fostering stronger connections with customers worldwide.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-table-of-contents">Table of Contents</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-i18n-and-why-use-it">What is i18n, and Why Use It?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lets-dive-right-in">Let’s dive right in</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-how-to-set-up-the-project">Step 1: How to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-how-to-set-up-internationalization-with-i18next">Step 2: How to Set Up Internationalization with i18next</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-how-to-build-components">Step 3: How to Build Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-main-app-component">Step 4: Main App Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-references">References</a></p>
</li>
</ul>
<h2 id="heading-what-is-i18n-and-why-use-it">What is i18n, and Why Use It?</h2>
<p>i18n, short for internationalization, means that an application supports multiple languages. "i18n" is derived from the fact that there are 18 letters between the first "i" and the last "n" in "internationalization." It’s all about making your app adaptable for global audiences by handling text translation, formatting dates and numbers, managing currencies, and accommodating regional conventions.</p>
<p>By enabling internationalization, your app becomes not just a tool but an inclusive platform that speaks directly to a user’s preference and culture.</p>
<h2 id="heading-lets-dive-right-in">Let’s dive right in</h2>
<p>We’ll create a very simple demo multilingual web application with a dark mode toggle feature to demonstrate how to achieve this concept.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ol>
<li><p>Basic Knowledge of React - You should understand how to create components, manage state, and use Hooks like <code>useState</code> and <code>useEffect</code>. If you’re new to React, I recommend starting with <a target="_blank" href="https://react.dev/">the official React docs</a> <a target="_blank" href="https://react.dev/">for a solid foundation</a>.</p>
</li>
<li><p>Familiarity with Internationalization Concepts - Knowing the basics of internationalization (i18n) and why it’s important will give you context for the project. This article's earlier sections cover the essentials.</p>
</li>
<li><p>Tailwind CSS - We'll use Tailwind CSS for styling. It's a utility-first CSS framework that helps you build modern, responsive designs without leaving your HTML. If you’re unfamiliar, check out <a target="_blank" href="https://tailwindcss.com/docs/installation">Tailwind's documentatio</a><a target="_blank" href="https://tailwindcss.com/docs/installation">n.</a></p>
</li>
<li><p>Node.js - Make sure Node.js is installed on your system to handle dependencies. You can download the latest version from <a target="_blank" href="https://nodejs.org/">Node.js</a>.</p>
</li>
<li><p>Package Manager - Either npm (included with Node.js) or yarn is needed to manage project dependencies</p>
</li>
</ol>
<h3 id="heading-tools-well-be-using">Tools we’ll be using</h3>
<ol>
<li><p>Code Editor</p>
</li>
<li><p>Localization Library: <a target="_blank" href="https://www.i18next.com/">react-i18next</a></p>
</li>
<li><p>Icons Library: <a target="_blank" href="https://www.npmjs.com/package/heroicons">hero-icons</a></p>
</li>
</ol>
<h2 id="heading-step-1-how-to-set-up-the-project">Step 1: How to Set Up the Project</h2>
<h3 id="heading-initialize-the-project">Initialize the Project</h3>
<p>Use Vite for fast setup:</p>
<pre><code class="lang-bash">npm create vite@latest multilingual-demo
</code></pre>
<p>Follow the instructions that show up in your terminal, selecting React and TypeScript for development as shown in the image below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733093238523/2d3ee169-bc99-4498-9779-b07067d5e5ee.png" alt="Image of React and Typescript installation" class="image--center mx-auto" width="1112" height="326" loading="lazy"></p>
<h3 id="heading-install-dependencies">Install Dependencies</h3>
<p>Run the following commands in your terminal to install the dependencies required for this project:</p>
<pre><code class="lang-bash">npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend heroicons 
npm install tailwindcss postcss autoprefixer  
npx tailwindcss init
</code></pre>
<h3 id="heading-configure-tailwindcss"><strong>Configure TailwindCSS</strong></h3>
<p>Update the <code>tailwind.config.ts</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/** @type {import('tailwindcss').Config} */</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  content: [<span class="hljs-string">"./src/**/*.{js,jsx,ts,tsx}"</span>],
  darkMode: <span class="hljs-string">"class"</span>, <span class="hljs-comment">//For our dark mode functionality</span>
  theme: {
    container: {
      center: <span class="hljs-literal">true</span>,
      padding: <span class="hljs-string">"1.25rem"</span>,
      screens: {
        sm: <span class="hljs-string">"1200px"</span>,
      },
    },
    extend: {},
  },
  plugins: [],
};
</code></pre>
<p>Add TailwindCSS to <code>src/index.css</code>:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;  
<span class="hljs-keyword">@tailwind</span> components;  
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<h2 id="heading-step-2-how-to-set-up-internationalization-with-i18next">Step 2: How to Set Up Internationalization with i18next</h2>
<h3 id="heading-initialize-i18next"><strong>Initialize i18next</strong></h3>
<p>Create an <code>i18n.tsx</code> file in the <code>src</code> folder and configure i18next:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> i18next <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next"</span>;
<span class="hljs-keyword">import</span> LanguageDetector <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next-browser-languagedetector"</span>;
<span class="hljs-keyword">import</span> { initReactI18next } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;
<span class="hljs-keyword">import</span> Backend <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next-http-backend"</span>;

i18next.use(LanguageDetector).use(initReactI18next).use(Backend).init({
  returnObjects: <span class="hljs-literal">true</span>,
  fallbackLng: <span class="hljs-string">"en"</span>, <span class="hljs-comment">// Language to fallback to if the selected is not configured</span>
  debug: <span class="hljs-literal">true</span>, <span class="hljs-comment">//To enable us see errors</span>
  <span class="hljs-comment">//   lng: "en", //Default language as english</span>
});
</code></pre>
<p>Let’s take a quick look at the contents of this file, as it plays a key role in enabling the translation functionality. This file is responsible for setting up the core of the translation process and making sure that the language-switching feature works smoothly across your app.</p>
<ul>
<li><p><code>i18next</code>: The core internalization library we’re using for translation.</p>
</li>
<li><p><code>LanguageDetector</code>: Helps us detect the user's preferred language automatically, based on browser settings.</p>
</li>
<li><p><code>initReactI18next</code>: Is responsible for integrating the <code>i18next</code> plugin with React and provides Hooks like the <code>useTranslation</code> Hook and other utilities.</p>
</li>
<li><p><code>Backend</code>: Fetches translation data dynamically from an external source. In this case, we’ll be using JSON files.</p>
</li>
</ul>
<p>Import this file into the <code>main.tsx</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//main.tsx</span>

<span class="hljs-keyword">import</span> React, { StrictMode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.tsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./i18n.tsx"</span>;  <span class="hljs-comment">//Import here</span>

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)!).render(
  &lt;StrictMode&gt;
    &lt;React.Suspense fallback=<span class="hljs-string">"loading"</span>&gt;
      &lt;App /&gt;
    &lt;/React.Suspense&gt;
  &lt;/StrictMode&gt;
);
</code></pre>
<h3 id="heading-create-translation-files"><strong>Create Translation Files</strong></h3>
<p>In the <code>public/locales</code> directory, create subfolders for each language (for example, <code>en</code>, <code>fr</code>) and include <code>translation.json</code> files:</p>
<p><code>en/translation.json</code></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"greeting"</span>: <span class="hljs-string">"Welcome to the Language Playground"</span>,
    <span class="hljs-attr">"detail"</span>: {
        <span class="hljs-attr">"line1"</span>: <span class="hljs-string">"Did you know that over 7,000 languages are spoken worldwide?"</span>,
        <span class="hljs-attr">"line2"</span>: <span class="hljs-string">"This Playground demonstrates how web applications can support users in multiple languages, making them accessible and inclusive to people from different backgrounds."</span>
    }
}
</code></pre>
<p><code>fr/translation.json</code></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"greeting"</span>: <span class="hljs-string">"Bienvenue sur le terrain de jeu linguistique"</span>,
    <span class="hljs-attr">"detail"</span>: {
        <span class="hljs-attr">"line1"</span>: <span class="hljs-string">"Saviez-vous que plus de 7 000 langues sont parlées dans le monde ?"</span>,
        <span class="hljs-attr">"line2"</span>: <span class="hljs-string">"Ce terrain de jeu démontre comment les applications web peuvent prendre en charge les utilisateurs dans plusieurs langues, les rendant accessibles et inclusives aux personnes de différents horizons."</span>
    }
}
</code></pre>
<p>Here, you can add as many languages with their translation files that will be supplied to <code>i18next</code>. Note that the keys in the JSON files are the same as these would be used as references when displaying them on the website.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733095771585/21cbb0f9-e767-426e-8fc6-2bb4e7abc5ef.png" alt="Image of folder structure of translation files" class="image--center mx-auto" width="376" height="522" loading="lazy"></p>
<h2 id="heading-step-3-how-to-build-components">Step 3: How to Build Components</h2>
<p>Create a <code>components</code> folder in the <code>src</code> directory and add the following components:</p>
<h3 id="heading-language-selector"><strong>Language Selector</strong></h3>
<p>Create the <code>LanguageSelector</code> component – contains a <code>select</code> element to help users switch languages dynamically:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> i18next <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next"</span>;
<span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;

<span class="hljs-keyword">type</span> languageOption = { language: <span class="hljs-built_in">string</span>; code: <span class="hljs-built_in">string</span> };

<span class="hljs-keyword">const</span> languageOptions: languageOption[] = [
  {
    language: <span class="hljs-string">"English"</span>,
    code: <span class="hljs-string">"en"</span>,
  },
  { language: <span class="hljs-string">"French"</span>, code: <span class="hljs-string">"fr"</span> },
  { language: <span class="hljs-string">"German"</span>, code: <span class="hljs-string">"de"</span> },
  { language: <span class="hljs-string">"Spanish"</span>, code: <span class="hljs-string">"es"</span> },
  { language: <span class="hljs-string">"Arabic"</span>, code: <span class="hljs-string">"ar"</span> },
  { language: <span class="hljs-string">"Yoruba"</span>, code: <span class="hljs-string">"yo"</span> },
];

<span class="hljs-keyword">const</span> LanguageSelector = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Set the initial language from i18next's detected or default language</span>
  <span class="hljs-keyword">const</span> [language, setLanguage] = useState(i18next.language);

  <span class="hljs-keyword">const</span> { i18n } = useTranslation();

  <span class="hljs-keyword">const</span> handleLanguageChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLSelectElement&gt;</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> selectedLanguage = e.target.value;
    setLanguage(selectedLanguage);
    i18next.changeLanguage(selectedLanguage); <span class="hljs-comment">// Update language in i18next</span>
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.body.dir = i18n.dir(); <span class="hljs-comment">//sets the body to ltr or rtl</span>
  }, [i18n, i18n.language]);

  <span class="hljs-keyword">return</span> (
    &lt;select
      id=<span class="hljs-string">"language"</span>
      value={language}
      onChange={handleLanguageChange}
      className=<span class="hljs-string">"p-2 border border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50
        dark:bg-gray-800 dark:border-gray-600 dark:text-gray-200 dark:focus:border-indigo-400 dark:focus:ring-indigo-700 dark:focus:ring-opacity-50"</span>
    &gt;
      {languageOptions.map(<span class="hljs-function">(<span class="hljs-params">{ language, code }, key</span>) =&gt;</span> (
        &lt;option value={code} key={key}&gt;
          {language}
        &lt;/option&gt;
      ))}
    &lt;/select&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LanguageSelector;
</code></pre>
<ul>
<li><p>Initialize the language with the language detected by <code>i18next</code> or the default set language.</p>
</li>
<li><p>The <code>useTranslation</code> Hook exposes <code>i18n</code> instance from <code>i18next</code> to interact with the internationalization settings.</p>
</li>
<li><p>The <code>handleLanguageChange</code> function would be used to update the language selected by the user. It’s triggered when the user selects a new language from the dropdown menu.</p>
</li>
</ul>
<h3 id="heading-implementing-text-direction"><strong>Implementing Text Direction</strong></h3>
<p>The <code>dir</code> attribute in HTML is a critical feature for ensuring accessibility and inclusivity in web applications, especially when dealing with languages that differ in text direction. For example:</p>
<ul>
<li><p><strong>Left-to-Right (LTR)</strong>: Most languages, including English, French, and Spanish, follow this direction.</p>
<p>  <strong>Right-to-Left (RTL)</strong>: Languages like Arabic, and Hebrew require text alignment and layout to be flipped to maintain readability and cultural context.</p>
</li>
</ul>
<p>To achieve this in our app, we set the <code>document.body.dir</code> to the <code>dir</code> from <code>i18n</code> while listening for changes in language selection using the <code>useEffect</code> hook</p>
<h3 id="heading-dark-mode-toggle"><strong>Dark Mode Toggle</strong></h3>
<p>Create the <code>DarkModeToggle</code> component to switch between light and dark mode as preferred by the user.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { SunIcon, MoonIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/solid"</span>;

<span class="hljs-keyword">const</span> DarkModeToggle = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [darkMode, setDarkMode] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Check local storage or system preference on first load</span>
    <span class="hljs-keyword">const</span> isDark =
      <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"theme"</span>) === <span class="hljs-string">"dark"</span> ||
      (!<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"theme"</span>) &amp;&amp;
        <span class="hljs-built_in">window</span>.matchMedia(<span class="hljs-string">"(prefers-color-scheme: dark)"</span>).matches);
    setDarkMode(isDark);
    <span class="hljs-built_in">document</span>.documentElement.classList.toggle(<span class="hljs-string">"dark"</span>, isDark);
  }, []);

  <span class="hljs-keyword">const</span> toggleDarkMode = <span class="hljs-function">() =&gt;</span> {
    setDarkMode(!darkMode);
    <span class="hljs-built_in">document</span>.documentElement.classList.toggle(<span class="hljs-string">"dark"</span>, !darkMode);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"theme"</span>, !darkMode ? <span class="hljs-string">"dark"</span> : <span class="hljs-string">"light"</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;button
      aria-label=<span class="hljs-string">"Toggle dark mode"</span>
      onClick={toggleDarkMode}
      className=<span class="hljs-string">"p-1 rounded"</span>
    &gt;
      {darkMode ? (
        &lt;SunIcon
          className=<span class="hljs-string">"w-6 h-6 text-yellow-500 "</span>
          onClick={toggleDarkMode}
        /&gt;
      ) : (
        &lt;MoonIcon className=<span class="hljs-string">"w-6 h-6 text-gray-900 "</span> onClick={toggleDarkMode} /&gt;
      )}
    &lt;/button&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DarkModeToggle;
</code></pre>
<h3 id="heading-header-component"><strong>Header Component</strong></h3>
<p>The <code>Header</code> component serves as a parent component to the <code>DarkModeToggle</code> and <code>languageSelector</code> components.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> DarkModeToggle <span class="hljs-keyword">from</span> <span class="hljs-string">"./DarkModeToggle"</span>;
<span class="hljs-keyword">import</span> LanguageSelector <span class="hljs-keyword">from</span> <span class="hljs-string">"./LanguageSelector"</span>;

<span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;header className=<span class="hljs-string">"container flex justify-between"</span>&gt;
      &lt;DarkModeToggle /&gt;
      &lt;LanguageSelector /&gt;
    &lt;/header&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Header;
</code></pre>
<h2 id="heading-step-4-main-app-component">Step 4: Main App Component</h2>
<p>In the <code>src/app</code> file, include the following:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;
<span class="hljs-keyword">import</span> Header <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Header"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { t } = useTranslation();

  <span class="hljs-keyword">const</span> line1 = t(<span class="hljs-string">"detail.line1"</span>);
  <span class="hljs-keyword">const</span> line2 = t(<span class="hljs-string">"detail.line2"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"h-[100vh] bg-white text-black dark:bg-gray-900 dark:text-white py-8"</span>&gt;
      &lt;Header /&gt;
      &lt;div className=<span class="hljs-string">"container text-center max-w-2xl mt-28"</span>&gt;
        &lt;h1 className=<span class="hljs-string">"text-4xl font-bold"</span>&gt;{t(<span class="hljs-string">"greeting"</span>)}&lt;/h1&gt;
        &lt;p className=<span class="hljs-string">"mt-8"</span>&gt;{line1}&lt;/p&gt;
        &lt;p className=<span class="hljs-string">"mt-2"</span>&gt;{line2}&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<ul>
<li><p>The <code>useTranslation</code> Hook from <code>react-i18next</code> exposes the <code>t</code> function, which is used to fetch translated text.</p>
</li>
<li><p>It fetches the translated string based on a key from your translation files (for example, <code>en.json</code>, <code>fr.json</code>).</p>
</li>
</ul>
<p>By following these steps, your app should now be fully functional with translations seamlessly integrated. This is what the final result of our app looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733099671232/67419cbe-ed58-4bb4-9e44-67de2ffa9be4.png" alt="Image of the app running on localhost" class="image--center mx-auto" width="2876" height="1280" loading="lazy"></p>
<p>Check out the <a target="_blank" href="https://multilingual-demo.vercel.app/">live demo</a> and the source code on <a target="_blank" href="https://github.com/timmy471/multilingual-demo">GitHub</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating websites that give users the flexibility to select their preferred language is not just a technical achievement but a step toward making the web more inclusive and welcoming.</p>
<p>By combining internationalization (i18n) with tools like React-i18next and styling with Tailwind CSS, you can build applications that are flexible, user-friendly, and accessible to a global audience.</p>
<p>In this project, we walked through setting up i18n, adding a language switcher, and including “dark mode” for better usability.</p>
<h2 id="heading-references">References</h2>
<p><a target="_blank" href="https://react.i18next.com/">https://react.i18next.com/</a></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=dltHi9GWMIo">https://www.youtube.com/watch?v=dltHi9GWMIo</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
