From dc509192178090db41c6e1e8579044f62b82b794 Mon Sep 17 00:00:00 2001 From: Guilherme Pressutto Date: Thu, 3 Jan 2019 00:06:17 -0200 Subject: [PATCH 1/8] Fixed: typo (#75) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b3ffd1..e9d5b67 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ var lang = new Lang({ 'en.fruits': { 'apple': 'apple|apples' }, - 'es.greetings': { + 'es.fruits': { 'apple': 'manzana|manzanas' } } From 3f30a89ed5262cc29e187942e5e2146ad542c91b Mon Sep 17 00:00:00 2001 From: Alfonso Bribiesca Date: Tue, 5 Feb 2019 21:55:45 -0600 Subject: [PATCH 2/8] Prioritize dot notations if has a parent key (#74) --- dist/lang.min.js | 2 +- src/lang.js | 35 +++++++++++++++++++++++++++-------- test/fixture/messages.json | 2 ++ test/spec/lang_get_spec.js | 4 ++++ 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/dist/lang.min.js b/dist/lang.min.js index dd78f5d..714c3b9 100644 --- a/dist/lang.min.js +++ b/dist/lang.min.js @@ -6,4 +6,4 @@ * @site https://github.com/rmariuzzo/Lang.js * @author Rubens Mariuzzo */ -(function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.Lang=factory()}})(this,function(){"use strict";function inferLocale(){if(typeof document!=="undefined"&&document.documentElement){return document.documentElement.lang}}function convertNumber(str){if(str==="-Inf"){return-Infinity}else if(str==="+Inf"||str==="Inf"||str==="*"){return Infinity}return parseInt(str,10)}var intervalRegexp=/^({\s*(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)\s*})|([\[\]])\s*(-Inf|\*|\-?\d+(\.\d+)?)\s*,\s*(\+?Inf|\*|\-?\d+(\.\d+)?)\s*([\[\]])$/;var anyIntervalRegexp=/({\s*(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)\s*})|([\[\]])\s*(-Inf|\*|\-?\d+(\.\d+)?)\s*,\s*(\+?Inf|\*|\-?\d+(\.\d+)?)\s*([\[\]])/;var defaults={locale:"en"};var Lang=function(options){options=options||{};this.locale=options.locale||inferLocale()||defaults.locale;this.fallback=options.fallback;this.messages=options.messages};Lang.prototype.setMessages=function(messages){this.messages=messages};Lang.prototype.getLocale=function(){return this.locale||this.fallback};Lang.prototype.setLocale=function(locale){this.locale=locale};Lang.prototype.getFallback=function(){return this.fallback};Lang.prototype.setFallback=function(fallback){this.fallback=fallback};Lang.prototype.has=function(key,locale){if(typeof key!=="string"||!this.messages){return false}return this._getMessage(key,locale)!==null};Lang.prototype.get=function(key,replacements,locale){if(!this.has(key,locale)){return key}var message=this._getMessage(key,locale);if(message===null){return key}if(replacements){message=this._applyReplacements(message,replacements)}return message};Lang.prototype.trans=function(key,replacements){return this.get(key,replacements)};Lang.prototype.choice=function(key,number,replacements,locale){replacements=typeof replacements!=="undefined"?replacements:{};replacements.count=number;var message=this.get(key,replacements,locale);if(message===null||message===undefined){return message}var messageParts=message.split("|");var explicitRules=[];for(var i=0;i=leftNumber:count>leftNumber)&&(rightDelimiter==="]"?count<=rightNumber:count=2&&count%10<=4&&(count%100<10||count%100>=20)?1:2;case"cs":case"sk":return count==1?0:count>=2&&count<=4?1:2;case"ga":return count==1?0:count==2?1:2;case"lt":return count%10==1&&count%100!=11?0:count%10>=2&&(count%100<10||count%100>=20)?1:2;case"sl":return count%100==1?0:count%100==2?1:count%100==3||count%100==4?2:3;case"mk":return count%10==1?0:1;case"mt":return count==1?0:count===0||count%100>1&&count%100<11?1:count%100>10&&count%100<20?2:3;case"lv":return count===0?0:count%10==1&&count%100!=11?1:2;case"pl":return count==1?0:count%10>=2&&count%10<=4&&(count%100<12||count%100>14)?1:2;case"cy":return count==1?0:count==2?1:count==8||count==11?2:3;case"ro":return count==1?0:count===0||count%100>0&&count%100<20?1:2;case"ar":return count===0?0:count==1?1:count==2?2:count%100>=3&&count%100<=10?3:count%100>=11&&count%100<=99?4:5;default:return 0}};return Lang}); \ No newline at end of file +(function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.Lang=factory()}})(this,function(){"use strict";function inferLocale(){if(typeof document!=="undefined"&&document.documentElement){return document.documentElement.lang}}function convertNumber(str){if(str==="-Inf"){return-Infinity}else if(str==="+Inf"||str==="Inf"||str==="*"){return Infinity}return parseInt(str,10)}var intervalRegexp=/^({\s*(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)\s*})|([\[\]])\s*(-Inf|\*|\-?\d+(\.\d+)?)\s*,\s*(\+?Inf|\*|\-?\d+(\.\d+)?)\s*([\[\]])$/;var anyIntervalRegexp=/({\s*(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)\s*})|([\[\]])\s*(-Inf|\*|\-?\d+(\.\d+)?)\s*,\s*(\+?Inf|\*|\-?\d+(\.\d+)?)\s*([\[\]])/;var defaults={locale:"en"};var Lang=function(options){options=options||{};this.locale=options.locale||inferLocale()||defaults.locale;this.fallback=options.fallback;this.messages=options.messages};Lang.prototype.setMessages=function(messages){this.messages=messages};Lang.prototype.getLocale=function(){return this.locale||this.fallback};Lang.prototype.setLocale=function(locale){this.locale=locale};Lang.prototype.getFallback=function(){return this.fallback};Lang.prototype.setFallback=function(fallback){this.fallback=fallback};Lang.prototype.has=function(key,locale){if(typeof key!=="string"||!this.messages){return false}return this._getMessage(key,locale)!==null};Lang.prototype.get=function(key,replacements,locale){if(!this.has(key,locale)){return key}var message=this._getMessage(key,locale);if(message===null){return key}if(replacements){message=this._applyReplacements(message,replacements)}return message};Lang.prototype.trans=function(key,replacements){return this.get(key,replacements)};Lang.prototype.choice=function(key,number,replacements,locale){replacements=typeof replacements!=="undefined"?replacements:{};replacements.count=number;var message=this.get(key,replacements,locale);if(message===null||message===undefined){return message}var messageParts=message.split("|");var explicitRules=[];for(var i=0;i=leftNumber:count>leftNumber)&&(rightDelimiter==="]"?count<=rightNumber:count=2&&count%10<=4&&(count%100<10||count%100>=20)?1:2;case"cs":case"sk":return count==1?0:count>=2&&count<=4?1:2;case"ga":return count==1?0:count==2?1:2;case"lt":return count%10==1&&count%100!=11?0:count%10>=2&&(count%100<10||count%100>=20)?1:2;case"sl":return count%100==1?0:count%100==2?1:count%100==3||count%100==4?2:3;case"mk":return count%10==1?0:1;case"mt":return count==1?0:count===0||count%100>1&&count%100<11?1:count%100>10&&count%100<20?2:3;case"lv":return count===0?0:count%10==1&&count%100!=11?1:2;case"pl":return count==1?0:count%10>=2&&count%10<=4&&(count%100<12||count%100>14)?1:2;case"cy":return count==1?0:count==2?1:count==8||count==11?2:3;case"ro":return count==1?0:count===0||count%100>0&&count%100<20?1:2;case"ar":return count===0?0:count==1?1:count==2?2:count%100>=3&&count%100<=10?3:count%100>=11&&count%100<=99?4:5;default:return 0}};return Lang}); \ No newline at end of file diff --git a/src/lang.js b/src/lang.js index 6335d98..781de3d 100644 --- a/src/lang.js +++ b/src/lang.js @@ -272,6 +272,7 @@ */ Lang.prototype._getMessage = function(key, locale) { locale = locale || this.getLocale(); + key = this._parseKey(key, locale); // Ensure message source exists. @@ -282,14 +283,9 @@ // Get message from default locale. var message = this.messages[key.source]; var entries = key.entries.slice(); - var subKey = ''; - while (entries.length && message !== undefined) { - var subKey = !subKey ? entries.shift() : subKey.concat('.', entries.shift()); - if (message[subKey] !== undefined) { - message = message[subKey] - subKey = ''; - } - } + var subKey = entries.join('.'); + message = message !== undefined ? this._getValueInKey(message, subKey) : undefined; + // Get message from fallback locale. if (typeof message !== 'string' && this.messages[key.sourceFallback]) { @@ -312,6 +308,29 @@ return message; }; + Lang.prototype._getValueInKey = function(obj, str) { + // If the full key exists just return the value + if (typeof obj[str] === 'string') { + return obj[str] + } + + str = str.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties + str = str.replace(/^\./, ''); // strip a leading dot + + var parts = str.split('.'); + + for (var i = 0, n = parts.length; i < n; ++i) { + var currentKey = parts.slice(0, i + 1).join('.'); + var restOfTheKey = parts.slice(i + 1, parts.length).join('.') + + if (obj[currentKey]) { + return this._getValueInKey(obj[currentKey], restOfTheKey) + } + } + + return obj; + }; + /** * Return the locale to be used between default and fallback. * @param {String} key diff --git a/test/fixture/messages.json b/test/fixture/messages.json index 2fab709..6c0fb40 100644 --- a/test/fixture/messages.json +++ b/test/fixture/messages.json @@ -109,6 +109,8 @@ }, "plural": "one apple|a million apples", "dot.in.key": "Dot In Key", + "with_parent": "Key That Is Subpart Of A Parent Key", + "with_parent.dot.in.key": "Dot In Key With a Parent Key", "dot.in.key2.nested": { "dot.in.key2.nested": "Dot In Key Nested Tricky" }, diff --git a/test/spec/lang_get_spec.js b/test/spec/lang_get_spec.js index 6c0f531..dee1bcd 100644 --- a/test/spec/lang_get_spec.js +++ b/test/spec/lang_get_spec.js @@ -69,6 +69,10 @@ describe('The lang.get() method', function () { expect(lang.get('messages.dot.in.key')).toBe('Dot In Key'); }); + it('should prioritize the dot in key', function() { + expect(lang.get('messages.with_parent.dot.in.key')).toBe('Dot In Key With a Parent Key'); + }); + it('should return the expected message if the key is nested and has a dot', function() { expect(lang.get('messages.dotInKey.dot.in.key')).toBe('Dot In Key Nested Simple'); expect(lang.get('messages.dot.in.key2.nested.dot.in.key2.nested')).toBe('Dot In Key Nested Tricky'); From 1d8e091d429816b4f09882b617603ccdae0d99d7 Mon Sep 17 00:00:00 2001 From: Rubens Mariuzzo Date: Wed, 6 Feb 2019 00:19:27 -0400 Subject: [PATCH 3/8] 1.1.14 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d273656..f6b8a8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lang.js", - "version": "1.1.13", + "version": "1.1.14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8b6c64d..63afd9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lang.js", - "version": "1.1.13", + "version": "1.1.14", "description": "Laravel's Lang in JavaScript!", "main": "src/lang.js", "types": "index.d.ts", From 789dafa8110fbc495a80e912d5748b971ff61e55 Mon Sep 17 00:00:00 2001 From: Rubens Mariuzzo Date: Sat, 9 Feb 2019 00:14:19 -0400 Subject: [PATCH 4/8] Add main.workflow. --- .github/main.workflow | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/main.workflow diff --git a/.github/main.workflow b/.github/main.workflow new file mode 100644 index 0000000..a4a6978 --- /dev/null +++ b/.github/main.workflow @@ -0,0 +1,10 @@ +workflow "New workflow" { + on = "push" + resolves = ["GitHub Action for npm"] +} + +action "GitHub Action for npm" { + uses = "actions/npm@master" + runs = "npm" + args = "test" +} From 79b5435875c66c0be80030170897f2a96108c52e Mon Sep 17 00:00:00 2001 From: Rubens Mariuzzo Date: Sat, 9 Feb 2019 00:17:00 -0400 Subject: [PATCH 5/8] Update main.workflow --- .github/main.workflow | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/main.workflow b/.github/main.workflow index a4a6978..0620ad0 100644 --- a/.github/main.workflow +++ b/.github/main.workflow @@ -1,10 +1,17 @@ workflow "New workflow" { on = "push" - resolves = ["GitHub Action for npm"] + resolves = ["Run Tests"] } -action "GitHub Action for npm" { +action "Install Dependencies" { + uses = "actions/npm@master" + runs = "npm" + args = "install" +} + +action "Run Tests" { uses = "actions/npm@master" runs = "npm" args = "test" + needs = ["Install Dependencies"] } From e31a0574597c66dfd57ffb4b441fcfdc62ff4630 Mon Sep 17 00:00:00 2001 From: Rubens Mariuzzo Date: Sat, 9 Feb 2019 02:02:07 -0400 Subject: [PATCH 6/8] Reformat README and add next version notice. --- .github/next-version.svg | 24 ++++++++++++++++++++++++ README.md | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 .github/next-version.svg diff --git a/.github/next-version.svg b/.github/next-version.svg new file mode 100644 index 0000000..644d625 --- /dev/null +++ b/.github/next-version.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + Are you interested in the next version? + + + + + + + diff --git a/README.md b/README.md index e9d5b67..9905598 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ ![NPM Montly Downloads](https://img.shields.io/npm/dm/lang.js.svg) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/rmariuzzo/Lang.js/master/LICENSE) +
+
+
+ ## Installation Different installation methods: @@ -14,6 +18,16 @@ Different installation methods: - Bower: `bower install lang.js` - Manually: [Download latest release](https://github.com/rmariuzzo/Lang.js/releases/latest) +
+
+
+ +[![Are you interested in the next version?](.github/next-version.svg)](https://github.com/rmariuzzo/Lang.js/tree/next) + +
+
+
+ ## Documentation ### Initialization @@ -251,6 +265,9 @@ lang.choice('fruits.apple', 22); This method act as an alias of [`choice()`](#choice). +
+
+
## Development @@ -260,6 +277,10 @@ This method act as an alias of [`choice()`](#choice). **[Get help!](https://gitter.im/rmariuzzo/Lang.js)** +
+
+
+ ## Testing To run the tests use the following commands: From eb43a3cf44ffbc76405b1cb58e168a3836e84f43 Mon Sep 17 00:00:00 2001 From: Joel Jaime Date: Thu, 8 Aug 2019 23:05:08 -0400 Subject: [PATCH 7/8] Change node version at the time of building (#77) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f790335..49b2706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "0.10" + - "7" install: - npm install script: npm run build From d9bd5f2d1728b4e3a17874f6444c42fa286efac0 Mon Sep 17 00:00:00 2001 From: Alwin Tom Date: Mon, 4 May 2020 11:11:37 +0530 Subject: [PATCH 8/8] Added support for Translation Strings as Keys --- src/lang.js | 35 +++++++++++++++++++++++++++++++++ test/fixture/messages.json | 4 ++++ test/spec/lang_fallback_spec.js | 19 ++++++++++++++++++ test/spec/lang_get_spec.js | 9 +++++++++ 4 files changed, 67 insertions(+) diff --git a/src/lang.js b/src/lang.js index 781de3d..1386607 100644 --- a/src/lang.js +++ b/src/lang.js @@ -272,6 +272,41 @@ */ Lang.prototype._getMessage = function(key, locale) { locale = locale || this.getLocale(); + let originalLocale = locale; + + // Handle the scenario where the tranlation string is used as the key. + // (https://laravel.com/docs/6.x/localization#using-translation-strings-as-keys) + // In this case the Key should be present at the root of the locale. + if (typeof(this.messages[locale]) === 'undefined') { + // The given locale does not have keys at the root, use the fallback instead. + locale = this.getFallback(); + } + + + // See if the key is defined. + if (typeof(this.messages[locale]) !== 'undefined') { + if (typeof(this.messages[locale][key]) !== 'undefined') { + return this.messages[locale][key]; + } + } + + //Try with the fallback as well. if we haven't looked there already. + if (locale === originalLocale) { + locale = this.getFallback(); + if (typeof(this.messages[locale]) !== 'undefined') { + if (typeof(this.messages[locale][key]) !== 'undefined') { + return this.messages[locale][key]; + } + } + } + + // If we reach here, that means the traslation key did not exist in the provided locale + // nor the fallback locale. At this point proceed as normal and expect the rest of the code + // to find a valid translation or return the key itself as the translation + // (which also takes care of 'Translation strings as key') + + // Reset to the original locale. + locale = originalLocale; key = this._parseKey(key, locale); diff --git a/test/fixture/messages.json b/test/fixture/messages.json index 6c0fb40..4e27f62 100644 --- a/test/fixture/messages.json +++ b/test/fixture/messages.json @@ -216,5 +216,9 @@ }, "en.unique": { "samePrefixKeys": "Your order contains :items items with :itemsPapayas papayas and :itemsMangoes mangoes" + }, + "es": { + "Hello": "Hola", + "Payment received. Thanks!": "Pago recibido. Gracias!" } } diff --git a/test/spec/lang_fallback_spec.js b/test/spec/lang_fallback_spec.js index 6844fae..87a8eac 100644 --- a/test/spec/lang_fallback_spec.js +++ b/test/spec/lang_fallback_spec.js @@ -58,4 +58,23 @@ describe('The lang\'s fallback locale feature', function() { lang.get('greetings.hello'); }).not.toThrow(); }); + + // JSON Translation string as keys + it('should return the fallback if tranlation is not availble.', function() { + var messages = { + 'en': { + 'Welcome': 'Welcome to the site.' + }, + 'es': { + 'Hello': 'Hola', + } + }; + lang = new Lang({ + messages: messages + }); + lang.setLocale('es'); + lang.setFallback('en'); + + expect(lang.get('Welcome', [], 'es')).toBe('Welcome to the site.'); + }) }); diff --git a/test/spec/lang_get_spec.js b/test/spec/lang_get_spec.js index dee1bcd..c492d8b 100644 --- a/test/spec/lang_get_spec.js +++ b/test/spec/lang_get_spec.js @@ -89,4 +89,13 @@ describe('The lang.get() method', function () { itemsMangoes: 2 })).toBe('Your order contains 5 items with 3 papayas and 2 mangoes'); }); + + // JSON Translation string as key + it('should return the spanish translation when a key exists', function() { + expect(lang.get('Hello', [], 'es')).toBe('Hola'); + }); + + it('should return the spanish translation when a key exists and key contains a period (.)', function() { + expect(lang.get('Payment received. Thanks!', [], 'es')).toBe('Pago recibido. Gracias!'); + }); });