How I Built Yummunity a social platform : - Click here to Read !

Build a Multilingual Blog Viewer in React using Intlayer | How Intlayer helps to speed up i18n

In this Blog I've demonstrate the Intlayer developer tool, the power of internationalization library created for developers

How Intlayer helps to speed up i18n

Introduction

Hello everyone, and welcome back to yet another fantastic article!  As the title implies, I will present to you today a distinctive Internationalization (i18n) that frequently seems like a laborious afterthought.  However, what if it could be integrated into your workflow right away, free from unorganized translation keys and bulky configurations? So, before that, I would like to explain what and why internationalization is important in day-to-day applications.

What is Internationalization (i18n)?

What is Internationalization (i18n)?
what is Internationalization

Internationalization is nothing but a language translation for all available languages, so it’s a commonly referred to as i18n as there are 18 letters between the first "i" and the last "n", so it is the process of designing and developing products, especially software, so they can be easily adapted for different languages, regions, and cultural preferences without requiring significant code changes.

Key aspects of Internationalization (i18n)

  • Code and content separation: Create systems with all localizable components (text, currencies, date and number formats, images, etc.) separate from the main software logic to facilitate simple localization.
  • Handle differences in writing systems, units of measurement, date/time formats, keyboard layouts, and address/phone number structures with local awareness.
  • Preparation for localization (l10n): By facilitating these adaptations, internationalization creates the foundation for localization, which is the actual process of modifying the product for a particular target location.

Why i18n Is Crucial

Why i18n Is Crucial
Why i18n Is Crucial

We often build apps assuming a single-language audience. But even for small blogs, portfolios, or tools, reaching users in their native language:

  1. Boosts accessibility
  2. Builds trust
  3. Increases engagement
  4. Improve the overall SEO
  5. Helps to get discovered easily

Internationalization (i18n) is an important step for any software or digital product intended for a global audience, making further localisation and translation possible without major changes to the underlying code.

Introducing Intlayer

So recently, when I was discovering a few open source repositories on the only dust site, I came up with this unique internationalization tool name INTLAYER.

Intlayer Home page
Intlayer Home page

Intlayer is an internationalization library created for developers. It enables the declaration of your content across your codebase. It translates multilingual content declarations to structured dictionaries that can be readily included in your code. Intlayer uses TypeScript to make your development stronger and more efficient.

Why Intlayer over others' Internationalization?

Here is a detailed comparison table of Intlayer with the leading i18n libraries commonly used in React and Next.js ecosystems, including react-Intl, React-i18next (i18next), LinguiJS, next-intl, and next-i18next. This comparison highlights not just feature checklists but also unique aspects like developer workflow, type safety, dynamic routing, and modern translation management.

Feature Intlayer React-i18next / i18next React-Intl (FormatJS) LinguiJS next-intl/next-i18next
Translations Near Components Yes, content collocated with each component No (centralized JSON/locale folders) No (centralized) Partial (custom structure) Partial (usually locales folder)
TypeScript Integration Advanced, autogen. strict types Basic; extra config for safety Good, but less strict Typings, needs config Basic to good
Missing Translation Detection Build-time error/warning Mostly fallback strings at runtime Fallback strings Needs extra config Runtime fallback/optional builds
Rich Content (JSX, Markdown) Direct support, even React nodes Limited/interpolation only ICU syntax, not real JSX Limited Not designed for rich nodes
AI-powered Translation Yes, supports multiple AI models No No No No
Visual CMS Editor Yes, built-in for non-devs No No No No
Localized Routing Built-in, middleware support Plugins or manual config Not built-in Plugin/manual config Partial/needs configuration
Dynamic Route Generation Yes Plugin/ecosystem or manual setup Not provided Plugin/manual Provided in next-i18next/next-intl
Pluralization & Formatting Standard JS Intl or content logic Configurable, plugin-based Advanced, built-in ICU ICU, CLI, extensions Good via plugins
Content Format .js/.ts/.tsx/JSON, objects, Markdown, JSX JSON or custom; string/ICU ICU, JSON, JS JSON, PO, ICU JSON plus few extended options
SEO Helpers (hreflang, sitemap) Built-in SEO tools Community plugins/manual Not core Not core Partial
Ecosystem / Community Smaller but modern Largest and most mature Large, enterprise Growing, smaller Mid-size, Next.js-focused
Server-side Rendering & Server Components Yes, streamlined for SSR/React Server Components Supported, some config needed Supported in Next.js Supported Full support
Automated Type-Safe Content Extraction Yes Not built-in Not built-in Needs config Partial/generation scripts
Tree-shaking (Load only used content) Yes Usually loads all Usually loads all Not default Partial/varies
Management of Large Projects Encourages modular, local content Needs good file discipline Central catalogs can get large May get complex Modular with setup
AI, Markdown/JSX, CMS, SEO (Unique) Yes to all Rare/No, No, No, Minimal No, No, No, Minimal No, No, No, Minimal No, No, No, Partial
  • Intlayer stands out for strong TypeScript integration, build-time validation, component-localized content, visual editing for non-devs, unique AI translation integration, out-of-the-box SEO features, and rich content (JSX/Markdown).
  • Mainstream tools like i18next and FormatJS offer a wider community and plugins, but often require centralization, lack CMS/editor features (But not for Intlayer), and need more manual setup for advanced localization.
  • LinguiJS and next-intl/next-i18next provide modern approaches or build on popular Next.js architectures, but still lack some advanced, integrated features of Intlayer - especially around real-time collaboration, AI, and CMS capabilities
  • For large, multilingual projects or if you want editors or non-developers to participate in localizing content, Intlayer brings unique advantages not matched by classic i18n solutions

My Project Overview

In this post, I’ll walk you through building a simple React Blog Viewer that:

  1. Fetches posts dynamically from the Blogger Services
  2. Supports multiple languages (in this example, I have implemented only 4 Languages; you can add as many as you can)
  3. Uses Intlayer for modern, integrated i18n

Project Structure

First and foremost, you can follow along with me for the project implementation. If you have that curiosity, you just need to know a little bit about React/Vite, JavaScript/TypeScript, and any previous internationalization tools (basic).

Here is the GitHub repo link, just download or fork it: Intlayer Project Demo

So for this project, I’ve showcased how Intlayer will help to translate the pages of the blog posts that demonstrate Intlayer's i18n capabilities with React. The project will feature multiple pages with dynamic language switching.

Here is the Tech Stack I’ve used throughout the making of the project.

Layer Technology
Frontend Framework React 19
Build Tool Vite
Internationalization Intlayer 5.7.5 (latest)
Routing React Router DOM
Styling CSS3 with modern features
Language TypeScript
UI Components Radix UI

A basic Project Structure goes here

intlayer project structure
intlayer project structure 

Features to Implement

  1. Home Page
    • Hero section with multilingual welcome message with background image
    • Featured blog posts grid after the hero section
    • A Header with an option to switch or change language with translated labels
  2. Blog Post Page
    • A blog service will fetch and show on the home page, as in blog grids
    • A dynamic image has to be implemented to match with content and post of it (optional)
    • A read more button to redirect to the post, respectively.
  3. About Us & Contribution Page
    • A short info of the project, the Intlayer, and its contribution guidelines to the repository.
  4. Global Components
    • Intlayer config file. (Important)
    • Header: Navigation menu, logo, language switcher
    • Footer: Links, copyright, social media
    • Language Switcher: Dropdown with flag icons
    • Blog Card: Preview cards with title, excerpt, date

Technical/Step-by-Step Implementation

1. Project Setup

  • Initialize the Project
    • Use Vite to bootstrap a new React + TypeScript project
npm create vite@latest intlayer-blog-demo -- --template react-ts
cd intlayer-blog-demo
npm install
  • Install and Configure Intlayer
