Skip to content

Commit

Permalink
πŸ“¦ v3.2.0
Browse files Browse the repository at this point in the history
__Changes:__

- πŸ‘¨β€πŸ’» Minor package codebase refactoring
- πŸ‘·β€β™‚οΈ Drop `underscore` dependency

__Other changes:__

- πŸ“” Update documentation
- 🀝 Compatibility and support for `[email protected]`

__Dependencies:__

- πŸ“¦ `ostrio:[email protected]`, *was `v2.2.1`*
  • Loading branch information
dr-dimitru committed May 31, 2022
1 parent 88aa39c commit 1776044
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 77 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,44 +72,44 @@ import I18N from 'meteor/ostrio:i18n';
const i18n = new I18N(config);
```

- `config.i18n` {*Object*} - [Internalization object](https://github.com/VeliovGroup/Meteor-Internationalization#object-based-structure)
- `config.returnKey` {*Boolean*} - Return key if l10n value not found, default: `true`
- `config.helperName` {*String*} - Template helper name, default: `i18n`
- `config.i18n` {*Object*} - [Internalization object](https://github.com/VeliovGroup/Meteor-Internationalization#object-based-structure)
- `config.returnKey` {*Boolean*} - Return key if l10n value not found, default: `true`
- `config.helperName` {*String*} - Template helper name, default: `i18n`
- `config.helperSettingsName` {*String*} - Settings helper name, default: `i18nSettings`

## API

### `get([locale,] key, [replacements...])`

- `locale` {*String*} - [Optional] Two-letter locale string, used to force locale, if not set __current locale__ is used
- `key` {*String*} - l10n key like: `folder.file.object.key`
- `key` {*String*} - l10n key like: `object.path.to.key`
- `replacements..` {*String*|[*String*]|*Object*} - [Optional] Replacements for placeholders in l10n string

```js
i18n.get('file.obj.key'); // Current locale, no replacements
i18n.get('object.path.to.key'); // Current locale, no replacements

i18n.get(locale, param); // Force locale, no replacements
i18n.get('en', 'file.obj.key');
i18n.get('en', 'object.path.to.key');

i18n.get(param, replacements); // Current locale, with replacements
i18n.get('file.obj.key', 'User Name'); // Hello {{username}} -> Hello User Name
i18n.get('object.path.to.key', 'Michael'); // Hello {{username}} -> Hello Michael

