From 8ec69b4f8304a63e3113b55feccc402d22a4aec5 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 5 Mar 2014 16:43:00 +0100 Subject: [PATCH 01/29] improve(i18n): move translations to their own module, use i18n from habitrpg-shared, @djuretic i have remove the tests because the code is now handled in habitrpg-shared, we may add them back there --- public/js/env.js | 8 +-- src/i18n.js | 95 +++++++++++++++++++++++++++++++++++ src/middleware.js | 102 ++++---------------------------------- src/server.js | 3 ++ test/spec/rootCtrlSpec.js | 26 ---------- 5 files changed, 110 insertions(+), 124 deletions(-) create mode 100644 src/i18n.js diff --git a/public/js/env.js b/public/js/env.js index 8a6611cd90..bcae78640c 100644 --- a/public/js/env.js +++ b/public/js/env.js @@ -12,9 +12,5 @@ if(window.moment && window.env.language && window.env.language.momentLang && win window.moment.lang(window.env.language.momentLangCode); } -window.env.t = function(stringName, vars){ - var string = window.env.translations[stringName]; - if(!string) return window._.template(window.env.translations.stringNotFound, {string: stringName}); - - return vars === undefined ? string : window._.template(string, vars); -} \ No newline at end of file +window.habitrpgShared.i18n.strings = window.env.translations; +window.env.t = window.habitrpgShared.i18n.t; \ No newline at end of file diff --git a/src/i18n.js b/src/i18n.js new file mode 100644 index 0000000000..9b1cf27998 --- /dev/null +++ b/src/i18n.js @@ -0,0 +1,95 @@ +var fs = require('fs'), + path = require('path'), + _ = require('lodash'), + User = require('./models/user').model, + shared = require('habitrpg-shared'), + translations = {}; + +var loadTranslations = function(locale){ + var files = fs.readdirSync(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale)); + translations[locale] = {}; + _.each(files, function(file){ + _.merge(translations[locale], require(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale, file))); + }); +}; + +// First fetch english so we can merge with missing strings in other languages +loadTranslations('en'); + +fs.readdirSync(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/")).forEach(function(file) { + if(file === 'en' || file === 'README.md') return; + loadTranslations(file); + // Merge missing strings from english + _.defaults(translations[file], translations.en); +}); + +var langCodes = Object.keys(translations); + +var avalaibleLanguages = _.map(langCodes, function(langCode){ + return { + code: langCode, + name: translations[langCode].languageName + } +}); + +// Load MomentJS localization files +var momentLangs = {}; + +// Handle different language codes from MomentJS and /locales +var momentLangsMapping = { + 'en': 'en-gb', + 'no': 'nn' +}; + +var momentLangs = {}; + +_.each(langCodes, function(code){ + var lang = _.find(avalaibleLanguages, {code: code}); + lang.momentLangCode = (momentLangsMapping[code] || code); + try{ + // MomentJS lang files are JS files that has to be executed in the browser so we load them as plain text files + var f = fs.readFileSync(path.join(__dirname, '/../node_modules/moment/lang/' + lang.momentLangCode + '.js'), 'utf8'); + momentLangs[code] = f; + }catch (e){} +}); + +var getUserLanguage = function(req, callback){ + var getFromBrowser = function(){ + var acceptable = _(req.acceptedLanguages).map(function(lang){ + return lang.slice(0, 2); + }).uniq().value(); + var matches = _.intersection(acceptable, langCodes); + return matches.length > 0 ? matches[0] : 'en'; + }; + + if(req.session && req.session.userId){ + User.findOne({_id: req.session.userId}, function(err, user){ + if(err) return callback(err); + if(user && user.preferences.language && translations[user.preferences.language]){ + return callback(null, _.find(avalaibleLanguages, {code: user.preferences.language})); + }else{ + var langCode = getFromBrowser(); + // Because english is usually always avalaible as an acceptable language for the browser, + // if the user visit the page when his own language is not avalaible yet + // he'll have english set in his preferences, which is not good. + //if(user && translations[langCode]){ + //user.preferences.language = langCode; + //user.save(); //callback? + //} + return callback(null, _.find(avalaibleLanguages, {code: langCode})) + } + }); + }else{ + return callback(null, _.find(avalaibleLanguages, {code: getFromBrowser()})); + } +}; + +shared.i18n.translations = translations; + +module.exports = { + translations: translations, + avalaibleLanguages: avalaibleLanguages, + langCodes: langCodes, + getUserLanguage: getUserLanguage, + momentLangs: momentLangs +}; \ No newline at end of file diff --git a/src/middleware.js b/src/middleware.js index bb40be8334..232c0ab355 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -7,6 +7,8 @@ var limiter = require('connect-ratelimit'); var logging = require('./logging'); var domainMiddleware = require('domain-middleware'); var cluster = require('cluster'); +var i18n = require('./i18n.js'); +var shared = require('habitrpg-shared'); module.exports.apiThrottle = function(app) { if (nconf.get('NODE_ENV') !== 'production') return; @@ -139,97 +141,14 @@ var getManifestFiles = function(page){ return code; } -// Translations - -var translations = {}; - -var loadTranslations = function(locale){ - var files = fs.readdirSync(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale)); - translations[locale] = {}; - _.each(files, function(file){ - _.merge(translations[locale], require(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale, file))); - }); -}; - -// First fetch english so we can merge with missing strings in other languages -loadTranslations('en'); - -fs.readdirSync(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/")).forEach(function(file) { - if(file === 'en') return; - loadTranslations(file); - // Merge missing strings from english - _.defaults(translations[file], translations.en); -}); - -var langCodes = Object.keys(translations); - -var avalaibleLanguages = _.map(langCodes, function(langCode){ - return { - code: langCode, - name: translations[langCode].languageName - } -}); - -// Load MomentJS localization files -var momentLangs = {}; - -// Handle different language codes from MomentJS and /locales -var momentLangsMapping = { - 'en': 'en-gb', - 'no': 'nn' -}; - -var momentLangs = {}; - -_.each(langCodes, function(code){ - var lang = _.find(avalaibleLanguages, {code: code}); - lang.momentLangCode = (momentLangsMapping[code] || code); - try{ - // MomentJS lang files are JS files that has to be executed in the browser so we load them as plain text files - var f = fs.readFileSync(path.join(__dirname, '/../node_modules/moment/lang/' + lang.momentLangCode + '.js'), 'utf8'); - momentLangs[code] = f; - }catch (e){} -}); - -var getUserLanguage = function(req, callback){ - var getFromBrowser = function(){ - var acceptable = _(req.acceptedLanguages).map(function(lang){ - return lang.slice(0, 2); - }).uniq().value(); - var matches = _.intersection(acceptable, langCodes); - return matches.length > 0 ? matches[0] : 'en'; - }; - - if(req.session && req.session.userId){ - User.findOne({_id: req.session.userId}, function(err, user){ - if(err) return callback(err); - if(user && user.preferences.language && translations[user.preferences.language]){ - return callback(null, _.find(avalaibleLanguages, {code: user.preferences.language})); - }else{ - var langCode = getFromBrowser(); - // Because english is usually always avalaible as an acceptable language for the browser, - // if the user visit the page when his own language is not avalaible yet - // he'll have english set in his preferences, which is not good. - //if(user && translations[langCode]){ - //user.preferences.language = langCode; - //user.save(); //callback? - //} - return callback(null, _.find(avalaibleLanguages, {code: langCode})) - } - }); - }else{ - return callback(null, _.find(avalaibleLanguages, {code: getFromBrowser()})); - } -} - module.exports.locals = function(req, res, next) { - getUserLanguage(req, function(err, language){ + i18n.getUserLanguage(req, function(err, language){ if(err) return res.json(500, {err: err}); var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' // Load moment.js language file only when not on static pages - language.momentLang = ((!isStaticPage && momentLangs[language.code])|| undefined); + language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code])|| undefined); res.locals.habitrpg = { NODE_ENV: nconf.get('NODE_ENV'), @@ -239,15 +158,14 @@ module.exports.locals = function(req, res, next) { STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY'), getManifestFiles: getManifestFiles, getBuildUrl: getBuildUrl, - avalaibleLanguages: avalaibleLanguages, + avalaibleLanguages: i18n.avalaibleLanguages, language: language, isStaticPage: isStaticPage, - translations: translations[language.code], - t: function(stringName, vars){ - var string = translations[language.code][stringName]; - if(!string) return _.template(translations[language.code].stringNotFound, {string: stringName}); - - return vars === undefined ? string : _.template(string, vars); + translations: i18n.translations[language.code], + t: function(){ // stringName and vars are the allowed parameters + var args = Array.prototype.slice.call(arguments, 0); + args.push(language.code); + return shared.i18n.t.apply(null, args); }, siteVersion: siteVersion } diff --git a/src/server.js b/src/server.js index 205e379d6b..c494641a5f 100644 --- a/src/server.js +++ b/src/server.js @@ -27,6 +27,9 @@ if (cluster.isMaster && (isDev || isProd)) { var swagger = require("swagger-node-express"); var autoinc = require('mongoose-id-autoinc'); + // Setup translations + var i18n = require('./i18n'); + var middleware = require('./middleware'); var TWO_WEEKS = 1000 * 60 * 60 * 24 * 14; diff --git a/test/spec/rootCtrlSpec.js b/test/spec/rootCtrlSpec.js index 20bb41857f..52d31a1375 100644 --- a/test/spec/rootCtrlSpec.js +++ b/test/spec/rootCtrlSpec.js @@ -28,30 +28,4 @@ describe('Root Controller', function() { expect(scope.contribText({level: 8, text: 'Blacksmith'}, {npc: 'NPC'})).to.eql('NPC'); }); - describe('i18n', function(){ - var t = env.t; - beforeEach(function(){ - env.translations = { - "text1": 'translatedText1', - "text2": '<%= number %> eggs', - "stringNotFound" : "String '<%= string %>' not found.", - }; - }); - - it('translates strings', function(){ - expect(t('')).to.eql("String '' not found."); - expect(t('text1')).to.eql('translatedText1'); - expect(t(' text1 ')).to.eql("String ' text1 ' not found."); - expect(t('text3')).to.eql("String 'text3' not found."); - }); - - it('interpolates strings', function(){ - expect(t('text2', {number: 2})).to.eql('2 eggs'); - expect(t('text2', {number: 'ten'})).to.eql('ten eggs'); - expect(t('text2', {n: 10, number: 'ten'})).to.eql('ten eggs'); - expect(t('text2')).to.eql('<%= number %> eggs'); - }); - }); - - }); \ No newline at end of file From 626352e04be1f20ec855cdc65b40924375222063 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 6 Mar 2014 18:10:58 +0100 Subject: [PATCH 02/29] improve(i18n): use strings for gear items and potion --- views/options/inventory/inventory.jade | 4 ++-- views/shared/tasks/lists.jade | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index c004d1b9ef..b59ef452c4 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -6,7 +6,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html') li.customize-menu.inventory-gear menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special", mystery:"Mystery"}', ng-show='gear[klass]') div(ng-repeat='item in gear[klass]') - button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}') + button.customize-option(popover='{{item.notes()}}', popover-title='{{item.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}') .col-md-6 h3.equipment-title.hint(popover-trigger='mouseenter', popover-placement='right', popover=env.t('costumeText'))=env.t('costume') .checkbox.equipment-title @@ -17,7 +17,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html') li.customize-menu(ng-if='user.preferences.costume') menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special", mystery:"Mystery"}', ng-show='gear[klass]') div(ng-repeat='item in gear[klass]') - button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}') + button.customize-option(popover='{{item.notes()}}', popover-title='{{item.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}') script(type='text/ng-template', id='partials/options.inventory.drops.html') .container-fluid diff --git a/views/shared/tasks/lists.jade b/views/shared/tasks/lists.jade index c2007e8a5b..d980f73a51 100644 --- a/views/shared/tasks/lists.jade +++ b/views/shared/tasks/lists.jade @@ -35,7 +35,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") // Static Rewards ul.items.rewards(ng-if='main && list.type=="reward" && user.flags.itemsEnabled') - li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.notes}}') + li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.notes()}}') // right-hand side control buttons .task-meta-controls span.task-notes @@ -47,7 +47,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span.shop_gold // main content span(bo-class='{"shop_{{item.key}} shop-sprite item-img": true}') - p.task-text {{item.text}} + p.task-text {{item.text()}} // Events ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball)') From d242ee3291e4c48c7818dc07c9e6c48d703e9f5b Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 10 Mar 2014 15:26:05 +0100 Subject: [PATCH 03/29] refactor(i18n): use strings for content --- public/js/controllers/inventoryCtrl.js | 4 ++-- public/js/controllers/rootCtrl.js | 8 +++---- src/controllers/user.js | 2 +- src/models/user.js | 31 +++++++++++++++++++++----- views/options/inventory/inventory.jade | 28 +++++++++++------------ views/options/inventory/stable.jade | 8 +++---- views/options/social/group.jade | 8 +++---- views/shared/modals/buy-gems.jade | 1 - views/shared/modals/drops.jade | 2 +- views/shared/modals/quests.jade | 18 +++++++-------- views/shared/profiles/stats.jade | 2 +- views/shared/tasks/lists.jade | 12 +++++----- 12 files changed, 72 insertions(+), 52 deletions(-) diff --git a/public/js/controllers/inventoryCtrl.js b/public/js/controllers/inventoryCtrl.js index 7f8b51da1e..ca3740f872 100644 --- a/public/js/controllers/inventoryCtrl.js +++ b/public/js/controllers/inventoryCtrl.js @@ -104,7 +104,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User', var food = $scope.selectedFood if (food.key == 'Saddle') { if (!$window.confirm(window.env.t('useSaddle', {pet: pet}))) return; - } else if (!$window.confirm(window.env.t('feedPet', {name: petDisplayName, article: food.article, text: food.text}))) { + } else if (!$window.confirm(window.env.t('feedPet', {name: petDisplayName, article: food.article, text: food.text()}))) { return; } User.user.ops.feed({params:{pet: pet, food: food.key}}); @@ -124,7 +124,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User', var item = Content.quests[quest]; var completedPrevious = !item.previous || (User.user.achievements.quests && User.user.achievements.quests[item.previous]); if (!completedPrevious) - return alert(window.env.t('mustComplete', {quest: $rootScope.Content.quests[item.previous].text})); + return alert(window.env.t('mustComplete', {quest: $rootScope.Content.quests[item.previous].text()})); if (item.lvl && item.lvl > user.stats.lvl) return alert(window.env.t('mustLevel', {level: item.lvl})); $rootScope.selectedQuest = item; diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index 924d0afe5a..5ecce87aa2 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -204,11 +204,11 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ $http.post('/api/v2/user/class/cast/'+spell.key+'?targetType='+type+'&targetId='+targetId) .success(function(){ - var msg = window.env.t('youCast', {spell: spell.text}); + var msg = window.env.t('youCast', {spell: spell.text()}); switch (type) { - case 'task': msg = window.env.t('youCastTarget', {spell: spell.text, target: target.text});break; - case 'user': msg = window.env.t('youCastTarget', {spell: spell.text, target: target.profile.name});break; - case 'party': msg = window.env.t('youCastParty', {spell: spell.text});break; + case 'task': msg = window.env.t('youCastTarget', {spell: spell.text(), target: target.text});break; + case 'user': msg = window.env.t('youCastTarget', {spell: spell.text(), target: target.profile.name});break; + case 'party': msg = window.env.t('youCastParty', {spell: spell.text()});break; } Notification.text(msg); }); diff --git a/src/controllers/user.js b/src/controllers/user.js index e1d15f213a..c4c8cb3cf9 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -336,7 +336,7 @@ api.cast = function(req, res, next) { if (group) { series.push(function(cb2){ - var message = '`'+user.profile.name+' casts '+spell.text + (targetType=='user' ? ' on '+found.profile.name : ' for the party')+'.`'; + var message = '`'+user.profile.name+' casts '+spell.text() + (targetType=='user' ? ' on '+found.profile.name : ' for the party')+'.`'; group.sendChat(message); group.save(cb2); }) diff --git a/src/models/user.js b/src/models/user.js index 4e019af4aa..c72989b21b 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -305,14 +305,14 @@ var UserSchema = new Schema({ id: { type: String, 'default': shared.uuid }, name: String, challenge: String - }], 'default': shared.content.userDefaults.tags}, + }]}, challenges: [{type: 'String', ref:'Challenge'}], - habits: {type:[TaskSchemas.HabitSchema], 'default': shared.content.userDefaults.habits}, - dailys: {type:[TaskSchemas.DailySchema], 'default': shared.content.userDefaults.dailys}, - todos: {type:[TaskSchemas.TodoSchema], 'default': shared.content.userDefaults.todos}, - rewards: {type:[TaskSchemas.RewardSchema], 'default': shared.content.userDefaults.rewards}, + habits: {type:[TaskSchemas.HabitSchema]}, + dailys: {type:[TaskSchemas.DailySchema]}, + todos: {type:[TaskSchemas.TodoSchema]}, + rewards: {type:[TaskSchemas.RewardSchema]}, extra: Schema.Types.Mixed @@ -348,6 +348,27 @@ UserSchema.post('init', function(doc){ UserSchema.pre('save', function(next) { + // Populate new users with default content + if (this.isNew){ + //TODO for some reason this doesn't work here: `_.merge(this, shared.content.userDefaults);` + var self = this; + + _.each('habits', 'dailys', 'todos', 'rewards', 'tags', function(taskType){ + self.taskType = _.map(shared.content.userDefaults[taskType], function(task){ + var newTask = task; + + // Render task's text and notes in user's language + newTask.text = task.text(); + newTask.notes = task.notes(); + + return newTask; + }); + }); + + // tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here + _.each(this.tags, function(tag){tag.id = shared.uuid();}) + } + //this.markModified('tasks'); if (_.isNaN(this.preferences.dayStart) || this.preferences.dayStart < 0 || this.preferences.dayStart > 23) { this.preferences.dayStart = 0; diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index b59ef452c4..b44f3a4a39 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -32,15 +32,15 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') p.muted(ng-show='eggCount < 1')=env.t('noEggs') div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)') //TODO move positioning this styling to css - button.customize-option(popover='{{Content.eggs[egg].notes}}', popover-title='{{Content.eggs[egg].text}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') + button.customize-option(popover='{{Content.eggs[egg].notes()}}', popover-title='{{Content.eggs[egg].text()}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') .badge.badge-info.stack-count {{points}} - //-p {{Content.eggs[egg].text}} + //-p {{Content.eggs[egg].text()}} li.customize-menu menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})')) p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions') div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)') - button.customize-option(popover='{{Content.hatchingPotions[pot].notes}}', popover-title='{{Content.hatchingPotions[pot].text}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') + button.customize-option(popover='{{Content.hatchingPotions[pot].notes()}}', popover-title='{{Content.hatchingPotions[pot].text()}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') .badge.badge-info.stack-count {{points}} li.customize-menu @@ -48,20 +48,20 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') p.muted(ng-show='questCount < 1')=env.t('noScrolls') p.muted!=env.t('scrollsText1') + ' ' + env.t('scrollsText2') + '' div(ng-repeat='(quest_key,points) in ownedItems(user.items.quests)', ng-init='quest = Content.quests[quest_key]') - button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='showQuest(quest_key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}') + button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes() | htmlDecode}}", popover-title='{{quest.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='showQuest(quest_key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}') .badge.badge-info.stack-count {{points}} li.customize-menu menu.pets-menu(label=env.t('food') + ' ({{foodCount}})') p(ng-show='foodCount < 1')=env.t('noFood') div(ng-repeat='(food,points) in ownedItems(user.items.food)') - button.customize-option(popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}') + button.customize-option(popover='{{Content.food[food].notes()}}', popover-title='{{Content.food[food].text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}') .badge.badge-info.stack-count {{points}} li.customize-menu(ng-if='user.items.special.snowball') menu.pets-menu(label=env.t('special')) div - button.customize-option(popover='{{Content.special.snowball.notes}}', popover-title='{{Content.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='castStart(Content.special.snowball)', class='inventory_special_snowball') + button.customize-option(popover='{{Content.special.snowball.notes()}}', popover-title='{{Content.special.snowball.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='castStart(Content.special.snowball)', class='inventory_special_snowball') .badge.badge-info.stack-count {{user.items.special.snowball}} li.customize-menu(ng-if='user.items.special.valentineReceived[0]') @@ -91,14 +91,14 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') .popover-content p=env.t('welcomeMarket') p - button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedEgg.text}}", gold: "{{selectedEgg.value}}"}) - button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedPotion.text}}", gold: "{{selectedPotion.value}}"}) - button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedFood.text}}", gold: "{{selectedFood.value}}"}) + button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedEgg.text()}}", gold: "{{selectedEgg.value}}"}) + button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedPotion.text()}}", gold: "{{selectedPotion.value}}"}) + button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedFood.text()}}", gold: "{{selectedFood.value}}"}) menu.inventory-list(type='list') li.customize-menu menu.pets-menu(label=env.t('eggs')) div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy') - button.customize-option(popover='{{egg.notes}}', popover-title='{{egg.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') + button.customize-option(popover='{{egg.notes()}}', popover-title='{{egg.text()}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') p | {{egg.value}} span.Pet_Currency_Gem1x.inline-gems @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('hatchingPotions')) div(ng-repeat='pot in Content.hatchingPotions') - button.customize-option(popover='{{pot.notes}}', popover-title='{{pot.text}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') + button.customize-option(popover='{{pot.notes()}}', popover-title='{{pot.text()}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') p | {{pot.value}} span.Pet_Currency_Gem1x.inline-gems @@ -129,7 +129,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('food')) div(ng-repeat='food in Content.food', ng-if='food.canBuy') - button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.key}}') + button.customize-option(popover='{{food.notes()}}', popover-title='{{food.text()}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.key}}') p | {{food.value}} span.Pet_Currency_Gem1x.inline-gems @@ -138,7 +138,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') menu.pets-menu(label=env.t('quests')) p.muted!=env.t('scrollsText1') + ' ' + env.t('scrollsText2') + '' div(ng-repeat='quest in Content.quests', ng-if='quest.canBuy') - button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='buyQuest(quest.key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}') + button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes() | htmlDecode}}", popover-title='{{quest.text()}}', popover-trigger='mouseenter', popover-placement='left', ng-click='buyQuest(quest.key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}') p | {{quest.value}} span.Pet_Currency_Gem1x.inline-gems @@ -151,7 +151,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') | 4 span.Pet_Currency_Gem1x.inline-gems //-div - button.customize-option(popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("special", Content.spells.special.snowball)', class='inventory_special_snowball') + button.customize-option(popover='{{Content.spells.special.snowball.notes()}}', popover-title='{{Content.spells.special.snowball.text()}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("special", Content.spells.special.snowball)', class='inventory_special_snowball') p | {{Content.spells.special.snowball.value}} span.Pet_Currency_Gem1x.inline-gems diff --git a/views/options/inventory/stable.jade b/views/options/inventory/stable.jade index 32247a0b1b..d3583012ea 100644 --- a/views/options/inventory/stable.jade +++ b/views/options/inventory/stable.jade @@ -15,7 +15,7 @@ script(type='text/ng-template', id='partials/options.inventory.mounts.html') menu.pets(type='list') li.customize-menu(ng-repeat='egg in Content.eggs') menu - div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key') + div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text()}} {{egg.mountText()}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key') button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.key, potion.key)') //div(class='Mount_Head_{{mount}}') button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]') @@ -33,7 +33,7 @@ mixin petList(source) menu.pets(type='list') li.customize-menu(ng-repeat='egg in #{source}') menu - div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key') + div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text()}} {{egg.text()}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key') button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.key, potion.key)') .progress(ng-show='!user.items.mounts[pet] && egg.key!="Egg"') .progress-bar.progress-bar-success(style="width:{{user.items.pets[pet]/.5}}%") @@ -85,7 +85,7 @@ script(type='text/ng-template', id='partials/options.inventory.pets.html') li.customize-menu menu.pets-menu(label=env.t('food')) div(ng-repeat='(food,points) in ownedItems(user.items.food)') - button.customize-option(popover-append-to-body='true', popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}') + button.customize-option(popover-append-to-body='true', popover='{{Content.food[food].notes()}}', popover-title='{{Content.food[food].text()}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}') .badge.badge-info.stack-count {{points}} // Remove this once we have images in - p {{Content.food[food].text}} + p {{Content.food[food].text()}} diff --git a/views/options/social/group.jade b/views/options/social/group.jade index 6bc92d1ac6..96ed43d961 100644 --- a/views/options/social/group.jade +++ b/views/options/social/group.jade @@ -12,8 +12,8 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title=env.t('guild // ------ Bosses ------- .panel.panel-default(bindonce='group', ng-if='group.type==="party" && group.quest.key') .panel-heading - h3.panel-title(ng-if='group.quest.active==false')=env.t('questInvitation') + ' {{Content.quests[group.quest.key].text}}' - h3.panel-title(ng-if='group.quest.active==true') {{Content.quests[group.quest.key].text}} + h3.panel-title(ng-if='group.quest.active==false')=env.t('questInvitation') + ' {{Content.quests[group.quest.key].text()}}' + h3.panel-title(ng-if='group.quest.active==true') {{Content.quests[group.quest.key].text()}} .panel-body.modal-fixed-height div(ng-if='group.quest.active==false') table.table.table-striped @@ -50,11 +50,11 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title=env.t('guild tr(ng-repeat='(k,v) in group.quest.progress.collect', class='quest_collected_{{v >= Content.quests[group.quest.key].collect[k].count}}') td div.pull-left(class='quest_{{group.quest.key}}_{{k}}') - | {{Content.quests[group.quest.key].collect[k].text}} + | {{Content.quests[group.quest.key].collect[k].text()}} td {{v}} / {{Content.quests[group.quest.key].collect[k].count}} - div(ng-bind-html='Content.quests[group.quest.key].notes') + div(ng-bind-html='Content.quests[group.quest.key].notes()') hr h5=env.t('participants') table.table.table-striped diff --git a/views/shared/modals/buy-gems.jade b/views/shared/modals/buy-gems.jade index 155a90d863..60f36bddf9 100644 --- a/views/shared/modals/buy-gems.jade +++ b/views/shared/modals/buy-gems.jade @@ -1,4 +1,3 @@ -//Why is shown? Because of script here at line 24!!!!!!!!! script(id='modals/buyGems.html', type='text/ng-template') .modal-body .buy-gems diff --git a/views/shared/modals/drops.jade b/views/shared/modals/drops.jade index fcb91e808a..7c12e4212b 100644 --- a/views/shared/modals/drops.jade +++ b/views/shared/modals/drops.jade @@ -5,7 +5,7 @@ script(type='text/ng-template', id='modals/dropsEnabled.html') p figure .item-drop-icon(class='Pet_Egg_Wolf') - span!=env.t('firstDrop', {eggText: "{{Content.eggs.Wolf.text}}", eggNotes: "{{Content.eggs.Wolf.notes}}"}) + span!=env.t('firstDrop', {eggText: "{{Content.eggs.Wolf.text()}}", eggNotes: "{{Content.eggs.Wolf.notes()}}"}) br p figure diff --git a/views/shared/modals/quests.jade b/views/shared/modals/quests.jade index 4d3a471efd..a34c96c5d7 100644 --- a/views/shared/modals/quests.jade +++ b/views/shared/modals/quests.jade @@ -3,7 +3,7 @@ script(id='partials/options.social.party.quest-rewards.html', type='text/ng-temp h5 {{header}} table.table.table-striped tr(ng-repeat='drop in quest.drop.items') - td {{drop.text}} + td {{drop.text()}} tr td {{quest.drop.exp}} =env.t('experience') @@ -13,20 +13,20 @@ script(id='partials/options.social.party.quest-rewards.html', type='text/ng-temp script(type='text/ng-template', id='modals/questCompleted.html') .modal-header - h4 "{{Content.quests[user.party.quest.completed].text}}" + h4 "{{Content.quests[user.party.quest.completed].text()}}" =env.t('completed') .modal-body - p {{Content.quests[user.party.quest.completed].completion}} + p {{Content.quests[user.party.quest.completed].completion()}} quest-rewards(key='{{user.party.quest.completed}}', header=env.t('youReceived')) .modal-footer button.btn.btn-primary(ng-click='set({"party.quest.completed":""}); $close()')=env.t('accept') script(type='text/ng-template', id='modals/showQuest.html') .modal-header - h4 {{selectedQuest.text}} + h4 {{selectedQuest.text()}} .modal-body .pull-right(class='quest_{{selectedQuest.key}}') - div(ng-bind-html='selectedQuest.notes') + div(ng-bind-html='selectedQuest.notes()') quest-rewards(key='{{selectedQuest.key}}') hr .npc_ian.pull-left @@ -38,10 +38,10 @@ script(type='text/ng-template', id='modals/showQuest.html') script(type='text/ng-template', id='modals/buyQuest.html') .modal-header - h4 {{selectedQuest.text}} + h4 {{selectedQuest.text()}} .modal-body .pull-right(class='quest_{{selectedQuest.key}}') - div(ng-bind-html='selectedQuest.notes') + div(ng-bind-html='selectedQuest.notes()') quest-rewards(key='{{selectedQuest.key}}') .modal-footer button.btn.btn-default(ng-click='closeQuest(); $close()')=env.t('neverMind') @@ -50,9 +50,9 @@ script(type='text/ng-template', id='modals/buyQuest.html') script(type='text/ng-template', id='modals/questInvitation.html') .modal-header h4=env.t('questInvitation') - | {{Content.quests[party.quest.key].text}} + | {{Content.quests[party.quest.key].text()}} .modal-body - div(ng-bind-html='Content.quests[party.quest.key].notes') + div(ng-bind-html='Content.quests[party.quest.key].notes()') quest-rewards(key='{{party.quest.key}}') .modal-footer button.btn.btn-default(ng-click='questHold = true; $close()')=env.t('askLater') diff --git a/views/shared/profiles/stats.jade b/views/shared/profiles/stats.jade index b833f27368..5b568e8002 100644 --- a/views/shared/profiles/stats.jade +++ b/views/shared/profiles/stats.jade @@ -22,7 +22,7 @@ table.table.table-striped(ng-show='user.flags.itemsEnabled') // FIXME this isn't refreshing properly. On first party modal, correct. Second party modal click gives the previous gear. It's always one behind. tr(ng-repeat='(k,v) in profile.items.gear.equipped', ng-init='piece=Content.gear.flat[v]', ng-show='piece') td - strong {{piece.text}}:  + strong {{piece.text()}}:  span(ng-repeat='stat in ["str","con","per","int"]', ng-show='piece[stat]') {{piece[stat]}} {{stat.toUpperCase()}}  h4=env.t('attributes') diff --git a/views/shared/tasks/lists.jade b/views/shared/tasks/lists.jade index d980f73a51..9eb9f01b75 100644 --- a/views/shared/tasks/lists.jade +++ b/views/shared/tasks/lists.jade @@ -52,7 +52,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") // Events ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball)') - li.task.reward-item(ng-if='user.items.special.snowball>0',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.snowball.notes}}') + li.task.reward-item(ng-if='user.items.special.snowball>0',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.snowball.notes()}}') .task-meta-controls span.task-notes span.glyphicon.glyphicon-comment @@ -62,9 +62,9 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span.reward-cost {{user.items.special.snowball}} span.shop_snowball(style='display:inline-block;vertical-align:top;') // main content - p.task-text {{Content.spells.special.snowball.text}} + p.task-text {{Content.spells.special.snowball.text()}} - li.task.reward-item(ng-if='user.stats.buffs.snowball',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.salt.notes}}') + li.task.reward-item(ng-if='user.stats.buffs.snowball',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.salt.notes()}}') .task-meta-controls span.task-notes span.glyphicon.glyphicon-comment @@ -75,11 +75,11 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span.shop_gold // main content span.shop_salt.shop-sprite.item-img - p.task-text {{Content.spells.special.salt.text}} + p.task-text {{Content.spells.special.salt.text()}} // Spells ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses') - li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= spell.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{spell.notes}}') + li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= spell.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{spell.notes()}}') .task-meta-controls span.task-notes span.glyphicon.glyphicon-comment @@ -91,7 +91,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") =env.t('mp') // main content span(ng-class='{"shop_{{spell.key}} shop-sprite item-img": true}') - p.task-text {{spell.text}} + p.task-text {{spell.text()}} br From 1927ce1de1f868b84f901e56e55721f50133c819 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 10 Mar 2014 17:28:49 +0100 Subject: [PATCH 04/29] refactor(i18n): refactor user language detection, add to api methods --- src/i18n.js | 33 +++++++-------- src/middleware.js | 51 +++++++++++------------ src/routes/apiv2.coffee | 89 +++++++++++++++++++++++++--------------- src/routes/dataexport.js | 7 ++-- src/routes/pages.js | 22 ++++++---- 5 files changed, 115 insertions(+), 87 deletions(-) diff --git a/src/i18n.js b/src/i18n.js index 9b1cf27998..b09e84f1c7 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -53,7 +53,7 @@ _.each(langCodes, function(code){ }catch (e){} }); -var getUserLanguage = function(req, callback){ +var getUserLanguage = function(req, res, next){ var getFromBrowser = function(){ var acceptable = _(req.acceptedLanguages).map(function(lang){ return lang.slice(0, 2); @@ -62,25 +62,26 @@ var getUserLanguage = function(req, callback){ return matches.length > 0 ? matches[0] : 'en'; }; - if(req.session && req.session.userId){ + var getFromUser = function(user){ + var lang; + if(user && user.preferences.language && translations[user.preferences.language]){ + lang = _.find(avalaibleLanguages, {code: user.preferences.language}) || 'en'; + }else{ + lang = _.find(avalaibleLanguages, {code: getFromBrowser()}) || 'en'; + } + req.language = lang; + next(); + }; + + if(req.locals && req.locals.user){ + getFromUser(req.locals.user); + }else if(req.session && req.session.userId){ User.findOne({_id: req.session.userId}, function(err, user){ if(err) return callback(err); - if(user && user.preferences.language && translations[user.preferences.language]){ - return callback(null, _.find(avalaibleLanguages, {code: user.preferences.language})); - }else{ - var langCode = getFromBrowser(); - // Because english is usually always avalaible as an acceptable language for the browser, - // if the user visit the page when his own language is not avalaible yet - // he'll have english set in his preferences, which is not good. - //if(user && translations[langCode]){ - //user.preferences.language = langCode; - //user.save(); //callback? - //} - return callback(null, _.find(avalaibleLanguages, {code: langCode})) - } + getFromUser(user); }); }else{ - return callback(null, _.find(avalaibleLanguages, {code: getFromBrowser()})); + getFromUser(null); } }; diff --git a/src/middleware.js b/src/middleware.js index 232c0ab355..60e4e3f0ae 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -142,36 +142,33 @@ var getManifestFiles = function(page){ } module.exports.locals = function(req, res, next) { - i18n.getUserLanguage(req, function(err, language){ - if(err) return res.json(500, {err: err}); + var language = req.language; + var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' - var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' + // Load moment.js language file only when not on static pages + language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined); - // Load moment.js language file only when not on static pages - language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code])|| undefined); + res.locals.habitrpg = { + NODE_ENV: nconf.get('NODE_ENV'), + BASE_URL: nconf.get('BASE_URL'), + GA_ID: nconf.get("GA_ID"), + IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), + STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY'), + getManifestFiles: getManifestFiles, + getBuildUrl: getBuildUrl, + avalaibleLanguages: i18n.avalaibleLanguages, + language: language, + isStaticPage: isStaticPage, + translations: i18n.translations[language.code], + t: function(){ // stringName and vars are the allowed parameters + var args = Array.prototype.slice.call(arguments, 0); + args.push(language.code); + return shared.i18n.t.apply(null, args); + }, + siteVersion: siteVersion + } - res.locals.habitrpg = { - NODE_ENV: nconf.get('NODE_ENV'), - BASE_URL: nconf.get('BASE_URL'), - GA_ID: nconf.get("GA_ID"), - IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), - STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY'), - getManifestFiles: getManifestFiles, - getBuildUrl: getBuildUrl, - avalaibleLanguages: i18n.avalaibleLanguages, - language: language, - isStaticPage: isStaticPage, - translations: i18n.translations[language.code], - t: function(){ // stringName and vars are the allowed parameters - var args = Array.prototype.slice.call(arguments, 0); - args.push(language.code); - return shared.i18n.t.apply(null, args); - }, - siteVersion: siteVersion - } - - next(); - }); + next(); } module.exports.enTranslations = function(stringName, vars){ diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index f78d8c5707..9fbc5c4b6a 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -19,6 +19,7 @@ middleware = require("../middleware") cron = user.cron _ = require('lodash') content = require('habitrpg-shared').content +i18n = require('../i18n') module.exports = (swagger, v2) -> @@ -47,7 +48,7 @@ module.exports = (swagger, v2) -> spec: description: "Export user history" method: 'GET' - middleware: auth.auth + middleware: [auth.auth, i18n.getUserLanguage] action: dataexport.history #[todo] encode data output options in the data controller and use these to build routes # --------------------------------- @@ -138,7 +139,7 @@ module.exports = (swagger, v2) -> path("id", "Task ID", "string") query 'keep',"When unlinking a challenge task, how to handle the orphans?",'string',['keep','keep-all','remove','remove-all'] ] - middleware: auth.auth ## removing cron since they may want to remove task first + middleware: [auth.auth, i18n.getUserLanguage] ## removing cron since they may want to remove task first action: challenges.unlink @@ -227,7 +228,7 @@ module.exports = (swagger, v2) -> path: '/user' method: 'DELETE' description: "Delete a user object entirely, USE WITH CAUTION!" - middleware: auth.auth + middleware: [auth.auth, i18n.getUserLanguage] action: user["delete"] "/user/revive": @@ -299,6 +300,26 @@ module.exports = (swagger, v2) -> ] action: user.unlock +<<<<<<< HEAD +======= + "/user/buy-gems": + spec: method: 'POST', description: "Do not use this route" + middleware: [auth.auth, i18n.getUserLanguage] + action:user.buyGems + + "/user/cancel-subscription": + spec: method: 'POST', description: "Do not use this route" + middleware: [auth.auth, i18n.getUserLanguage] + action:user.cancelSubscription + + "/user/buy-gems/paypal-ipn": + spec: + method: 'POST' + description: "Don't use this route" + middleware: [] + action: user.buyGemsPaypalIPN + +>>>>>>> refactor(i18n): refactor user language detection, add to api methods "/user/batch-update": spec: method: 'POST' @@ -306,7 +327,7 @@ module.exports = (swagger, v2) -> parameters:[ body '','The array of batch-operations to perform','object' ] - middleware: [middleware.forceRefresh, auth.auth, cron] + middleware: [middleware.forceRefresh, auth.auth, i18n.getUserLanguage, cron] action: user.batchUpdate # Tags @@ -350,7 +371,7 @@ module.exports = (swagger, v2) -> parameters: [ query 'type',"Comma-separated types of groups to return, eg 'party,guilds,public,tavern'",'string' ] - middleware: auth.auth + middleware: [auth.auth, i18n.getUserLanguage] action: groups.list @@ -362,7 +383,7 @@ module.exports = (swagger, v2) -> parameters: [ body '','Group object (see GroupSchema)','object' ] - middleware: auth.auth + middleware: [auth.auth, i18n.getUserLanguage] action: groups.create "/groups/{gid}:GET": @@ -370,7 +391,7 @@ module.exports = (swagger, v2) -> path: '/groups/{gid}' description: "Get a group" parameters: [path('gid','Group ID','string')] - middleware: auth.auth + middleware: [auth.auth, i18n.getUserLanguage] action: groups.get "/groups/{gid}:POST": @@ -379,7 +400,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: "Edit a group" parameters: [body('','Group object (see GroupSchema)','object')] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.update "/groups/{gid}/join": @@ -387,7 +408,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: 'Join a group' parameters: [path('gid','Id of the group to join','string')] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.join "/groups/{gid}/leave": @@ -395,7 +416,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: 'Leave a group' parameters: [path('gid','ID of the group to leave','string')] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.leave "/groups/{gid}/invite": @@ -406,7 +427,7 @@ module.exports = (swagger, v2) -> path 'gid','Group id','string' query 'uuid','User id to invite','string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.invite "/groups/{gid}/removeMember": @@ -417,7 +438,7 @@ module.exports = (swagger, v2) -> path 'gid','Group id','string' query 'uuid','User id to boot','string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.removeMember "/groups/{gid}/questAccept": @@ -428,7 +449,7 @@ module.exports = (swagger, v2) -> path 'gid',"Group id",'string' query 'key',"optional. if provided, trigger new invite, if not, accept existing invite",'string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.questAccept "/groups/{gid}/questReject": @@ -438,7 +459,7 @@ module.exports = (swagger, v2) -> parameters: [ path 'gid','Group id','string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.questReject "/groups/{gid}/questAbort": @@ -446,7 +467,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: 'Abort quest' parameters: [path('gid','Group to abort quest in','string')] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.questAbort #TODO PUT /groups/:gid/chat/:messageId @@ -455,8 +476,12 @@ module.exports = (swagger, v2) -> spec: path: "/groups/{gid}/chat" description: "Get all chat messages" +<<<<<<< HEAD parameters: [path('gid','Group to return the chat from ','string')] middleware: [auth.auth, groups.attachGroup] +======= + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] +>>>>>>> refactor(i18n): refactor user language detection, add to api methods action: groups.getChat @@ -469,7 +494,7 @@ module.exports = (swagger, v2) -> query 'message', 'Chat message','string' path 'gid','Group id','string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.postChat # placing before route below, so that if !=='seen' it goes to next() @@ -480,7 +505,7 @@ module.exports = (swagger, v2) -> parameters: [ path 'gid','Group id','string' ] - middleware: [] + middleware: [i18n.getUserLanguage] action: groups.seenMessage "/groups/{gid}/chat/{messageId}": @@ -488,7 +513,7 @@ module.exports = (swagger, v2) -> method: 'DELETE' description: 'Delete a group' parameters: [path('gid','ID of group to delete','string')] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.deleteChatMessage "/groups/{gid}/chat/{mid}/like": @@ -499,7 +524,7 @@ module.exports = (swagger, v2) -> path 'gid','Group id','string' path 'mid','Message id','string' ] - middleware: [auth.auth, groups.attachGroup] + middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action: groups.likeChatMessage # --------------------------------- @@ -514,19 +539,19 @@ module.exports = (swagger, v2) -> # --------------------------------- "/hall/heroes": spec: {} - middleware:[auth.auth] + middleware:[auth.auth, i18n.getUserLanguage] action: hall.getHeroes "/hall/heroes/{uid}:GET": spec: path: "/hall/heroes/{uid}" - middleware:[auth.auth, hall.ensureAdmin] + middleware:[auth.auth, i18n.getUserLanguage, hall.ensureAdmin] action: hall.getHero "/hall/heroes/{uid}:POST": spec: method: 'POST' path: "/hall/heroes/{uid}" - middleware: [auth.auth, hall.ensureAdmin] + middleware: [auth.auth, i18n.getUserLanguage, hall.ensureAdmin] action: hall.updateHero "/hall/patrons": @@ -534,7 +559,7 @@ module.exports = (swagger, v2) -> parameters: [ query 'page','Page number to fetch (this list is long)','string' ] - middleware:[auth.auth] + middleware:[auth.auth, i18n.getUserLanguage] action: hall.getPatrons @@ -549,7 +574,7 @@ module.exports = (swagger, v2) -> spec: path: '/challenges' description: "Get a list of challenges" - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.list @@ -559,7 +584,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: "Create a challenge" parameters: [body('','Challenge object (see ChallengeSchema)','object')] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.create "/challenges/{cid}:GET": @@ -584,7 +609,7 @@ module.exports = (swagger, v2) -> path 'cid','Challenge id','string' body('','Challenge object (see ChallengeSchema)','object') ] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.update "/challenges/{cid}:DELETE": @@ -593,7 +618,7 @@ module.exports = (swagger, v2) -> method: 'DELETE' description: "Delete a challenge" parameters: [path('cid','Challenge id','string')] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges["delete"] "/challenges/{cid}/close": @@ -604,7 +629,7 @@ module.exports = (swagger, v2) -> path 'cid','Challenge id','string' query 'uid','User ID of the winner','string',true ] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.selectWinner "/challenges/{cid}/join": @@ -612,7 +637,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: "Join a challenge" parameters: [path('cid','Challenge id','string')] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.join "/challenges/{cid}/leave": @@ -620,7 +645,7 @@ module.exports = (swagger, v2) -> method: 'POST' description: 'Leave a challenge' parameters: [path('cid','Challenge id','string')] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.leave "/challenges/{cid}/member/{uid}": @@ -630,7 +655,7 @@ module.exports = (swagger, v2) -> path 'cid','Challenge id','string' path 'uid','User id','string' ] - middleware: [auth.auth] + middleware: [auth.auth, i18n.getUserLanguage] action: challenges.getMember @@ -662,7 +687,7 @@ module.exports = (swagger, v2) -> #type: 'Pet' errorResponses: [] method: 'GET' - route.middleware ?= if path.indexOf('/user') is 0 then [auth.auth, cron] else [] + route.middleware ?= if path.indexOf('/user') is 0 then [auth.auth, i18n.getUserLanguage, cron] else [] swagger["add#{route.spec.method}"](route);true diff --git a/src/routes/dataexport.js b/src/routes/dataexport.js index b84fe09bd3..ad2e2797d0 100644 --- a/src/routes/dataexport.js +++ b/src/routes/dataexport.js @@ -3,10 +3,11 @@ var router = new express.Router(); var dataexport = require('../controllers/dataexport'); var auth = require('../controllers/auth'); var nconf = require('nconf'); +var i18n = require('../i18n') /* Data export */ -router.get('/history.csv',auth.authWithSession,dataexport.history); //[todo] encode data output options in the data controller and use these to build routes -router.get('/userdata.xml',auth.authWithSession,dataexport.leanuser,dataexport.userdata.xml); -router.get('/userdata.json',auth.authWithSession,dataexport.leanuser,dataexport.userdata.json); +router.get('/history.csv',auth.authWithSession,i18n.getUserLanguage,dataexport.history); //[todo] encode data output options in the data controller and use these to build routes +router.get('/userdata.xml',auth.authWithSession,i18n.getUserLanguage,dataexport.leanuser,dataexport.userdata.xml); +router.get('/userdata.json',auth.authWithSession,i18n.getUserLanguage,dataexport.leanuser,dataexport.userdata.json); module.exports = router; diff --git a/src/routes/pages.js b/src/routes/pages.js index 80e7be54e1..d18a50cfaa 100644 --- a/src/routes/pages.js +++ b/src/routes/pages.js @@ -3,11 +3,15 @@ var express = require('express'); var router = new express.Router(); var _ = require('lodash'); var middleware = require('../middleware'); +<<<<<<< HEAD var user = require('../controllers/user'); var auth = require('../controllers/auth'); +======= +var i18n = require('../i18n'); +>>>>>>> refactor(i18n): refactor user language detection, add to api methods // -------- App -------- -router.get('/', middleware.locals, function(req, res) { +router.get('/', i18n.getUserLanguage, middleware.locals, function(req, res) { if (!req.headers['x-api-user'] && !req.headers['x-api-key'] && !(req.session && req.session.userId)) return res.redirect('/static/front') @@ -19,35 +23,35 @@ router.get('/', middleware.locals, function(req, res) { // -------- Marketing -------- -router.get('/static/front', middleware.locals, function(req, res) { +router.get('/static/front', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/front', {env: res.locals.habitrpg}); }); -router.get('/static/privacy', middleware.locals, function(req, res) { +router.get('/static/privacy', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/privacy', {env: res.locals.habitrpg}); }); -router.get('/static/terms', middleware.locals, function(req, res) { +router.get('/static/terms', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/terms', {env: res.locals.habitrpg}); }); -router.get('/static/api', middleware.locals, function(req, res) { +router.get('/static/api', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/api', {env: res.locals.habitrpg}); }); -router.get('/static/features', middleware.locals, function(req, res) { +router.get('/static/features', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/features', {env: res.locals.habitrpg}); }); -router.get('/static/videos', middleware.locals, function(req, res) { +router.get('/static/videos', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/videos', {env: res.locals.habitrpg}); }); -router.get('/static/contact', middleware.locals, function(req, res) { +router.get('/static/contact', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/contact', {env: res.locals.habitrpg}); }); -router.get('/static/plans', middleware.locals, function(req, res) { +router.get('/static/plans', i18n.getUserLanguage, middleware.locals, function(req, res) { res.render('static/plans', {env: res.locals.habitrpg}); }); From 12fa87ef31f44d8eb27e920cc96e4925ea78b3f1 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 10 Mar 2014 17:38:17 +0100 Subject: [PATCH 05/29] refactor(i18n): add language detection to new user --- src/controllers/auth.js | 3 +++ src/models/user.js | 6 +++--- src/routes/auth.js | 17 +++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/controllers/auth.js b/src/controllers/auth.js index 1cde8de72d..ae2e29593e 100644 --- a/src/controllers/auth.js +++ b/src/controllers/auth.js @@ -88,6 +88,7 @@ api.registerUser = function(req, res, next) { timestamps: {created: +new Date(), loggedIn: +new Date()} } }; + user.language = req.language; user = new User(newUser); // temporary for conventions @@ -255,7 +256,9 @@ api.setupPassport = function(router) { }, function(user, cb){ if (user) return cb(null, user); + user = new User({ + language: req.language, auth: { facebook: req.user, timestamps: {created: +new Date(), loggedIn: +new Date()} diff --git a/src/models/user.js b/src/models/user.js index c72989b21b..6a7d468da4 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -358,13 +358,13 @@ UserSchema.pre('save', function(next) { var newTask = task; // Render task's text and notes in user's language - newTask.text = task.text(); - newTask.notes = task.notes(); + newTask.text = task.text(this.language); + newTask.notes = task.notes(this.language); return newTask; }); }); - + // tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here _.each(this.tags, function(tag){tag.id = shared.uuid();}) } diff --git a/src/routes/auth.js b/src/routes/auth.js index 12b7769a41..edc54bc81d 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.js @@ -1,17 +1,18 @@ var auth = require('../controllers/auth'); var express = require('express'); +var i18n = require('../i18n'); var router = new express.Router(); /* auth.auth*/ auth.setupPassport(router); //FIXME make this consistent with the others -router.post('/api/v2/register', auth.registerUser); -router.post('/api/v2/user/auth/local', auth.loginLocal); -router.post('/api/v2/user/auth/facebook', auth.loginFacebook); -router.post('/api/v2/user/reset-password', auth.resetPassword); -router.post('/api/v2/user/change-password', auth.auth, auth.changePassword); +router.post('/api/v2/register', i18n.getUserLanguage, auth.registerUser); +router.post('/api/v2/user/auth/local', i18n.getUserLanguage, auth.loginLocal); +router.post('/api/v2/user/auth/facebook', i18n.getUserLanguage, auth.loginFacebook); +router.post('/api/v2/user/reset-password', i18n.getUserLanguage, auth.resetPassword); +router.post('/api/v2/user/change-password', i18n.getUserLanguage, auth.auth, auth.changePassword); -router.post('/api/v1/register', auth.registerUser); -router.post('/api/v1/user/auth/local', auth.loginLocal); -router.post('/api/v1/user/auth/facebook', auth.loginFacebook); +router.post('/api/v1/register', i18n.getUserLanguage, auth.registerUser); +router.post('/api/v1/user/auth/local', i18n.getUserLanguage, auth.loginLocal); +router.post('/api/v1/user/auth/facebook', i18n.getUserLanguage, auth.loginFacebook); module.exports = router; \ No newline at end of file From 62637cf676d41661c119510bf977d7d05b88020e Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 10 Mar 2014 17:50:46 +0100 Subject: [PATCH 06/29] refactor(i18n): add comments --- src/controllers/auth.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/auth.js b/src/controllers/auth.js index ae2e29593e..861a813e6a 100644 --- a/src/controllers/auth.js +++ b/src/controllers/auth.js @@ -88,7 +88,7 @@ api.registerUser = function(req, res, next) { timestamps: {created: +new Date(), loggedIn: +new Date()} } }; - user.language = req.language; + user.language = req.language; // User language detected from browser, not saved user = new User(newUser); // temporary for conventions @@ -258,7 +258,7 @@ api.setupPassport = function(router) { if (user) return cb(null, user); user = new User({ - language: req.language, + language: req.language, // User language detected from browser, not saved auth: { facebook: req.user, timestamps: {created: +new Date(), loggedIn: +new Date()} From b887127fb0a48899d6825e1afee63a31e1cee0b4 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 10 Mar 2014 19:36:07 +0100 Subject: [PATCH 07/29] refactor(i18n): refactor & fix --- src/controllers/auth.js | 7 +++++-- src/i18n.js | 5 +++-- src/middleware.js | 2 +- src/models/user.js | 18 +++++++++++------- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/controllers/auth.js b/src/controllers/auth.js index 861a813e6a..71b40bbc17 100644 --- a/src/controllers/auth.js +++ b/src/controllers/auth.js @@ -88,7 +88,8 @@ api.registerUser = function(req, res, next) { timestamps: {created: +new Date(), loggedIn: +new Date()} } }; - user.language = req.language; // User language detected from browser, not saved + newUser.preferences = {}; + newUser.preferences.language = req.language; // User language detected from browser, not saved user = new User(newUser); // temporary for conventions @@ -258,7 +259,9 @@ api.setupPassport = function(router) { if (user) return cb(null, user); user = new User({ - language: req.language, // User language detected from browser, not saved + preferences: { + language: req.language // User language detected from browser, not saved + }, auth: { facebook: req.user, timestamps: {created: +new Date(), loggedIn: +new Date()} diff --git a/src/i18n.js b/src/i18n.js index b09e84f1c7..5ea96380af 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -65,9 +65,10 @@ var getUserLanguage = function(req, res, next){ var getFromUser = function(user){ var lang; if(user && user.preferences.language && translations[user.preferences.language]){ - lang = _.find(avalaibleLanguages, {code: user.preferences.language}) || 'en'; + lang = user.preferences.language; }else{ - lang = _.find(avalaibleLanguages, {code: getFromBrowser()}) || 'en'; + var preferred = getFromBrowser(); + lang = translations[preferred] ? preferred : 'en'; } req.language = lang; next(); diff --git a/src/middleware.js b/src/middleware.js index 60e4e3f0ae..79df5f8608 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -142,7 +142,7 @@ var getManifestFiles = function(page){ } module.exports.locals = function(req, res, next) { - var language = req.language; + var language = _.find(i18n.avalaibleLanguages, {code: req.language}); var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' // Load moment.js language file only when not on static pages diff --git a/src/models/user.js b/src/models/user.js index 6a7d468da4..f261d72498 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -352,21 +352,25 @@ UserSchema.pre('save', function(next) { if (this.isNew){ //TODO for some reason this doesn't work here: `_.merge(this, shared.content.userDefaults);` var self = this; - - _.each('habits', 'dailys', 'todos', 'rewards', 'tags', function(taskType){ - self.taskType = _.map(shared.content.userDefaults[taskType], function(task){ + _.each(['habits', 'dailys', 'todos', 'rewards', 'tags'], function(taskType){ + self[taskType] = _.map(shared.content.userDefaults[taskType], function(task){ var newTask = task; // Render task's text and notes in user's language - newTask.text = task.text(this.language); - newTask.notes = task.notes(this.language); + if(taskType === 'tags'){ + // tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here + newTask.id = shared.uuid(); + newTask.name = task.name(self.preferences.language); + }else{ + newTask.text = task.text(self.preferences.language); + newTask.notes = task.notes(self.preferences.language); + } return newTask; }); }); - // tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here - _.each(this.tags, function(tag){tag.id = shared.uuid();}) + this.preferences.language = undefined; } //this.markModified('tasks'); From 11eca7e947b0966ded799a95850db5abc4b5212d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 27 Mar 2014 22:02:55 +0100 Subject: [PATCH 08/29] fix(i18n) --- package.json | 2 +- src/routes/apiv2.coffee | 20 -------------------- src/routes/pages.js | 3 --- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/package.json b/package.json index d020f7bedd..3e6a2425ad 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0-152", "main": "./src/server.js", "dependencies": { - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#develop", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#paglias/translate", "connect-mongo": "*", "express": "3.5.x", "gzippo": "*", diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 9fbc5c4b6a..6411815e4f 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -300,26 +300,6 @@ module.exports = (swagger, v2) -> ] action: user.unlock -<<<<<<< HEAD -======= - "/user/buy-gems": - spec: method: 'POST', description: "Do not use this route" - middleware: [auth.auth, i18n.getUserLanguage] - action:user.buyGems - - "/user/cancel-subscription": - spec: method: 'POST', description: "Do not use this route" - middleware: [auth.auth, i18n.getUserLanguage] - action:user.cancelSubscription - - "/user/buy-gems/paypal-ipn": - spec: - method: 'POST' - description: "Don't use this route" - middleware: [] - action: user.buyGemsPaypalIPN - ->>>>>>> refactor(i18n): refactor user language detection, add to api methods "/user/batch-update": spec: method: 'POST' diff --git a/src/routes/pages.js b/src/routes/pages.js index d18a50cfaa..863139a60e 100644 --- a/src/routes/pages.js +++ b/src/routes/pages.js @@ -3,12 +3,9 @@ var express = require('express'); var router = new express.Router(); var _ = require('lodash'); var middleware = require('../middleware'); -<<<<<<< HEAD var user = require('../controllers/user'); var auth = require('../controllers/auth'); -======= var i18n = require('../i18n'); ->>>>>>> refactor(i18n): refactor user language detection, add to api methods // -------- App -------- router.get('/', i18n.getUserLanguage, middleware.locals, function(req, res) { From d485ea71432705b4def7bda105fe88e0f2b78bae Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 28 Mar 2014 19:48:20 +0100 Subject: [PATCH 09/29] fix(i18n): use habitrpg-shared branch for bower --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index d60f85d489..a6e41d859d 100644 --- a/bower.json +++ b/bower.json @@ -30,7 +30,7 @@ "bootstrap": "~3.1.0", "bootstrap-growl": "git://github.com/ifightcrime/bootstrap-growl.git#master", "bootstrap-tour": "~0.8.1", - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#develop", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#paglias/translate", "BrowserQuest": "git://github.com/mozilla/BrowserQuest.git", "github-buttons": "git://github.com/mdo/github-buttons.git", "marked": "~0.2.9", From 21efe44d4d42d9fbad85bd1fe1f9927d88f9c502 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sat, 29 Mar 2014 20:42:07 +0100 Subject: [PATCH 10/29] fix(i18n): use strings --- views/options/inventory/inventory.jade | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index b44f3a4a39..a2bb7f4726 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -98,22 +98,22 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('eggs')) div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy') - button.customize-option(popover='{{egg.notes()}}', popover-title='{{egg.text()}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') + button.customize-option(popover='{{egg.notes()}}', popover-title='{{egg.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') p | {{egg.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.gryphon > 1') - button.customize-option(popover='{{Content.eggs.Gryphon.notes}}', popover-title='{{Content.eggs.Gryphon.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') + button.customize-option(popover='{{Content.eggs.Gryphon.notes}}', popover-title='{{Content.eggs.Gryphon.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') p | {{Content.eggs.Gryphon.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.hedgehog > 1') - button.customize-option(popover='{{Content.eggs.Hedgehog.notes}}', popover-title='{{Content.eggs.Hedgehog.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') + button.customize-option(popover='{{Content.eggs.Hedgehog.notes}}', popover-title='{{Content.eggs.Hedgehog.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') p | {{Content.eggs.Hedgehog.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.ghost_stag > 1') - button.customize-option(popover='{{Content.eggs.Deer.notes}}', popover-title='{{Content.eggs.Deer.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') + button.customize-option(popover='{{Content.eggs.Deer.notes}}', popover-title='{{Content.eggs.Deer.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') p | {{Content.eggs.Deer.value}} span.Pet_Currency_Gem1x.inline-gems @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('hatchingPotions')) div(ng-repeat='pot in Content.hatchingPotions') - button.customize-option(popover='{{pot.notes()}}', popover-title='{{pot.text()}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') + button.customize-option(popover='{{pot.notes()}}', popover-title='{{pot.text() + env.t("potion")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') p | {{pot.value}} span.Pet_Currency_Gem1x.inline-gems From 6930b693e0ebe05321ececd612fffedf67ea2c56 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sat, 29 Mar 2014 21:00:53 +0100 Subject: [PATCH 11/29] fix(i18n): better strings for items --- views/options/inventory/inventory.jade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index a2bb7f4726..6bb744c65c 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -32,7 +32,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') p.muted(ng-show='eggCount < 1')=env.t('noEggs') div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)') //TODO move positioning this styling to css - button.customize-option(popover='{{Content.eggs[egg].notes()}}', popover-title='{{Content.eggs[egg].text()}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') + button.customize-option(popover='{{Content.eggs[egg].notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs[egg].text()}}"})', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') .badge.badge-info.stack-count {{points}} //-p {{Content.eggs[egg].text()}} @@ -40,7 +40,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})')) p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions') div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)') - button.customize-option(popover='{{Content.hatchingPotions[pot].notes()}}', popover-title='{{Content.hatchingPotions[pot].text()}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') + button.customize-option(popover='{{Content.hatchingPotions[pot].notes()}}', popover-title='env.t("potion", {potionType: "{{Content.hatchingPotions[pot].text()}}"})', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') .badge.badge-info.stack-count {{points}} li.customize-menu @@ -98,22 +98,22 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('eggs')) div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy') - button.customize-option(popover='{{egg.notes()}}', popover-title='{{egg.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') + button.customize-option(popover='{{egg.notes()}}', popover-title='env.t("egg", {eggType: "{{egg.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') p | {{egg.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.gryphon > 1') - button.customize-option(popover='{{Content.eggs.Gryphon.notes}}', popover-title='{{Content.eggs.Gryphon.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') + button.customize-option(popover='{{Content.eggs.Gryphon.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Gryphon.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') p | {{Content.eggs.Gryphon.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.hedgehog > 1') - button.customize-option(popover='{{Content.eggs.Hedgehog.notes}}', popover-title='{{Content.eggs.Hedgehog.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') + button.customize-option(popover='{{Content.eggs.Hedgehog.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Hedgehog.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') p | {{Content.eggs.Hedgehog.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.ghost_stag > 1') - button.customize-option(popover='{{Content.eggs.Deer.notes}}', popover-title='{{Content.eggs.Deer.text() + env.t("egg")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') + button.customize-option(popover='{{Content.eggs.Deer.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Deer.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') p | {{Content.eggs.Deer.value}} span.Pet_Currency_Gem1x.inline-gems @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('hatchingPotions')) div(ng-repeat='pot in Content.hatchingPotions') - button.customize-option(popover='{{pot.notes()}}', popover-title='{{pot.text() + env.t("potion")}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') + button.customize-option(popover='{{pot.notes()}}', popover-title='env.t("potion", {potionType: "{{pot.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') p | {{pot.value}} span.Pet_Currency_Gem1x.inline-gems From 1f8722cb5724404f535a104461e68e58285dde81 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sat, 29 Mar 2014 21:08:01 +0100 Subject: [PATCH 12/29] fix(i18n): use strings --- views/options/inventory/inventory.jade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index 6bb744c65c..86f93ecabb 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -32,7 +32,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') p.muted(ng-show='eggCount < 1')=env.t('noEggs') div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)') //TODO move positioning this styling to css - button.customize-option(popover='{{Content.eggs[egg].notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs[egg].text()}}"})', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') + button.customize-option(popover='{{Content.eggs[egg].notes()}}', popover-title!=env.t("egg", {eggType: "{{Content.eggs[egg].text()}}"}), popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}') .badge.badge-info.stack-count {{points}} //-p {{Content.eggs[egg].text()}} @@ -40,7 +40,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})')) p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions') div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)') - button.customize-option(popover='{{Content.hatchingPotions[pot].notes()}}', popover-title='env.t("potion", {potionType: "{{Content.hatchingPotions[pot].text()}}"})', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') + button.customize-option(popover='{{Content.hatchingPotions[pot].notes()}}', popover-title!=env.t("potion", {potionType: "{{Content.hatchingPotions[pot].text()}}"}), popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}') .badge.badge-info.stack-count {{points}} li.customize-menu @@ -98,22 +98,22 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('eggs')) div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy') - button.customize-option(popover='{{egg.notes()}}', popover-title='env.t("egg", {eggType: "{{egg.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') + button.customize-option(popover='{{egg.notes()}}', popover-title!=env.t("egg", {eggType: "{{egg.text()}}"}), popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') p | {{egg.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.gryphon > 1') - button.customize-option(popover='{{Content.eggs.Gryphon.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Gryphon.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') + button.customize-option(popover='{{Content.eggs.Gryphon.notes()}}', popover-title!=env.t("egg", {eggType: "{{Content.eggs.Gryphon.text()}}"}), popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Gryphon)', class='Pet_Egg_Gryphon') p | {{Content.eggs.Gryphon.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.hedgehog > 1') - button.customize-option(popover='{{Content.eggs.Hedgehog.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Hedgehog.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') + button.customize-option(popover='{{Content.eggs.Hedgehog.notes()}}', popover-title!=env.t("egg", {eggType: "{{Content.eggs.Hedgehog.text()}}"}), popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Hedgehog)', class='Pet_Egg_Hedgehog') p | {{Content.eggs.Hedgehog.value}} span.Pet_Currency_Gem1x.inline-gems div(ng-show='user.achievements.quests.ghost_stag > 1') - button.customize-option(popover='{{Content.eggs.Deer.notes()}}', popover-title='env.t("egg", {eggType: "{{Content.eggs.Deer.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') + button.customize-option(popover='{{Content.eggs.Deer.notes()}}', popover-title!=env.t("egg", {eggType: "{{Content.eggs.Deer.text()}}"}), popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", Content.eggs.Deer)', class='Pet_Egg_Deer') p | {{Content.eggs.Deer.value}} span.Pet_Currency_Gem1x.inline-gems @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label=env.t('hatchingPotions')) div(ng-repeat='pot in Content.hatchingPotions') - button.customize-option(popover='{{pot.notes()}}', popover-title='env.t("potion", {potionType: "{{pot.text()}}"})', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') + button.customize-option(popover='{{pot.notes()}}', popover-title!=env.t("potion", {potionType: "{{pot.text()}}"}), popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') p | {{pot.value}} span.Pet_Currency_Gem1x.inline-gems From 95d57590422f64986cb8550a3c48a4d72240a755 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sat, 29 Mar 2014 21:13:17 +0100 Subject: [PATCH 13/29] fix(i18n): use right strings --- views/options/inventory/inventory.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index 86f93ecabb..bd3fb54916 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -44,7 +44,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') .badge.badge-info.stack-count {{points}} li.customize-menu - menu.pets-menu(label=(env.t('scrolls') + ' ({{questCount}})')) + menu.pets-menu(label=(env.t('quests') + ' ({{questCount}})')) p.muted(ng-show='questCount < 1')=env.t('noScrolls') p.muted!=env.t('scrollsText1') + ' ' + env.t('scrollsText2') + '' div(ng-repeat='(quest_key,points) in ownedItems(user.items.quests)', ng-init='quest = Content.quests[quest_key]') From 314497271a74e98c323c73c75fdba8109f0bca5a Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 2 Apr 2014 15:32:26 +0200 Subject: [PATCH 14/29] fix(i18n): group name --- public/js/controllers/groupsCtrl.js | 4 ++-- views/options/social/create-group.jade | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index c0ba02c5a1..898f0a0d8f 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -213,7 +213,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' "public": Groups.publicGuilds() } $scope.type = 'guild'; - $scope.text = 'Guild'; + $scope.text = window.env.t('guild'); var newGroup = function(){ return new Groups.Group({type:'guild', privacy:'private'}); } @@ -316,7 +316,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' .controller("PartyCtrl", ['$rootScope','$scope', 'Groups', 'User', 'Challenges', '$state', '$compile', function($rootScope,$scope, Groups, User, Challenges, $state, $compile) { $scope.type = 'party'; - $scope.text = 'Party'; + $scope.text = window.env.t('party'); $scope.group = $rootScope.party = Groups.party(); $scope.newGroup = new Groups.Group({type:'party'}); diff --git a/views/options/social/create-group.jade b/views/options/social/create-group.jade index bd2563cd76..7fd8059596 100644 --- a/views/options/social/create-group.jade +++ b/views/options/social/create-group.jade @@ -3,9 +3,8 @@ form.col-md-12.form-horizontal(ng-submit='create(newGroup)') .form-group label.control-label(for='new-group-name') - | {{text}}  - =env.t('name') - input.form-control#new-group-name.input-medium.option-content(required, type='text', placeholder=('{{text}} ' + env.t('name')), ng-model='newGroup.name') + env.t('newGroupName', {groupType: "{{text}}"}) + input.form-control#new-group-name.input-medium.option-content(required, type='text', placeholder=env.t('newGroupName', {groupType: "{{text}}"}), ng-model='newGroup.name') .form-group label(for='new-group-description')=env.t('description') textarea.form-control#new-group-description.option-content(cols='3', placeholder=env.t('description'), ng-model='newGroup.description') From dd4accf56f0bb84edfc52ada475722490cb34392 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 2 Apr 2014 15:36:07 +0200 Subject: [PATCH 15/29] fix(i18n): group name --- views/options/social/create-group.jade | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/views/options/social/create-group.jade b/views/options/social/create-group.jade index 7fd8059596..6217bcb58c 100644 --- a/views/options/social/create-group.jade +++ b/views/options/social/create-group.jade @@ -2,8 +2,7 @@ .row form.col-md-12.form-horizontal(ng-submit='create(newGroup)') .form-group - label.control-label(for='new-group-name') - env.t('newGroupName', {groupType: "{{text}}"}) + label.control-label(for='new-group-name')=env.t('newGroupName', {groupType: "{{text}}"}) input.form-control#new-group-name.input-medium.option-content(required, type='text', placeholder=env.t('newGroupName', {groupType: "{{text}}"}), ng-model='newGroup.name') .form-group label(for='new-group-description')=env.t('description') From 70ecad3c65f90b967b2f1a211082092492fa3b82 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 3 Apr 2014 18:13:10 +0200 Subject: [PATCH 16/29] fix(i18n): user creation does not override preferences --- src/controllers/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/auth.js b/src/controllers/auth.js index 71b40bbc17..a00912c70b 100644 --- a/src/controllers/auth.js +++ b/src/controllers/auth.js @@ -88,7 +88,7 @@ api.registerUser = function(req, res, next) { timestamps: {created: +new Date(), loggedIn: +new Date()} } }; - newUser.preferences = {}; + newUser.preferences = newUser.preferences || {}; newUser.preferences.language = req.language; // User language detected from browser, not saved user = new User(newUser); From 8eb65126379416eb76b328cf2b5f75fac8450037 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 3 Apr 2014 18:17:07 +0200 Subject: [PATCH 17/29] fix(i18n): spaces around string --- views/options/social/index.jade | 2 ++ 1 file changed, 2 insertions(+) diff --git a/views/options/social/index.jade b/views/options/social/index.jade index 570fcce153..99b4dfe27d 100644 --- a/views/options/social/index.jade +++ b/views/options/social/index.jade @@ -23,7 +23,9 @@ script(type='text/ng-template', id='partials/options.social.party.html') {{user.id}} p =env.t('startLFG') + |  a(href="http://habitrpg.wikia.com/wiki/Board:The_Archery_-_LFG")=env.t('linkLFG') + |  =env.t('endLFG') include ./create-group From d94f874194651b92f42628a1375b0bc5c8196d19 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 3 Apr 2014 18:34:39 +0200 Subject: [PATCH 18/29] refactor(tour): start using custom template --- public/js/services/guideServices.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/public/js/services/guideServices.js b/public/js/services/guideServices.js index 98879e040b..68f7f7f22f 100644 --- a/public/js/services/guideServices.js +++ b/public/js/services/guideServices.js @@ -78,6 +78,13 @@ angular.module('guideServices', []). }); $('.main-herobox').popover('destroy'); var tour = new Tour({ + template: "
" + + "

