Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Translations (i18n)

Julien Constant edited this page Nov 8, 2023 · 5 revisions

Introduction

When making requests to the API, the end-user can be led to encounter some text messages which can and should be translated to help him understand the response from the API.

Behaviors

Despite the Association of Student being from France, all base strings from the project are written in English and French is moved as a secondary langage. You can found all base strings in the src/i18n/en-US directory, all adjacents directory are managed by our translating "service"

Crowdin

"Crowdin is a web-based platform that provides localization and translation management services for software and content developers. It allows organizations to collaborate with a crowd of translators and linguists to translate and adapt their products or content into multiple languages. Crowdin streamlines the localization process, making it more efficient and accessible for global audiences."

ChatGPT 3.5

As Crowdin is free to use for open-source projects, we created a special organisation to translate both the Sith 4 and the API: https://ae-utbm.crowdin.com, you can easily create an account for that organisation using either your Google account or GitHub profile.

Crowdin allows us to flowlessly manages translated files as they directly provide a GitHub integration; Alas, this integration requires to use a GitHub account which led us to the creation of the @ae-bot bot account (credentials are on the AE's bitwarden) and avoid having our personal account being used for the PRs; To edit the integration, you will need to log-in using the bot's crowdin account (credentials are also on the bitwarden)

Warning To avoid all target langages to be pushed (e.g. here) at once when new source strings are added, configure this page to skip untranslated strings & files

Configure the GitHub Integration

Crowdin is configured with the crowdin.yml file present at the root of the project:

files:
  - source: /src/i18n/en-US/*.json
    translation: /src/i18n/%locale%/%original_file_name%

Note
For easiness, a personal user token has been used to setup the associated GitHub account to the integration, here @ae-bot (the token can be found on the bitwarden)

Everything else is managed trough the Crowdin interface here with the following settings:

1. Repository

The repository should be set to this repository (thanks captain obvious). But more importantly, the account used to set up the integration should have write access to it. In our case, @ae-bot.

2. Select branches for translation

Branch for Translation Service branch name
develop crowdin

This setting allows to select which branches should be translated (here only develop) and which branch should be used to push translations to (here crowdin).

3. Sync options

  • Always import new translations from the repository:
    This set the integration to update Crowdin's translations files when repository is updated

  • Push sources:
    Allows users to edit source files from Crowdin (they will be pushed back to the watched branch with the PR)

  • Sync schedule:
    Set the frequency of the synchronization between Crowdin and the repository, currently set to 1 hour

  • Branch to sync automatically:
    develop

  • Default configuration file name:
    crowdin.yml (default value)

Process

When new files or if current sources files are modified within the repository, Crowdin will automatically fetch those changes after some time (see this to setup the frequency) and expose those new strings to be translated;

Once some strings have been translated by Crowdin users, Crowdin will create a new PR authored by @ae-bot with New Crowdin updates as name, you can wait for new translations before merging the PR as newly translated strings will still be added to the PR.

Within the API

Let's imagine we have the following translation file:

// src/i18n/en-US/example.json
{
  "foobaz": {
    "message": "{str} is awesome!"
  }
}

Then you can use nestjs-i18n to translate everything:

// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { I18n, I18nContext } from 'nestjs-i18n';

@Controller()
export class AppController {
  @Get()
  async getHello(@I18n() i18n: I18nContext) {
    return await i18n.t('test.HELLO');
  }
}

You can also do translation on your service as:

// src/app.service.ts
import { Injectable } from '@nestjs/common';
import { I18nContext, I18nService } from 'nestjs-i18n';


@Injectable()
export class AppService {
  constructor(private readonly i18n: I18nService) {}
  getHello(): string {
    return this.i18n.t('test.HELLO',{ lang: I18nContext.current().lang });
  }
}

Important The filename should always be added when referencing a string, e.g. example.foobaz.message is valid while foobaz.message is not. You can use the type definition to ensure that the keys you're using are defined:

import type { I18nTranslations } from '#types/api';
import { Path } from 'nestjs-i18n';

type keys = Path<I18nTranslations>; // -> 'example.foobaz.message' | 'example.foobaz' | 'example'

Note For more information, you can consult the nestjs-i18n website