Skip to main content

Command Palette

Search for a command to run...

Data-i18n for Small Web Projects: A Complete Guide to Internationalization

Published
6 min read
Data-i18n for Small Web Projects: A Complete Guide to Internationalization

Modern web applications are used by people across different countries and languages. If your website only supports one language, it limits your audience. This is where internationalization (i18n) comes in.

In this blog, we will explore how to implement a simple and powerful data-i18n system in a small web project using HTML, CSS, and JavaScript, without any heavy frameworks.


What is Internationalization (i18n)?

Internationalization (i18n) is the process of designing your application so it can easily support multiple languages and regions.

The abbreviation i18n means:

  • i → first letter

  • 18 → number of letters between

  • n → last letter

Example:

internationalization
i + 18 letters + n

Internationalization allows applications to switch between languages like:

  • English

  • French

  • Spanish

  • Hindi

  • Japanese

without rewriting the entire application.


What is data-i18n?

data-i18n is a custom HTML attribute used to mark elements that should be translated.

Instead of hardcoding text in HTML, we assign a translation key.

Example:

<h1 data-i18n="title">Welcome</h1>
<p data-i18n="description">This is a demo app.</p>

Here:

  • title

  • description

are translation keys, not the actual translation.

JavaScript will dynamically replace the text based on the selected language.


How the System Works

The data-i18n system usually follows these steps:

  1. HTML contains translation keys

  2. Translations are stored in JSON files

  3. JavaScript loads the selected language

  4. JavaScript replaces the text dynamically

Flow diagram:

HTML (data-i18n keys)
        ↓
Translation JSON files
        ↓
JavaScript loads selected language
        ↓
Text updated dynamically

Step 1: Create the HTML Structure

First, we mark the text that needs translation.

<!DOCTYPE html>
<html>
<head>
  <title>i18n Demo</title>
</head>
<body>

<h1 data-i18n="title">Welcome</h1>

<p data-i18n="description">
This is a demo application.
</p>

<button data-i18n="login">Login</button>

<div>
  <button onclick="loadLanguage('en')">English</button>
  <button onclick="loadLanguage('fr')">French</button>
</div>

<script src="script.js"></script>

</body>
</html>

Notice that we still include default text so the page does not appear empty before JavaScript loads.


Step 2: Create Translation Files

Create a language folder.

project
│
├── index.html
├── script.js
│
└── lang
    ├── en.json
    └── fr.json

English Translation

lang/en.json

{
  "title": "Welcome",
  "description": "This is a demo application.",
  "login": "Login"
}

French Translation

lang/fr.json

{
  "title": "Bienvenue",
  "description": "Ceci est une application de démonstration.",
  "login": "Connexion"
}

Each key must match the data-i18n value.


Step 3: JavaScript Translation Engine

Now we create a function that loads the selected language and updates the page.

script.js

async function loadLanguage(lang) {

  const response = await fetch(`./lang/${lang}.json`);

  const translations = await response.json();

  const elements = document.querySelectorAll("[data-i18n]");

  elements.forEach(element => {

    const key = element.getAttribute("data-i18n");

    if (translations[key]) {
      element.textContent = translations[key];
    }

  });

}

This script does three things:

  1. Loads the translation JSON file

  2. Finds all elements with data-i18n

  3. Replaces the text with the translated value


Step 4: Language Switching

We can switch languages using buttons.

<button onclick="loadLanguage('en')">English</button>
<button onclick="loadLanguage('fr')">French</button>

When clicked:

loadLanguage("en") → loads English
loadLanguage("fr") → loads French

The page text updates instantly.


Step 5: Saving Language Preference

In real applications we usually save the user's preferred language.

We can use localStorage.

Example:

async function loadLanguage(lang) {

  localStorage.setItem("language", lang);

  const response = await fetch(`./lang/${lang}.json`);

  const translations = await response.json();

  document.querySelectorAll("[data-i18n]").forEach(el => {

    const key = el.dataset.i18n;

    if (translations[key]) {
      el.textContent = translations[key];
    }

  });

}

Auto Load Language on Page Start

window.addEventListener("DOMContentLoaded", () => {

  const savedLang = localStorage.getItem("language") || "en";

  loadLanguage(savedLang);

});

Now the site remembers the user's language.


Step 6: Translating Attributes

Sometimes we need to translate attributes like:

  • placeholders

  • titles

  • aria labels

Example:

<input type="text" data-i18n-placeholder="search" placeholder="Search">

Translation file:

{
  "search": "Search..."
}

JavaScript:

document.querySelectorAll("[data-i18n-placeholder]").forEach(el => {

  const key = el.getAttribute("data-i18n-placeholder");

  el.placeholder = translations[key];

});

Performance Considerations

For small projects this approach is perfect, but large applications may require optimization.

Possible improvements:

Lazy loading languages

Load only the language being used.

Caching translations

Store translations in memory to avoid repeated network requests.

Preloading common languages

Load frequently used languages on startup.


Advantages of the data-i18n Approach

Simple implementation

No frameworks required.

Clean HTML

Translation logic stays separate from markup.

Lightweight

Only a few lines of JavaScript.

Easy to maintain

Translators can edit JSON files without touching code.

Flexible

Works with any frontend stack.


Limitations

Although useful, the data-i18n approach has some limitations.

No pluralization rules

Languages like Russian or Arabic require complex plural logic.

No date or number formatting

Formatting currencies and dates requires additional libraries.

No nested translations

Large projects often require structured translations.


When to Use a Full i18n Library

If your project becomes large, consider using a professional library like:

  • i18next

  • react-i18next

  • vue-i18n

These tools support:

  • pluralization

  • date formatting

  • dynamic translations

  • server side rendering

  • language detection


Example Use Cases

The data-i18n pattern works well for:

  • Landing pages

  • SaaS dashboards

  • Documentation sites

  • Small web apps

  • Portfolio websites

  • MVP products

For example, if you build a multi-language SaaS dashboard, you can translate UI labels like:

Dashboard
Analytics
Settings
Logout

without changing the layout.


Conclusion

Internationalization is an important feature for modern web applications. Even small projects benefit from supporting multiple languages.

The data-i18n approach provides a lightweight and flexible solution for implementing translations using simple HTML attributes and JSON files.

With just a small amount of JavaScript, you can create a system that:

  • dynamically switches languages

  • loads translations from JSON files

  • remembers user preferences

  • keeps HTML clean and maintainable

As your application grows, you can later migrate to advanced libraries while keeping the same translation structure.