Skip to main content

i18n

General

The hub supports a number of languages (see list), which we currently manually maintain.

Hub language settings

Hub users can set their displayed language under their User settings.

General language settings for a Hub can be found and set by a Hub owner under:

Settings → General → Language → Default language

Hub language settings

Alternatively, you can you click on the dropdown menu in the top right corner before logging in.

Hub language settings

Using translations in the Hub

Use the useTranslation hook inside your functional components to access the translation function.

KeyDescriptionen-GB
analytics_activity_logActivity log

Usage in Hub:

import {useTranslation} from 'react-i18next';

function Component() {

const {t} = useTranslation();

return (
<InlineStatsPanel.assetActivityLog
title={t('analytics_activity_log')} // translation key
data={asset}
/>
);
}

In some places, e.g. in basic functions or in old class components, the useTranslation hook cannot be utilised and we fallback to using i18n from i18next. The downside to using i18n is that it does not automatically retrigger if the user changes their user language. As such, the old language will be shown until the user refreshes the page.

KeyDescriptionen-GB
role_ownerOwner
role_adminAdmin
role_memberMember
role_userUser

Usage in Hub:

import i18n from 'i18next';

function getRoleName(role) {
const ROLE_NAMES = {
admin: i18n.t('role_admin'),
owner: i18n.t('role_owner'),
member: i18n.t('role_member'),
user: i18n.t('role_user'),
};

return ROLE_NAMES[role.toLowerCase()] || role;
}
Manually test your translations

DO test any new translations by changing the language in the Hub UI before putting them up for review.

See also: React i18n documentation - useTranslation Hook

Translations with dynamic parts

Dynamic values can be inserted into a translation. Simply pass the value through when using the translation key in the hub and then utilise it within the translation by wrapping it in two curly brackets. Multiple values can be passed through this way.

KeyDescriptionen-GB
form_uploaded_progressReads eg as: 67% uploaded{{progress}} uploaded

Usage in Hub:

	const progress = `${t('form_uploaded_progress', {
progress: `${Math.ceil(uploadProgress)}%`,
})}`;
Adding strings as dynamic values

When adding dynamic string values, other than dynamic numeric values, these might require additional translation. For example, avoid the following patterns:

❌ ** DON'T DO THIS: **

This would lead to English words appearing in the translations

// Given the translation: 'playlist_user_status': 'Playlist {{progress}}'

const statusLabel = t('playlist_user_status', {
progress: isComplete ? 'completed' : 'in progress',
});

❌ ** DON'T DO THIS: **

Adding translated values should also be avoided due to differing grammar across languages

// Given the translation: 'playlist_user_status': 'Playlist {{progress}}'

const statusLabel = t('playlist_user_status', {
progress: isComplete ? t('status_completed') : t('status_in_progress'),
});

Instead, it is better to simply add a completely new translation key for each dynamic string value.

✅ ** DO THIS: **

// Use two separate, complete translations:
// 'playlist_user_status_complete': 'Playlist completed'
// 'playlist_user_status_in_progress': 'Playlist in progress'

const statusLabel = isComplete
? t('playlist_user_status_complete')
: t('playlist_user_status_in_progress');

If a interpolated translation with dynamic values is needed, ensure that the dynamic string values are also translated correctly.

DO test any new translations by changing the language in the Hub UI before putting them up for review.

See also: i18n documentation - Interpolation

Plurals in translations

i18next can automatically pluralise translations based on a passed-in count variable. For this to happen, add a basic key for the singular translation, and the same key ending in _plural for the pluralised translation.

KeyDescriptionen-GB
duration_days{{count}} day
duration_days_plural{{count}} days

Usage in Hub:

When using the pluralised key in the hub, there is no need to add both translation keys (singular and plural). Instead, use only the singular key and i18n will automatically use the plural key when the count is not 1.

<MetricCard
value={t('duration_days', {
count: daysSinceLastAccess,
})}
/>

Please note, you can also add more specific pluralisations, as some languages use multiple plurals. However, currently we only use the general plural key.

See also: i18n documentation - Plurals

Translations with punctuation

For cases where a word/sentence is used with punctuation such as a colon :, we need to consider it as part of the translation. This is due to differing grammar between languages, e.g. in French you'd put a space in front of the colon, whilst in English you don't.

EnglishDate:
FrenchDate :

Translations with colons

If the string to be translated is a single word with a colon, e.g. in the context of a form, we want to keep the translation as general and reusable as possible. For these cases we use the prefix property and the ending colon

