DEV Community

Cover image for 11 Step Checklist for Translating a Website
Lukas Mauser
Lukas Mauser Subscriber

Posted on • Edited on

10 3 3 3 3

11 Step Checklist for Translating a Website

At sliplane.io we recently added another language to our website and since I did this in another project before, I knew it was going to be a huge hassle! That's why this time, I derived a checklist, that you can follow when translating your own website. I use nuxt/i18n in the examples, but the checklist generally applies to all technologies.

Strategies:

Before we get into it, let me clarify what this checklist is for. There are several strategies when it comes to internationalizing a website:

  1. Separate websites for each language
  2. Same website but different content
  3. Same website, same content, but localized

I will only focus on number 3 here, I think in most cases this is the least effort to pull off and maintain.

Checklist

Before getting started, create a list of all layouts, pages and components that need to be translated. It helps to do this in advance, to keep an overview over the status of translations. You then go through each layout/ page/ component and follow the checklist below:

html lang attribute

The first thing to do is to add the html lang attribute:

<html lang="de-de"> 
...
</html>
Enter fullscreen mode Exit fullscreen mode

Two letter language codes like de also work, but it's best practice to include the country.

Internal and external links

You want to make sure, that on a German site, internal and external links point to German content. I18n plugins usually provide utilities to deal with internal routing in SPAs, for external links it's important to adjust the href accordingly.

<a href="/">Homepage</a>
Enter fullscreen mode Exit fullscreen mode

becomes

<a :href="localePath('/')">{{ $t('homepage') }}</a>
Enter fullscreen mode Exit fullscreen mode

Images

Sometimes images contain text or they are localized in another way, so that it's necessary to show a different image for each language. Remember to localize the alt and src property if necessary.

<img alt="A picture of myself" src="/me.png" >
Enter fullscreen mode Exit fullscreen mode

becomes

<img :alt="$t('me.alt')" :src="$t('me.src')" >
Enter fullscreen mode Exit fullscreen mode

Aria Labels

Aria labels are sometimes overlooked, when translating a website. In case you use them, remember to also translate Aria labels.

<button aria-label="Open Menu"><icon menu /></button>
Enter fullscreen mode Exit fullscreen mode

becomes

<button :aria-label="$t('open-menu')"><icon menu /></button>
Enter fullscreen mode Exit fullscreen mode

Variables and pluralization in Text:

Variables in text can be challenging to translate, since you can't just provide a static string, but have to run some sort of interpolation to inject your variables and dynamically adjust the pluralization.

Usually the i18n plugin ships with this feature, but it can be pain to use it consistently since it just adds a lot of code, so sometimes it's easier to rephrase your sentences like this: "There are 5 apples in my box" becomes: "Apples in my box: 5"

There are {{ numberOfApples }} in my box.
Enter fullscreen mode Exit fullscreen mode

becomes

{{ $t('applesText', numberOfApples) }}
Enter fullscreen mode Exit fullscreen mode

Datetime and number formatting

Make sure to adjust how date times and numbers are formatted. In the US, decimals are separated by . in Europe it's a ,. Also adjust currency formats: in some languages the currency symbol is in front of the number $5.00 sometimes it's after 10,00€. On top you need to consider conversions of other units like distance (feet to meters), weight (pounds to kilograms) or volumes (ounces to liters)…

You can either leverage your i18n plugin or use native functionality like date.toLocaleDateString(locale, {...}) (toLocaleDateString) or new Intl.NumberFormat(locale).format(count)(Intl).

Total cost: $5.00
Enter fullscreen mode Exit fullscreen mode

becomes

{{ $t('totalCost') }}: {{ $n(5, 'currency', locale) }}
Enter fullscreen mode Exit fullscreen mode

HTML

In a couple of cases I stumbled over this situation:

This is <strong>very</stong> important!
Enter fullscreen mode Exit fullscreen mode

In order to translate that, without loosing the styling, you can translate the html and render it on screen:

{
   ...
   translated: 'Das ist <strong>sehr</strong> wichtig!'
}
Enter fullscreen mode Exit fullscreen mode

In Vue you can render this using the v-html directive:

<div v-html="$t('translated')" />
Enter fullscreen mode Exit fullscreen mode

In plain js you would do something like this:

document.getElementById("myDiv").innerHTML = $t('translated');
Enter fullscreen mode Exit fullscreen mode

Note:
Rendering html strings is a potential XSS vulnerability, so you either want to avoid it if possible, or sanitize your html string before with a library like sanitize-html:

import * as sanitizeHtml from 'sanitize-html';
const translatedString = "Das ist <strong>sehr</strong> wichtig!"
const sanitized = sanitizeHtml(translatedString)
document.getElementById("myDiv").innerHTML = sanitized;
Enter fullscreen mode Exit fullscreen mode

