Skip to content

Internationalisation

If you’re looking to translate your website to multiple languages, there are a number of factors to consider.

  1. Language Dictionary - The collection of language strings. Typically in JSON format.
  2. Routing by Language - Path based rules that dictate which language dictionary and configuration to load.
  3. API Localisation - A route to request translated data from the API.
  4. Domains - How to associate a domian to a specific locale.
  5. Previewing Language Strings - How to preview the object structure that represent a particular string on a website. Used to support non-technical stakeholders with understanding what keys to update.

In this guide we will go through how to achieve each of these steps.

Language Dictionaries

Using Ingenuity’s Properties Service for managing your language dictionary is recommended as this allows non-technical users to manage the language used across the website without a deployment.

Ingenuity Properties Service is a UI for managing your language dictionary. It’s a list of keys and values.

For the purpose of this guide we assume you have access to our Ingenuity Service’s. If you do not, you can request access from your Ingenuity Project team.

Adding Properties

For Altitude deployed sites we syncronise the values in the Ingenuity Properties Service to a key-value store that lives with your deployed website. Typically referred to as an Edge KV.

This allows for high-performance read operations and for the site to update language entries without requiring a deployment.

We will sync any values from Properties Service that begin following the following format: altitude.<anystring>

Linking Properties Service to your KV

Reading Properties

Once you have linked Properties Service to your KV you can begin to read the KV from your codebase. Refer to the framework guides below on how to read from a KV.

If you’re utilising our integrations there are helper methods available for i18n. Refer to the guides referenced below.

Framework Guides

Local Dictionary

You can establish a local language dictionary in the codebase by creating local JSON files. For ease of access you can apply these in a middleware to make them accessible across your application.

If you are using the Astro Integration, a local copy of your language dictionary can alternatively be supplied as part of the configuration setup for KV. This enables local environments to read directly from a local JSON file at runtime. See more

Astro Integration

Users of the integration have the ability to opt in to i18n to unlock localisation on their application. The integration is responsible for mapping to locale specific configs and validating a locale is supported when a request is made.

To opt in to this behaviour additional config must be provided to the configuration of a site.

i18n.fallbackLocale

Type: String
Required: True

The fallback locale if the locale of the request is invalid.

i18n: {
fallbackLocale: "en-gb";
}

i18n.exclusionList

Type: Array[]
Required: False

An array containing the prefix of the path that should not be localised and subject to localisation at runtime i.e proxies

i18n: {
exclusionList: ["account", "images"];
}

i18n.localeCookie

Type: String
Required: False
Fallback: locale_V6

The name of the cookie that the locale will be stored in. This is also used to determine a users preferred locale from previous sessions and exposed on the altitude global context. If no value has been supplied, the integration will attempt to look for a cookie named locale_V6. If the integration is unable to resolve a value from the cookie or the locale is not supported, Accept-Language headers from the request will attempted to be used and exposed, otherwise the preferred locale will be null.

i18n: {
localeCookie: "site_locale";
}

i18n.locales

Type: Array[]
Required: True

An array of locale configs can be supplied. Below are the options that should be supplied per entry.

i18n: {
locales: [
{
// en-gb setup
},
{
// fr-fr setup
},
];
}

Locale Inheritance

Locale configs are treated in a special way in the Astro integration and will inherit from the main config file e.g. this config

{
domains: {
default: 'www.acme.com',
variants: ['www.acme.com']
},
commerce: {
endpoint: 'https://www.acme.com'
},
i18n: {
locales: [
{
prefix: 'en-gb',
domain: 'www.acme.com',
kv: [
{
key: 'acme',
namespace: 'config'
}
]
}
],
fallbackLocale: 'en-gb'
}
}

Will be treated like the below config by the integration.

{
domains: {
default: 'www.acme.com',
variants: ['www.acme.com']
},
commerce: {
endpoint: 'https://www.acme.com'
},
i18n: {
locales: [
{
prefix: 'en-gb',
domain: 'www.acme.com',
kv: [
{
key: 'acme',
namespace: 'config'
}
],
domains: {
default: 'www.acme.com',
variants: ['www.acme.com']
},
commerce: {
endpoint: 'https://www.acme.com'
}
}
],
fallbackLocale: 'en-gb'
}
}

Notice how the domains and commerce objects from the top level config are copied into the locale specific config. If a key is present in the locale specific it will always take precedence over the same key in the main config and thus act as an override. This inheritance and override behaviour is then applied to nested fields in the main and locale configs. However it does not apply to array elements, arrays are inherited or overidden in their entirety. If you want to explicitly opt out of inheriting a particular key from the main config then set that key or its parent as null in the locale config.

i18n.locales.<Object>.prefix

Type: String
Required: True

The locale this config is associated with.

locales: [
{
prefix: "en-gb",
},
];

i18n.locales.<Object>.domain

Type: String
Required: False

The global top level domain(gTLDs) of this locale excluding protocol. The domain must be specified in the variants key of the domains object at the root of the config to ensure the integration can map to the sites config.

locales: [
{
prefix: "en-gb",
domain: "www.example.com",
},
{
prefix: "fr-fr",
domain: "www.example.fr",
},
];

i18n.locales.<Object>.kv

Any locale specific KV keys to be retrieved from the cloudflare namespace. See config setup here.

If there are no locale specific KV settings then favour putting them in the top-level kv object instead.

i18n.locales.<Object>.commerce.endpoint

Any locale specific api endpoint to be used. See config setup here

Custom

Custom keys can also be supplied to the build config at locale level as well. See more

Routing by Language

Localised Domains

Global top level domains or gTLDs provide SEO benefits by providing localised content on a separate domain. The integration provides application owners the flexibility to configure whether valid locales should redirect to an associated gTLD.

To enable localised domains, a locale should supply a domain within its respective locale config file. The integration will rewrite the underlying request to prefix the locale to the request which will resolve to the specific config file the locale and gTLD of the request is associated with. This domain should also be added to the domains.variants array within the sites config file.

To mitigate the risk of duplicate content, any requests directly to the prefix that have not been subject to a rewrite will 404.

Example request pattern:

www.example.com => rewrite => www.example.com/en-gb/
www.example.com/en-gb/ => www.example.com/en-gb/ (404)

Application setup

As well as configuration updates, application owners must amend routing logic within their application. Routes within the application should be nested inside of a dynamic route unless specified in the exclusionList as outlined in the above configuration. The param to use for this dynamic route must be locale.

Further to this, to handle invalid locales as part of the request, an additional catch all page should be created at the root of the pages directory to force on demand rendering. If your application already contains a catch all route, this should be moved inside of the dynamic [locale] route and the following snippet added to the new catch all route.

pages/[...https].astro
// new catch all page
---
return new Response(null, Astro.response)
---

The 404.astro page should remain at the root of the pages directory to serve any custom 404 pages.

API Localisation

When switching the language of a site either through path based routing or gTLDs (Global top level domains) it might be desired that the copy and content/products on site also change if they are independently traded. The integration is able to seamlessly achieve API switching by enabling applications to configure custom configs per locale for sites, including defining different API endpoints. This value should be supplied in the i18n.locales locale specific config.