i18n.get(locale, param, replacements); // Force locale, with replacements
i18n.get('en', 'file.obj.key', 'User Name'); // Hello {{username}} -> Hello User Name
i18n.get('en', 'object.path.to.key', 'John Doe'); // Hello {{username}} -> Hello John Doe
```

### `has([locale,] key)`

*Determine whenever key is exists in configuration file(s).*

- `locale` {*String*} - [Optional] Two-letter locale string, used to force locale, if not set __current locale__ is used
- `key` {*String*} - l10n key like: `folder.file.object.key`
- `key` {*String*} - l10n key like: `object.path.to.key`

```js
i18n.has('file.obj.key'); // Current locale
i18n.has('object.path.to.key'); // Current locale
i18n.has(locale, param); // Force locale
i18n.has('ca', 'file.obj.key'); //false
i18n.has('en', 'file.obj.key'); //true
i18n.has('ca', 'object.path.to.key'); //false
i18n.has('en', 'object.path.to.key'); //true
```

### `setLocale(locale)`
Expand Down
102 changes: 59 additions & 43 deletions i18n.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { check, Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { check, Match } from 'meteor/check';
import { ClientStorage } from 'meteor/ostrio:cstorage';

const clientStorage = new ClientStorage();
const isObject = (obj) => {
if (!obj) {
return false;
}

return Object.prototype.toString.call(obj) === '[object Object]';
};

/**
* @private
* @locus Anywhere
Expand All @@ -13,10 +21,10 @@ import { ClientStorage } from 'meteor/ostrio:cstorage';
const toDottedString = function (obj, prepend = 'i18n') {
let final = {};
for (let key in obj) {
if (_.isFunction(obj[key]) || _.isString(obj[key])) {
final[prepend + '.' + key] = obj[key];
if (typeof obj[key] === 'function' || typeof obj[key] === 'string') {
final[`${prepend}.${key}`] = obj[key];
} else {
final = _.extend(final, toDottedString.call(this, obj[key], prepend + '.' + key));
final = Object.assign({}, final, toDottedString.call(this, obj[key], `${prepend}.${key}`));
}
}
return final;
Expand All @@ -32,15 +40,19 @@ const proceedPlaceholders = function (string, replacements) {
if (string) {
let key;
for (let replacement of replacements) {
if (replacement && replacement.hash && _.isObject(replacement.hash)) {
if (replacement && replacement.hash && isObject(replacement.hash)) {
for (key in replacement.hash) {
string = string.replace(new RegExp(`\{\{(\s)*(${key})+(\s)*\}\}`, 'ig'), replacement.hash[key]);
if (typeof replacement.hash[key] === 'string') {
string = string.replace(new RegExp(`\{\{(\s)*(${key})+(\s)*\}\}`, 'ig'), replacement.hash[key]);
}
}
} else if (_.isObject(replacement)) {
} else if (isObject(replacement)) {
for (key in replacement) {
string = string.replace(new RegExp(`\{\{(\s)*(${key})+(\s)*\}\}`, 'ig'), replacement[key]);
if (typeof replacement[key] === 'string') {
string = string.replace(new RegExp(`\{\{(\s)*(${key})+(\s)*\}\}`, 'ig'), replacement[key]);
}
}
} else {
} else if (typeof replacement === 'string') {
string = string.replace(/\{\{(\s)*([A-z])+(\s)*\}\}/i, replacement);
}
}
Expand All @@ -65,11 +77,11 @@ export default class I18N {
check(config, Object);

let key;
const self = this;
this.returnKey = config.returnKey || true;
this.helperName = config.helperName || 'i18n';
const self = this;
this.returnKey = config.returnKey || true;
this.helperName = config.helperName || 'i18n';
this.currentLocale = new ReactiveVar(void 0);
this.helperSettingsName = config.helperSettingsName || 'i18nSettings';
this.currentLocale = new ReactiveVar(void 0);

check(this.returnKey, Boolean);
check(this.helperName, String);
Expand All @@ -81,7 +93,7 @@ export default class I18N {

this.addl10n(config.i18n);

if (_.isObject(config.i18n)) {
if (isObject(config.i18n)) {
check(config.i18n.settings, Object);
this.settings = config.i18n.settings;
this.defaultLocale = this.settings.defaultLocale;
Expand All @@ -91,11 +103,13 @@ export default class I18N {
const dotted = toDottedString.call(this, this.settings, '__settings');

for (key in dotted) {
this.strings[key] = dotted[key];
if (typeof dotted[key] === 'string') {
this.strings[key] = dotted[key];
}
}

for (key in this.settings) {
if (this.settings[key] && this.settings[key].code) {
if (this.settings[key]?.code) {
this.locales.push(key);
this.strings['__settings.__langSet__'].push(this.settings[key].code);
this.strings['__settings.__langConfig__'].push(this.settings[key]);
Expand All @@ -122,22 +136,22 @@ export default class I18N {
});
}

const savedLocale = ClientStorage.get('___i18n.locale___');
const savedLocale = clientStorage.get('___i18n.locale___');
if (!this.currentLocale.get()) {
if (!savedLocale) {
for (let lang of this.strings['__settings.__langConfig__']) {
if (lang.code === this.userLocale || lang.isoCode === this.userLocale) {
this.currentLocale.set(lang.code);
ClientStorage.set('___i18n.locale___', lang.code);
clientStorage.set('___i18n.locale___', lang.code);
break;
}
}
} else {
if (!!~this.strings['__settings.__langSet__'].indexOf(savedLocale)) {
if (this.strings['__settings.__langSet__'].includes(savedLocale)) {
this.currentLocale.set(savedLocale);
} else {
this.currentLocale.set(this.defaultLocale);
ClientStorage.set('___i18n.locale___', this.defaultLocale);
clientStorage.set('___i18n.locale___', this.defaultLocale);
}
}
}
Expand All @@ -148,7 +162,7 @@ export default class I18N {

if (!this.currentLocale.get()) {
this.currentLocale.set(this.defaultLocale);
ClientStorage.set('___i18n.locale___', this.defaultLocale);
clientStorage.set('___i18n.locale___', this.defaultLocale);
}
}

Expand All @@ -166,36 +180,36 @@ export default class I18N {
let lang;
let replacements;

if (!args.length || !args[0] || !_.isString(args[0])) {
if (!args.length || !args[0] || typeof args[0] !== 'string') {
return '';
}

if (!!~this.locales.indexOf(args[0])) {
lang = args[0];
key = args[1];
lang = args[0];
key = args[1];
replacements = args.slice(2);
} else {
lang = this.currentLocale.get() || this.defaultLocale || 'en';
key = args[0];
lang = this.currentLocale.get() || this.defaultLocale || 'en';
key = args[0];
replacements = args.slice(1);
}

if (lang) {
const _key = lang + '.' + key;
const _key = `${lang}.${key}`;
let result = (this.strings && this.strings[_key] ? this.strings[_key] : undefined) || (this.returnKey ? _key : '');

if (_.isFunction(result)) {
if (typeof result === 'function') {
result = result.call(this);
}

if ((result !== _key) && result && result.length && Object.keys((replacements[0] && replacements[0].hash ? replacements[0].hash : undefined) || replacements).length) {
if ((result !== _key) && result && result.length && Object.keys(replacements?.[0]?.hash || replacements).length) {
result = proceedPlaceholders(result, replacements);
}

return result;
}

return (this.returnKey) ? key : '';
return this.returnKey ? key : '';
}

/**
Expand All @@ -214,17 +228,17 @@ export default class I18N {
return '';
}

if (!!~this.locales.indexOf(args[0])) {
if (this.locales.includes(args[0])) {
lang = args[0];
key = args[1];
key = args[1];
} else {
lang = this.currentLocale.get() || this.defaultLocale || 'en';
key = args[0];
key = args[0];
}

if (lang) {
key = lang + '.' + key;
return !!(this.strings && this.strings[key] ? this.strings[key] : undefined);
key = `${lang}.${key}`;
return !!(this.strings?.[key] ? this.strings[key] : undefined);
}

return false;
Expand All @@ -243,7 +257,7 @@ export default class I18N {
if (this.settings && this.settings[locale]) {
this.currentLocale.set(locale);
if (Meteor.isClient) {
ClientStorage.set('___i18n.locale___', locale);
clientStorage.set('___i18n.locale___', locale);
}
} else {
throw new Meteor.Error(404, `No such locale: \"${locale}\"`);
Expand Down Expand Up @@ -282,7 +296,7 @@ export default class I18N {
all: (() => {
const result = [];
for (key in this.settings) {
if (_.isObject(this.settings[key])) {
if (isObject(this.settings[key])) {
result.push(this.settings[key]);
}
}
Expand All @@ -291,7 +305,7 @@ export default class I18N {
other: (() => {
const result = [];
for (key in this.settings) {
if (_.isObject(this.settings[key]) && (key !== locale)) {
if (isObject(this.settings[key]) && (key !== locale)) {
result.push(this.settings[key]);
}
}
Expand All @@ -300,7 +314,7 @@ export default class I18N {
locales: (() => {
const result = [];
for (key in this.settings) {
if (_.isObject(this.settings[key])) {
if (isObject(this.settings[key])) {
result.push(this.settings[key].code);
}
}
Expand All @@ -326,7 +340,9 @@ export default class I18N {
if (key !== 'settings') {
object = toDottedString.call(this, l10n[key], key);
for (k in object) {
this.strings[k] = object[k];
if (typeof object[k] === 'string') {
this.strings[k] = object[k];
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions package.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Package.describe({
name: 'ostrio:i18n',
summary: 'Super-Lightweight and fast i18n isomorphic driver for Meteor with support of placeholders.',
version: '3.1.0',
version: '3.2.0',
git: 'https://github.com/VeliovGroup/Meteor-Internationalization',
documentation: 'README.md'
});

Package.onUse(function (api) {
api.versionsFrom('1.6.1');
api.use(['underscore', 'check', 'reactive-var', 'ecmascript', 'ostrio:cstorage@2.2.1'], ['client', 'server']);
api.use(['check', 'reactive-var', 'ecmascript', 'ostrio:cstorage@4.0.1'], ['client', 'server']);
api.mainModule('i18n.js', ['client', 'server']);
});

0 comments on commit 1776044

Please sign in to comment.