diff --git a/README.md b/README.md index a1945bf..51673e1 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,26 @@ mongoose-localize A nodejs module to convert mongoose model property to set of localized properties. -As soon as mongoose_localize has been required... +As soon as mongoose_localize has been required with CommonJS ... ```javascript +var + mongoose = require('mongoose'), + localize = require('mongoose-localize'); +``` + +or imported and initialized with ES6 syntax +```javascript +import mongoose from 'mongoose'; import mongoose_localize from 'mongoose-localize'; -mongoose_localize.setLocales(['locale1','locale2',...,'localeN']); +mongoose_localize.localize(mongoose,[currentLocale[,locales]]); +``` + +or with another (better) ES6 syntax +```javascript +import mongoose from 'mongoose'; +import {localize as mongoose_localize} from 'mongoose-localize'; +mongoose_localize(mongoose,'ru',['en','ru']); ``` ...every attribute of mongoose Scheme containing "localize" attribute set to true... @@ -31,15 +46,26 @@ approverSchema = new mongoose.Schema({ localeN: {type:String}, } }); -approverSchema.virtual('localized.name').get(function () { +approverSchema.virtual('name._').get(function () { // return name in the current locale ... -}); +}).set(function (v) { +// set name of the current locale to v + ... +}) +; ``` -The "localize" attribute will be removed from source Scheme. It's nor a bug neither a feature, it is "by design". While the module must be required and setLocales must be called before the first Schema added the current locale may be set and changed in any moment. ```javascript -mongoose_localize.setLocale('locale2'); +mongoose_localize.setCurrenLocale('locale2'); +``` + +Locales and current locales may be retrieved with + +```javascript +mongoose_localize.locales(); +mongoose_localize.currentLocale(); ``` + diff --git a/index.js b/index.js index 925c4bb..270fa92 100644 --- a/index.js +++ b/index.js @@ -1,95 +1,148 @@ 'use strict'; -var mongoose = require('mongoose'); +//var mongoose = require('mongoose'); var locales=['en','ru']; -var locale='en'; - -var prototype_mongoose=function(){ - var ma = mongoose.Schema.prototype.add; - var addI18n=function(schema,obj){ - var keys = Object.keys(obj); - - if (keys.length==1 && keys=='_id') return obj; - - var ret={}; - - for (var i = 0; i < keys.length; ++i) { - var key = keys[i]; - var val = obj[key]; - - if (key==='type'){ - ret[key]=val; - continue; - } - - if (typeof val != "object") { - ret[key]=val; - continue; - }; - - if (val instanceof Array) { - ret[key]=val; - continue; - }; - - var kkeys=Object.keys(val); - var localize=false; - for (var ii=0; ii<kkeys.length;++ii){ - var kkey=kkeys[ii]; - var vval=val[kkey]; - if (typeof vval==="object"){ - val[kkey]=addI18n(schema,vval) - }else{ - if (vval && kkey=="localize"){ - localize=true; - } - } - } - if (localize){ - delete(val.localize); - var nval={}; - for (var j=0;j<locales.length;j++){ - nval[locales[j]]=val;// Note: must live without copy JSON.parse(JSON.stringify(va)) because of [Function]; - //nval[locales[j]]=JSON.parse(JSON.stringify(val)); - } - //ret['_localized_'+key]=nval; - ret[key]=nval; - schema.virtual('localized.'+key) - .get(function(value,virtual){ - var n=virtual.path.substring(10); - return this[n][locale]; - })/* - .set(function(value,virtual){ - var n=virtual.path.substring(10); - this[n]=value; - });*/ - }else{ - ret[key]=val; - } - }; - return ret; - } - - mongoose.Schema.prototype.add = function add (obj, prefix) { - var oobj=addI18n(this,obj); - ma.call(this,oobj,prefix); - }; +var locale=locales[0]; + +function setLocales(sLocales){ + locales=sLocales; +} + +function currentLocale(){ + return locale?locale:((locales.length>0)?locales[0]:undefined); +} + +function setCurrentLocale(sLocale){ + if (locales.indexOf(sLocale)>=0) + locale=sLocale; + else{ + let i=sLocale.indexOf('-'); + if (i>0){ + return setCurrentLocale(sLocale.substring(0,i)); + }else{ + i=sLocale.indexOf('_'); + if (i>0){ + return setCurrentLocale(sLocale.substring(0,i)); + }else{ + if (locales.length>0){ + setCurrentLocale(locales[0]); + } + } + } + } +} + +function isLocalized(){ + return true; +} + +var prototype_mongoose=function(mongoose_instance,_currentLocale,_locales){ + + function localizedAdd(obj, prefix) { + //console.log({in:obj}); + var oobj=addI18n(this,obj,prefix); + //console.log({out:oobj}); + ma.call(this,oobj,prefix); + }; + + + if (_currentLocale) setCurrentLocale(_currentLocale); + if (_locales) setLocales(_locales); + if (!mongoose_instance) + mongoose_instance=require('mongoose'); + + //if (mongoose_instance.Schema.prototype.add === localizedAdd){ + if (mongoose_instance.Schema.prototype.localized === isLocalized){ + //console.log('WARN: mongoose already has been localized'); + return; + }else{ + //console.log('INFO: mongoose will be localized'); + }; + + var ma = mongoose_instance.Schema.prototype.add; + if (mongoose_instance.Schema.prototype.localized) return; + + //traverse over all fields and modify the objects having "localize" attribute + var addI18n=function(schema,obj,prefix){ + var keys = Object.keys(obj); + + if (keys.length==1 && keys=='_id') return obj; + + var ret={}; + + for (var i = 0; i < keys.length; i++) { + //keys of fields + var key = keys[i]; + var field = obj[key]; + + if (key==='type'){ + ret[key]=field; + continue; + } + + if (typeof field != "object") { + ret[key]=field; + continue; + }; + + if (field instanceof Array) { + //TODO: Should traverse? Than a problem with virtual name path + ret[key]=field.slice(); + continue; + }; + + //now we are sure "field" is an object + //field=addI18n(schema,field,path+(path==''?'':'.')+key); + + if (field.localize){ + if ((locales instanceof Array) && locales.length>0){ + var nfield={}; + for (var li=0;li<locales.length;li++){ + //TODO: remove ES6 + nfield[locales[li]]=Object.assign({},field); + delete(nfield[locales[li]].localize); + } + ret[key]=nfield; + var vpath=(prefix?prefix:'')+key; + schema.virtual(vpath+'._') + .get(function(){ + var l=currentLocale(); + if (l) return this.get(vpath+'.'+l); + return undefined; + }).set(function(value,virtual){ + var l=currentLocale(); + if (l) + this.set(vpath+'.'+l,value); + }); + }else{ + ret[key]=Object.assign({},field); + delete(ret[key].localize); + } + }else{ + ret[key]=field; + } + }; + return ret; + } + + mongoose_instance.Schema.prototype.add = localizedAdd; + mongoose_instance.Schema.prototype.localized=isLocalized; }; -prototype_mongoose(); +prototype_mongoose() + module.exports = { -locale:function(){ - return locale; -}, -setLocale:function(sLocale){ - locale=sLocale; -}, -locales:function(){ - return locales; -}, -setLocales:function(sLocales){ - locales=sLocales; -} + currentLocale:currentLocale, + setCurrentLocale:setCurrentLocale, + locales:function(){ + return locales; + }, + setLocales:setLocales, + localize:prototype_mongoose, + localized:function(){mongoose.Schema.prototype.localized==isLocalized} } + + + diff --git a/package.json b/package.json index 7add82b..1820c1b 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,18 @@ { "author": "S4Y Solution <e@s4y.solutions>", - "contributors": ["Sergey Dolin <e@sergey.email>"], + "contributors": [ + "Sergey Dolin <e@sergey.email>" + ], "name": "mongoose-localize", - "description": "A module to conver mongoose model property to set of localized properties.", - "version": "0.1.0", - "keywords": ["mongoose","localize","l10n","i19n"], + "description": "A module to convert mongoose model property to set of localized properties.", + "version": "1.0.10", + "keywords": [ + "mongoose", + "localize", + "translation", + "l10n", + "i19n" + ], "license": "ISC", "repository": { "url": "git://github.com/dsame/mongoose-localize.git" @@ -14,6 +22,13 @@ "node": "*" }, "scripts": { - "test": "mocha test" - } + "test": "mocha test" + }, + "devDependencies": { + "chai": "3.5.0", + "mocha": "3.1.2" + }, + "dependencies": { + "mongoose": "4.6.5" + } } diff --git a/test/model.js b/test/model.js index 2a1ccb1..be2f196 100644 --- a/test/model.js +++ b/test/model.js @@ -3,64 +3,112 @@ /** * Module dependencies. */ -var should = require('should'), - mongoose = require('mongoose'), - localize = require('mongoose-localize'); -// Application = mongoose.model('Application'); +var chai = require('chai'), + mongoose = require('mongoose'), + localize = require('../index'); -var TestSchema = new mongoose.Schema({ - name: { - type: String, - default: 'test', - trim: true, - localize: false - } -}); -mongoose.model('Test', TestSchema); -var Test=mongoose.model('Test'); - -var TestLSchema = new mongoose.Schema({ - name: { - type: String, - default: 'testl', - trim: true, - localize: true - } -}); -mongoose.model('TestL', TestLSchema); -var TestL=mongoose.model('TestL'); +var assert=chai.assert; +it('Test set/get locales',function(){ + localize.setLocales(['letter','digit']); + assert.equal(localize.locales().length,2,'by default there are 2 locales'); + assert.equal(localize.locales()[0],'letter','check 1st locale'); + assert.equal(localize.locales()[1],'digit','check 2nd locale'); +}) -//The tests -describe('<Mongoose Localize Test>', function() { +it('Test set/get current locale',function(){ + localize.setCurrentLocale('xxx'); + assert.equal(localize.currentLocale(),'xxx'); + localize.setCurrentLocale('digit'); + assert.equal(localize.currentLocale(),'digit'); + localize.setCurrentLocale(false); + assert.equal(localize.currentLocale(),'letter'); + localize.setCurrentLocale('letter'); + assert.equal(localize.currentLocale(),'letter'); +}) - describe('Test Schema Available', function() { - var t=new Test(); - it('non localized should have name="test" by default', function(done) { - t.should.have.property('name','test'); - done(); - }); - }); - describe('Localized Test Schema Available', function() { - var tl=new TestL(); - console.log(tl); - it('localized should have property name', function(done) { - tl.should.have.property('name'); - done(); - }); - }); /* - describe('Method Save', function() { - it('should begin without the test user', function(done) { - Application.find({ name: 'Some name' }, function(err, applications) { - applications.should.have.length(0); - done(); - }); - }); +it('Test simple model localizations', function() { + + var TestSchema = new mongoose.Schema({ + _id:mongoose.Schema.ObjectId, + name: { + type: String, + localize: false + } + }); + assert.equal(TestSchema.path('name').instance,'String','with localization=false the type should stay "String"'); + + var TestLSchema = new mongoose.Schema({ + _id:mongoose.Schema.ObjectId, + name: { + type: String, + localize: true + }, + }); + + //console.log(TestLSchema); + assert.isDefined(TestLSchema.path('name.letter'),'"letter" locale exist'); + assert.isDefined(TestLSchema.path('name.digit'),'"digit" locale exist'); + assert.isDefined(TestLSchema.virtuals['name._']); - it('should be able to save without problems', function(done) { - application.save(done); - }); - }); + mongoose.model('TestL', TestLSchema); + var TestLModel=mongoose.model('TestL'); + var testL=new TestLModel({name:{letter:'a',digit:'1'}}); + assert.equal(testL.name.digit,1); + assert.equal(testL.name.letter,'a'); + localize.setCurrentLocale('letter'); + assert.equal(testL.name._,'a'); + localize.setCurrentLocale('digit'); + assert.equal(testL.name._,1); + localize.setCurrentLocale(false); + assert.equal(testL.name._,'a'); +}); */ +it('Test sub-document localizations', function() { + + var TestLSchema = new mongoose.Schema({ + _id:mongoose.Schema.ObjectId, + name: { + type: String, + localize: true + }, + sub: { + name: { + type: String, + localize: true + } + } + }); + + //console.log(TestLSchema); + assert.isDefined(TestLSchema.path('name.letter'),'"letter" locale exists in document'); + assert.isDefined(TestLSchema.path('name.digit'),'"digit" locale exists in ducument'); + assert.isDefined(TestLSchema.virtuals['name._'],'name._ exists in document'); + + assert.isDefined(TestLSchema.path('sub.name.letter'),'"letter" locale exist in subdocument'); + assert.isDefined(TestLSchema.path('sub.name.digit'),'"digit" locale exists in subdocument'); + assert.isDefined(TestLSchema.virtuals['sub.name._'],'name._ exists in subdocument]'); + + mongoose.model('TestL', TestLSchema); + var TestLModel=mongoose.model('TestL'); + var testL=new TestLModel({name:{letter:'a',digit:'1'},sub:{name:{letter:'b',digit:2}}}); + //console.log(testL); + + assert.equal(testL.name.digit,1,'document digit=1'); + assert.equal(testL.name.letter,'a','docuemnt letter=a'); + localize.setCurrentLocale('letter'); + assert.equal(testL.name._,'a','document name in current locale should be "a"'); + localize.setCurrentLocale('digit'); + assert.equal(testL.name._,1); + localize.setCurrentLocale(false); + assert.equal(testL.name._,'a'); + assert.equal(testL.sub.name.digit,2); + assert.equal(testL.sub.name.letter,'b'); + localize.setCurrentLocale('letter'); + assert.equal(testL.sub.name._,'b'); + localize.setCurrentLocale('digit'); + assert.equal(testL.sub.name._,2); + localize.setCurrentLocale(false); + assert.equal(testL.sub.name._,'b'); });