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
Alternatively, you can you click on the dropdown menu in the top right corner before logging in.
Using translations in the Hub
Use the useTranslation
hook inside your functional components to access the translation function.
Key | Description | en-GB |
---|---|---|
analytics_activity_log | Activity 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.
Key | Description | en-GB |
---|---|---|
role_owner | Owner | |
role_admin | Admin | |
role_member | Member | |
role_user | User |
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;
}
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.
Key | Description | en-GB |
---|---|---|
form_uploaded_progress | Reads eg as: 67% uploaded | {{progress}} uploaded |
Usage in Hub:
const progress = `${t('form_uploaded_progress', {
progress: `${Math.ceil(uploadProgress)}%`,
})}`;
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.
Key | Description | en-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.
English | Date: |
---|---|
French | Date : |
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
Case | Translation key | EN translation |
---|---|---|
With colon | property_date_colon | Date: |
Without colon | property_date | Date |
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.
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.
Key | Description | en-GB |
---|---|---|
user_importer_drop_file_cta | Drop CSV file here or <1> browse</1> to upload | |
editable_item_delete_confirmation | Are 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.
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.
Key | Description | en-GB |
---|---|---|
actions_add | Add | |
actions_add_content | Add content | |
alert_topic_deleted_success | Topic deleted successfully | |
alert_topic_deleted_error | Topic could not be deleted |
When needed, a description can be added to a translation to provide more information regarding its usecase.
Key | Description | en-GB |
---|---|---|
nudge_trigger_hint_get_started_reminder | Units are either "days" or "weeks", value is a number | This 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.
Key | Description | en-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.
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.
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
Locale | Hub Language |
---|---|
da-DK | Danish |
de-DE | German (Du) |
de-DE-Sie | German (Sie) |
en-GB | English |
en-US | US English |
es-ES | Spanish |
fi-FI | Finnish |
fr-FR | French |
hu-HU | Hungarian |
it-IT | Italian |
ja-JP | Japanese |
ko-KR | Korean |
nl-NL | Dutch |
no-NO | Norwegian |
pl-PL | Polish |
pt-PT | Portuguese |
ro-RO | Romanian |
sv-SE | Swedish |
th-Th | Thai |
zh-CN | Chinese |
zh-TW | Chinese (Traditional) |