If your static website has a sales funnel and you’re wondering why visitors from specific regions are not converting at all, the reason could be the absence of a multilingual website that supports the languages of these specific regions. But is it possible to add multilingual support to a static website? Yes, it is! And you don’t need a complex framework or CMS to do that. You can do it by just using HTML and a little sprinkle of vanilla JavaScript. In this tutorial, we’ll learn a step-by-step method to implement multilingual support on a static website. You can apply it easily on your existing website. Let’s get started!
Use web analytics data to analyze whether your website actually needs a multilingual version or not. Sales funnel tracking data can help you make the right decision. Look for countries with the fewest conversions.
Always work on a clone if you're going to implement this feature on an existing website. And only add languages that are actually required. You can add more later as and when needed.
Step 1: Plan and Decide Before Touching the Code
First decide the essentials before starting the code editing session. Here's what you need to plan and decide.
Shortlist the Languages You're Going to Support
As mentioned above, first skim the analytics data and decide on the languages you're going to support. Keep only the essential ones. The goal is to avoid unnecessary language additions.
Decide on the URL Structure
This is the most critical decision you have to make before editing the website code. The following are the four different ways you can apply the URL structure:
- Subdirectory - An example URL structure is
domain.com/de/. This URL inherits the domain authority and can be implemented easily. - Subdomain - An example URL structure is
de.domain.com. This approach passes little or no domain authority of the primary domain. Implementing this approach is moderately difficult. - ccTLD - An example URL structure is
domain.de. This approach gives the strongest local signal. Implementing it is somewhat hectic and needs more resources as you build a separate website for every region. - Query Parameter - An example URL structure is
domain.com/?lang=de. It has the weakest SEO strength and generally should be avoided.
I'd recommend going with the subdirectory approach as it is easy to implement and passes on domain authority.
Decide About Translation Management
Another important thing to consider is translation management. Are you going to translate content on your own, or will you hire a professional for the same?
If you choose the latter option, you'll get the translations in the form of JSON, YAML, or .po files. Accordingly, you have to plan and structure your content format.
Step 2: Manual Implementation (No Framework)
If you are not using a static site generator and are just using HTML, CSS, and JavaScript for your static website, it is better to go with the manual approach. Here's a simple setup you can apply in this scenario.
Files and Folders Organization
Here you can see that the default language files are at the root, and the language-specific files are in their respective folders. For example, the path domain.com/fr/index.html is ideal both for the search engines and for the regular visitors.
Include hreflang Tags In Every Page
Here you need to be very careful. First of all, make sure you include the full set of hreflang tags in the <head> of every page. This also includes a self-referencing tag.
<head>
<link rel="alternate" hreflang="en" href="https://domain.com/about.html" />
<link rel="alternate" hreflang="fr" href="https://domain.com/fr/about.html" />
<link rel="alternate" hreflang="es" href="https://domain.com/es/about.html" />
<link rel="alternate" hreflang="x-default" href="https://domain.com/about.html" />
</head>
Here are a few things you need to take care of while adding these tags:
- Every page should link to all the other pages, including itself. If you miss one of the tags, the whole system will not work, and Google will ignore it altogether.
- Never use relative URLs in these tags. Always use absolute URLs.
- The tag with the
x-defaultattribute tells Google which page to redirect to when none of the languages match with the browser settings of the user. - When adding the language codes, always follow the ISO 639-1 format. For example,
en,de,fr.
Add a Simple Language Switcher
Make sure to add a simple drop-down menu to the website so that the visitor can select his preferred language. Here's a simple implementation of the same:
<select id="lang-switcher">
<option value="/about.html">English</option>
<option value="/fr/about.html">Français</option>
<option value="/es/about.html">Español</option>
</select>
<script>
document.getElementById('lang-switcher').addEventListener('change', function (e) {
window.location.href = e.target.value;
});
</script>
Always ensure to store the visitor's language preference in the browser's localStorage so that the correct language version is presented to the visitor whenever he visits the website again.
Failing to implement this feature would make the visitor select the language options again and again, which may lead to frustration.
// Save the preference whenever a user picks a language
localStorage.setItem('preferredLang', 'fr');
// On page load, offer (don't force) the saved preference
const saved = localStorage.getItem('preferredLang');
if (saved && !window.location.pathname.startsWith('/' + saved)) {
// show a small banner/prompt: "Continue in Français?"
}
Step 3: Using Built-In i18n of a Static Site Generator
Much of the work done in the previous section is handled automatically if you're using a static site generator for a website. Let's see how it is used in the most popular static site generators.
Hugo
Hugo supports multilingual features out of the box. It handles the necessary routing and automatically adds the necessary hreflang tags on every page.
# config.toml
defaultContentLanguage = "en"
[languages]
[languages.en]
languageName = "English"
weight = 1
[languages.fr]
languageName = "Français"
weight = 2
[languages.es]
languageName = "Español"
weight = 3
Hugo uses a language suffix for the file names so that it can pick the right web page whenever required. Here's what it looks like.
It also has a built-in {{ hreflang.Render }} template partial that facilitates automatic addition of hreflang tags on every webpage.
Eleventy (11ty)
Eleventy has an @11ty/elevety-plugin-i18n official plugin to implement the multilingual feature on a static website. It supports URL locale prefixing, translation lookups, and locale-aware links.
// .eleventy.js
const { EleventyI18nPlugin } = require("@11ty/eleventy-i18n");
module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(EleventyI18nPlugin, {
defaultLanguage: "en",
});
};
After activating this plugin, all you need to do is create language-specific content directories and the locale flags in the front matter. Now, Eleventy will automatically generate URLs with a locale prefix and will automatically build a language switcher for the website.
Astro
Astro has built-in multilingual support through the native i18n routing. All you need to do is configure the necessary settings in the astro.config.js file.
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
i18n: {
locales: ["en", "fr", "es"],
defaultLocale: "en",
routing: {
prefixDefaultLocale: false, // English stays at "/", others get "/fr/", "/es/"
},
},
});
The src/pages/ is the directory where all the language-specific folders reside. The structure and format are shown in the image below.
You can use the Astro.currentLocale and Astro.prefferedLocale helpers to build a custom language switcher for the website.
Jekyll
Now Jekyll doesn't have an i18n system baked in, but it does have a popular community-maintained jekll-multiple-languages-plugin plugin that works like charm. It uses YAML translation files, and the configuration is done in the _config.yml file. Once configured, it automatically generates locale-prefixed pages while building the website.
Step 4: Translated Content Structuring
No matter which static site generator you are using, you need a way to store translatable strings (for example, navigation labels, buttons, and content text in the header and footer) in a structured manner.
You can use YAML or JSON files for the same. Here are two examples to show you how it is done.
// locales/en.json
{
"nav": {
"home": "Home",
"about": "About",
"contact": "Contact"
},
"cta": {
"subscribe": "Subscribe to our newsletter"
}
}
// locales/fr.json
{
"nav": {
"home": "Accueil",
"about": "À propos",
"contact": "Contact"
},
"cta": {
"subscribe": "Abonnez-vous à notre newsletter"
}
}
The benefit of structuring the translatable strings in this manner is that you can easily edit and extend them whenever required in the future. And you never have to dive into the raw HTML of the website files.
Step 5: Configuring the SEO Settings
At this point, the job is half done. You have translated things and done the necessary settings in the configuration files and pages, but some essential SEO settings need to be configured.
Add hreflang to the Sitemap
Apart from adding hreflang tags on the web pages, you can also add them in the sitemap.xml file. This ensures that the search engines can better understand the page relationships in a multilingual environment. It is useful for large static websites.
<url>
<loc>https://domain.com/about.html</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://domain.com/about.html" />
<xhtml:link rel="alternate" hreflang="fr" href="https://domain.com/fr/about.html" />
<xhtml:link rel="alternate" hreflang="es" href="https://domain.com/es/about.html" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://domain.com/about.html" />
</url>
Create Correct Canonical Tags
Remember, the translated pages' canonical tag should point to itself and not to the one using the default language of the site. This mistake is often made by developers who ensure that all the canonical tags are pointing to the default language pages.
<link rel="canonical" href="https://domain.com/fr/about.html" />
Translate Important Metadata
Make sure you also translate the <title>, meta description, Open Graph tags, and image alt text, so that the pages are fully localized as per the language. This ensures search engines as well as various social media platforms can make the right decision about which page to show to the user.
Step 6: Configuring Support for RTL Languages
If one or more RTL languages are part of your multilingual website, the layout direction of the language text is critical. Fortunately, modern CSS and HTML make the implementation of this feature much easier than it used to be.
To get started, set the dir attribute on the <html> tag of every RTL language page.
<html lang="ar" dir="rtl">
Now, all you need to do is add the necessary CSS to support the RTL language on that page. Here's an example.
/* Instead of this: */
.card {
padding-left: 1rem;
text-align: left;
}
/* Use this: */
.card {
padding-inline-start: 1rem;
text-align: start;
}
Logical properties in CSS like inline-start, inline-end, block-start, and block-end are supported by all modern browsers. You must adopt them in your core CSS style sheet, right from the beginning.
Conclusion
Adding multilingual support on a static website is not as difficult as it seems. All you need to do is pick a URL structure and add the hreflang tags on the web pages. If you are using a static site generator, use the built-in i18n feature. Once configured, make sure you do the necessary SEO settings and add support for RTL languages, if any.
So what are you waiting for? Use this guide and add support for multiple languages on your static website.