DEV Community

Cover image for Mongez Localization, The simplest way to translate your website regardless your favorite framework
Hasan Zohdy
Hasan Zohdy

Posted on

Mongez Localization, The simplest way to translate your website regardless your favorite framework

Introduction

There are many packages that are out for translation, either dedicated for certain frameworks or for general usage, but honestly, they are all harder than what i see how localization would be, so i created Mongez Localization package, a package that can be used with literally any javascript environment with easy configurations.

Installation

Using npm

npm i @mongez/localization

Using Yarn

yarn add @mongez/localization

Once the installation is done, create a localization-config.ts file in your project (or .js, typescript is recommended though) so we can set our configurations.

import the file in an early stage of your project, at the start of the src/index.ts for example or in your main project file entry.

Let's define our config file.

// localization-config.ts
import {
  TranslationsList,
  setLocalizationConfigurations,
} from "@mongez/localization";

setLocalizationConfigurations({
  /**
   * Default locale code
   */
  defaultLocaleCode: "ar",
  /**
   * Fall back locale code
   */
  fallback: "en",
});
Enter fullscreen mode Exit fullscreen mode

Here we defined our current default locale code, fallback locale code, let's add some translation keywords.

Defining Translation Keywords

This can be done through multiple way, suit yourself with your favorite one, i personally prefer the grouped translations so i don't miss any keyword, let's have a look.

extend method

The basic and primary way to set translation keywords is by importing extend method

import { extend } from '@mongez/localization';

// let's add some keywords for English translations
extend('en', {
  home: 'Home Page',
  welcomeUser: 'Hello User, Welcome Home!',
  login: 'Login',
  createAccount: 'Create Account'
});

// now let's add same keywords but for Arabic
extend('en', {
  home: 'الصفحة الرئيسية',
  welcomeUser: 'مرحبا بك!',
  login: 'تسجيل الدخلو',
  createAccount: 'إنشاء حساب جديد'
});
Enter fullscreen mode Exit fullscreen mode

Easy Peasy, we defined the locale code as first argument, the second one is an object with our keywords, the object keys are the keywords that will be used to get the proper translation text and its value obviously will be the translation text.

trans method

We'll see the other ways of translation in a bit, but let's see our result in action, so we want to start using the translation, we can use trans method for getting the translation text.

// later in your application html|views for example
import { trans } from '@mongez/localization';

console.log(trans('home')); // as default locale code is `ar` so it will return الصفحة الرئيسية
Enter fullscreen mode Exit fullscreen mode

So we just pass the keyword to the method and the proper translation will be returned for the current locale code.

Grouped Translations

Let's head back again to the translation definition section, another and this is my preferred way to define translations is by using the grouped translation method groupedTranslation

import { extend, groupedTranslation } from '@mongez/localization';

groupedTranslation({
  home: {
    en: 'Home Page',
    ar: 'الصفحة الرئيسية'
  },
  welcomeUser: {
    en: 'Hello User, Welcome Home!',
    ar: 'مرحبا بك!',
  },
  login: {
    en: 'Login',
    ar: 'تسجيل الدخلو',
  },
  createAccount: {
    en: 'Create Account',
    ar: 'إنشاء حساب جديد'
  }
})
Enter fullscreen mode Exit fullscreen mode

This is more convenient to work with translations as we make sure every keyword is translated to all locale codes so we don't miss any language, however the extend method is quite useful if we're working with dynamic translations either if we're getting it from backend api or from json files.

Changing current locale code

We can change the current locale code in the runtime by using setCurrentLocaleCode method, it will update the current locale code.

import { trans, setCurrentLocaleCode } from '@mongez/localization';

// let's log the translation before and after we change the locale code
console.log(trans('home')); // الصفحة الرئيسية

setCurrentLocaleCode('en');

// now let's log it again
console.log(trans('home')); // Home Page
Enter fullscreen mode Exit fullscreen mode

Fallback Translation

Earlier, we defined in the configurations section the fallback locale code, this is useful if the translation key is missing form current locale code, let's it in action

import { trans, groupedTranslation } from '@mongez/localization';

groupedTranslation({
  otherUnknownKeyword: {
    en: 'Welcome Unknown keyword'
  }
});

// Remember the current locale code is `ar` so when we call `trans` method with `otherUnknownKeyword`
// the keyword does not have any translation in `ar`, the fallback locale code will be returned instead

console.log(trans('otherUnknownKeyword')); // Welcome Unknown keyword
Enter fullscreen mode Exit fullscreen mode

Unknown keyword

If the given keyword is not listed in the current or fallback locale code, then the keyword will be returned.

import { trans } from '@mongez/localization';

console.log(trans('missingKeyword')); // will output missingKeyword as the key is missing in all our locale codes
Enter fullscreen mode Exit fullscreen mode

Translate from certain locale code

In some edge cases, we might need to make the translation from certain locale code regardless the current locale code, transFrom can be handy for this situation.

import { transFrom } from '@mongez/localization';

// current locale code is ar

console.log(transFrom('en', 'home')); // Home Page
Enter fullscreen mode Exit fullscreen mode

We just pass the locale code as first argument, the second argument receives the translation keyword.

Nested keywords

Another good feature that can be used is to group your translations, this pattern is used in Mongez Validator as we can group the translation keywords under one keyword.

import { extend, groupedTranslation } from '@mongez/localization';

// using extend
extend('en', {
  validation: {
    required: 'This field is required',
    email: 'Invalid Email Address',
  }
});

// using groupedTranslation
groupedTranslation('validator', {
  required: {
    en: 'This field is required',
  },
  email: {
    en: 'Invalid Email Address',
  }
});
Enter fullscreen mode Exit fullscreen mode

The keyword now can be stored as validator.required and validator.email directly in trans method.

import { trans } from '@mongez/localization';

console.log(trans('validator.required')); // This field is required
Enter fullscreen mode Exit fullscreen mode

Dynamic translation

That was great with static keywords, but what if we want to have a translation that can have a dynamic content for example Create new %s where %s can be changed so we don't have to create dozens of translations, let's see it in action.

import { trans, extend } from '@mongez/localization';

extend('en', {
  createItem: 'Create new %s',
});

console.log(trans('createItem', 'User')); // Create New User
console.log(trans('createItem', 'Order')); // Create New Order
console.log(trans('createItem', 'Category')); // Create New Category
console.log(trans('createItem', 'Product')); // Create New Product
Enter fullscreen mode Exit fullscreen mode

That would be much better than creating 4 translations keywords, or even worse if the application has dozens of modules to be created, updated or deleted.

This is done under the hood using Sprintf-js.

Probably your most used placeholders are %s for strings like User and %d for digits like any number.

import { trans, extend } from '@mongez/localization';

extend('en', {
  orderTotal: 'Total Order: %d',
});

console.log(trans('orderTotal', 125.25)); // Total Order: 125.25


extend('en', {
  userOrderTotal: 'Total Order for %s is %d USD',
});

console.log(trans('userOrderTotal', 'Hasan', 125.25)); // Total Order for Hasan is 125.25 USD
Enter fullscreen mode Exit fullscreen mode

Don't forget order matters here

Conclusion

For more detailed documentation about the package, feel free to visit the Github repository.

There are more features that i didn't cover in this article that can be found in the repository docs like events updating fallbacks and so on.

I'll start working on version 2.0 where the placeholders will be enhanced, and also to support JSX for placeholders as well.

I hope you enjoy the package and any feedback is appreciated.

Enjoy and happy coding.

Top comments (0)