" + + "
" + + "" + + "" + + "
" + + "
", onEnd: function(){ User.set({'flags.showTour': false}); } From e4f8ee1b93d6b8c5c919499b8056dbc6c1835320 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sun, 6 Apr 2014 20:07:26 +0200 Subject: [PATCH 19/29] fix(i18n): spacing --- views/shared/profiles/achievements.jade | 1 + 1 file changed, 1 insertion(+) diff --git a/views/shared/profiles/achievements.jade b/views/shared/profiles/achievements.jade index 85c5a41628..5b5243bdeb 100644 --- a/views/shared/profiles/achievements.jade +++ b/views/shared/profiles/achievements.jade @@ -28,6 +28,7 @@ div(ng-if='profile.contributor.level || user._id == profile._id') span.label.label-default(ng-if='!profile.contributor.level')=env.t('contribName') small =env.t('contribText') + |  a(href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG', target='_blank')=env.t('readMore') | . hr From 12c8e3314e60e10ae1c78968726f0670ce4f5294 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sun, 6 Apr 2014 20:32:10 +0200 Subject: [PATCH 20/29] refactor(i18n): add strings for features page --- views/static/features.jade | 67 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/views/static/features.jade b/views/static/features.jade index bb7ed4e76a..3a01e2ff24 100644 --- a/views/static/features.jade +++ b/views/static/features.jade @@ -11,76 +11,81 @@ block content .row#about-page(ng-controller='AboutCtrl') .col-md-12#aboutPage .marketing - h1 Improve Your Habits By Playing A Game + h1=env.t('marketing1Header') .row .col-md-6 - a.gallery(href='/marketing/screenshot.png', title='Improve Your Habits By Playing A Game') + a.gallery(href='/marketing/screenshot.png', title=env.t('marketing1Header')) img(src='/marketing/screenshot.png') - p.lead HabitRPG is a video game to help you improve real life habits. It "gamifies" your life by turning all your tasks (habits, dailies, and to-dos) into little monsters you have to conquor. The better you are at this, the more you progress in the game. If you slip up in life, your character starts backsliding in the game. + p.lead=env.t('marketing1Lead1') .col-md-6 - a.gallery(href='/marketing/gear.png', title='Get Sweet Gear') + a.gallery(href='/marketing/gear.png', title=env.t('marketing1Lead2Title')) img(src='/marketing/gear.png') - p.lead Get Sweet Gear. Improve your habits to build up your avatar. Show off the sweet gear you've earned + p.lead!=env.t('marketing1Lead2') - a.gallery(href='/marketing/drops.png', title='Find Random Prizes') + a.gallery(href='/marketing/drops.png', title=env.t('marketing1Lead3Title')) img(src='/marketing/drops.png',style='max-height:200px') - p.lead Find Random Prizes. For some, it's the gamble which motivates them, a system called "stochastic rewarding". HabitRPG accommodates all reinforcement styles: positive, negative, predictable, and random. + p.lead!=env.t('marketing1Lead3') // TODO achievements hr.clearfix - h1 Compete With Friends, Join Interest Groups + h1=env.t('marketing2Header') .row .col-md-6 - a.gallery(href='/marketing/guild.png', title='Compete With Friends, Join Interest Groups') + a.gallery(href='/marketing/guild.png', title=env.t('marketing2Header')) img(src='/marketing/guild.png') - p.lead While you can solo-play HabitRPG, the lights really turn on when you start collaborating, competing, and holding eachother accountable. The most effective part of any self-improvement program is social accountability, and what better an environment for accountability and competition than a video game? + p.lead=env.t('marketing2Lead1') - a.gallery(href='/bower_components/habitrpg-shared/img/sprites/spritesmith/quests/quest_vice3.png', title='Bosses') + a.gallery(href='/bower_components/habitrpg-shared/img/sprites/spritesmith/quests/quest_vice3.png', title=env.t('marketing2Lead2Title')) img(src='/bower_components/habitrpg-shared/img/sprites/spritesmith/quests/quest_vice3.png') - p.lead Fight Bosses. What's a Role Playing Game without battles? Fight bosses with your party. Bosses are "super accountability mode" - a day you miss the gym is a day the boss hurts everyone. + p.lead!=env.t('marketing2Lead2') .col-md-6 - a.gallery(href='/marketing/challenge.png', title='Challenges') + a.gallery(href='/marketing/challenge.png', title=env.t('challenges')) img(src='/marketing/challenge.png') - p.lead Challenges let you compete with friends and strangers. Whoever does the best at the end of a challenge wins special prizes. + p.lead!=env.t('marketing2Lead3') hr.clearfix - h1 Apps + h1=env.t('marketing3Header') .row .col-md-6 - a.gallery(href='/marketing/android_iphone.png', title='iPhone & Android') + a.gallery(href='/marketing/android_iphone.png', title=env.t('marketing3LeadTitle')) img(src='/marketing/android_iphone.png',style='box-shadow:none;') - p.lead The iPhone & Android apps let you take care of business on the go. We realize that logging into the website to click buttons can be a drag. + p.lead!=env.t('marketing3Lead1') .col-md-6 - a.gallery(href='/marketing/integration.png', title='iPhone & Android') + a.gallery(href='/marketing/integration.png', title=env.t('marketing3LeadTitle')) img(src='/marketing/integration.png') - p.lead Other 3rd Party Tools tie HabitRPG into various aspects of your life. Our API provides easy integration for things like the Chrome Extension, for which you lose points when browsing unproductive websites, and gain points when on productive ones. See more here + p.lead!=env.t('marketing3Lead2') hr.clearfix - h1 Organizational Use + h1=env.t('marketing4Header') .row .col-md-6 - h3 Gamification In Education + h3=env.t('marketing4Lead1Title') img.pull-left(src='/marketing/education.png') - p.lead Education is one of the best sectors for gamification. We all know how glued to phones and games students are these days, harness that power! Pit your students against eachother in friendly competition. Reward good behavior with rare prizes. Watch their grades and behavior soar. + p.lead=env.t('marketing4Lead1') .col-md-6 - h3 Gamification In Health and Wellness + h3=env.t('marketing4Lead2Title') img.pull-left(src='/marketing/wellness.png') - p.lead Health care costs are on the rise, and something's gotta give. Hundreds of programs are built to reduce costs and improve wellness. We believe HabitRPG can pave a substantial path towards healthy lifestyles. + p.lead=env.t('marketing4Lead2') .row .col-md-6.col-md-offset-3 - h3 Gamify Everything + h3=env.t('marketing4Lead3Title') img(src='/marketing/lefnire.png') p.lead - | Want to gamify your life?  - a.btn.btn-primary(ng-click='playButtonClick()') Play - | Interested in running a group in education, wellness, and more?  - a.btn.btn-primary(href='/static/plans',target='_blank') Contact Us - | Want to learn more?  - a.btn.btn-primary(href='/static/videos') Watch Videos + =env.t('marketing4Lead3-1') + |  + a.btn.btn-primary(ng-click='playButtonClick()')=env.t('playButton') + |  + =env.t('marketing4Lead3-2') + |  + a.btn.btn-primary(href='/static/plans',target='_blank')=env.t('contactUs') + |  + =env.t('marketing4Lead3-3') + |  + a.btn.btn-primary(href='/static/videos')=env.t('watchVideos') From d0f144077e45145e1dfcbca01bb7e05a1b3e7b7f Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 7 Apr 2014 18:27:12 +0200 Subject: [PATCH 21/29] fix(i18n): end tour --- public/js/services/guideServices.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/services/guideServices.js b/public/js/services/guideServices.js index 68f7f7f22f..bd59b4ea4b 100644 --- a/public/js/services/guideServices.js +++ b/public/js/services/guideServices.js @@ -84,7 +84,7 @@ angular.module('guideServices', []). "" + "" + "" + - "", + "", onEnd: function(){ User.set({'flags.showTour': false}); } From 99f50b0461af1b3a08610402eafa0f62a691637f Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 7 Apr 2014 18:40:51 +0200 Subject: [PATCH 22/29] fix(i18n): missing strings --- views/options/profile.jade | 2 +- views/options/social/challenge-box.jade | 3 +-- views/options/social/challenges.jade | 4 ++-- views/shared/modals/new-stuff.jade | 6 +++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/views/options/profile.jade b/views/options/profile.jade index 0cf4158c43..a5b41878be 100644 --- a/views/options/profile.jade +++ b/views/options/profile.jade @@ -81,7 +81,7 @@ mixin customizeProfile(mobile) // Flower li.customize-menu - menu(label="Flower") + menu(label=env.t('flower')) button(class='head_0 customize-option', type='button', ng-click='set({"preferences.hair.flower":0})') each num in [1,2,3,4,5,6] button(class='hair_flower_#{num} customize-option', type='button', ng-click='set({"preferences.hair.flower":#{num}})') diff --git a/views/options/social/challenge-box.jade b/views/options/social/challenge-box.jade index 65de163eb8..fa47595697 100644 --- a/views/options/social/challenge-box.jade +++ b/views/options/social/challenge-box.jade @@ -4,8 +4,7 @@ h3.panel-title=env.t('challenges')   a.pull-right(target='_blank', href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58') - small - ="More info" + small=env.t('moreInfo') .panel-body.modal-fixed-height(bindonce='group.challenges') div(ng-if='group.challenges.length > 0') table.table.table-striped diff --git a/views/options/social/challenges.jade b/views/options/social/challenges.jade index aac9d759da..541c814358 100644 --- a/views/options/social/challenges.jade +++ b/views/options/social/challenges.jade @@ -107,7 +107,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.html') input.form-control(type='text', minlength="3", maxlength="16", ng-model='newChallenge.shortName', placeholder=env.t('challengeTag'), required)   a.hint.vertical-20(target='_blank', href='http://habitrpg.wikia.com/wiki/Tags', popover=env.t('challengeTagPop'), popover-trigger='mouseenter', popover-placement='right') - ="More info" + =env.t('moreInfo') .form-group textarea.form-control(cols='3', placeholder=env.t('challengeDescr'), ng-model='newChallenge.description') @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.html') span.input-suffix.Pet_Currency_Gem1x.inline-gems   span.hint.vertical-20(popover=env.t('prizePop'), popover-trigger='mouseenter', popover-placement='right') - ="More info" + =env.t('moreInfo') span(ng-show='newChallenge.group=="habitrpg"') !=env.t('publicChallenges') diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade index e6b0422b40..400196574f 100644 --- a/views/shared/modals/new-stuff.jade +++ b/views/shared/modals/new-stuff.jade @@ -1,6 +1,6 @@ script(type='text/ng-template', id='modals/newStuff.html') .modal-header - h4 New Stuff! + h4=env.t('newStuff') .modal-body.new-stuff-modal.modal-fixed-height table tr @@ -723,5 +723,5 @@ script(type='text/ng-template', id='modals/newStuff.html') a(href='https://trello.com/card/custom-day-start/50e5d3684fe3a7266b0036d6/15') Add custom day start .modal-footer - button.btn.btn-default(ng-click='$close()') Cool - button.btn.btn-warning(ng-click='dismissAlert(); $close()') Dismiss This Alert + button.btn.btn-default(ng-click='$close()')=env.t('cool') + button.btn.btn-warning(ng-click='dismissAlert(); $close()')=env.t('dismissAlert') From dce4dd3ad65a8b016dcb79dc29cd2adb015bd122 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 9 Apr 2014 17:20:20 +0200 Subject: [PATCH 23/29] fix(i18n): translate class names in equipment --- views/options/inventory/inventory.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index bd3fb54916..28cf0b8b9c 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -4,7 +4,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html') .col-md-6.border-right h3.equipment-title.hint(popover-trigger='mouseenter', popover-placement='right', popover=env.t('battleGearText'))=env.t('battleGear') li.customize-menu.inventory-gear - menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special", mystery:"Mystery"}', ng-show='gear[klass]') + menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery")}', ng-show='gear[klass]') div(ng-repeat='item in gear[klass]') button.customize-option(popover='{{item.notes()}}', popover-title='{{item.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}') .col-md-6 @@ -15,7 +15,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html') |  =env.t('useCostume') li.customize-menu(ng-if='user.preferences.costume') - menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special", mystery:"Mystery"}', ng-show='gear[klass]') + menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery")}', ng-show='gear[klass]') div(ng-repeat='item in gear[klass]') button.customize-option(popover='{{item.notes()}}', popover-title='{{item.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}') From 52d2693d94f883fce4766c9f43bb75f976f04d08 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 9 Apr 2014 17:30:37 +0200 Subject: [PATCH 24/29] fix(i18n): use translated attributes and classes --- views/options/profile.jade | 2 +- views/shared/profiles/stats.jade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/views/options/profile.jade b/views/options/profile.jade index a5b41878be..b0f0d0bdcb 100644 --- a/views/options/profile.jade +++ b/views/options/profile.jade @@ -141,7 +141,7 @@ script(id='partials/options.profile.stats.html', type='text/ng-template') h3=env.t('characterBuild') h4 =env.t('class') + ': ' - span {{ {warrior:'Warrior',wizard:'Mage',healer:'Healer',rogue:'Rogue'}[user.stats.class] }}  + span {{ {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer")}[user.stats.class] }}  a.btn.btn-danger.btn-xs(ng-click='changeClass(null)')=env.t('changeClass') small.cost 3 table.table.table-striped diff --git a/views/shared/profiles/stats.jade b/views/shared/profiles/stats.jade index 5b568e8002..2ae6ad7f85 100644 --- a/views/shared/profiles/stats.jade +++ b/views/shared/profiles/stats.jade @@ -27,7 +27,7 @@ table.table.table-striped(ng-show='user.flags.itemsEnabled') h4=env.t('attributes') table.table.table-striped - tr(ng-repeat='(k,v) in {str:"Strength (STR)",int:"Intelligence (INT)",con:"Constitution (CON)",per:"Perception (PER)"}') + tr(ng-repeat='(k,v) in {str: env.t("strength") + " (STR)",int: env.t("intelligence") + " (INT)",con: env.t("constitution") + " (CON)",per:env.t("perception") + " (PER)"}') td span.hint(ng-if='k=="str"', popover-title=env.t('strength'), popover-placement='right', popover=env.t('strengthText'), popover-trigger='mouseenter', style='margin-right:3px') strong {{v}} From ddf5ad8ec948d123c5e9c534ab2e914ea7804dcc Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 15 Apr 2014 17:48:58 +0200 Subject: [PATCH 25/29] fix(i18n): pass req.language when using batchUpdate --- src/controllers/user.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controllers/user.js b/src/controllers/user.js index c4c8cb3cf9..eb178c91aa 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -397,6 +397,8 @@ api.batchUpdate = function(req, res, next) { res.locals.ops = []; var ops = _.transform(req.body, function(m,_req){ if (_.isEmpty(_req)) return; + _req.language = req.language; + m.push(function() { var cb = arguments[arguments.length-1]; res.locals.ops.push(_req); From 93ca6cf6931306793cd4e548d6f59069f51c652f Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 15 Apr 2014 17:56:54 +0200 Subject: [PATCH 26/29] fix(i18n) --- src/routes/apiv2.coffee | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 6411815e4f..10fec102df 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -456,12 +456,8 @@ module.exports = (swagger, v2) -> spec: path: "/groups/{gid}/chat" description: "Get all chat messages" -<<<<<<< HEAD parameters: [path('gid','Group to return the chat from ','string')] - middleware: [auth.auth, groups.attachGroup] -======= middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] ->>>>>>> refactor(i18n): refactor user language detection, add to api methods action: groups.getChat From 9b4350266922a4f2f698e20569dacbad8f21d98a Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 15 Apr 2014 18:13:42 +0200 Subject: [PATCH 27/29] fix(i18n): pet and mounts --- views/options/inventory/stable.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/options/inventory/stable.jade b/views/options/inventory/stable.jade index d3583012ea..52d5b16f15 100644 --- a/views/options/inventory/stable.jade +++ b/views/options/inventory/stable.jade @@ -15,7 +15,7 @@ script(type='text/ng-template', id='partials/options.inventory.mounts.html') menu.pets(type='list') li.customize-menu(ng-repeat='egg in Content.eggs') menu - div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text()}} {{egg.mountText()}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key') + div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover=env.t('mountName', {potion: '{{potion.text()}}', mount: '{{egg.mountText()}}'}), popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key') button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.key, potion.key)') //div(class='Mount_Head_{{mount}}') button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]') @@ -33,7 +33,7 @@ mixin petList(source) menu.pets(type='list') li.customize-menu(ng-repeat='egg in #{source}') menu - div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text()}} {{egg.text()}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key') + div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover=env.t('petName', {potion: '{{potion.text()}}', egg: '{{egg.text()}}'}), popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key') button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.key, potion.key)') .progress(ng-show='!user.items.mounts[pet] && egg.key!="Egg"') .progress-bar.progress-bar-success(style="width:{{user.items.pets[pet]/.5}}%") From 57e93d6623e468136a1cdab5c8bf5cbe3b10ae93 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 15 Apr 2014 18:35:54 +0200 Subject: [PATCH 28/29] fix(i18n): misc --- src/controllers/user.js | 2 +- views/static/login-modal.jade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index eb178c91aa..3545d507b5 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -76,7 +76,7 @@ api.score = function(req, res, next) { if (task.type === 'daily' || task.type === 'todo') task.completed = direction === 'up'; } - var delta = user.ops.score({params:{id:task.id, direction:direction}}); + var delta = user.ops.score({params:{id:task.id, direction:direction}, language: req.language}); user.save(function(err,saved){ if (err) return next(err); diff --git a/views/static/login-modal.jade b/views/static/login-modal.jade index 0201b35504..46c0ca5f51 100644 --- a/views/static/login-modal.jade +++ b/views/static/login-modal.jade @@ -6,7 +6,7 @@ script(id='modals/login.html', type='text/ng-template') a(href='/auth/facebook') img(src='/bower_components/habitrpg-shared/img/facebook-login-register.jpeg', alt=env.t('loginFacebookAlt')) //can we add in google auth? I like google auth - h3 Or + h3=env.t('or') ul.nav.nav-tabs li.active a(data-toggle='tab',data-target='#login-tab')=env.t('login') From f3d15c9b91e1518d6b7b049db30a8ab1e1510c2c Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 6 May 2014 20:16:28 +0200 Subject: [PATCH 29/29] fix(i18n): use correct branch --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index a6e41d859d..46a4bbc841 100644 --- a/bower.json +++ b/bower.json @@ -30,7 +30,7 @@ "bootstrap": "~3.1.0", "bootstrap-growl": "git://github.com/ifightcrime/bootstrap-growl.git#master", "bootstrap-tour": "~0.8.1", - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#paglias/translate", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git", "BrowserQuest": "git://github.com/mozilla/BrowserQuest.git", "github-buttons": "git://github.com/mdo/github-buttons.git", "marked": "~0.2.9", diff --git a/package.json b/package.json index 3e6a2425ad..8c063f0131 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0-152", "main": "./src/server.js", "dependencies": { - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#paglias/translate", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared", "connect-mongo": "*", "express": "3.5.x", "gzippo": "*",