A simple i18n localization handler.
yarn add @mongez/localization
Or
npm i @mongez/localization
Let's set our package configurations so we can move on with our usage.
Create a src/config/localization.ts
or localization.js
of you still use Javascript and in somewhere earlier in your app, import the config file.
// src/config/localization.ts
import {
TranslationsList,
setLocalizationConfigurations,
} from "@mongez/localization";
const translations: TranslationsList = {
en: {
home: "Home Page",
contactUs: "Contact Us",
},
ar: {
home: "الصفحة الرئيسية",
},
};
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
/**
* Set translations list
*/
translations: translations,
});
All configurations are optional, you can set only the configurations you need.
Here is the list of configurations:
export type LocalizationConfigurations = {
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode?: string;
/**
* Fall back locale code
*
* @default en
*/
fallback?: string;
/**
* Set translations list
*/
translations?: TranslationsList;
/**
* Set placeholder converter
*/
converter?: Converter;
/**
* Set placeholder pattern
*
* @default colon
*/
placeholderPattern?: "colon" | "doubleCurly" | RegExp;
};
Here we defined our current default locale code, fallback locale code and our translations list, now we're ready to use our translator.
Don't forget to import the file in some point earlier in your project,
src/index.ts
or/src/index.js
.
Now we can start using our translator by calling the trans
method.
// some-file-in-the-project.ts
import { trans } from "@mongez/localization";
// based on our previous configurations, the default locale code is ar, so translation will be taken from its object.
trans("home"); // الصفحة الرئيسية
As we set our fallback locale code as en
, now whenever the keyword is not defined in our current locale code, it will be checked in the fallback locale code object instead.
// some-file-in-the-project.ts
import { trans } from "@mongez/localization";
// the `contactUs` keyword is not defined in `ar` locale code but defined in the fallback locale code `en`, so translation will be taken from `en` object
trans("contactUs"); // Contact Us
If the keyword doesn't exist in the current locale code nor in the fallback locale code, then the keyword itself will be returned.
// some-file-in-the-project.ts
import { trans } from "@mongez/localization";
trans("unknownKeyword"); // unknownKeyword
We can get a translation keyword from certain locale code by using transFrom
function, the function arguments is the same as trans
except the first argument is the locale code name.
// some-file-in-the-project.ts
import { transFrom } from "@mongez/localization";
transFrom("en", "contactUs"); // Contact Us
We may not define our translations list in the localization configurations, instead we can define each locale code translation in separate files and extend the translations keywords, this is done by extend
function.
Let's create a src/locales
directory and add en.ts
and ar.ts
files inside it.
// src/locales/en.ts
import { extend } from "@mongez/localization";
extend("en", {
home: "Home Page",
contactUs: "Contact Us",
});
// src/locales/ar.ts
import { extend } from "@mongez/localization";
extend("ar", {
home: "الصفحة الرئيسية",
});
Now let's just import our locales file in the src/config/localization.ts
file
// src/config/localization.ts
import "src/locales/en";
import "src/locales/ar";
import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
});
Our code is now much organized and easier for modification.
Another way to set translations is to define a keyword and inside it list of translations based on the locale code using groupedTranslations
function.
// src/locales/localization.ts
import { groupedTranslations } from "@mongez/localization";
groupedTranslations({
home: {
en: "Home Page",
ar: "الصفحة الرئيسية",
},
contactUs: {
en: "Contact Us",
ar: "اتصل بنا",
},
});
You can also specify a group name (dot.notation-syntax is allowed as well
) by sending 2nd argument to the function
Added in 1.0.19
// src/locales/localization.ts
import { groupedTranslations } from "@mongez/localization";
groupedTranslations("store", {
orders: {
en: "Orders",
ar: "الطلبات",
},
products: {
en: "Products",
ar: "المنتجات",
},
});
trans("store.orders"); // Products
Updated in v2.0
Another powerful feature is to set a placeholder that can be modified dynamically based on the given value.
// src/locales/en.ts
import { extend } from "@mongez/localization";
extend("en", {
createItem: "Create New :item",
minimumOrderPurchase: "Minimum purchase amount for this order is :amount USD",
});
Now we defined two keywords, createItem
and minimumOrderPurchase
, in the createItem
keyword there is a placeholder :item
, this placeholder means that there will be a text that replace this placeholder when calling the translation function, let's see it in action.
// somewhere in the app
import { trans } from "@mongez/localization";
trans("createItem", { item: "Order" }); // Create New Order
trans("createItem", { item: "Customer" }); // Create New Customer
trans("createItem", { item: "Category" }); // Create New Category
As easy as that!, now let's see the other keyword minimumOrderPurchase
it contains :amount
placeholder, that means this placeholder will be replaced with a value.
Please note that using
:
with keywords might make conflicts if it appears to be needed remained, so pickup a different word instead for the placeholder.
// somewhere in the app
import { trans } from "@mongez/localization";
trans("minimumOrderPurchase", { amount: 12 }); // Minimum purchase amount for this order is 12 USD
Added in V3.0.0
You can also nest grouped translations, this will allow you to group translations in a more organized way.
// src/locales/localization.ts
import { groupedTranslations } from "@mongez/localization";
groupedTranslations({
store: {
orders: {
en: "Orders",
ar: "الطلبات",
},
products: {
en: "Products",
ar: "المنتجات",
},
});
Added in V2.0
You might also specify the placeholder to be a jsx element instead of just a string or an integer, this will drive us to set a converter function in our configurations to allow jsx elements.
But we need to install the converter first
npm i @mongez/react-localization
OR
yarn add @mongez/react-localization
// src/config/localization.ts
import { jsxConverter } from "@mongez/react-localization";
import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
/**
* Converter function to convert the placeholder value to jsx element
*/
converter: jsxConverter,
});
You might also use your own converter function, the converter function receives the translated string and the placeholders list
// src/config/localization.ts
import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
/**
* Converter function to convert the placeholder value to jsx element
*/
converter: (
translatedString: string,
placeholders: any,
placeholder: RegExp,
) => {
// do something with the translated string and the placeholders
return translatedString;
},
});
import { trans } from '@mongez/localization';
export function RedComponent() {
return (
<>
{trans('minimumOrderPurchase', { amount: <strong style={{color: 'red'}}>12</strong> })}
</>
)
}
Keep in mind that the return value for the trans
function will be an array not a string.
You can use use the translation text with jsx by using transX
function instead of trans
this will always use the jsxConverter
unlike the trans
method which uses the converter from the defined configurations list.
import { trans } from '@mongez/localization';
import { transX } from "@mongez/react-localization";
export function RedComponent() {
return (
<>
{/* will convert the jsx value to [object Object] if the converter is not set to jsxConverter in the configurations.*/}
{trans('minimumOrderPurchase', { amount: <strong style={{color: 'red'}}>12</strong> })}
{/* works fine regardless configurations. */}
{transX('minimumOrderPurchase', { amount: <strong style={{color: 'red'}}>12</strong> })}
</>
)
}
Added in v2.0.10
You can use the plain converter directly regardless current converter using plainTrans
function.
import { plainTrans } from "@mongez/localization";
plainTrans("minimumOrderPurchase", { amount: 12 }); // Minimum purchase amount for this order is 12 USD
Added in v3.0
By default, the placeholder pattern is colon
, but you can change it to doubleCurly
or a custom regex pattern.
// src/config/localization.ts
import {
setLocalizationConfigurations,
extend,
trans,
} from "@mongez/localization";
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
/**
* Set placeholder pattern
*
* @default colon
*/
placeholderPattern: "doubleCurly",
});
// now the placeholder pattern is double curly
extend("en", {
createItem: "Create New {{item}}",
minimumOrderPurchase:
"Minimum purchase amount for this order is {{amount}} USD",
});
trans("createItem", { item: "Order" });
We can also set it as a custom regex pattern.
// src/config/localization.ts
import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({
/**
* Default locale code
*
* @default en
*/
defaultLocaleCode: "ar",
/**
* Fall back locale code
*
* @default en
*/
fallback: "en",
/**
* Set placeholder pattern
*
* @default colon
*/
placeholderPattern: /{{(.*?)}}/g,
});
Added in v2.1.0
Now trans
and transFrom
functions can receive keyword as a string
or an object of locale codes and their translations.
// src/locales/en.ts
import { trans, transFrom } from "@mongez/localization";
const translations = {
home: {
en: "Home Page",
ar: "الصفحة الرئيسية",
},
};
trans(translations.home); // Home Page (based on current locale code)
// Or using transFrom function
transFrom("en", translations.home); // Home Page (based on current locale code
If the given locale code does not exist in the given object, the fallback
locale code will be used instead.
The main reason behind adding this feature is to allow us to use the same keyword in different files, for example, we have a file called home.ts
that contains the translations for the home page, and we have another file called dashboard.ts
that contains the translations for the dashboard page, and both files have a keyword called home
, so we can use the same keyword in both files without conflicts.
// Dashboard Page
import { trans } from "@mongez/localization";
import dashboardTranslation from "./dashboard";
import frontOfficeTranslation from "./front-office";
trans(dashboardTranslation.home); // Dashboard
trans(frontOfficeTranslation.home); // Home Page
This can be useful as mentioned earlier, but if you registered these files using groupedTranslations
function, the last added keyword will be used when using the dynamic string i.e trans('home')
.
Added in v2.2.0
Another way to use translation by generating a translatable object, let's see an example to make it more clear.
Normal Usage:
import { trans, groupedTranslations } from "@mongez/localization";
groupedTranslations({
home: {
en: "Home Page",
ar: "الصفحة الرئيسية",
},
dashboard: {
en: "Dashboard",
ar: "لوحة القيادة",
},
});
trans("home"); // Home Page
Works just fine, but what if we want to make sure that the keyword is unique, and we don't want to use the same keyword in different files, also to reduce the syntax by not using trans
function, we need then to use transObject
instead of groupedTranslations
function.
import { transObject } from "@mongez/localization";
export const translations = transObject({
home: {
en: "Home Page",
ar: "الصفحة الرئيسية",
},
dashboard: {
en: "Dashboard",
ar: "لوحة القيادة",
},
});
// import translation from anywhere in the application
console.log(translations.home); // Home Page
You see here, we used the direct access of the translation keyword directly without using trans
function, and we can use the same keyword in different files without conflicts.
If the keyword is not found, the
fallback
locale code will be used instead.
If the keyword is not found in both current locale code and the fallback locale code, the keyword itself will be returned.
But, What if the keyword has placeholders, in that case, use the translations.p
function that receives the keyword as first argument and the object of placeholders as the second argument.
import { transObject } from "@mongez/localization";
export const translations = {
welcome: {
en: "Hello :name",
ar: "مرحبا :name",
},
};
console.log(translations.p("welcome", { name: "Ahmed" })); // Hello Ahmed
Kindly not the
p
property is reserved, you can not use it as a keyword.
If for example, you're using the jsx converter
by default, but you need to use plain converter
for a specific keyword, you can use the translations.plain
function, it also works with and without placeholders.
import { transObject } from "@mongez/localization";
export const translations = {
welcome: {
en: 'Hello :name',
ar: 'مرحبا :name',
}
homePage: {
en: 'Home Page',
ar: 'الصفحة الرئيسية',
}
};
console.log(translations.plain('welcome', { name: 'Ahmed' })); // Hello Ahmed
By default, The package will use the current locale code defined in the configurations list, but we can change current locale code later in the project for example when a locale code is changed to a new locale code using setCurrentLocaleCode
function.
// somewhere in the app
import { setCurrentLocaleCode } from "@mongez/localization";
// if current locale code is ar
trans("home"); // الصفحة الرئيسية
setCurrentLocaleCode("en");
trans("home"); // Home Page
Same applies in fallback locale code, it can be changed later from anywhere in your project using setFallbackLocaleCode
function.
// somewhere in the app
import { setFallbackLocaleCode } from "@mongez/localization";
setFallbackLocaleCode("ar"); // Now fallback is changed to `ar`
You can get current locale code using getCurrentLocaleCode
function.
// somewhere in the app
import { getCurrentLocaleCode } from "@mongez/localization";
getCurrentLocaleCode(); // ar
You can get fallback locale code using getFallbackLocaleCode
function.
// somewhere in the app
import { getFallbackLocaleCode } from "@mongez/localization";
getFallbackLocaleCode(); // en
To get the entire translations list of all locale codes, use getTranslationsList
function.
// somewhere in the app
import { getTranslationsList } from "@mongez/localization";
getTranslationsList(); // something like {en: {home: 'Home Page'}, ar: {home: 'الصفحة الرئيسية'}}
To Get keywords list of certain locale code, use getKeywordsListOf
function.
// somewhere in the app
import { getKeywordsListOf } from "@mongez/localization";
getKeywordsListOf("en"); // something like {home: 'Home Page'}}
You can be notified once a locale code is changed, or once the fallback locale code is changed as well using localizationEvents
object.
// somewhere in the app
import { setCurrentLocaleCode, localizationEvents } from "@mongez/localization";
localizationEvents.onChange("localeCode", (newLocaleCode, oldLocaleCode) => {
console.log(newLocaleCode, oldLocaleCode); // en ar
});
// assuming current locale code is `ar`
setCurrentLocaleCode("en"); // once calling the `setCurrentLocaleCode` the `onChange.localeCode` event will be triggered.
Fallback locale codes is also available to be detected once it is changed.
// somewhere in the app
import {
setFallbackLocaleCode,
localizationEvents,
} from "@mongez/localization";
localizationEvents.onChange("fallback", (newLocaleCode, oldLocaleCode) => {
console.log(newLocaleCode, oldLocaleCode); // ar en
});
// assuming current fallback locale code is `en`
setFallbackLocaleCode("ar"); // once calling the `setFallbackLocaleCode` the `onChange.fallback` event will be triggered.
To run tests, run the following command
yarn test
OR
npm run test
Contributions, issues and feature requests are welcome!.
If you're going to make a pull request, please make sure to follow the next steps:
- Fork the repository
- Create your feature branch (git checkout -b feature/AmazingFeature)
- Commit your changes (git commit -m 'Add some AmazingFeature')
- Make sure to add tests for your changes
- Run tests (yarn test)
- Push to the branch (git push origin feature/AmazingFeature)
- Open a pull request
- 2.2.0 (12 Apr 2023)
- Added Translatable object function.
- Renamed default
converter
toplainConverter
. - Enhanced typings for
plainConverter
. - Added unit tests for
transObject
function.
- 2.1.1 (19 Feb 2023)
- Enhanced translation when object is passed as a keyword.
- 2.1.0 (15 Feb 2023)
- Now
trans
andtransFrom
function acceptskeyword
as string or object
- Now
- 2.0.11 (28 Nov 2022)
- 2.0.10 (13 Nov 2022)
- Added
plainTrans
function.
- Added
- 2.0.0 (27 Sept 2022)
- Added Converters for placeholders, as translation now supports jsx for replacements.
- Removed
sprintf-js
package. - Added Unit tests
- 1.0.19 (23 Aug 2022)
- Now grouped translations accepts
groupKey
- Now grouped translations accepts
- 1.0.17 (8 Jun 2022)
- Added
sprintf-js
dependency.
- Added
- 1.0.12 (06 Jan 2022)
- Added Translations list