Skip to content

Commit

Permalink
refactor: re-implement translate & pluralize helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
lykmapipo committed Jun 20, 2020
1 parent 26349a2 commit 6674d65
Show file tree
Hide file tree
Showing 3 changed files with 317 additions and 9 deletions.
5 changes: 5 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { keys } from 'lodash';
import pkg from './package.json';

const imports = [
'lodash/clone',
'lodash/get',
'lodash/filter',
'lodash/first',
'lodash/isEmpty',
'lodash/isFunction',
'lodash/isNumber',
'lodash/isPlainObject',
'lodash/isString',
'lodash/trim',
];

export default [
Expand Down
195 changes: 187 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import path from 'path';
import clone from 'lodash/clone';
import isFunction from 'lodash/isFunction';
import isNumber from 'lodash/isNumber';
import isPlainObject from 'lodash/isPlainObject';
import isString from 'lodash/isString';
import trim from 'lodash/trim';
import { firstValue, mergeObjects, sortedUniq } from '@lykmapipo/common';
import { getString, getStringSet } from '@lykmapipo/env';
import I18N from 'i18n';
Expand All @@ -13,7 +18,7 @@ let i18n = {};
/**
* @function withEnv
* @name withEnv
* @description Grab defaults from environment variables.
* @description Grab defaults from environment variables
* @returns {object} environment options
* @author lally elias <lallyelias87@mail.com>
* @license MIT
Expand Down Expand Up @@ -79,7 +84,7 @@ export const withEnv = () => {
/**
* @function withDefaults
* @name withDefaults
* @description Merge provided options with defaults.
* @description Merge provided options with defaults
* @param {object} [optns={}] provided options
* @returns {object} merged options
* @author lally elias <lallyelias87@mail.com>
Expand Down Expand Up @@ -141,11 +146,8 @@ export const withDefaults = (optns = {}) => {
*
* const i18n = configure({ ... });
*
* i18n.__('hello'); // Hello
* i18n.__('hello', 'sw'); // Mambo
*
* i18n.t('hello'); // Hello
* i18n.t('hello', 'sw'); // Mambo
* i18n.t('hello'); // => Hello
* i18n.t('hello', 'sw'); // => Mambo
*/
export const configure = (optns) => {
// merge options
Expand Down Expand Up @@ -188,10 +190,187 @@ export const configure = (optns) => {
* import { reset } from '@lykmapipo/i18n';
*
* reset();
* //=> undefined
* // => undefined
*
*/
export const reset = () => {
i18n = {};
return i18n;
};

/**
* @name t
* @function t
* @description Translates a single phrase and adds it to locales if unknown
* @param {string} phrase localized phrase
* @param {string} [locale=en] locale to use in translation or default
* @param {object} [optns={}] data to use on parse and substitution
* @returns {string} translated parsed and substituted string
* @author lally elias <lallyelias87@gmail.com>
* @since 0.1.0
* @version 0.1.0
* @license MIT
* @public
* @static
* @example
*
* import { t } from '@lykmapipo/i18n';
*
* t('hello'); // => Hello
* t('hello', 'sw'); // => Mambo
* t('greeting', { name: 'John' }); // => Hello John
* t('greeting', 'sw', { name: 'John' }); // => Mambo John
*
*/
export const t = (phrase, locale, optns) => {
// ensure initialize
configure();

// obtain defaults
const { defaultLocale } = withDefaults();

// ensure params
const localPhrase = clone(phrase);
const localLocale = isString(locale)
? clone(trim(locale) || defaultLocale)
: defaultLocale;
const options = isPlainObject(locale)
? mergeObjects(locale)
: mergeObjects(optns);

// translate
const translated = i18n.t(
{ phrase: localPhrase, locale: localLocale },
options
);

// return translated
return translated;
};

/**
* @name l
* @function l
* @description Provides list of translations for a given phrase in
* each language
* @param {string} phrase localized phrase
* @returns {string} translated parsed and substituted string
* @author lally elias <lallyelias87@gmail.com>
* @since 0.1.0
* @version 0.1.0
* @license MIT
* @public
* @static
* @example
*
* import { l } from '@lykmapipo/i18n';
*
* l('hello');
* // => [ 'Hello', 'Mambo' ]
*
*/
export const l = (phrase) => {
// ensure initialize
configure();

// ensure params
const localPhrase = clone(phrase);

// obtain translations
const translates = i18n.l(localPhrase);

// return translates
return translates;
};

/**
* @name h
* @function h
* @description Provides hashed list of translations for a given phrase in
* each language.
* @param {string} phrase localized phrase
* @returns {string} translated parsed and substituted string
* @author lally elias <lallyelias87@gmail.com>
* @since 0.1.0
* @version 0.1.0
* @license MIT
* @public
* @static
* @example
*
* import { h } from '@lykmapipo/i18n';
*
* h('hello');
* // => [ { en: 'Hello' }, { sw: 'Mambo'} ]
*
*/
export const h = (phrase) => {
// ensure initialize
configure();

// ensure params
const localPhrase = clone(phrase);

// obtain translations hash list
const translates = i18n.h(localPhrase);

// return translates
return translates;
};

/**
* @name n
* @function n
* @description Plurals translation of a single phrase
*
* Note: Singular and plural forms will get added to locales if unknown
*
*
* @param {string} phrase localized phrase
* @param {string} [locale=en] locale to use in translation or default
* @param {number} [count=0] count to use on parse and substitution
* @returns {string} translated parsed and substituted string based on last
* count parameter
* @author lally elias <lallyelias87@gmail.com>
* @since 0.1.0
* @version 0.1.0
* @license MIT
* @public
* @static
* @example
*
* import { n } from '@lykmapipo/i18n';
*
* n('You have %s message', 1); // You have 1 message
* n('You have %s message', 'sw', 1); // Una meseji 1
* n('You have %s message', 4); // You have 4 messages
* n('You have %s message', 'sw', 4); // Una meseji 4
*
*/
export const n = (phrase, locale, count) => {
// ensure initialize
configure();

// obtain defaults
const { defaultLocale } = withDefaults();

// ensure params
const localPhrase = clone(phrase);
const localLocal = isString(locale)
? clone(trim(locale) || defaultLocale)
: defaultLocale;
const localCount = isNumber(locale) ? clone(locale) : clone(count || 0);

// pluralize
// see https://github.com/mashpie/i18n-node#pluralization
const options = {
singular: localPhrase,
plural: localPhrase,
locale: localLocal,
count: localCount,
};
const pluralized = i18n.n(options);

// return pluralized
return pluralized;
};
126 changes: 125 additions & 1 deletion test/unit/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from '@lykmapipo/test-helpers';

import { withEnv, withDefaults, configure, reset } from '../../src';
import { withEnv, withDefaults, configure, reset, t, h, l, n } from '../../src';

describe('i18n', () => {
const { BASE_PATH } = process.env;
Expand Down Expand Up @@ -86,6 +86,130 @@ describe('i18n', () => {
expect(reset()).to.be.empty;
});

describe('', () => {
// translation

it('should translate', () => {
expect(t).to.exist;
expect(t).to.be.a('function');
expect(t.name).to.be.equal('t');
expect(t).to.have.length(3);
});

it('should translate(string) using default locale', () => {
const translated = t('hello');
expect(translated).to.exist;
expect(translated).to.be.equal('Hello');
});

it('should translate(object) using default locale', () => {
const translated = t('gender');
expect(translated).to.exist;

expect(translated.male).to.exist;
expect(translated.male).to.equal('Male');
expect(translated.male).to.be.equal(t('gender.male'));

expect(translated.female).to.exist;
expect(translated.female).to.be.equal('Female');
expect(translated.female).to.be.equal(t('gender.female'));
});

it('should translate(string) using provided locale', () => {
const translated = t('hello', 'sw');
expect(translated).to.exist;
expect(translated).to.be.equal('Mambo');
});

it('should translate(object) using provided locale', () => {
const translated = t('gender', 'sw');
expect(translated).to.exist;

expect(translated.male).to.exist;
expect(translated.male).to.equal('Mme');
expect(translated.male).to.be.equal(t('gender.male', 'sw'));

expect(translated.female).to.exist;
expect(translated.female).to.be.equal('Mke');
expect(translated.female).to.be.equal(t('gender.female', 'sw'));
});

it('should parse and translate(string) using default locale', () => {
const translated = t('greeting', { name: 'John' });
expect(translated).to.exist;
expect(translated).to.be.equal('Hello John');
});

it('should parse and translate(string) using provided locale', () => {
const translated = t('greeting', 'sw', { name: 'John' });
expect(translated).to.exist;
expect(translated).to.be.equal('Mambo John');
});

it('should obtain phrase translations list', () => {
const translations = l('hello');
expect(translations).to.exist;
expect(translations).to.be.an('array');
expect(translations).to.have.length(2);
expect(translations).to.be.eql(['Hello', 'Mambo']);
});

it('should obtain phrase translations hash', () => {
const translations = h('hello');
expect(translations).to.exist;
expect(translations).to.be.an('array');
expect(translations).to.have.length(2);
expect(translations).to.be.eql([{ en: 'Hello' }, { sw: 'Mambo' }]);
});
});

describe('', () => {
// pluralization

it('should be able to pluralize', () => {
expect(n).to.exist;
expect(n).to.be.a('function');
expect(n.name).to.be.equal('n');
expect(n).to.have.length(3);
});

it('should pluralize using default locale', () => {
const pluralized = n('You have %s message', 0);
expect(pluralized).to.exist;
expect(pluralized).to.equal('You have 0 messages');
});

it('should pluralize using default locale', () => {
const pluralized = n('You have %s message', 1);
expect(pluralized).to.exist;
expect(pluralized).to.equal('You have 1 message');
});

it('should pluralize using default locale', () => {
const pluralized = n('You have %s message', 10);
expect(pluralized).to.exist;
expect(pluralized).to.equal('You have 10 messages');
});

it('should pluralize using specified locale', () => {
const pluralized = n('You have %s message', 'sw', 0);
expect(pluralized).to.exist;
expect(pluralized).to.equal('Una meseji 0');
});

it('should pluralize using specified locale', () => {
const pluralized = n('You have %s message', 'sw', 1);
expect(pluralized).to.exist;
expect(pluralized).to.equal('Una meseji 1');
});

it('should pluralize using specified locale', () => {
const pluralized = n('You have %s message', 'sw', 10);
expect(pluralized).to.exist;
expect(pluralized).to.equal('Una meseji 10');
});
});

after(() => {
process.env.BASE_PATH = BASE_PATH;
});
Expand Down

0 comments on commit 6674d65

Please sign in to comment.