CaseTranslation keyEN translation
With colonproperty_date_colonDate:
Without colonproperty_dateDate

For cases where the string (with colon ) to be translated is a more specific use case and needs a more precise translation key (instead of property), we should still aim to add the colon ending.

Interpolating React elements and the Trans component

Trans lets you interpolate or translate complex React elements.

Overusing Trans

As long you have no React/HTML nodes integrated into a cohesive sentence (text formatting like strong, em, link components, maybe others), you won't need it - most of the times you will be using the t function.

KeyDescriptionen-GB
user_importer_drop_file_ctaDrop CSV file here or <1>browse</1> to upload
editable_item_delete_confirmationAre you sure you want to delete <1><0>{{name}}</0></1>?

Usage in Hub:

When using the Trans component in the hub, pass in the translation key as the i18nKey prop. Pass in any components as children to the Trans component.

const BrowseLink = ({children}) => (
<>
<br />
<TextLink as="span">{children}</TextLink>
</>
);

<Trans t={t} i18nKey="user_importer_drop_file_cta">
Drop CSV file here or
{<BrowseLink>browse</BrowseLink>} to upload
</Trans>
const {name} = props;

<Trans
t={t}
i18nKey="editable_item_delete_confirmation"
name={name}
>
Are you sure you want to delete
<strong>{name}</strong>?
</Trans>

See also: React i18n documentation - Trans component

Updating translations in the Hub and for emails

New translation keys and translations are added to the Hub translations Google spreadsheet and/or the Hub email translations Google spreadsheet.

Editing the spreadsheets

Translations are only to be updated in the Hub translations or Email translations spreadsheets.

The Hub translations (generated) spreadsheet is generated based of the Hub translations and missing translations are automatically added in via Google translate. Do NOT manually edit this sheet.

Adding a new translation key

The translation string and their corresponding keys are grouped thematically on the spreadsheets. E.g. new copy for alerts, are usually added to the grouping of translation keys beginning with alert_, actions are are usually added to the grouping of translation keys beginning with actions_ etc.

Translations that don't clearly fall into these groupings should be grouped with copy that appears close-by in the UI, if possible.

KeyDescriptionen-GB
actions_addAdd
actions_add_contentAdd content
alert_topic_deleted_successTopic deleted successfully
alert_topic_deleted_errorTopic could not be deleted

When needed, a description can be added to a translation to provide more information regarding its usecase.

KeyDescriptionen-GB
nudge_trigger_hint_get_started_reminderUnits are either "days" or "weeks", value is a numberThis nudge is triggered when an invited user has not registered after exactly {{value}} {{unit}}. Users who were invited earlier will not be notified.

Deprecating a translation key

To remove a deprecated translation string and key, do not delete the row. Instead mark it as deleted by writing DELETED behind the translation key.

KeyDescriptionen-GB
search_asset_audit (DELETED)asset audit

Updating the Hub translation files

Translations are ingested via the Translations repo. When the translation script is run, the Translations repo connects to our translations Google spreadsheet. It then extracts and checks the content.

Translation checks

Duplicate translation keys will cause the checks to fail. Fix this by simply updating the newly added duplicate key.

If the content passes the checks, any missing translations are automatically added via Google translate. After the automated translations are completed and have passed all the checks, the documents which can be inserted into our application bundling pipeline are created.

Running the translation script

Before running the translation script, please ensure no one else is currently editing the translation spreadsheet and deleting / editing any translations, as this can cause the generated translations to be added into the wrong row - associating translation keys with the wrong translations 💣.

In a final step, the generated translation documents are manually copied over to the i18n folder in the Hub repo.

When creating a PR for your translation updates, please ensure only your translation changes are included in the translation files of your PR. If there are any other translation changes, please check that these were intentionally added by another developer and that these are correct (and not accidentally caused by a mismatched translation row).

Missing translations

In case a translation string is missing for a key in the language used in the hub, the string of the fallback language is shown.

The default fallback language is en-GB, however Hub owners can set a different fallback language via the Default Hub Language option.

Supported languages

LocaleHub Language
da-DKDanish
de-DEGerman (Du)
de-DE-SieGerman (Sie)
en-GBEnglish
en-USUS English
es-ESSpanish
fi-FIFinnish
fr-FRFrench
hu-HUHungarian
it-ITItalian
ja-JPJapanese
ko-KRKorean
nl-NLDutch
no-NONorwegian
pl-PLPolish
pt-PTPortuguese
ro-RORomanian
sv-SESwedish
th-ThThai
zh-CNChinese
zh-TWChinese (Traditional)

Further resources