npm install intlayer react-intlayer

2. Configure Intlayer

  • Set Up Intlayer Provider

    • Create an intlayer.config.ts for language and content configuration.

    • Wrap your app with the IntlayerProvider in app.tsx.

  • import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [
          Locales.ENGLISH,
          Locales.FRENCH,
          Locales.SPANISH,
          Locales.HINDI  // added our national language
          // add more languages
        ],
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
        
    import { IntlayerProvider } from "react-intlayer";
    import { BrowserRouter, Routes, Route } from "react-router-dom";
    import { Home } from "./pages/Home";
    import { BlogViewer } from "./components/BlogViewer/BlogViewer";
    import { Contribution } from "./pages/Contribution/Contribution";
    import About from "./pages/About/About";
    
    function App() {
      return (
        <IntlayerProvider>
          <BrowserRouter>
            <Routes>
              <Route path="/" element={<Home />} />
              <Route path="/blog/:postId" element={<BlogViewer />} />
              <Route path="/contribution" element={<Contribution />} />
              <Route path="/about" element={<About />} />
            </Routes>
          </BrowserRouter>
        </IntlayerProvider>
      );
    }
    
    export default App;
        

    3. Creating Reusable Components

    • Let’s now create components that will be reusable

      • All the components are created in src/components. Reusable UI components are as follows
      • Header

      Header.tsx and Header.content.ts

      NOTE : For all the CSS File kindly refer my Repo for Css file refer this link : Header.css

      // Header.tsx
      
      import React, { useState } from 'react';
      import { useIntlayer, useLocale } from 'react-intlayer';
      import { Link } from 'react-router-dom';
      import * as Select from '@radix-ui/react-select';
      import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
      import './Header.css';
      
      export const Header: React.FC = () => {
        const [isMenuOpen, setIsMenuOpen] = useState(false);
        const { siteName, navigation } = useIntlayer('header');
        const { locale, setLocale } = useLocale();
      
        const toggleMenu = () => {
          setIsMenuOpen(!isMenuOpen);
        };
      
        return (
          <header className="header">
            <div className="header-container">
              {/* Logo Section */}
              <div className="logo">
                <Link to="/" className="logo-link">
                  <span className="logo-text">{siteName}</span>
                </Link>
              </div>
      
              {/* Desktop Navigation */}
              <nav className="desktop-nav">
              <ul className="nav-list">
                <div className="language-selector">
                  <Select.Root 
                    value={locale}
                    onValueChange={setLocale}
                  >
                    <Select.Trigger className="select-trigger" aria-label="Select language">
                      <Select.Value />
                      <Select.Icon className="select-icon">
                        <ChevronDownIcon />
                      </Select.Icon>
                    </Select.Trigger>
      
                    <Select.Portal>
                      <Select.Content className="select-content">
                        <Select.ScrollUpButton className="select-scroll-button">
                          <ChevronUpIcon />
                        </Select.ScrollUpButton>
                        <Select.Viewport className="select-viewport">
                          <Select.Item value="en" className="select-item">
                            <Select.ItemText>English</Select.ItemText>
                            <Select.ItemIndicator className="select-item-indicator">
                              <CheckIcon />
                            </Select.ItemIndicator>
                          </Select.Item>
                          <Select.Item value="fr" className="select-item">
                            <Select.ItemText>French</Select.ItemText>
                            <Select.ItemIndicator className="select-item-indicator">
                              <CheckIcon />
                            </Select.ItemIndicator>
                          </Select.Item>
                          <Select.Item value="es" className="select-item">
                            <Select.ItemText>Spanish</Select.ItemText>
                            <Select.ItemIndicator className="select-item-indicator">
                              <CheckIcon />
                            </Select.ItemIndicator>
                          </Select.Item>
                          <Select.Item value="hi" className="select-item">
                            <Select.ItemText>Hindi</Select.ItemText>
                            <Select.ItemIndicator className="select-item-indicator">
                              <CheckIcon />
                            </Select.ItemIndicator>
                          </Select.Item>
                        </Select.Viewport>
                        <Select.ScrollDownButton className="select-scroll-button">
                          <ChevronDownIcon />
                        </Select.ScrollDownButton>
                      </Select.Content>
                    </Select.Portal>
                  </Select.Root>
                </div>
                  <li>
                    <Link to="/about" className="nav-link">
                      {navigation[0].label}
                    </Link>
                  </li>
                  <li>
                    <Link to="/contribution" className="nav-link">
                      {navigation[1].label}
                    </Link>
                  </li>
                  <li>
                    <a 
                      href="<https://github.com/aymericzip/intlayer>" 
                      target="_blank" 
                      rel="noopener noreferrer"
                      className="github-button"
                    >
                      <svg 
                        className="github-icon" 
                        viewBox="0 0 24 24" 
                        fill="currentColor"
                        width="20" 
                        height="20"
                      >
                        <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
                      </svg>
                      {navigation[2].label}
                    </a>
                  </li>
              </ul>
              </nav>
      
              {/* Mobile Menu Button */}
              <button 
                className="mobile-menu-button"
                onClick={toggleMenu}
                aria-label="Toggle menu"
              >
                <span className={`hamburger ${isMenuOpen ? 'open' : ''}`}>
                  <span></span>
                  <span></span>
                  <span></span>
                </span>
              </button>
            </div>
      
            {/* Mobile Navigation */}
            <nav className={`mobile-nav ${isMenuOpen ? 'open' : ''}`}>
              <ul className="mobile-nav-list">
                <li className="mobile-language-selector">
                  <div className="mobile-language-wrapper">
                    <span className="mobile-language-label">Language:</span>
                    <Select.Root 
                      value={locale}
                      onValueChange={(value) => {
                        setLocale(value as any);
                        setIsMenuOpen(false);
                      }}
                    >
                      <Select.Trigger className="mobile-select-trigger" aria-label="Select language">
                        <Select.Value />
                        <Select.Icon className="mobile-select-icon">
                          <ChevronDownIcon />
                        </Select.Icon>
                      </Select.Trigger>
      
                      <Select.Portal>
                        <Select.Content className="mobile-select-content">
                          <Select.ScrollUpButton className="select-scroll-button">
                            <ChevronUpIcon />
                          </Select.ScrollUpButton>
                          <Select.Viewport className="select-viewport">
                            <Select.Item value="en" className="select-item">
                              <Select.ItemText>English</Select.ItemText>
                              <Select.ItemIndicator className="select-item-indicator">
                                <CheckIcon />
                              </Select.ItemIndicator>
                            </Select.Item>
                            <Select.Item value="fr" className="select-item">
                              <Select.ItemText>Français</Select.ItemText>
                              <Select.ItemIndicator className="select-item-indicator">
                                <CheckIcon />
                              </Select.ItemIndicator>
                            </Select.Item>
                            <Select.Item value="es" className="select-item">
                              <Select.ItemText>Español</Select.ItemText>
                              <Select.ItemIndicator className="select-item-indicator">
                                <CheckIcon />
                              </Select.ItemIndicator>
                            </Select.Item>
                            <Select.Item value="hi" className="select-item">
                              <Select.ItemText>हिन्दी</Select.ItemText>
                              <Select.ItemIndicator className="select-item-indicator">
                                <CheckIcon />
                              </Select.ItemIndicator>
                            </Select.Item>
                          </Select.Viewport>
                          <Select.ScrollDownButton className="select-scroll-button">
                            <ChevronDownIcon />
                          </Select.ScrollDownButton>
                        </Select.Content>
                      </Select.Portal>
                    </Select.Root>
                  </div>
                </li>
                <li>
                  <Link 
                    to="/about" 
                    className="mobile-nav-link"
                    onClick={() => setIsMenuOpen(false)}
                  >
                    {navigation[0].label}
                  </Link>
                </li>
                <li>
                  <Link 
                    to="/contribution" 
                    className="mobile-nav-link"
                    onClick={() => setIsMenuOpen(false)}
                  >
                    {navigation[1].label}
                  </Link>
                </li>
                <li>
                  <a 
                    href="<https://github.com/aymericzip/intlayer>" 
                    target="_blank" 
                    rel="noopener noreferrer"
                    className="mobile-github-button"
                    onClick={() => setIsMenuOpen(false)}
                  >
                    <svg 
                      className="github-icon" 
                      viewBox="0 0 24 24" 
                      fill="currentColor"
                      width="20" 
                      height="20"
                    >
                      <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
                    </svg>
                    {navigation[2].label}
                  </a>
                </li>
              </ul>
            </nav>
      
          </header>
        );
      };
          
      import { t } from 'intlayer';
      
      const headerContent = {
        key: 'header',
        content: {
          siteName: t({
            en: 'Intlayer Blog Demo',
            fr: 'Démo du blog Intlayer',
            es: 'Demostración del blog de Intlayer',
            hi: 'इंटलेयर ब्लॉग डेमो'
          }),
          navigation: [
            {
              label: t({
                en: 'About Us',
                fr: 'A propos de nous',
                es: 'Sobre nosotros',
                hi: 'हमारे बारे में'
              }),
              url: '/about'
            },
            {
              label: t({
                en: 'Contribution Guidelines',
                fr: 'Directives de contribution',
                es: 'Pautas de contribución',
                hi: 'सहयोग के लिए नियम'
              }),
              url: '/contribution'
            },
            {
              label:t({
                en: 'GitHub',
                fr: 'GitHub',
                es: 'GitHub',
                hi: 'गिटहब'
              }),
              url: '<https://github.com/aymericzip/intlayer>'
            }
          ],
        }
      }
      
      export default headerContent;
          

      Footer

      // Footer.tsx
      import React from 'react';
      import { useIntlayer } from 'react-intlayer';
      
      export const Footer: React.FC = () => {
        const currentYear = new Date().getFullYear();
        const { copyright } = useIntlayer('footer');
      
        return (
          <footer className="py-4 text-center text-gray-600 text-sm">
            <div className="container mx-auto">
              <p style={{
                textAlign: 'center'
              }}>
                {currentYear} {copyright}
                {/* {currentYear} {copyright}&nbsp;{community} */}
                </p>
            </div>
          </footer>
        );
      };
      
      // footer.content.ts
      
      import { t } from 'intlayer';
      
      const footerContent = {
        key: 'footer',
        content: {
          copyright: t({
            en: 'Intlayer Blog. All rights reserved.',
            fr: 'Blog Intlayer. Tous droits réservés.',
            es: 'Blog Intlayer. Todos los derechos reservados.',
            hi: 'इंटलेयर ब्लॉग सभी अधिकार राखे।'
          })
        }
      }
      
      export default footerContent;
      

      BlogSummaryList

      for Css file refer this link : BlogSummaryList.css

      import { useEffect, useState } from 'react';
      import { useNavigate } from 'react-router-dom';
      import { useIntlayer, useLocale } from 'react-intlayer';
      import type { BlogPost } from '../../services/blogService';
      import { fetchBlogPosts } from '../../services/blogService';
      import './BlogSummaryList.css';
      
      export const BlogSummaryList = () => {
        const [posts, setPosts] = useState<BlogPost[]>([]);
        const [loading, setLoading] = useState(true);
        const [error, setError] = useState<string | null>(null);
        const navigate = useNavigate();
        const { locale } = useLocale();
        
        const content = useIntlayer('blog-summary-list');
      
        useEffect(() => {
          const loadPosts = async () => {
            try {
              setLoading(true);
              const blogPosts = await fetchBlogPosts(locale);
              setPosts(blogPosts);
              setError(null);
            } catch (err) {
              console.error('Error loading blog posts:', err);
              setError(content.error?.value || 'Failed to load blog posts');
            } finally {
              setLoading(false);
            }
          };
      
          loadPosts();
        }, [locale]); // Removed content from dependencies to prevent infinite loops
      
        const handlePostClick = (post: BlogPost) => {
          // Create a URL-friendly slug from the post title
          const slug = post.link
            .toLowerCase()
            .replace(/[^a-z0-9]+/g, '-')
            .replace(/(^-|-$)/g, '');
          
          // Navigate to the blog post with the slug in the URL and post data in state
          navigate(`/blog/${slug}`, { 
            state: { post, key: `${slug}-${Date.now()}`},
          });
        };
      
        if (loading) {
          return <div className="loading">{content.loading || 'Loading...'}</div>;
        }
      
        if (error) {
          return <div className="error">{error}</div>;
        }
      
        if (posts.length === 0) {
          return <div className="empty">{content.emptyMessage}</div>;
        }
      
        return (
          <div className="blog-summary-list">
            <h2>{content.title}</h2>
            <p className="description">{content.description}</p>
            <div className="blog-grid">
              {posts.map((post) => (
                <div 
                  key={`${post.link}-${post.language}`} 
                  className="blog-card"
                  onClick={() => handlePostClick(post)}
                  role="button"
                  tabIndex={0}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter' || e.key === ' ') {
                      e.preventDefault();
                      handlePostClick(post);
                    }
                  }}
                >
                  {post.thumbnail && (
                    <div className="blog-thumbnail">
                      <img src={post.thumbnail} alt={post.title} />
                    </div>
                  )}
                  <div className="blog-content">
                    <h3>{post.title}</h3>
                    <div className="blog-meta">
                      <span className="date">
                        {new Date(post.pubDate).toLocaleDateString(locale, {
                          year: 'numeric',
                          month: 'long',
                          day: 'numeric',
                        })}
                      </span>
                    </div>
                    <p className="excerpt">
                      {post.description.replace(/<[^>]*>?/gm, '').substring(0, 150)}...
                    </p>
                    <span className="read-more">{content.readMore}</span>
                  </div>
                </div>
              ))}
            </div>
          </div>
        );
      };
      
      import { t, type DeclarationContent } from 'intlayer';
      
      const blogSummaryListContent: DeclarationContent = {
        key: 'blog-summary-list',
        content: {
          title: t({
            en: 'Latest Blog Posts',
            fr: 'Derniers articles de blog',
            es: 'Últimas entradas del blog',
            hi: 'नवीनतम ब्लॉग पोस्ट'
          }),
          description: t({
            en: 'A collection of our latest blog posts',
            fr: 'Une collection de nos derniers articles de blog',
            es: 'Una colección de nuestras últimas entradas de blog',
            hi: 'हमारी नवीनतम ब्लॉग पोस्ट का संग्रह'
          }),
          emptyMessage: t({
            en: 'No blog posts found',
            fr: 'Aucun article de blog trouvé',
            es: 'No se encontraron entradas de blog',
            hi: 'कोई ब्लॉग पोस्ट नहीं मिली'
          }),
          readMore: t({
            en: 'Read more',
            fr: 'Lire la suite',
            es: 'Leer más',
            hi: 'और पढ़ें'
          }),
          loading: t({
            en: 'Loading blog posts...',
            fr: 'Chargement des articles...',
            es: 'Cargando publicaciones...',
            hi: 'ब्लॉग पोस्ट लोड हो रहा है...'
          }),
          error: t({
            en: 'Failed to load blog posts. Please try again later.',
            fr: 'Échec du chargement des articles. Veuillez réessayer plus tard.',
            es: 'Error al cargar las publicaciones. Por favor, inténtelo de nuevo más tarde.',
            hi: 'ब्लॉग पोस्ट लोड करने में विफल। कृपया बाद में पुनः प्रयास करें।'
          })
        }
      }
      
      export default blogSummaryListContent;
      

      BlogViewer

      for Css file refer this link : BlogViewer.css

      import { useEffect, useState } from 'react';
      import { useParams, useNavigate, useLocation } from 'react-router-dom';
      import type { BlogPost } from '../../services/blogService';
      import { fetchBlogPosts } from '../../services/blogService';
      import { useIntlayer, useLocale } from 'react-intlayer';
      import './BlogViewer.css';
      import { Header } from '../Header/Header';
      import { Footer } from '../Footer/Footer';
      // import blogViewerContent from './BlogViewer.content';
      
      // Extend the location state type
      type LocationState = {
        post?: BlogPost;
      };
      
      export const BlogViewer = () => {
        const { postId } = useParams<{ postId: string }>();
        const location = useLocation();
        const locationState = location.state as LocationState;
        const [post, setPost] = useState<BlogPost | null>(locationState?.post || null);
        const [loading, setLoading] = useState(!locationState?.post);
        const [error, setError] = useState<string | null>(null);
        const navigate = useNavigate();
        const { locale } = useLocale();
        
        const content = useIntlayer('blog-viewer');
      
        useEffect(() => {
          // If we have a post in location state and it's in the current locale, use it
          if (locationState?.post && locationState.post.language === locale) {
            return;
          }
      
          let isMounted = true;
          const loadPost = async () => {
            try {
              if (isMounted) setLoading(true); 
              const posts = await fetchBlogPosts(locale); 
              if (!isMounted) return;
              
              // Try to find the post by URL slug first, then by title
              const foundPost = posts.find(p => {
                if (!postId) return false;
                // const postSlug = p.title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
                const postSlug = p.link
                return p.link.includes(postId) || postSlug === postId;
              });
              
              if (isMounted) {
                if (foundPost) {
                  setPost(foundPost);
                } else {
                  setError(content.notFound?.value || 'Post not found');
                }
              }
            } catch (err) {
              console.error('Error loading blog post:', err);
              if (isMounted) {
                setError(content.error?.value || 'Failed to load blog post');
              }
            } finally {
              if (isMounted) {
                setLoading(false);
              }
            }
          };
      
          loadPost();
          // Cleanup function to prevent state updates after component unmounts
          return () => {
            isMounted = false;
          };
        }, [postId, locale]);
      
        const handleBack = () => {
          navigate(-1);
        };
      
        if (loading) {
          return <div className="loading">{content.loading || 'Loading...'}</div>;
        }
      
        if (error) {
          return (
            <div className="error-container">
              <p>{error}</p>
              <button onClick={handleBack} className="back-button">
                {content.backToBlog || 'Back to Blog'}
              </button>
            </div>
          );
        }
      
        if (!post) {
          return (
            <div className="not-found">
              <p>{content.notFound || 'Post not found'}</p>
              <button onClick={handleBack} className="back-button">
                {content.backToBlog || 'Back to Blog'}
              </button>
            </div>
          );
        }
      
        return (
          <>
          <Header />
          <div className="blog-viewer">
            <button onClick={handleBack} className="back-button">
              {content.backToBlog || 'Back to Blog'}
            </button>
            
            <article className="blog-post">
              <header className="post-header">
                <h1>{post.title}</h1>
                <div className="post-meta">
                  <span>{content.publishedOn || 'Published on'} </span>
                  <time dateTime={new Date(post.pubDate).toISOString()}>
                    {new Date(post.pubDate).toLocaleDateString(locale, {
                      year: 'numeric',
                      month: 'long',
                      day: 'numeric',
                    })}
                  </time>
                </div>
                {post.thumbnail && (
                  <div className="post-thumbnail">
                    <img src={post.thumbnail} alt={post.title} />
                  </div>
                )}
              </header>
      
              <div 
                className="post-content"
                dangerouslySetInnerHTML={{ __html: post.content || post.description }}
              />
            </article>
          </div>
          <Footer />
          </>
          
        );
      };
      
      import { t, type DeclarationContent } from 'intlayer';
      
      const blogViewerContent: DeclarationContent = {
        key: 'blog-viewer',
        content: {
          loading: t({
            en: 'Loading post...',
            fr: 'Chargement de l\\'article...',
            es: 'Cargando publicación...',
            hi: 'पोस्ट लोड हो रहा है...'
          }),
          notFound: t({
            en: 'The requested blog post could not be found.',
            fr: 'L\\'article de blog demandé est introuvable.',
            es: 'No se pudo encontrar la publicación de blog solicitada.',
            hi: 'अनुरोधित ब्लॉग पोस्ट नहीं मिल सकी।'
          }),
          error: t({
            en: 'An error occurred while loading the blog post.',
            fr: 'Une erreur est survenue lors du chargement de l\\'article.',
            es: 'Se produjo un error al cargar la publicación del blog.',
            hi: 'ब्लॉग पोस्ट लोड करते समय एक त्रुटि हुई।'
          }),
          backToBlog: t({
            en: 'Back to Blog',
            fr: 'Retour au blog',
            es: 'Volver al blog',
            hi: 'ब्लॉग पर वापस जाएं'
          }),
          readOriginal: t({
            en: 'Read original post',
            fr: 'Lire l\\'article original',
            es: 'Leer publicación original',
            hi: 'मूल पोस्ट पढ़ें'
          }),
          publishedOn: t({
            en: 'Published on',
            fr: 'Publié le',
            es: 'Publicado el',
            hi: 'प्रकाशित तिथि'
          })
        }
      };
      
      export default blogViewerContent;
      
      • src/pages: Page-level components like Home, About us, and contribution pages

      Home component

      for Css file refer this link : Home.css

      import { Header } from '../components/Header/Header';
      import { Footer } from '../components/Footer/Footer';
      import { BlogSummaryList } from '../components/BlogSummaryList/BlogSummaryList';
      import { useIntlayer } from 'react-intlayer';
      import './Home.css';
      
      // Import the content to register it with Intlayer
      import homeContent from './Home.content';
      
      // This ensures the content is registered with Intlayer
      // The export is needed to prevent tree-shaking
      // @ts-ignore - This is a side-effect import
      export const __homeContent = homeContent;
      
      // Define the type for our content
      interface HomeContent {
        welcome: string;
        description: string;
      }
      
      export const Home = () => {
        // Use the content from home content file
        const content = useIntlayer('home') as unknown as HomeContent;
      
        return (
          <div className="home-page">
            <Header />
            <main className="main-content">
              <div className="container">
                {/* Hero Section with Translator Image Background */}
                <section className="hero-section">
                  <div className="hero-content">
                    <h1>{content.welcome}</h1>
                    <p>{content.description}</p>
                  </div>
                </section>
                
                {/* Blog Section */}
                <section className="blog-section">
                  <BlogSummaryList />
                </section>
              </div>
            </main>
            <Footer />
          </div>
        );
      };
      
      import { t } from 'intlayer';
      
      const homeContent = {
        key: 'home',
        content: {
          welcome: t({
            en: 'Welcome to Intlayer Blog Demo',
            fr: 'Bienvenue sur la démo du blog Intlayer',
            es: 'Bienvenido a la demostración del blog de Intlayer',
            hi: 'इंटलेयर ब्लॉग डेमो में आपका स्वागत है'
          }),
          description: t({
            en: 'This is a demo showing how to use Intlayer for content management in a React application.',
            fr: 'Ceci est une démonstration montrant comment utiliser Intlayer pour la gestion de contenu dans une application React.',
            es: 'Esta es una demostración que muestra cómo usar Intlayer para la gestión de contenido en una aplicación React.',
            hi: 'यह एक डेमो है जो रिएक्ट एप्लिकेशन में सामग्री प्रबंधन के लिए इंटलेयर का उपयोग कैसे करें, इसे दिखाता है।'
          })
        }
      };
      
      export default homeContent;
      

      About component

      for Css file refer this link : About.css

      import React from 'react';
      import { useIntlayer } from 'react-intlayer';
      import { Link } from 'react-router-dom';
      import { Header } from '../../components/Header/Header';
      import { Footer } from '../../components/Footer/Footer';
      import './About.css';
      
      // Import the content to register it with Intlayer
      import aboutContent from './About.content';
      
      // This ensures the content is registered with Intlayer
      // The export is needed to prevent tree-shaking
      // @ts-ignore - This is a side-effect import
      export const __aboutContent = aboutContent;
      
      // Define the type for our content
      interface AboutContent {
        title: string;
        subtitle: string;
        missionTitle: string;
        missionText: string;
        featuresTitle: string;
        featuresText: string;
        learnMoreButton: string;
        backToHome: string;
      }
      
      export const About: React.FC = () => {
        // Use the content from about content file
        const content = useIntlayer('about') as unknown as AboutContent;
      
        const handleLearnMore = () => {
          window.open('<https://github.com/aymericzip/intlayer>', '_blank');
        };
      
        return (
          <div className="about-page">
            <Header />
            <main className="about-main">
              <div className="about-container">
                {/* Hero Section */}
                <section className="about-hero">
                  <h1 className="about-title">{content.title}</h1>
                  <p className="about-subtitle">{content.subtitle}</p>
                </section>
      
                {/* Content Sections */}
                <div className="about-content">
                  {/* Mission Section */}
                  <section className="about-section">
                    <h2 className="section-title">{content.missionTitle}</h2>
                    <p className="section-text">{content.missionText}</p>
                  </section>
      
                  {/* Features Section */}
                  <section className="about-section">
                    <h2 className="section-title">{content.featuresTitle}</h2>
                    <p className="section-text">{content.featuresText}</p>
                  </section>
      
                  {/* Action Buttons */}
                  <section className="about-actions">
                    <button 
                      onClick={handleLearnMore}
                      className="learn-more-button"
                    >
                      {content.learnMoreButton}
                      <svg 
                        className="external-link-icon" 
                        viewBox="0 0 24 24" 
                        fill="none" 
                        stroke="currentColor" 
                        strokeWidth="2"
                      >
                        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                        <polyline points="15,3 21,3 21,9"/>
                        <line x1="10" y1="14" x2="21" y2="3"/>
                      </svg>
                    </button>
                    
                    <Link to="/" className="back-home-button">
                      {content.backToHome}
                    </Link>
                  </section>
                </div>
              </div>
            </main>
            <Footer />
          </div>
        );
      };
      
      export default About;
      
      import { t } from 'intlayer';
      
      const aboutContent = {
        key: 'about',
        content: {
          title: t({
            en: 'About Intlayer',
            fr: 'À propos d\\'Intlayer',
            es: 'Acerca de Intlayer',
            hi: 'इंटलेयर के बारे में'
          }),
          subtitle: t({
            en: 'Revolutionizing internationalization for modern web applications',
            fr: 'Révolutionner l\\'internationalisation pour les applications web modernes',
            es: 'Revolucionando la internacionalización para aplicaciones web modernas',
            hi: 'आधुनिक वेब एप्लिकेशन के लिए अंतर्राष्ट्रीयकरण में क्रांति'
          }),
          missionTitle: t({
            en: 'Our Mission',
            fr: 'Notre mission',
            es: 'Nuestra misión',
            hi: 'हमारा मिशन'
          }),
          missionText: t({
            en: 'Intlayer is an internationalization library created exclusively for JavaScript developers. We believe that building multilingual applications should be intuitive, efficient, and maintainable. Our mission is to provide developers with the tools they need to create truly global applications without the complexity traditionally associated with internationalization.',
            fr: 'Intlayer est une bibliothèque d\\'internationalisation créée exclusivement pour les développeurs JavaScript. Nous croyons que la création d\\'applications multilingues devrait être intuitive, efficace et maintenable. Notre mission est de fournir aux développeurs les outils dont ils ont besoin pour créer des applications vraiment globales sans la complexité traditionnellement associée à l\\'internationalisation.',
            es: 'Intlayer es una biblioteca de internacionalización creada exclusivamente para desarrolladores de JavaScript. Creemos que construir aplicaciones multilingües debería ser intuitivo, eficiente y mantenible. Nuestra misión es proporcionar a los desarrolladores las herramientas que necesitan para crear aplicaciones verdaderamente globales sin la complejidad tradicionalmente asociada con la internacionalización.',
            hi: 'इंटलेयर एक अंतर्राष्ट्रीयकरण लाइब्रेरी है जो विशेष रूप से जावास्क्रिप्ट डेवलपर्स के लिए बनाई गई है। हमारा मानना है कि बहुभाषी एप्लिकेशन बनाना सहज, कुशल और रखरखाव योग्य होना चाहिए। हमारा मिशन डेवलपर्स को वे उपकरण प्रदान करना है जिनकी उन्हें वास्तव में वैश्विक एप्लिकेशन बनाने के लिए आवश्यकता है, बिना पारंपरिक रूप से अंतर्राष्ट्रीयकरण से जुड़ी जटिलता के।'
          }),
          featuresTitle: t({
            en: 'What Makes Intlayer Special',
            fr: 'Ce qui rend Intlayer spécial',
            es: 'Lo que hace especial a Intlayer',
            hi: 'इंटलेयर को क्या खास बनाता है'
          }),
          featuresText: t({
            en: 'Unlike traditional i18n solutions that separate translations from components, Intlayer keeps everything together for better developer experience and maintainability. It enables the declaration of your content across your code, translates multilingual content declarations to structured dictionaries, and uses TypeScript to make your development stronger and more efficient.',
            fr: 'Contrairement aux solutions i18n traditionnelles qui séparent les traductions des composants, Intlayer garde tout ensemble pour une meilleure expérience développeur et maintenabilité. Il permet la déclaration de votre contenu à travers votre code, traduit les déclarations de contenu multilingue en dictionnaires structurés, et utilise TypeScript pour rendre votre développement plus fort et plus efficace.',
            es: 'A diferencia de las soluciones i18n tradicionales que separan las traducciones de los componentes, Intlayer mantiene todo junto para una mejor experiencia del desarrollador y mantenibilidad. Permite la declaración de tu contenido a través de tu código, traduce las declaraciones de contenido multilingüe a diccionarios estructurados, y usa TypeScript para hacer tu desarrollo más fuerte y eficiente.',
            hi: 'पारंपरिक i18n समाधानों के विपरीत जो अनुवादों को घटकों से अलग करते हैं, इंटलेयर बेहतर डेवलपर अनुभव और रखरखाव के लिए सब कुछ एक साथ रखता है। यह आपके कोड में आपकी सामग्री की घोषणा को सक्षम बनाता है, बहुभाषी सामग्री घोषणाओं को संरचित शब्दकोशों में अनुवादित करता है, और आपके विकास को मजबूत और अधिक कुशल बनाने के लिए टाइपस्क्रिप्ट का उपयोग करता है।'
          }),
          learnMoreButton: t({
            en: 'Learn More About Intlayer',
            fr: 'En savoir plus sur Intlayer',
            es: 'Aprende más sobre Intlayer',
            hi: 'इंटलेयर के बारे में और जानें'
          }),
          backToHome: t({
            en: 'Back to Home',
            fr: 'Retour à l\\'accueil',
            es: 'Volver al inicio',
            hi: 'होम पर वापस जाएं'
          })
        }
      };
      
      export default aboutContent;
      

      Contribution component

      for Css file refer this link : Contribution.css

      import React from 'react';
      import { useIntlayer } from 'react-intlayer';
      import { Link } from 'react-router-dom';
      import { Header } from '../../components/Header/Header';
      import { Footer } from '../../components/Footer/Footer';
      import './Contribution.css';
      
      // Import the content to register it with Intlayer
      import contributionContent from './Contribution.content';
      
      // This ensures the content is registered with Intlayer
      // The export is needed to prevent tree-shaking
      // @ts-ignore - This is a side-effect import
      export const __contributionContent = contributionContent;
      
      // Define the type for our content
      interface ContributionContent {
        title: string;
        subtitle: string;
        understandingTitle: string;
        understandingText: string;
        developmentTitle: string;
        developmentText: string;
        fullGuideButton: string;
        backToHome: string;
      }
      
      export const Contribution: React.FC = () => {
        // Use the content from contribution content file
        const content = useIntlayer('contribution') as unknown as ContributionContent;
      
        const handleFullGuideClick = () => {
          window.open('<https://github.com/aymericzip/intlayer/blob/main/CONTRIBUTING.md>', '_blank');
        };
      
        return (
          <div className="contribution-page">
            <Header />
            <main className="contribution-main">
              <div className="contribution-container">
                {/* Hero Section */}
                <section className="contribution-hero">
                  <h1 className="contribution-title">{content.title}</h1>
                  <p className="contribution-subtitle">{content.subtitle}</p>
                </section>
      
                {/* Content Sections */}
                <div className="contribution-content">
                  {/* Understanding the Project */}
                  <section className="contribution-section">
                    <h2 className="section-title">{content.understandingTitle}</h2>
                    <p className="section-text">{content.understandingText}</p>
                  </section>
      
                  {/* Development Setup */}
                  <section className="contribution-section">
                    <h2 className="section-title">{content.developmentTitle}</h2>
                    <p className="section-text">{content.developmentText}</p>
                  </section>
      
                  {/* Action Buttons */}
                  <section className="contribution-actions">
                    <button 
                      onClick={handleFullGuideClick}
                      className="full-guide-button"
                    >
                      {content.fullGuideButton}
                      <svg 
                        className="external-link-icon" 
                        viewBox="0 0 24 24" 
                        fill="none" 
                        stroke="currentColor" 
                        strokeWidth="2"
                      >
                        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                        <polyline points="15,3 21,3 21,9"/>
                        <line x1="10" y1="14" x2="21" y2="3"/>
                      </svg>
                    </button>
                    
                    <Link to="/" className="back-home-button">
                      {content.backToHome}
                    </Link>
                  </section>
                </div>
              </div>
            </main>
            <Footer />
          </div>
        );
      };
      
      export default Contribution;
      
      import { t } from 'intlayer';
      
      const contributionContent = {
        key: 'contribution',
        content: {
          title: t({
            en: 'Contributing to Intlayer',
            fr: 'Contribuer à Intlayer',
            es: 'Contribuir a Intlayer',
            hi: 'इंटलेयर में योगदान'
          }),
          subtitle: t({
            en: 'Help us build the future of internationalization',
            fr: 'Aidez-nous à construire l\\'avenir de l\\'internationalisation',
            es: 'Ayúdanos a construir el futuro de la internacionalización',
            hi: 'अंतर्राष्ट्रीयकरण के भविष्य के निर्माण में हमारी सहायता करें'
          }),
          understandingTitle: t({
            en: 'Understanding the Project',
            fr: 'Comprendre le projet',
            es: 'Entender el proyecto',
            hi: 'परियोजना को समझना'
          }),
          understandingText: t({
            en: 'To understand the project, you can read the documentation named "How Intlayer Works". This will give you a comprehensive overview of the architecture and how different packages work together to provide seamless internationalization.',
            fr: 'Pour comprendre le projet, vous pouvez lire la documentation intitulée "Comment fonctionne Intlayer". Cela vous donnera un aperçu complet de l\\'architecture et de la façon dont les différents packages fonctionnent ensemble pour fournir une internationalisation transparente.',
            es: 'Para entender el proyecto, puedes leer la documentación llamada "Cómo funciona Intlayer". Esto te dará una visión general completa de la arquitectura y cómo los diferentes paquetes trabajan juntos para proporcionar internacionalización sin problemas.',
            hi: 'परियोजना को समझने के लिए, आप "इंटलेयर कैसे काम करता है" नामक दस्तावेज़ पढ़ सकते हैं। यह आपको आर्किटेक्चर का व्यापक अवलोकन देगा और विभिन्न पैकेज कैसे मिलकर निर्बाध अंतर्राष्ट्रीयकरण प्रदान करते हैं।'
          }),
          developmentTitle: t({
            en: 'Development Setup',
            fr: 'Configuration de développement',
            es: 'Configuración de desarrollo',
            hi: 'विकास सेटअप'
          }),
          developmentText: t({
            en: 'Intlayer is developed as a mono-repo using pnpm. To set up the repository, you will need to follow these steps: Clone the repository, Install the approved version of pnpm, Install dependencies, Build packages, Start dev mode, and Launch apps to interact with frontend, CMS, online docs, etc.',
            fr: 'Intlayer est développé comme un mono-repo utilisant pnpm. Pour configurer le référentiel, vous devrez suivre ces étapes : Cloner le référentiel, Installer la version approuvée de pnpm, Installer les dépendances, Construire les packages, Démarrer le mode dev, et Lancer les applications pour interagir avec le frontend, CMS, docs en ligne, etc.',
            es: 'Intlayer se desarrolla como un mono-repo usando pnpm. Para configurar el repositorio, necesitarás seguir estos pasos: Clonar el repositorio, Instalar la versión aprobada de pnpm, Instalar dependencias, Construir paquetes, Iniciar modo dev, y Lanzar aplicaciones para interactuar con frontend, CMS, docs en línea, etc.',
            hi: 'इंटलेयर को pnpm का उपयोग करके मोनो-रेपो के रूप में विकसित किया गया है। रिपॉजिटरी सेट करने के लिए, आपको इन चरणों का पालन करना होगा: रिपॉजिटरी क्लोन करें, pnpm का अनुमोदित संस्करण इंस्टॉल करें, निर्भरताएं इंस्टॉल करें, पैकेज बिल्ड करें, डेव मोड शुरू करें, और फ्रंटएंड, CMS, ऑनलाइन डॉक्स आदि के साथ इंटरैक्ट करने के लिए ऐप्स लॉन्च करें।'
          }),
          fullGuideButton: t({
            en: 'View Full Contributing Guide',
            fr: 'Voir le guide complet de contribution',
            es: 'Ver la guía completa de contribución',
            hi: 'पूर्ण योगदान गाइड देखें'
          }),
          backToHome: t({
            en: 'Back to Home',
            fr: 'Retour à l\\'accueil',
            es: 'Volver al inicio',
            hi: 'होम पर वापस जाएं'
          })
        }
      };
      
      export default contributionContent;
      
      • src/services: Data fetching logic blogService.ts

      blogService.ts

      💡 Note : For Change the language inside the image I’ve used placehold.co so that while switching the language it can change.

        export interface BlogPost {
        title: string;
        link: string;
        pubDate: string;
        description: string;
        content: string;
        thumbnail?: string;
        language: string;
      }
      
      // Multilingual mock data for testing
      const blogTranslations: Record<string, BlogPost[]> = {
        en: [
          {
            title: 'What is internationalisation (i18n)',
            link: '/what-is-internationalisation',
            pubDate: new Date('2025-07-31').toISOString(),
            description: 'Get to Know about internationalization.',
            content: `<p>Internationalisation is nothing but a language translation for all available languages, so it’s a commonly referred to as i18n as there are 18 letters between the first "i" and the last "n", so it is the process of designing and developing products, especially software, so they can be easily adapted for different languages, regions, and cultural preferences without requiring significant code changes.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=What+is+internationalisation&font=poppins>',
            language: 'en',
          },
          {
            title: 'Key aspects of internationalisation (i18n)',
            link: '/aspects-of-internationalisation',
            pubDate: new Date('2025-08-01').toISOString(),
            description: 'Get to know about the key aspects of internationalisation.',
            content: `<p>So Here are the Key Aspects of Internationalisation:</p><ul><li>Code and content separation: Create systems with all localizable components (text, currencies, date and number formats, images, etc.) separate from the main software logic to facilitate simple localization.</li><li>Handle differences in writing systems, units of measurement, date/time formats, keyboard layouts, and address/phone number structures with local awareness.</li><li>Preparation for localization (l10n): By facilitating these adaptations, internationalization creates the foundation for localization, which is the actual process of modifying the product for a particular target location.</li></ul>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Aspects+of+internationalisation&font=poppins>',
            language: 'en',
          },
          {
            title: 'Introducing Intlayer',
            link: '/introducing-intlayer',
            pubDate: new Date('2025-08-02').toISOString(),
            description: 'Intlayer is a React library that provides a set of tools to help you build internationalized applications.',
            content: `<p>Intlayer is an internationalization library created exclusively for JavaScript developers. It enables the declaration of your content across your code. It translates multilingual content declarations to structured dictionaries that can be readily included in your code. Intlayer uses TypeScript to make your development stronger and more efficient.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Introducing+Intlayer&font=poppins>',
            language: 'en',
          },
        ],
        fr: [
          {
            title: 'Qu\\'est-ce que l\\'internationalisation (i18n)',
            link: '/what-is-internationalisation',
            pubDate: new Date('2025-07-31').toISOString(),
            description: 'Découvrez l\\'internationalisation.',
            content: `<p>L\\'internationalisation est la traduction linguistique pour toutes les langues disponibles, souvent appelée i18n car il y a 18 lettres entre le premier "i" et le dernier "n". C\\'est le processus de conception et de développement de produits, en particulier de logiciels, afin qu\\'ils puissent être facilement adaptés à différentes langues, régions et préférences culturelles sans nécessiter de modifications majeures du code.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Qu%27est-ce+que+l%27internationalisation&font=poppins>',
            language: 'fr',
          },
          {
            title: "Principaux aspects de l'internationalisation (i18n)",
            link: '/aspects-of-internationalisation',
            pubDate: new Date('2025-08-01').toISOString(),
            description: "Découvrez les aspects clés de l'internationalisation.",
            content: `<p>Voici les principaux aspects de l'internationalisation :</p><ul><li>Séparation du code et du contenu : créez des systèmes avec tous les composants localisables séparés de la logique principale pour faciliter la localisation.</li><li>Gérez les différences de systèmes d'écriture, unités de mesure, formats de date/heure, dispositions de clavier, et structures d'adresse/numéro de téléphone avec une conscience locale.</li><li>Préparation à la localisation (l10n) : en facilitant ces adaptations, l'internationalisation crée la base pour la localisation, qui consiste à modifier le produit pour un lieu cible particulier.</li></ul>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Aspects+de+l%27internationalisation&font=poppins>',
            language: 'fr',
          },
          {
            title: 'Présentation d\\'Intlayer',
            link: '/introducing-intlayer',
            pubDate: new Date('2025-08-02').toISOString(),
            description: 'Intlayer est une bibliothèque React pour créer des applications internationalisées.',
            content: `<p>Intlayer est une bibliothèque d'internationalisation créée exclusivement pour les développeurs JavaScript. Elle permet de déclarer votre contenu dans votre code. Intlayer traduit les déclarations de contenu multilingues en dictionnaires structurés facilement intégrables. Intlayer utilise TypeScript pour renforcer et optimiser le développement.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Présentation+d%27Intlayer&font=poppins>',
            language: 'fr',
          },
        ],
        es: [
          {
            title: '¿Qué es la internacionalización (i18n)?',
            link: '/what-is-internationalisation',
            pubDate: new Date('2025-07-31').toISOString(),
            description: 'Conozca la internacionalización.',
            content: `<p>La internacionalización es la traducción de idiomas para todos los idiomas disponibles, comúnmente llamada i18n porque hay 18 letras entre la primera "i" y la última "n". Es el proceso de diseñar y desarrollar productos, especialmente software, para que puedan adaptarse fácilmente a diferentes idiomas, regiones y preferencias culturales sin requerir cambios significativos en el código.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Qué+es+la+internacionalización&font=poppins>',
            language: 'es',
          },
          {
            title: 'Aspectos clave de la internacionalización (i18n)',
            link: '/aspects-of-internationalisation',
            pubDate: new Date('2025-08-01').toISOString(),
            description: 'Conozca los aspectos clave de la internacionalización.',
            content: `<p>Estos son los aspectos clave de la internacionalización:</p><ul><li>Separación de código y contenido: cree sistemas con todos los componentes localizables separados de la lógica principal para facilitar la localización.</li><li>Maneje diferencias en sistemas de escritura, unidades de medida, formatos de fecha/hora, distribuciones de teclado y estructuras de dirección/teléfono con conocimiento local.</li><li>Preparación para la localización (l10n): al facilitar estas adaptaciones, la internacionalización crea la base para la localización, que es el proceso de modificar el producto para una ubicación objetivo.</li></ul>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Aspectos+de+la+internacionalización&font=poppins>',
            language: 'es',
          },
          {
            title: 'Presentando Intlayer',
            link: '/introducing-intlayer',
            pubDate: new Date('2025-08-02').toISOString(),
            description: 'Intlayer es una biblioteca de React para aplicaciones internacionalizadas.',
            content: `<p>Intlayer es una biblioteca de internacionalización creada exclusivamente para desarrolladores JavaScript. Permite declarar contenido multilingüe en el código. Intlayer traduce estas declaraciones a diccionarios estructurados fácilmente integrables. Utiliza TypeScript para un desarrollo más sólido y eficiente.</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=Presentando+Intlayer&font=poppins>',
            language: 'es',
          },
        ],
        hi: [
          {
            title: 'अंतर्राष्ट्रीयकरण (i18n) क्या है?',
            link: '/what-is-internationalisation',
            pubDate: new Date('2025-07-31').toISOString(),
            description: 'अंतर्राष्ट्रीयकरण के बारे में जानें।',
            content: `<p>अंतर्राष्ट्रीयकरण सभी उपलब्ध भाषाओं के लिए भाषा अनुवाद है, जिसे आमतौर पर i18n कहा जाता है क्योंकि पहले "i" और अंतिम "n" के बीच 18 अक्षर होते हैं। यह विभिन्न भाषाओं, क्षेत्रों और सांस्कृतिक प्राथमिकताओं के लिए उत्पादों, विशेष रूप से सॉफ़्टवेयर, को आसानी से अनुकूलित करने के लिए डिज़ाइन और विकास की प्रक्रिया है, जिसमें महत्वपूर्ण कोड परिवर्तन की आवश्यकता नहीं होती।</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=अंतर्राष्ट्रीयकरण+(i18n)+क्या+है&font=poppins>',
            language: 'hi',
          },
          {
            title: 'अंतर्राष्ट्रीयकरण (i18n) के मुख्य पहलू',
            link: '/aspects-of-internationalisation',
            pubDate: new Date('2025-08-01').toISOString(),
            description: 'अंतर्राष्ट्रीयकरण के मुख्य पहलुओं के बारे में जानें।',
            content: `<p>यहाँ अंतर्राष्ट्रीयकरण के मुख्य पहलू दिए गए हैं:</p><ul><li>कोड और सामग्री को अलग करना: सभी स्थानीयकरण योग्य घटकों को मुख्य सॉफ़्टवेयर लॉजिक से अलग करें ताकि स्थानीयकरण आसान हो सके।</li><li>लिपि, माप की इकाइयाँ, दिनांक/समय प्रारूप, कीबोर्ड लेआउट और पता/फोन नंबर संरचनाओं में अंतर को स्थानीय जागरूकता के साथ संभालें।</li><li>स्थानीयकरण (l10n) की तैयारी: इन अनुकूलनों को आसान बनाकर, अंतर्राष्ट्रीयकरण स्थानीयकरण की नींव रखता है, जो किसी विशेष लक्ष्य स्थान के लिए उत्पाद को अनुकूलित करने की प्रक्रिया है।</li></ul>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=अंतर्राष्ट्रीयकरण+(i18n)+के+मुख्य+पहलू&font=poppins>',
            language: 'hi',
          },
          {
            title: 'इंटलेयर का परिचय',
            link: '/introducing-intlayer',
            pubDate: new Date('2025-08-02').toISOString(),
            description: 'इंटलेयर एक React लाइब्रेरी है जो अंतर्राष्ट्रीयकृत एप्लिकेशन बनाने में मदद करती है।',
            content: `<p>इंटलेयर एक अंतर्राष्ट्रीयकरण लाइब्रेरी है जो विशेष रूप से JavaScript डेवलपर्स के लिए बनाई गई है। यह आपके कोड में सामग्री की घोषणा करने की अनुमति देती है। Intlayer बहुभाषी सामग्री घोषणाओं को संरचित शब्दकोशों में अनुवाद करती है जिन्हें आसानी से आपके कोड में शामिल किया जा सकता है। Intlayer TypeScript का उपयोग करता है ताकि आपका विकास मजबूत और कुशल हो।</p>`,
            thumbnail: '<https://placehold.co/300x200/2563eb/FFF?text=इंटलेयर+का+परिचय&font=poppins>',
            language: 'hi',
          },
        ],
      };
      
      export const fetchBlogPosts = async (language: string = 'en'): Promise<BlogPost[]> => {
        // Return posts for the requested language, fallback to English if not found
        return blogTranslations[language] || blogTranslations['en'];
      };
        

      4. Implement Internationalization with an explanation for all the above code files

      • Component-Level Content

        • For each component, create a .content.ts file exporting the multilingual content using Intlayer’s API.
        • BlogSummaryList.content.ts with content for EN, FR, ES, HI.
      • Dynamic Language Switching

        • Add a language selector UI.
        • Use Intlayer’s hooks to switch and retrieve localized content.
      • How is Intlayer working while running your code?

        dot intlayer folder after compiling
        dot intlayer folder after compiling
      • What is the .intlayer Folder?

      The .intlayer folder is an auto-generated directory created by the Intlayer toolchain when you run or build your project. It acts as an internal cache and compilation output for all your Intlayer-managed content and translations.

      • Key Points:

        • You should NOT manually edit files inside .intlayer.
        • This folder is usually git-ignored (not committed to version control).
        • It is regenerated automatically whenever you start or build your project.

        How Does Intlayer Work at Runtime?

        1. Component-Level Content Declarations: In your source code (e.g., BlogSummaryList.content.ts), you declare multilingual content using Intlayer’s API. Each component/page can have its content file, keeping translations close to the code.
        2. Compilation Step: When you run (npm run dev) or build (npm run build) your app, Intlayer scans your project for all *.content.ts files. It compiles these content files into a fast, unified format and outputs them into the .intlayer directory.

        This pre-compilation step ensures that all translations and content are type-safe and optimized for runtime.

        1. Runtime Usage: At runtime, the Intlayer provider and hooks fetch content directly from the compiled output in .intlayer. This makes content retrieval instant and ensures that only the required translations are loaded.

        Why is this Compilation Important?

        1. Performance: By compiling all content ahead of time, Intlayer avoids runtime parsing and delivers translations instantly.

        2. Type Safety: Compilation checks your content for errors and type mismatches, catching issues before they reach production.

        3. Separation of Concerns: You write content next to your components, but Intlayer handles the merging and optimization behind the scenes.

          Typical Directory Structure

            /src
            /components
              BlogSummaryList.tsx
              BlogSummaryList.content.ts
            ...
          /.intlayer
            (auto-generated content and translation files)
          /package.json
          
        4. Summary: The .intlayer folder is where Intlayer compiles and caches all your multilingual content for fast, type-safe, and efficient access at runtime. It’s a build artifact, not a place for manual changes.

      5. Build Core Features

      • Hero Section
        • Implement a visually appealing hero with a background image and overlay text from Intlayer.
      • Blog Management
        • Create a blogService.ts to simulate blog data.
        • Display blog summaries using BlogSummaryList.
        • Implement navigation to detailed blog views (BlogViewer) via React Router.

      6. Responsive Design & Testing

      • Mobile-First Approach
        • Use CSS modules or styled-components for responsive layouts.
        • Test on various screen sizes.
        • Test Internationalization
          • Switch between languages and ensure all content updates correctly.
        • Check Navigation
          • Validate routing between summary and detail pages.

      7. Deployment

      • Build the App
        • Run npm run build to generate production assets. (optional step) But recommend for best practices.
      npm run build command
      npm run build command
      • Now this will provide a dist folder for the production deployment. However, we will use a different hosting provider for this project, as it will connect it with our GitHub repository, which helps us to directly deploy our code into production.
      after build of dot intlayer folder
      after build of dot intlayer folder
      • Deploy
        • Last but not least is Deployment, so I’m gonna use Vercel for this demo, you are free to choose whatever platform you prefer
        • Log in to Vercel using GitHub and import your repository and Choose where you want to create the project and give it a name, and then hit deploy and wait for a few minutes. Then, it will successfully deploy.
      vercel deployment
      Vercel Project To Deploy


      Live Demo

      Intlayer Blog Demo Live
      Completed Project


      Live URL: Intlayer Blog Live Demo

      GitHub Repo (Final Output): Intlayer Demo Blog Repo

      My Final Thoughts and our Conclusion.

      In React, multilingual support is not only feasible but pleasurable when Intlayer for i18n is used.  This little project serves as a strong basis for larger projects when paired with Redux and an organized Webpack configuration.

      With libraries like react-intl, react-i18next, and others dominating the market, It has a chance to stand out from the competition. Its ability to achieve the ideal balance between feature richness and simplicity is probably what makes it stand out from the competition. It may provide better performance through sophisticated compilation, a more user-friendly developer interface, or a more cohesive end-to-end localization procedure. By tackling the typical compromises and disarray seen in alternative systems, it may establish itself as a simplified, unified, and very effective instrument for handling the full localization process.

      In the end, Intlayer is a strong option for developers and businesses hoping to create truly worldwide applications. Its potential advantages in performance, developer experience, and integrated tooling can make the sometimes intimidating process of internationalization easier, allowing for better user experiences and quicker market growth. Using a practical demonstration and highlighting the unique advantages in the changing i18n ecosystem.

      So thank you very much for reading till end of the post and take our precious time and i hope you have finished your project along with me if you have any doubts regarding to this project feel free to ping me, I will try to reply and clear your doubts.

      Thank you very much.

      Do you wish to contribute or have questions? Or saw something buggy? Do check out the GitHub repo, we are open source Intlayer GitHub

      Founder of Intlayer   Aymeric’s Message (Founder of Intlayer)

      Have you ever felt that adding internationalization slows down your development?

      Intlayer aims to rethink the way you implement i18n, to help you maintain your codebase and scale your project.

      We’d love to hear your feedback! Come supporting us on GitHub 🙌

      References

      Intlayer.orgproducthunt page of Intlayerproducthunt page

Hey! 👋 I’m Pratap, a Frontend Developer with 2+ years of experience crafting digital experiences through code and design. I specialize in frontend web development and UI/UX design, Through this blog…

Post a Comment