Skip to content

Translations

Danny SMc edited this page Dec 6, 2021 · 1 revision

This feature adds support for translations in the framework, this comes in two key parts, the first is manual translation which works on calling (from any controller), this.translator.translate(sourceText, language), which will simply return the translated text or the source if nothing is found (a shortcut has been made for that which is this._t(sourceText, language)). The second is automatic translation which is done by reading the string of data you return via either HTTP or WS, both of these plugins support translations, this works by checking for _t(Something) in your content and it will read everything between the _t( and ) and translate it. For WebSocket support, you need to do context.shouldTranslate(true) and for HTTP, you need to do new Http.Response(200, {}).shouldTranslate(true) this is because enabling it by default may affect the output code, depending on your data. I have detailed some more examples below.

Note: It's worth mentioning that by default, the translator module will automatically look at the Accept-Language header that is sent from the client, if you want to change this you can set the language yourself or if you have language based routes where the language is in the URL like: https://example.com/en-GB/about then you can create a middleware to automatically set the language, see the "Setting the Language" section below.


Configuration

There is only a single option called translations which should be the folder path for the translations, this MUST be defined for translations to work, otherwise translations will not be loaded, and all calls will just return the source text.

We expect the translations option to be an absolute path, we suggest using the resolve method from the path built-on package.


Example

In this example, our folders are stored in the project root under /translations, this is because both the uncompiled dev mode and compiled prod mode will be able to access the same files.

import { Engine } from '@symbux/turbo';
import { resolve } from 'path';

const engine = new Engine({
	autowire: true,
	translations: resolve(__dirname, '../translations'),
});

Translation Files

As of the initial release, we only support JSON formats for languages, and we structure them like so:

// fr-FR.json
{
	"Home": "Accueil",
	"Our Work": "Notre travail",
	"About Us": "À propos de nous",
	"Contact Us": "Nous contacter",
	"Get In Touch": "Entrer en contact"
}

Please note that ALL translation files in the translations folder should be named under the following format, for example, fr-FR.json for French/France.

The demo application in the main project has an example here.


Manual Translation

If you wish to use translations in any of your controllers you can call on the translator module, which is, by default, injected to the abstract controller.


Example: HTTP Controller

An example below for a controller using the HTTP plugin.

import { AbstractController, Http } from '@symbux/turbo';

@Http.Controller('/test')
export default class WsApiController extends AbstractController {

	@Http.Get('/translate')
	public async translate(context: Http.Context): Promise<Http.Response> {
		const response1 = new Http.Response(200, {
			message: this.translator.translate('Hello World', 'fr-FR'),
		});

		// OR

		const response2 = new Http.Response(200, {
			message: this._t('Hello World', 'fr-FR'),
		});
	}
}

Example: WS Controller

An example below for a controller using the WS plugin.

import { AbstractController, Ws } from '@symbux/turbo';

@Ws.Controller('wsapi')
export default class WsApiController extends AbstractController {

	@Ws.Action()
	public async translate(context: Ws.Context): Promise<string> {
		context.send({
			command: 'wsapi/translate',
			content: {
				message: this.translator.translate('Home', 'fr-FR'),
			},
		});

		// OR
		context.send({
			command: 'wsapi/translate',
			content: {
				message: this._t('Home', 'fr-FR'),
			},
		});
	}
}

Setting the Language

In some cases, your application may not utilise the Accept-Language header and you want something a custom instead. There are various ways to do this, by default, the Accept-Language header produces an array of supported languages, you can add a language by adding a new item at the front of that, as the translator module will loop through the languages and attempt to find a matching language you have on file.

So in this example we have a en-US language defined, but the user wants French, so you may have set some session information that says they want to use french, or it could be in your route, in the below example we are going to explore the "route" method.

We shall create a middleware first:

import { Middleware, Http, AbstractMiddleware } from '@symbux/turbo';

// Note the http part at the end, we are saying ALL http requests should use this.
@Middleware('http.lang', {}, 'http')
export default class LanguageReader extends AbstractMiddleware implements Http.IMiddleware {
	public async handle(context: Http.Context): Promise<boolean> {

		// Add base language (english).
		context.setLanguage('en-US');

		// Now let's check for a URL parameter, if none, we ignore.
		const userLang = context.getParams()?.lang;
		if (!userLang) return true;

		// Enable auto translation.
		context.shouldTranslate(true);

		// Now we want to set it to the context.
		context.setLanguage(userLang);
		return true;
	}
}

Now that the above has been done, all HTTP routes will now use the language set in the URL, but if there is no language defined in the params, it will fall back to en-US rather than the user's accept-language header.

Features

Plugins

Future Plans

Resources

Clone this wiki locally