Simple and Effective Multilingual Implementation for Landing Pages 🌍
Alina Khmilevska

Alina Khmilevska @alina_khmilevska_lee

About: I'm a Full-stack Drupal developer with 3+ years building complex web applications, from e-commerce platforms to educational sites. I contribute to open-source projects and focus on creating clean.

Location:
Ukraine
Joined:
Apr 2, 2025

Simple and Effective Multilingual Implementation for Landing Pages 🌍

Publish Date: Apr 9
1 0

Hello, developers! 👋 Today I want to share a proven approach for adding multilingual support to landing pages without using heavy external libraries. In this article, we'll explore an architecture that allows you to quickly and easily implement support for multiple languages on static websites.

Why Multilingual Support Matters 🤔

In today's global world, even a simple landing page may need to support multiple languages:

  • 🚀 Expanding your product's audience
  • 🌟 Improving user experience for international visitors
  • 📈 Increasing conversions from foreign users
  • 🔍 Improving SEO for different regions

While specialized libraries (i18next, Angular Translate, etc.) are often used for large projects, such an approach may be excessive for a simple landing page. Instead, you can implement an elegant solution using pure JavaScript.

Architecture of a Multilingual Site 📁

To implement multilingual support on a landing page, we need just three components:

  1. HTML structure with translation attributes
  2. Translation file (translations.js)
  3. Language switching system (language-switcher.js)

This architecture provides:

  • 🔄 Easy addition of new languages without changing the core code
  • 🔍 Improved SEO thanks to properly set language attributes
  • 📱 Support for remembering the user's language choice
  • 🔌 No external dependencies

Step 1: Preparing HTML with Translation Attributes 📝

The key aspect of our approach is using data-i18n attributes for elements that need translation. Here's an example:

<header>
    <div class="logo">
        <img src="images/logo.png" alt="Logo">
    </div>
    <div class="language-dropdown">
        <button class="language-btn" id="language-btn">
            <span class="lang-icon en-icon">EN</span>
            <span class="lang-text">English</span>
            <span class="dropdown-arrow">
                <!-- Arrow icon -->
            </span>
        </button>
        <div class="language-menu" id="language-menu">
            <div class="language-option active" data-lang="en">
                <span class="lang-icon en-icon">EN</span>
                <span class="lang-text">English</span>
                <span class="check-mark"></span>
            </div>
            <div class="language-option" data-lang="ua">
                <span class="lang-icon ua-icon">UA</span>
                <span class="lang-text">Українська</span>
            </div>
            <!-- Other languages -->
        </div>
    </div>
</header>

<section class="hero">
    <h1 data-i18n="main_title">Main Title</h1>
    <p data-i18n="subtitle">Subtitle that will be translated</p>
    <button class="cta" data-i18n="get_started">Get Started</button>
</section>
Enter fullscreen mode Exit fullscreen mode

For elements containing placeholder attributes, we use data-i18n-placeholder:

<input type="email" placeholder="Your email" data-i18n-placeholder="email_placeholder">
Enter fullscreen mode Exit fullscreen mode

Step 2: Translation File Structure 🔤

The translations.js file contains an object with translations for all supported languages:

// Example structure of translations.js file
const translations = {
    en: {
        "main_title": "Main Title",
        "subtitle": "Subtitle that will be translated",
        "get_started": "Get Started",
        "email_placeholder": "Your email"
        // Other translations for English
    },
    ua: {
        "main_title": "Головний заголовок",
        "subtitle": "Підзаголовок, який буде перекладатися",
        "get_started": "Почати",
        "email_placeholder": "Ваш email"
        // Other translations for Ukrainian
    },
    // Other languages
}
Enter fullscreen mode Exit fullscreen mode

This structure allows:

  • Easy addition of new languages
  • Logical grouping of keys (by sections or components)
  • Quick finding and updating of translations

Step 3: Implementing the Language Switcher 🔄

The key part of the system is the language-switcher.js script, which handles:

  • 🔍 Determining the initial language (from URL, localStorage, or browser)
  • 🔄 Switching between languages
  • 💾 Saving the user's choice
  • 🌐 Setting language attributes for SEO

Let's look at the main functions of this script:

Language System Initialization:

// Constants for better code readability
const STORAGE_KEY = 'site-language';
const DEFAULT_LANG = 'en';
const SUPPORTED_LANGUAGES = ['en', 'ua', 'fr', 'ca', 'es', 'pl', 'ru'];

// Cached DOM elements to improve performance
let cachedElements = null;

// Language system initialization
function initLanguageSystem() {
  // Check URL for language parameter
  const urlParams = new URLSearchParams(window.location.search);
  const urlLang = urlParams.get('lang');

  // Language selection priority: URL > localStorage > browser > English
  let selectedLang;

  if (urlLang && isLanguageSupported(urlLang)) {
    // Language is specified in URL and supported
    selectedLang = urlLang;
    localStorage.setItem(STORAGE_KEY, selectedLang);
  } else {
    // Get from localStorage or determine from browser
    selectedLang = localStorage.getItem(STORAGE_KEY);

    if (!selectedLang || !isLanguageSupported(selectedLang)) {
      // Try to detect browser language
      selectedLang = getBrowserLanguage();

      if (!isLanguageSupported(selectedLang)) {
        // If browser language is not supported, use English
        selectedLang = DEFAULT_LANG;
      }
    }
  }

  // Apply the selected language
  setLanguage(selectedLang);
  updateLanguageUI(selectedLang);
}
Enter fullscreen mode Exit fullscreen mode