Meta tags

Don't forget to translate your pages meta tags. Meta title, description, and potentially the image are all important for consistent localization.

<title>Welcome to my homepage!<title>
<meta name="description" content="Sliplane is a fully managed container as a service platform, made to simplify Docker hosting. It provides you with the tools to manage and scale your containerized applications.">
Enter fullscreen mode Exit fullscreen mode

This meta section is often generated by the framework so make sure to localize it there and don't forget to check the generated html.

Alternate links

Add references to your markup, to indicate to search engines, that there are alternate versions of the page in different languages. You can do so using alternate links:

<link rel="alternate" hreflang="de-de" href="https://sliplane.io/de-de">

<link rel="alternate" hreflang="en-us" href="https://sliplane.io/">
Enter fullscreen mode Exit fullscreen mode

Make sure to include all languages, even a reference to the current page itself. If you set these links via your framework it's best to inspect the generated html code, in order to make sure that everything went as expected.

Sitemap

There are different strategies for your sitemap and it mainly depends how big your sitemap is. As a reference, everything below 10k individual pages is considered small. You can get away with just a single sitemap and add alternate links like this:

<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<loc>https://sliplane.io/de-de/about</loc>
<xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="de-de" href="https://sliplane.io/de-de/about" />
<xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-us" href="https://sliplane.io/about" />
</url>

Enter fullscreen mode Exit fullscreen mode

If your page is bigger, you want to work with multiple sitemaps for each language and maybe even some more nesting of sitemaps below that level.

External plugins

It's important to also localize any external plugins that you might use on your website, e.g. a chat widget or a third party form. If the whole website is in english, but the checkout form is German, it will be very bad for conversion rate, so make sure the third party plugin comes with localization.

Going Further

Now we went pretty far already and for a lot of cases that will do the trick, but I want to quickly mention some more areas that make localization tricky:

  • Slugs: The words in your slug has impact on SEO. Ideally, your German pages use German words in the slug and your English pages use English words. However, maintaining a different slug for every language is making things complicated and even big companies like Microsoft Azure don't do this. It's hard to quantify the actual SEO impact, but we decided not to go down this rabbit hole and leave the slugs as they are.
  • Legal requirements: different countries have different legal requirements, for example if you decide to expand to Europe, there are specific obligations to make your website compliant with the local law, like including a cookie banner, creating a data privacy statement or the way buttons have to be named and how you display prices on your website.
  • Localizing your fonts: Different countries use different special characters. In Russia or China for example, you need a completely different glyph set. You only want to serve the glyphs that are needed
  • Right-to left support: similar to different fonts, some countries write right to left or top to bottom. If you want to go all in on localization, this is something to think about - but it's probably going to mess up everything and makes you reconsider your career choice - so let's just all agree on silently ignoring this 🤫
  • Advertising: if you run ads to your website, you might have to consider localizing them as well. Although I did not deal with this use case, a close friend of mine is running shopping ads in several different countries and it's important that the localized ads point to the right pages and pricing and shipping info is adjusted on each page.

Summary

Doing localization right, is actually pretty hard and it goes way beyond just your website. There are numerous things to keep in mind and it's very easy to miss something. By using this checklist, I was able to pull it off for our website, but it still remains a lot of work. I also made a post about 5 practical tips to help you simplify the process of internationalizing a website.

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo 📊✨

Top comments (10)

Collapse
 
xwero profile image
david duymelinck

An often overlooked language quirk are grammatical cases. For example English has 3 cases; "he" (nominative) vs. "him" (accusative/dative) and "his" (genitive). But Chinese has no cases and Hungarian has 18.
So to be sure native speakers should sit together to create the translation to get the message of the text right.

Collapse
 
wimadev profile image
Lukas Mauser

great tip!

Collapse
 
code42cate profile image
Jonas Scholz

oh yes! Thats why we only translated to german for now (our native language)

Collapse
 
code42cate profile image
Jonas Scholz

i can finally understand our own landing page 🙏

Collapse
 
wimadev profile image
Lukas Mauser

haha 😂

Collapse
 
maxprilutskiy profile image
Max Prilutskiy

Awesome tips, Lukas!

I think you might find lingo.dev interesting ;)

github.com/lingodotdev/lingo.dev

Collapse
 
wimadev profile image
Lukas Mauser

Interesting! Thank you for sharing 🙏🏻

Collapse
 
madhurima_rawat profile image
Madhurima Rawat

Such an insightful article 👏

I will try to implement this for my portfolio website... 🌐

Thanks for sharing ✨️

Collapse
 
stevsharp profile image
Spyros Ponaris

Thanks for sharing..

Collapse
 
eloquens profile image
Eloquens AI

Cool!