Applying Translations:

// Set the page language and update all text elements
function setLanguage(lang) {
  // Cache elements on first call to improve performance
  if (!cachedElements) {
    cachedElements = {
      textElements: document.querySelectorAll('[data-i18n]'),
      placeholderElements: document.querySelectorAll('[data-i18n-placeholder]'),
      selectElements: document.querySelectorAll('option[data-i18n]')
    };
  }

  // Save language preference
  localStorage.setItem(STORAGE_KEY, lang);

  // Set the lang attribute for HTML
  document.documentElement.setAttribute('lang', lang);

  // Get translations for the selected language
  const trans = translations[lang] || translations[DEFAULT_LANG]; // Fallback to English

  // Update page title
  const titleElement = document.querySelector('title');
  if (titleElement && titleElement.getAttribute('data-i18n')) {
    const titleKey = titleElement.getAttribute('data-i18n');
    if (trans[titleKey]) {
      titleElement.textContent = trans[titleKey];
    }
  }

  // Update all elements with 'data-i18n' attribute
  cachedElements.textElements.forEach(element => {
    const key = element.getAttribute('data-i18n');
    if (trans[key]) {
      element.textContent = trans[key];
    }
  });

  // Update all elements with 'data-i18n-placeholder' attribute
  cachedElements.placeholderElements.forEach(element => {
    const key = element.getAttribute('data-i18n-placeholder');
    if (trans[key]) {
      element.setAttribute('placeholder', trans[key]);
    }
  });

  // Update all select options with 'data-i18n' attribute
  cachedElements.selectElements.forEach(option => {
    const key = option.getAttribute('data-i18n');
    if (trans[key]) {
      option.textContent = trans[key];
    }
  });

  // Dispatch language change event
  document.dispatchEvent(new CustomEvent('languageChanged', { detail: { language: lang }}));
}
Enter fullscreen mode Exit fullscreen mode

Optimizations for Better Performance 🚀

Our approach includes several important optimizations:

  1. DOM Element Caching:
    We cache all elements with translation attributes on the first call to setLanguage(), which significantly speeds up subsequent language switches.

  2. Browser Language Detection:
    The function automatically detects the browser language to show the site in the user's native language:

   function getBrowserLanguage() {
     // Get language from navigator.language (e.g., 'en-US', 'ru', 'fr')
     const fullLang = navigator.language || navigator.userLanguage || DEFAULT_LANG;
     // Take only the first part of the code (e.g., 'en' from 'en-US')
     return fullLang.split('-')[0];
   }
Enter fullscreen mode Exit fullscreen mode
  1. Saving User's Choice:
    The language choice is saved in localStorage so the user sees the site in their language on subsequent visits.

  2. URL Updates:
    Adding a language parameter to the URL for better SEO and the ability to share links to the site in a specific language:

   function updateUrlWithLanguage(lang) {
     // Don't change URL if not needed
     if (!shouldUpdateUrlWithLang()) return;

     const url = new URL(window.location.href);
     url.searchParams.set('lang', lang);

     // Use History API to update URL without reloading
     window.history.replaceState({}, '', url.toString());
   }
Enter fullscreen mode Exit fullscreen mode

Advantages of This Approach Compared to Libraries 🏆

  1. Speed and Simplicity:

    • Minimal code (less than 200 lines of JavaScript)
    • No external dependencies
    • Faster page loading
  2. Flexibility and Control:

    • Full control over the code
    • Easy to modify for specific needs
    • Possibility of integration with other systems
  3. Performance:

    • DOM element caching
    • Minimal repainting operations
    • Optimized selectors
  4. SEO-Friendliness:

    • Proper setting of language attributes
    • Support for alternative links for different languages
    • Language parameters in URL

Practical Implementation Tips 💡

  1. Structure Translations Logically: Group translation keys by sections or components for easier maintenance:
   const translations = {
     en: {
       // Site header
       header: {
         nav_home: "Home",
         nav_features: "Features"
       },
       // Main section
       hero: {
         title: "Welcome",
         subtitle: "Discover our platform"
       }
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Use Automatic Language Detection with Opt-Out:
    Automatically detect the user's language, but always provide the option to change it.

  2. Optimize for SEO:

    • Add hreflang attributes in the header
    • Set the lang attribute for the HTML element
    • Use language parameters in the URL
  3. Ensure Smooth User Experience:

    • Avoid flickering when changing languages
    • Save the user's choice
    • Provide clear language labels (with flags or codes)

Conclusion 📌

Multilingual support doesn't have to be complex or require heavy frameworks. For static landing pages and small sites, the lightweight system we've discussed in this article is ideal. It provides all the necessary functions with minimal code.

This approach can be easily extended or integrated with CMS, communication systems, and other components of your project. And best of all, you have full control over the code and can customize the system exactly to your needs.

What approach to multilingual support do you use? Share your experience in the comments! 💬

Comments 0 total

    Add comment