Compare commits

..

17 Commits

Author SHA1 Message Date
Matteo Pagliazzi
2bca92b4d5 3.44.4 2016-09-29 23:22:30 +02:00
Matteo Pagliazzi
c3843cae80 client: fix bug that prevented drop notifications from showing up 2016-09-29 23:19:46 +02:00
Sabe Jones
816e4a2f19 3.44.3 2016-09-29 18:12:31 +00:00
Sabe Jones
d0d4927e59 fix(login): uncomment Google auth 2016-09-29 18:11:47 +00:00
Sabe Jones
023ff5789d 3.44.2 2016-09-29 17:13:16 +00:00
Blade Barringer
cc9be6f4a1 chore(i18n): update locales 2016-09-29 11:53:29 -05:00
Sabe Jones
145bcb6f7c 3.44.1 2016-09-29 16:46:26 +00:00
Sabe Jones
d7db599f88 chore(npm): update shrinkwrap 2016-09-29 16:22:44 +00:00
Sabe Jones
ca935670f7 chore(event): GaymerX armor & news 2016-09-29 16:16:43 +00:00
AccioBooks
c2eb113672 Make Wikia Links Translatable (#7036)
* Wikia Links

* Update contrib.json (Added comma)

* Implement @Alys's Suggestions

* conLearnLink -> conLearnURL

* add link to plans.jade

* Appended "URL" to locale strings with URLs

* Add 's'
2016-09-29 21:57:44 +10:00
Matteo Pagliazzi
257e932bc3 Vue Store (#8071)
* vue: use our own store in place of vuex

* vue store: add getters, watcher and use internal vue instance

* vue store: better state getter and credits to Vuex

* vue store: $watch -> watch

* vuex store: pass store to getters and fix typos

* add comments to store, start writing tests

* fix unit tests and add missing ones

* cleanup components, add less folder, fetch tassks

* use Vuex helpers

* pin vuex version

* move semantic-ui theme to assets/less, keep website/build empty but in git

* import helpers from vuex
2016-09-29 13:32:36 +02:00
Sabe Jones
50e2731811 chore(assets): remove unused promos 2016-09-28 18:47:04 +00:00
Matteo Pagliazzi
d67b9e5688 do not send welcome email if user already exists 2016-09-28 19:23:07 +02:00
Blade Barringer
bfc7b9d3e8 fix(client): allow admins to open flag modal regardless of flag status
fixes #8078
2016-09-28 08:16:06 -05:00
Blade Barringer
eb0e234afa chore(i18n): update locales 2016-09-28 07:44:30 -05:00
Matteo Pagliazzi
177f78cbb0 3.44.0 2016-09-28 12:49:30 +02:00
Phillip Thelen
e3b484b29a Add Google Signin (#7969)
* Start adding google login

* fix local js issue

* implement syntax suggestions

* fix delete social tests

* Add service for authentication alerts

* fix social login tests

* make suggested google sign in changes

* fix accidentally deleted code

* refactor social network sign in

* fix incorrect find

* implement suggested google sign in changes

* fix(tests): Inject fake Auth module for auth controller

* fix(test): prevent social service from causing page reload

* fix loading user info

* Use lodash's implimentation of find for IE compatibility

* chore: increase test coverage around deletion route

* chore: clean up social auth test

* chore: Fix social login tests

* remove profile from login scope

* fix(api): Allow social accounts to deregister as user has auth backup

* temporarily disable google login button
2016-09-28 12:11:10 +02:00
428 changed files with 2911 additions and 1571 deletions

View File

@@ -23,4 +23,6 @@ Gruntfile.js
gulpfile.js
gulp
webpack
test/client
test/client/e2e
test/client/unit/index.js
test/client/unit/karma.conf.js

1
.gitignore vendored
View File

@@ -14,7 +14,6 @@ npm-debug.log*
lib
website/client-old/bower_components
website/client-old/new-stuff.html
website/build
newrelic_agent.log
.bower-tmp
.bower-registry

View File

@@ -7,6 +7,8 @@
"FACEBOOK_ANALYTICS":"1234567890123456",
"FACEBOOK_KEY":"123456789012345",
"FACEBOOK_SECRET":"aaaabbbbccccddddeeeeffff00001111",
"GOOGLE_CLIENT_ID":"123456789012345",
"GOOGLE_CLIENT_SECRET":"aaaabbbbccccddddeeeeffff00001111",
"NODE_DB_URI":"mongodb://localhost/habitrpg",
"TEST_DB_URI":"mongodb://localhost/habitrpg_test",
"NODE_ENV":"development",

View File

@@ -5,7 +5,7 @@ import fs from 'fs';
// Code taken from https://www.artembutusov.com/webpack-semantic-ui/
// Relative to node_modules/semantic-ui-less
const SEMANTIC_THEME_PATH = '../../website/client/assets/semantic-ui/theme.config';
const SEMANTIC_THEME_PATH = '../../website/client/assets/less/semantic-ui/theme.config';
// fix well known bug with default distribution
function fixFontPath (filename) {

67
npm-shrinkwrap.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "habitica",
"version": "3.43.2",
"version": "3.44.4",
"dependencies": {
"@slack/client": {
"version": "3.6.0",
@@ -533,6 +533,11 @@
"from": "babel-plugin-syntax-async-functions@>=6.8.0 <7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz"
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"from": "babel-plugin-syntax-object-rest-spread@>=6.8.0 <7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz"
},
"babel-plugin-transform-async-to-module-method": {
"version": "6.8.0",
"from": "babel-plugin-transform-async-to-module-method@>=6.8.0 <7.0.0",
@@ -655,6 +660,11 @@
"from": "babel-plugin-transform-es2015-unicode-regex@>=6.3.13 <7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz"
},
"babel-plugin-transform-object-rest-spread": {
"version": "6.16.0",
"from": "babel-plugin-transform-object-rest-spread@>=6.16.0 <7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz"
},
"babel-plugin-transform-regenerator": {
"version": "6.14.0",
"from": "babel-plugin-transform-regenerator@>=6.14.0 <7.0.0",
@@ -5193,6 +5203,11 @@
"resolved": "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-3.1.0.tgz",
"optional": true
},
"jquery": {
"version": "3.1.1",
"from": "jquery@*",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.1.1.tgz"
},
"js-base64": {
"version": "2.1.9",
"from": "js-base64@>=2.1.9 <3.0.0",
@@ -5379,6 +5394,36 @@
"from": "lcid@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz"
},
"less": {
"version": "2.7.1",
"from": "less@>=2.7.1 <3.0.0",
"resolved": "https://registry.npmjs.org/less/-/less-2.7.1.tgz",
"dependencies": {
"asap": {
"version": "2.0.5",
"from": "asap@>=2.0.3 <2.1.0",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz",
"optional": true
},
"image-size": {
"version": "0.5.0",
"from": "image-size@>=0.5.0 <0.6.0",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.0.tgz",
"optional": true
},
"promise": {
"version": "7.1.1",
"from": "promise@>=7.1.1 <8.0.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz",
"optional": true
}
}
},
"less-loader": {
"version": "2.2.3",
"from": "less-loader@>=2.2.3 <3.0.0",
"resolved": "https://registry.npmjs.org/less-loader/-/less-loader-2.2.3.tgz"
},
"lexical-scope": {
"version": "1.2.0",
"from": "lexical-scope@>=1.2.0 <2.0.0",
@@ -6931,6 +6976,11 @@
"from": "passport-facebook@2.0.0",
"resolved": "https://registry.npmjs.org/passport-facebook/-/passport-facebook-2.0.0.tgz"
},
"passport-google-oauth20": {
"version": "1.0.0",
"from": "passport-google-oauth20@1.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-1.0.0.tgz"
},
"passport-oauth2": {
"version": "1.3.0",
"from": "passport-oauth2@>=1.0.0 <2.0.0",
@@ -8017,6 +8067,11 @@
}
}
},
"semantic-ui-less": {
"version": "2.2.4",
"from": "semantic-ui-less@>=2.2.4 <2.3.0",
"resolved": "https://registry.npmjs.org/semantic-ui-less/-/semantic-ui-less-2.2.4.tgz"
},
"semver": {
"version": "5.0.3",
"from": "semver@>=5.0.1 <5.1.0",
@@ -9444,16 +9499,6 @@
"from": "vue-template-es2015-compiler@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.0.0.tgz"
},
"vuex": {
"version": "2.0.0-rc.5",
"from": "vuex@>=2.0.0-rc.5 <3.0.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-2.0.0-rc.5.tgz"
},
"vuex-router-sync": {
"version": "3.0.0",
"from": "vuex-router-sync@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vuex-router-sync/-/vuex-router-sync-3.0.0.tgz"
},
"w3counter": {
"version": "2.0.1",
"from": "w3counter@>=2.0.0 <3.0.0",

View File

@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "3.43.2",
"version": "3.44.4",
"main": "./website/server/index.js",
"dependencies": {
"@slack/client": "3.6.0",
@@ -16,6 +16,7 @@
"babel-core": "^6.0.0",
"babel-loader": "^6.0.0",
"babel-plugin-transform-async-to-module-method": "^6.8.0",
"babel-plugin-transform-object-rest-spread": "^6.16.0",
"babel-polyfill": "^6.6.1",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.6.0",
@@ -85,6 +86,7 @@
"pageres": "^4.1.1",
"passport": "~0.2.1",
"passport-facebook": "2.0.0",
"passport-google-oauth20": "1.0.0",
"paypal-ipn": "3.0.0",
"paypal-rest-sdk": "^1.2.1",
"pretty-data": "^0.40.0",
@@ -113,8 +115,6 @@
"vue-loader": "^9.4.0",
"vue-resource": "^1.0.2",
"vue-router": "^2.0.0-rc.5",
"vuex": "^2.0.0-rc.5",
"vuex-router-sync": "^3.0.0",
"webpack": "^1.12.2",
"webpack-merge": "^0.8.3",
"winston": "^2.1.0",
@@ -146,6 +146,7 @@
"client:dev": "node webpack/dev-server.js",
"client:build": "node webpack/build.js",
"client:unit": "karma start test/client/unit/karma.conf.js --single-run",
"client:unit:watch": "karma start test/client/unit/karma.conf.js",
"client:e2e": "node test/client/e2e/runner.js",
"client:test": "npm run client:unit && npm run client:e2e",
"start": "gulp run:dev",

View File

@@ -5,36 +5,94 @@ import {
describe('DELETE social registration', () => {
let user;
let endpoint = '/user/auth/social/facebook';
beforeEach(async () => {
user = await generateUser();
await user.update({ 'auth.facebook.id': 'some-fb-id' });
expect(user.auth.local.username).to.not.be.empty;
expect(user.auth.facebook).to.not.be.empty;
});
context('of NOT-FACEBOOK', () => {
context('NOT-SUPPORTED', () => {
it('is not supported', async () => {
await expect(user.del('/user/auth/social/SOME-OTHER-NETWORK')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('onlyFbSupported'),
code: 400,
error: 'BadRequest',
message: t('unsupportedNetwork'),
});
});
});
context('of facebook', () => {
it('fails if local registration does not exist for this user', async () => {
await user.update({ 'auth.local': { ok: true } });
await expect(user.del(endpoint)).to.eventually.be.rejected.and.eql({
context('Facebook', () => {
it('fails if user does not have an alternative registration method', async () => {
await user.update({
'auth.facebook.id': 'some-fb-id',
'auth.local': { ok: true },
});
await expect(user.del('/user/auth/social/facebook')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('cantDetachFb'),
message: t('cantDetachSocial'),
});
});
it('succeeds', async () => {
let response = await user.del(endpoint);
it('succeeds if user has a local registration', async () => {
await user.update({
'auth.facebook.id': 'some-fb-id',
});
let response = await user.del('/user/auth/social/facebook');
expect(response).to.eql({});
await user.sync();
expect(user.auth.facebook).to.be.empty;
});
it('succeeds if user has a google registration', async () => {
await user.update({
'auth.facebook.id': 'some-fb-id',
'auth.google.id': 'some-google-id',
'auth.local': { ok: true },
});
let response = await user.del('/user/auth/social/facebook');
expect(response).to.eql({});
await user.sync();
expect(user.auth.facebook).to.be.empty;
});
});
context('Google', () => {
it('fails if user does not have an alternative registration method', async () => {
await user.update({
'auth.google.id': 'some-google-id',
'auth.local': { ok: true },
});
await expect(user.del('/user/auth/social/google')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('cantDetachSocial'),
});
});
it('succeeds if user has a local registration', async () => {
await user.update({
'auth.google.id': 'some-google-id',
});
let response = await user.del('/user/auth/social/google');
expect(response).to.eql({});
await user.sync();
expect(user.auth.google).to.be.empty;
});
it('succeeds if user has a facebook registration', async () => {
await user.update({
'auth.google.id': 'some-google-id',
'auth.facebook.id': 'some-facebook-id',
'auth.local': { ok: true },
});
let response = await user.del('/user/auth/social/google');
expect(response).to.eql({});
await user.sync();
expect(user.auth.google).to.be.empty;
});
});
});

View File

@@ -12,58 +12,132 @@ describe('POST /user/auth/social', () => {
let endpoint = '/user/auth/social';
let randomAccessToken = '123456';
let facebookId = 'facebookId';
let network = 'facebook';
let googleId = 'googleId';
let network = 'NoNetwork';
before(async () => {
beforeEach(async () => {
api = requester();
user = await generateUser();
let expectedResult = {id: facebookId};
let passportFacebookProfile = sandbox.stub(passport._strategies.facebook, 'userProfile');
passportFacebookProfile.yields(null, expectedResult);
});
it('fails if network is not facebook', async () => {
it('fails if network is not supported', async () => {
await expect(api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network: 'NotFacebook',
network,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('onlyFbSupported'),
code: 400,
error: 'BadRequest',
message: t('unsupportedNetwork'),
});
});
it('registers a new user', async () => {
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
describe('facebook', () => {
before(async () => {
let expectedResult = {id: facebookId};
sandbox.stub(passport._strategies.facebook, 'userProfile').yields(null, expectedResult);
network = 'facebook';
});
expect(response.apiToken).to.exist;
expect(response.id).to.exist;
expect(response.newUser).to.be.true;
it('registers a new user', async () => {
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
expect(response.apiToken).to.exist;
expect(response.id).to.exist;
expect(response.newUser).to.be.true;
});
it('logs an existing user in', async () => {
let registerResponse = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
expect(response.apiToken).to.eql(registerResponse.apiToken);
expect(response.id).to.eql(registerResponse.id);
expect(response.newUser).to.be.false;
});
it('add social auth to an existing user', async () => {
let response = await user.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
expect(response.apiToken).to.exist;
expect(response.id).to.exist;
expect(response.newUser).to.be.false;
});
it('enrolls a new user in an A/B test', async () => {
await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
await expect(getProperty('users', user._id, '_ABtest')).to.eventually.be.a('string');
});
});
it('enrolls a new user in an A/B test', async () => {
await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
describe('google', () => {
before(async () => {
let expectedResult = {id: googleId};
sandbox.stub(passport._strategies.google, 'userProfile').yields(null, expectedResult);
network = 'google';
});
await expect(getProperty('users', user._id, '_ABtest')).to.eventually.be.a('string');
});
it('registers a new user', async () => {
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
it('logs an existing user in', async () => {
await user.update({ 'auth.facebook.id': facebookId });
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
expect(response.apiToken).to.exist;
expect(response.id).to.exist;
expect(response.newUser).to.be.true;
});
expect(response.apiToken).to.eql(user.apiToken);
expect(response.id).to.eql(user._id);
expect(response.newUser).to.be.false;
it('logs an existing user in', async () => {
let registerResponse = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
let response = await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
expect(response.apiToken).to.eql(registerResponse.apiToken);
expect(response.id).to.eql(registerResponse.id);
expect(response.newUser).to.be.false;
});
it('add social auth to an existing user', async () => {
let response = await user.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
expect(response.apiToken).to.exist;
expect(response.id).to.exist;
expect(response.newUser).to.be.false;
});
it('enrolls a new user in an A/B test', async () => {
await api.post(endpoint, {
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
network,
});
await expect(getProperty('users', user._id, '_ABtest')).to.eventually.be.a('string');
});
});
});

View File

@@ -1,12 +1,16 @@
'use strict';
describe('Auth Controller', function() {
var scope, ctrl, user, $httpBackend, $window, $modal;
var scope, ctrl, user, $httpBackend, $window, $modal, alert, Auth;
beforeEach(function(){
module(function($provide) {
Auth = {
runAuth: sandbox.spy(),
};
$provide.value('Analytics', analyticsMock);
$provide.value('Chat', { seenMessage: function() {} });
$provide.value('Auth', Auth);
});
inject(function(_$httpBackend_, $rootScope, $controller, _$modal_) {
@@ -17,27 +21,27 @@ describe('Auth Controller', function() {
$window = { location: { href: ""}, alert: sandbox.spy() };
$modal = _$modal_;
user = { user: {}, authenticate: sandbox.spy() };
alert = { authErrorAlert: sandbox.spy() };
ctrl = $controller('AuthCtrl', {$scope: scope, $window: $window, User: user});
ctrl = $controller('AuthCtrl', {$scope: scope, $window: $window, User: user, Alert: alert});
})
});
describe('logging in', function() {
it('should log in users with correct uname / pass', function() {
$httpBackend.expectPOST('/api/v3/user/auth/local/login').respond({data: {id: 'abc', apiToken: 'abc'}});
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.be.calledOnce;
expect($window.alert).to.not.be.called;
expect(Auth.runAuth).to.be.calledOnce;
expect(alert.authErrorAlert).to.not.be.called;
});
it('should not log in users with incorrect uname / pass', function() {
$httpBackend.expectPOST('/api/v3/user/auth/local/login').respond(404, '');
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.not.be.called;
expect($window.alert).to.be.calledOnce;
expect(Auth.runAuth).to.not.be.called;
expect(alert.authErrorAlert).to.be.calledOnce;
});
});

View File

@@ -13,7 +13,7 @@ describe('Footer Controller', function() {
user: user
};
scope = $rootScope.$new();
$controller('FooterCtrl', {$scope: scope, User: User});
$controller('FooterCtrl', {$scope: scope, User: User, Social: {}});
}));
context('Debug mode', function() {

5
test/client/.babelrc Normal file
View File

@@ -0,0 +1,5 @@
{
"presets": ["es2015"],
"plugins": ["transform-object-rest-spread"],
"comments": false
}

View File

@@ -1,16 +0,0 @@
import Vue from 'vue';
// import Hello from 'src/components/Hello';
describe('Hello.vue', () => {
xit('should render correct contents', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(Hello),
});
expect(vm.$el.querySelector('.hello h1').textContent).to.equal('Hello Vue!');
});
it('should make assertions', () => {
expect(true).to.equal(true);
});
});

View File

@@ -0,0 +1,120 @@
import Vue from 'vue';
import storeInjector from 'inject?-vue!client/store';
import { mapState, mapGetters, mapActions } from 'client/store';
describe('Store', () => {
let injectedStore;
beforeEach(() => {
injectedStore = storeInjector({ // eslint-disable-line babel/new-cap
'./state': {
name: 'test',
},
'./getters': {
computedName ({ state }) {
return `${state.name} computed!`;
},
},
'./actions': {
getName ({ state }, ...args) {
return [state.name, ...args];
},
},
}).default;
});
it('injects itself in all component', (done) => {
new Vue({ // eslint-disable-line no-new
created () {
expect(this.$store).to.equal(injectedStore);
done();
},
});
});
it('can watch a function on the state', (done) => {
injectedStore.watch(state => state.name, (newName) => {
expect(newName).to.equal('test updated');
done();
});
injectedStore.state.name = 'test updated';
});
it('supports getters', () => {
expect(injectedStore.getters.computedName).to.equal('test computed!');
injectedStore.state.name = 'test updated';
expect(injectedStore.getters.computedName).to.equal('test updated computed!');
});
describe('actions', () => {
it('can be dispatched', () => {
expect(injectedStore.dispatch('getName', 1, 2, 3)).to.deep.equal(['test', 1, 2, 3]);
});
it('throws an error is the action doesn\'t exists', () => {
expect(() => injectedStore.dispatched('wrong')).to.throw;
});
});
describe('helpers', () => {
it('mapState', (done) => {
new Vue({ // eslint-disable-line no-new
data: {
title: 'internal',
},
computed: {
...mapState(['name']),
...mapState({
nameComputed (state, getters) {
return `${this.title} ${getters.computedName} ${state.name}`;
},
}),
},
created () {
expect(this.name).to.equal('test');
expect(this.nameComputed).to.equal('internal test computed! test');
done();
},
});
});
it('mapGetters', (done) => {
new Vue({ // eslint-disable-line no-new
data: {
title: 'internal',
},
computed: {
...mapGetters(['computedName']),
...mapGetters({
nameComputedTwice: 'computedName',
}),
},
created () {
expect(this.computedName).to.equal('test computed!');
expect(this.nameComputedTwice).to.equal('test computed!');
done();
},
});
});
it('mapActions', (done) => {
new Vue({ // eslint-disable-line no-new
data: {
title: 'internal',
},
methods: {
...mapActions(['getName']),
...mapActions({
getNameRenamed: 'getName',
}),
},
created () {
expect(this.getName('123')).to.deep.equal(['test', '123']);
expect(this.getNameRenamed('123')).to.deep.equal(['test', '123']);
done();
},
});
});
});
});

View File

@@ -17,7 +17,7 @@ var baseConfig = {
extensions: ['', '.js', '.vue'],
fallback: [path.join(__dirname, '../node_modules')],
alias: {
src: path.resolve(__dirname, '../website/client'),
client: path.resolve(__dirname, '../website/client'),
assets: path.resolve(__dirname, '../website/client/assets'),
components: path.resolve(__dirname, '../website/client/components'),
},

View File

@@ -1,54 +1,30 @@
.2014_Fall_HealerPROMO2 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1212px -1488px;
width: 90px;
height: 90px;
}
.2014_Fall_Mage_PROMO9 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -452px -884px;
width: 120px;
height: 90px;
}
.2014_Fall_RoguePROMO3 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -558px -1385px;
width: 105px;
height: 90px;
}
.2014_Fall_Warrior_PROMO {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -848px -1488px;
width: 90px;
height: 90px;
}
.promo_android {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -978px -573px;
background-position: -1094px -151px;
width: 175px;
height: 175px;
}
.promo_backgrounds_armoire_201602 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1417px -103px;
background-position: -1275px -103px;
width: 141px;
height: 294px;
}
.promo_backgrounds_armoire_201603 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1275px -103px;
background-position: -1417px -103px;
width: 141px;
height: 294px;
}
.promo_backgrounds_armoire_201604 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -452px -442px;
background-position: -593px 0px;
width: 140px;
height: 441px;
}
.promo_backgrounds_armoire_201605 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -593px 0px;
background-position: -281px -525px;
width: 140px;
height: 441px;
}
@@ -78,7 +54,7 @@
}
.promo_backtoschool {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -151px -1488px;
background-position: -1522px -712px;
width: 150px;
height: 150px;
}
@@ -120,13 +96,13 @@
}
.promo_cow {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -281px -525px;
background-position: -452px 0px;
width: 140px;
height: 441px;
}
.promo_dilatoryDistress {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1316px -1385px;
background-position: -904px -1385px;
width: 90px;
height: 90px;
}
@@ -144,7 +120,7 @@
}
.promo_enchanted_armoire_201507 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -289px -1294px;
background-position: -507px -1294px;
width: 217px;
height: 90px;
}
@@ -156,7 +132,7 @@
}
.promo_enchanted_armoire_201509 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -666px -1488px;
background-position: -995px -1385px;
width: 90px;
height: 90px;
}
@@ -168,7 +144,7 @@
}
.promo_enchanted_armoire_201601 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -939px -1488px;
background-position: -1450px -1385px;
width: 90px;
height: 90px;
}
@@ -180,13 +156,13 @@
}
.promo_ghost_potions {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -452px 0px;
background-position: -452px -442px;
width: 140px;
height: 441px;
}
.promo_habitica {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1094px -151px;
background-position: -978px -573px;
width: 175px;
height: 175px;
}
@@ -210,7 +186,7 @@
}
.promo_mystery_201405 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1589px -1385px;
background-position: -1177px -1385px;
width: 90px;
height: 90px;
}
@@ -222,7 +198,7 @@
}
.promo_mystery_201407 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1064px -1114px;
background-position: -1107px -1114px;
width: 42px;
height: 62px;
}
@@ -234,25 +210,25 @@
}
.promo_mystery_201409 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1030px -1488px;
background-position: -1268px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201410 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1131px -840px;
background-position: -1202px -840px;
width: 72px;
height: 63px;
}
.promo_mystery_201411 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1225px -1385px;
background-position: -1359px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201412 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1021px -1114px;
background-position: -1064px -1114px;
width: 42px;
height: 66px;
}
@@ -264,13 +240,13 @@
}
.promo_mystery_201502 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -393px -1488px;
background-position: -1485px -1294px;
width: 90px;
height: 90px;
}
.promo_mystery_201503 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -575px -1488px;
background-position: -631px -1385px;
width: 90px;
height: 90px;
}
@@ -282,43 +258,43 @@
}
.promo_mystery_201505 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -757px -1488px;
background-position: -449px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201506 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -654px -1030px;
background-position: -1021px -1114px;
width: 42px;
height: 69px;
}
.promo_mystery_201507 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1601px -1081px;
background-position: -302px -1488px;
width: 90px;
height: 105px;
}
.promo_mystery_201508 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -664px -1385px;
background-position: -1203px -1294px;
width: 93px;
height: 90px;
}
.promo_mystery_201509 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1121px -1488px;
background-position: -1541px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201510 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -758px -1385px;
background-position: -1391px -1294px;
width: 93px;
height: 90px;
}
.promo_mystery_201511 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1134px -1385px;
background-position: -540px -1385px;
width: 90px;
height: 90px;
}
@@ -330,31 +306,31 @@
}
.promo_mystery_201601 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -452px -975px;
background-position: -452px -884px;
width: 120px;
height: 90px;
}
.promo_mystery_201602 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1407px -1385px;
background-position: -813px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201603 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1498px -1385px;
background-position: -722px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201604 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -852px -1385px;
background-position: -1109px -1294px;
width: 93px;
height: 90px;
}
.promo_mystery_201605 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -302px -1488px;
background-position: -1576px -1294px;
width: 90px;
height: 90px;
}
@@ -366,25 +342,25 @@
}
.promo_mystery_201607 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -484px -1488px;
background-position: -1086px -1385px;
width: 90px;
height: 90px;
}
.promo_mystery_201608 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1040px -1385px;
background-position: -1297px -1294px;
width: 93px;
height: 90px;
}
.promo_mystery_201609 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -946px -1385px;
background-position: -1015px -1294px;
width: 93px;
height: 90px;
}
.promo_mystery_3014 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -507px -1294px;
background-position: -289px -1294px;
width: 217px;
height: 90px;
}
@@ -430,6 +406,12 @@
width: 60px;
height: 60px;
}
.promo_rainbow_armor {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1601px -1081px;
width: 92px;
height: 103px;
}
.promo_shimmer_hair {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: 0px -1210px;
@@ -456,13 +438,13 @@
}
.promo_springclasses2014 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: 0px -1294px;
background-position: -978px -749px;
width: 288px;
height: 90px;
}
.promo_springclasses2015 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -978px -749px;
background-position: 0px -1294px;
width: 288px;
height: 90px;
}
@@ -504,22 +486,28 @@
}
.promo_takeThis_gear {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -306px -431px;
background-position: -452px -975px;
width: 114px;
height: 87px;
}
.promo_takethis_armor {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -906px -1294px;
background-position: -306px -431px;
width: 114px;
height: 87px;
}
.promo_unconventional_armor {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1204px -840px;
background-position: -654px -1030px;
width: 60px;
height: 60px;
}
.promo_unconventional_armor2 {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1131px -840px;
width: 70px;
height: 74px;
}
.promo_updos {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1522px -546px;
@@ -558,7 +546,7 @@
}
.npc_viirus {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -449px -1385px;
background-position: -906px -1294px;
width: 108px;
height: 90px;
}
@@ -576,7 +564,7 @@
}
.scene_phone_peek {
background-image: url(/spritesmith-largeSprites-0.png);
background-position: -1522px -712px;
background-position: -151px -1488px;
width: 150px;
height: 150px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 KiB

After

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

3
website/build/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Ignore everything except this file so that the folder stays in git
*
!.gitignore

View File

@@ -5,8 +5,8 @@
*/
angular.module('habitrpg')
.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','ApiUrl', '$modal', 'Analytics',
function($scope, $rootScope, User, $http, $location, $window, ApiUrl, $modal, Analytics) {
.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','ApiUrl', '$modal', 'Alert', 'Analytics', 'Auth',
function($scope, $rootScope, User, $http, $location, $window, ApiUrl, $modal, Alert, Analytics, Auth) {
$scope.Analytics = Analytics;
$scope.logout = function() {
@@ -14,30 +14,6 @@ angular.module('habitrpg')
$window.location.href = '/logout';
};
var runAuth = function(id, token) {
User.authenticate(id, token, function(err) {
if(!err) $scope.registrationInProgress = false;
Analytics.login();
Analytics.updateUser();
$window.location.href = ('/' + window.location.hash);
});
};
function errorAlert(data, status, headers, config) {
$scope.registrationInProgress = false;
if (status === 0) {
$window.alert(window.env.t('noReachServer'));
} else if (status === 400 && data.errors && _.isArray(data.errors)) { // bad requests
data.errors.forEach(function (err) {
$window.alert(err.message);
});
} else if (!!data && !!data.error) {
$window.alert(data.message);
} else {
$window.alert(window.env.t('errorUpCase') + ' ' + status);
}
};
$scope.registrationInProgress = false;
$scope.register = function() {
@@ -60,9 +36,12 @@ angular.module('habitrpg')
}
$http.post(url, scope.registerVals).success(function(res, status, headers, config) {
runAuth(res.data._id, res.data.apiToken);
Auth.runAuth(res.data._id, res.data.apiToken);
Analytics.register();
}).error(errorAlert);
}).error(function(data, status, headers, config) {
$scope.registrationInProgress = false;
Alert.authErrorAlert(data, status, headers, config)
});
};
$scope.auth = function() {
@@ -73,8 +52,8 @@ angular.module('habitrpg')
//@TODO: Move all the $http methods to a service
$http.post(ApiUrl.get() + "/api/v3/user/auth/local/login", data)
.success(function(res, status, headers, config) {
runAuth(res.data.id, res.data.apiToken);
}).error(errorAlert);
Auth.runAuth(res.data.id, res.data.apiToken);
}).error(Alert.authErrorAlert);
};
$scope.playButtonClick = function() {
@@ -113,8 +92,8 @@ angular.module('habitrpg')
hello(network).login({scope:'email'}).then(function(auth){
$http.post(ApiUrl.get() + "/api/v3/user/auth/social", auth)
.success(function(res, status, headers, config) {
runAuth(res.data.id, res.data.apiToken);
}).error(errorAlert);
Auth.runAuth(res.data.id, res.data.apiToken);
}).error(Alert.authErrorAlert);
}, function( e ){
alert("Signin error: " + e.message );
});

View File

@@ -91,7 +91,7 @@ habitrpg.controller('ChatCtrl', ['$scope', 'Groups', 'Chat', 'User', '$http', 'A
$scope.flagChatMessage = function(groupId,message) {
if(!message.flags) message.flags = {};
if (message.flags[User.user._id]) {
if (!User.user.contributor.admin && message.flags[User.user._id]) {
Notification.text(window.env.t('abuseAlreadyReported'));
} else {
$scope.abuseObject = message;

View File

@@ -49,9 +49,11 @@ habitrpg
};
$scope.reportAbuse = function(reporter, message, groupId) {
message.flags[reporter._id] = true;
Chat.flagChatMessage(groupId, message.id)
.then(function(data){
var res = data.data.data;
message.flags = res.flags;
message.flagCount = res.flagCount;
Notification.text(window.env.t('abuseReported'));
$scope.$close();
});

View File

@@ -2,14 +2,17 @@
// Make user and settings available for everyone through root scope.
habitrpg.controller('SettingsCtrl',
['$scope', 'User', '$rootScope', '$http', 'ApiUrl', 'Guide', '$location', '$timeout', 'Content', 'Notification', 'Shared', '$compile',
function($scope, User, $rootScope, $http, ApiUrl, Guide, $location, $timeout, Content, Notification, Shared, $compile) {
['$scope', 'User', '$rootScope', '$http', 'ApiUrl', 'Guide', '$location', '$timeout', 'Content', 'Notification', 'Shared', 'Social', '$compile',
function($scope, User, $rootScope, $http, ApiUrl, Guide, $location, $timeout, Content, Notification, Shared, Social, $compile) {
var RELEASE_ANIMAL_TYPES = {
pets: 'releasePets',
mounts: 'releaseMounts',
both: 'releaseBoth',
};
var SOCIAL_AUTH_NETWORKS = Shared.constants.SUPPORTED_SOCIAL_NETWORKS;
$scope.SOCIAL_AUTH_NETWORKS = SOCIAL_AUTH_NETWORKS;
// FIXME we have this re-declared everywhere, figure which is the canonical version and delete the rest
// $scope.auth = function (id, token) {
// User.authenticate(id, token, function (err) {
@@ -287,6 +290,40 @@ habitrpg.controller('SettingsCtrl',
return Math.floor(numberOfHourglasses);
};
$scope.hasBackupAuthOption = function(user, checkedNetworkKey) {
if (user.auth.local.username) {
return true;
}
return _.find(SOCIAL_AUTH_NETWORKS, function (network) {
if (network.key !== checkedNetworkKey) {
if (user.auth.hasOwnProperty(network.key)) {
return user.auth[network.key].id;
}
}
});
};
$scope.hasSocialAuth = function (user) {
return _.find(SOCIAL_AUTH_NETWORKS, function (network) {
if (user.auth.hasOwnProperty(network.key)) {
return user.auth[network.key].id;
}
});
};
$scope.deleteSocialAuth = function (networkKey) {
var network = _.find(SOCIAL_AUTH_NETWORKS, function (network) {
return network.key === networkKey;
});
$http.delete(ApiUrl.get() + "/api/v3/user/auth/social/"+networkKey).success(function(){
Notification.text(env.t("detachedSocial", {network: network.name}));
User.sync();
});
};
$scope.socialLogin = Social.socialLogin;
function _calculateNextCron() {
$scope.dayStart;

View File

@@ -0,0 +1,32 @@
'use strict';
(function(){
angular
.module('habitrpg')
.factory('Alert', alertFactory);
alertFactory.$inject = [
'$window'
];
function alertFactory($window) {
function authErrorAlert(data, status, headers, config) {
if (status === 0) {
$window.alert(window.env.t('noReachServer'));
} else if (status === 400 && data.errors && _.isArray(data.errors)) { // bad requests
data.errors.forEach(function (err) {
$window.alert(err.message);
});
} else if (!!data && !!data.error) {
$window.alert(data.message);
} else {
$window.alert(window.env.t('errorUpCase') + ' ' + status);
}
};
return {
authErrorAlert: authErrorAlert,
}
}
}());

View File

@@ -0,0 +1,28 @@
'use strict';
(function(){
angular
.module('habitrpg')
.factory('Auth', authFactory);
authFactory.$inject = [
'$window',
'User',
'Analytics'
];
function authFactory($window, User, Analytics) {
var runAuth = function(id, token) {
User.authenticate(id, token, function(err) {
Analytics.login();
Analytics.updateUser();
$window.location.href = ('/' + window.location.hash);
});
};
return {
runAuth: runAuth,
}
}
}());

View File

@@ -82,11 +82,11 @@ function($rootScope, User, $timeout, $state, Analytics) {
}, {
element: ".meter.mana",
title: window.env.t('spells'),
content: window.env.t('spellsText') + " <a target='_blank' href='http://habitica.wikia.com/wiki/Todos'>" + window.env.t('toDo') + "</a>."
content: window.env.t('spellsText')
}, {
orphan: true,
title: window.env.t('readMore'),
content: window.env.t('moreClass') + " <a href='http://habitica.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
content: window.env.t('moreClass'),
final: true
}
]

View File

@@ -5,9 +5,11 @@
.module('habitrpg')
.factory('Social', socialFactory);
socialFactory.$inject = [];
socialFactory.$inject = [
'$http','ApiUrl', 'Alert', 'Auth'
];
function socialFactory() {
function socialFactory($http, ApiUrl, Alert, Auth) {
function loadWidgets() {
// Facebook
@@ -34,8 +36,27 @@
}
}
hello.init({
facebook : window.env.FACEBOOK_KEY,
google : window.env.GOOGLE_CLIENT_ID
});
function socialLogin(network){
hello(network).login({scope:['email']}).then(function(auth){
$http.post(ApiUrl.get() + "/api/v3/user/auth/social", auth)
.success(function(res, status, headers, config) {
Auth.runAuth(res.data.id, res.data.apiToken);
}).error(Alert.authErrorAlert);
}, function( err ){
alert("Signin error: " + err.message );
});
};
return {
loadWidgets: loadWidgets
loadWidgets: loadWidgets,
socialLogin: socialLogin
}
}
}());

View File

@@ -254,7 +254,7 @@ angular.module('habitrpg')
Notification.crit(critBonus);
}
if (quest && user.party.quest) {
if (quest && user.party.quest && user.party.quest.key) {
var userQuest = Content.quests[user.party.quest.key];
if (quest.progressDelta && userQuest.boss) {
Notification.quest('questDamage', quest.progressDelta.toFixed(1));

View File

@@ -42,6 +42,8 @@
"js/config.js",
"js/services/sharedServices.js",
"js/services/alertServices.js",
"js/services/authServices.js",
"js/services/notificationServices.js",
"js/directives/directives.js",
"js/services/analyticsServices.js",
@@ -134,7 +136,9 @@
"js/env.js",
"js/static.js",
"js/services/alertServices.js",
"js/services/analyticsServices.js",
"js/services/authServices.js",
"js/services/notificationServices.js",
"js/services/userNotificationsService.js",
"js/services/userServices.js",
@@ -172,7 +176,9 @@
"js/env.js",
"js/static.js",
"js/services/alertServices.js",
"js/services/analyticsServices.js",
"js/services/authServices.js",
"js/services/notificationServices.js",
"js/services/sharedServices.js",
"js/services/socialServices.js",

View File

@@ -1,4 +1,5 @@
{
"presets": ["es2015"],
"plugins": ["transform-object-rest-spread"],
"comments": false
}

22
website/client/app.vue Normal file
View File

@@ -0,0 +1,22 @@
<!-- Entry point component for the entire app -->
<template lang="pug">
#app.ui.fluid.container
app-header
router-view.view
</template>
<script>
import AppHeader from './components/appHeader';
export default {
components: {
AppHeader,
},
};
</script>
<style lang="less">
// Load CSS that doesn't belong to any specific component
@import './assets/less/index';
</style>

View File

@@ -0,0 +1,3 @@
// CSS that doesn't belong to any specific Vue compoennt
@import './semantic-ui/semantic.less';
@import './loading-screen';

View File

@@ -0,0 +1,4 @@
// Rendered outside Vue
#loading-screen {
height: 100%;
}

View File

@@ -79,8 +79,8 @@
/* Path to theme packages */
@themesFolder : 'themes';
/* Path to site override folder */
@siteFolder : '../../website/client/assets/semantic-ui/site';
/* Path to site override folder - relative to node_modules/semantic-ui */
@siteFolder : '../../website/client/assets/less/semantic-ui/site';
/*******************************

View File

@@ -1,34 +0,0 @@
<template lang="pug">
#app.ui.fluid.container
site-header
p Welcome back {{user.profile.name}}!
ul
li
router-link(to='/') Home
li
router-link(to='/page') Another Page
router-view.view
</template>
<script>
import SiteHeader from './siteHeader';
import { mapState } from 'vuex';
export default {
components: {
SiteHeader,
},
computed: mapState(['user']),
};
</script>
<style lang="less">
@import '../assets/semantic-ui/semantic.less';
// Element is rendered outside of Vue because it cannot wait for JS to be loaded
// Placing CSS here so it benefits from pre-processing
#loading-screen {
height: 100%;
}
</style>

View File

@@ -1,14 +1,18 @@
<template lang="pug">
h1 {{ title }}
#app-header
h1 {{title}}
ul
li
router-link(to='/') Home
li
router-link(to='/page') Another Page
</template>
<script>
import { mapState } from 'vuex';
import { mapState } from '../store';
export default {
computed: mapState([
'title',
]),
computed: mapState(['title']),
};
</script>

View File

@@ -1,13 +1,24 @@
<template lang="pug">
p {{ msg }}
div
p {{ msg }}
p Welcome back {{profileName}}!
p You have {{tasksCount}} tasks!
</template>
<script>
import { mapState, mapGetters } from '../store';
export default {
data () {
return {
msg: 'You\'re on the Home page!',
};
},
computed: {
...mapState({
tasksCount: (state) => state.tasks.length,
}),
...mapGetters(['profileName']),
},
};
</script>

View File

@@ -3,15 +3,13 @@
require('babel-polyfill');
import Vue from 'vue';
import VuexRouterSync from 'vuex-router-sync';
import VueResource from 'vue-resource';
import AppComponent from './components/app';
import AppComponent from './app';
import router from './router';
import store from './vuex/store';
Vue.use(VueResource);
import store from './store';
// TODO just for the beginning
Vue.use(VueResource);
let authSettings = localStorage.getItem('habit-mobile-settings');
@@ -21,12 +19,8 @@ if (authSettings) {
Vue.http.headers.common['x-api-key'] = authSettings.auth.apiToken;
}
// Sync Vuex and Router
VuexRouterSync.sync(store, router);
const app = new Vue({ // eslint-disable-line no-new
const app = new Vue({
router,
store,
render: h => h(AppComponent),
mounted () { // Remove the loading screen when the app is mounted
let loadingScreen = document.getElementById('loading-screen');
@@ -34,21 +28,23 @@ const app = new Vue({ // eslint-disable-line no-new
},
});
// Setup listener for title that is outside Vue's scope
// Setup listener for title
store.watch(state => state.title, (title) => {
document.title = title;
});
// Mount the app when the user is loaded
let userWatcher = store.watch(state => state.user, (user) => {
if (user && user._id) {
userWatcher(); // remove the watcher
// Mount the app when user and tasks are loaded
let userDataWatcher = store.watch(state => [state.user, state.tasks], ([user, tasks]) => {
if (user && user._id && tasks && tasks.length) {
userDataWatcher(); // remove the watcher
app.$mount('#app');
}
});
// Load the user
store.dispatch('fetchUser')
.catch(() => {
alert('Impossible to fetch user. Copy into localStorage a valid habit-mobile-settings object.');
});
// Load the user and the user tasks
Promise.all([
store.dispatch('fetchUser'),
store.dispatch('fetchUserTasks'),
]).catch(() => {
alert('Impossible to fetch user. Copy into localStorage a valid habit-mobile-settings object.');
});

View File

@@ -0,0 +1,25 @@
import Vue from 'vue';
export function setTitle (store, title) {
store.state.title = title;
}
export function fetchUser (store) {
let promise = Vue.http.get('/api/v3/user');
promise.then((response) => {
store.state.user = response.body.data;
});
return promise;
}
export function fetchUserTasks (store) {
let promise = Vue.http.get('/api/v3/tasks/user');
promise.then((response) => {
store.state.tasks = response.body.data;
});
return promise;
}

View File

@@ -0,0 +1,15 @@
export function profileName ({ state }) {
let userProfileName = state.user.profile && state.user.profile.name;
if (!userProfileName) {
if (state.user.auth.local && state.user.auth.local.username) {
userProfileName = state.user.auth.local.username;
} else if (state.user.auth.facebook) {
userProfileName = state.user.auth.facebook.displayName || state.user.auth.facebook.username;
} else {
userProfileName = 'Anonymous';
}
}
return userProfileName;
}

View File

@@ -0,0 +1,67 @@
/* The MIT License (MIT)
Copyright (c) 2015-2016 Evan You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
--------------------------------------------------------------------------
mapState, mapGetters and mapActions taken from Vuex v2.0.0-rc.6 as they're compatible with our
store implementation. mapMutations is not present because we do not use mutations.
Source code https://github.com/vuejs/vuex/blob/v2.0.0-rc.6/src/helpers.js
The code has been slightly changed to match our code style.
*/
function normalizeMap (map) {
return Array.isArray(map) ?
map.map(key => ({ key, val: key })) :
Object.keys(map).map(key => ({ key, val: map[key] }));
}
export function mapState (states) {
const res = {};
normalizeMap(states).forEach(({ key, val }) => {
res[key] = function mappedState () {
return typeof val === 'function' ?
val.call(this, this.$store.state, this.$store.getters) :
this.$store.state[val];
};
});
return res;
}
export function mapGetters (getters) {
const res = {};
normalizeMap(getters).forEach(({ key, val }) => {
res[key] = function mappedGetter () {
return this.$store.getters[val];
};
});
return res;
}
export function mapActions (actions) {
const res = {};
normalizeMap(actions).forEach(({ key, val }) => {
res[key] = function mappedAction (...args) {
return this.$store.dispatch.apply(this.$store, [val].concat(args)); // eslint-disable-line prefer-spread
};
});
return res;
}

View File

@@ -0,0 +1,76 @@
import Vue from 'vue';
import state from './state';
import * as actions from './actions';
import * as getters from './getters';
// Central application store for Habitica
// Heavily inspired to Vuex (https://github.com/vuejs/vuex) with a very
// similar internal implementation (thanks!), main difference is the absence of mutations.
// Create a Vue instance (defined below) detatched from any DOM element to handle app data
let _vm;
// The actual store interface
const store = {
// App wide computed properties, calculated as computed properties in the internal VM
getters: {},
// Return the store's state
get state () {
return _vm.$data.state;
},
// Actions should be called using store.dispatch(ACTION_NAME, ...ARGS)
// They get passed the store instance and any additional argument passed to dispatch()
dispatch (type, ...args) {
let action = actions[type];
if (!action) throw new Error(`Action "${type}" not found.`);
return action(store, ...args);
},
// Watch data on the store's state
// Internally it uses vm.$watch and accept the same argument except
// for the first one that must be a getter function to which the state is passed
// For documentation see https://vuejs.org/api/#vm-watch
watch (getter, cb, options) {
if (typeof getter !== 'function') {
throw new Error('The first argument of store.watch must be a function.');
}
return _vm.$watch(() => getter(state), cb, options);
},
};
// Setup getters
const _computed = {};
Object.keys(getters).forEach(key => {
let getter = getters[key];
// Each getter is compiled to a computed property on the internal VM
_computed[key] = () => getter(store);
Object.defineProperty(store.getters, key, {
get: () => _vm[key],
});
});
// Setup internal Vue instance to make state and getters reactive
_vm = new Vue({
data: { state },
computed: _computed,
});
export default store;
export {
mapState,
mapGetters,
mapActions,
} from './helpers';
// Inject the store into all components as this.$store
Vue.mixin({
beforeCreate () {
this.$store = store;
},
});

View File

@@ -0,0 +1,7 @@
const state = {
title: 'Habitica',
user: null,
tasks: null, // user tasks
};
export default state;

View File

@@ -1,15 +0,0 @@
import Vue from 'vue';
export function setTitle (store, title) {
store.commit('SET_TITLE', title);
}
export function fetchUser (store) {
let promise = Vue.http.get('/api/v3/user');
promise.then(response => {
store.commit('SET_USER', response.body.data);
});
return promise;
}

View File

@@ -1,7 +0,0 @@
export function SET_TITLE (state, title) {
state.title = title;
}
export function SET_USER (state, userJson) {
state.user = userJson;
}

View File

@@ -1,17 +0,0 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as mutations from './mutations';
import * as actions from './actions';
Vue.use(Vuex);
const state = {
title: 'Habitica',
user: {},
};
export default new Vuex.Store({
state,
mutations,
actions,
});

View File

@@ -195,5 +195,12 @@
"backgroundFarmhouseText": "Ферма",
"backgroundFarmhouseNotes": "Поздравете животните по пътя към фермата.",
"backgroundOrchardText": "Овощна градина",
"backgroundOrchardNotes": "Откъснете си плод от овощна градина."
"backgroundOrchardNotes": "Откъснете си плод от овощна градина.",
"backgrounds102016": "КОМПЛЕКТ 29: октомври 2016 г.",
"backgroundSpiderWebText": "Паяжина",
"backgroundSpiderWebNotes": "Оплетете се в паяжина.",
"backgroundStrangeSewersText": "Странни канали",
"backgroundStrangeSewersNotes": "Промъкнете се през странните канали",
"backgroundRainyCityText": "Дъждовен град",
"backgroundRainyCityNotes": "Скачайте в локвите в дъждовен град"
}

View File

@@ -11,6 +11,7 @@
"unsubChallenge": "Повредена връзка на предизвикателство: тази задача е била част от предизвикателство, но Вие сте се отписали от него. Какво искате да направите с останалите задачи?",
"challengeWinner": "Беше победител в следните предизвикателства",
"challenges": "Предизвикателства",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"noChallenges": "Все още няма предизвикателства. Посетете",
"toCreate": "за да създадете.",
"selectWinner": "Изберете победител и завършете предизвикателството:",

View File

@@ -162,7 +162,7 @@
"commGuideLink01description": "гилдия, в която новите потребители могат да задават въпросите си!",
"commGuideLink02": "Гилдията на Задния ъгъл",
"commGuideLink02description": "гилдия за обсъждане на дълги или чувствителни теми.",
"commGuideLink03": "Уикито",
"commGuideLink03": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>",
"commGuideLink03description": "най-изчерпателната информация за Хабитика.",
"commGuideLink04": "GitHub",
"commGuideLink04description": "за докладване на проблеми или помощ с програмирането!",

View File

@@ -54,8 +54,10 @@
"playerTiers": "Нива на играчите",
"tier": "Ниво",
"visitHeroes": "Посетете залата на героите (сътрудници и дарители)",
"conLearn": "Научете повече относно наградите за сътрудниците",
"conLearn": "<a href='http://habitica.wikia.com/wiki/Contributor_Rewards' target='_blank'>Learn more about contributor rewards</a>",
"conLearnHow": "Научете как да допринесете за развитието на Хабитика",
"conLearnURL": "http://habitica.wikia.com/wiki/Contributing_to_Habitica",
"conRewardsURL": "http://habitica.wikia.com/wiki/Contributor_Rewards",
"surveysSingle": "Помогнал(а) за развитието на Хабитика чрез попълване на въпросник или включване в мащабно организирано изпитание. Благодарим Ви!",
"surveysMultiple": "Помогнал(а) за развитието на Хабитика <%= surveys %> пъти, чрез попълване на въпросник или включване в мащабно организирано изпитание. Благодарим Ви!",
"currentSurvey": "Настоящо проучване",

View File

@@ -20,17 +20,17 @@
"chores": "Домакинска работа",
"clearBrowserData": "Изчистване на данните на браузъра",
"communityBug": "Докладване на проблем",
"communityExtensions": "Добавки и разширения",
"communityExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Add-ons & Extensions</a>",
"communityFacebook": "Фейсбук",
"communityFeature": "Предлагане на функционалност",
"communityForum": "Форум",
"communityForum": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Forum</a>",
"communityKickstarter": "Кикстартер",
"communityReddit": "Редит",
"companyAbout": "Как работи",
"companyBlog": "Блог",
"devBlog": "Блог на разработчиците",
"companyDonate": "Дарете",
"companyExtensions": "Разширения",
"companyExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Extensions</a>",
"companyPrivacy": "Поверителност",
"companyTerms": "Условия",
"companyVideos": "Видеоклипове",
@@ -95,7 +95,8 @@
"leadText": "Хабитика е безплатно приложение за продуктивност и изграждане на навици, което превръща живота Ви в игра. Хабитика Ви помага да постигнете целите си и да живеете по-здравословно, да работите по-концентрирано и да сте по-щастлив(а), като Ви мотивира чрез награди и наказания и Ви осигурява силна общност, която да Ви насърчава.",
"login": "Вход",
"loginAndReg": "Вход / регистрация",
"loginFacebookAlt": "Вход / регистрация с Фейсбук",
"loginFacebookAlt": "Sign in with Facebook",
"loginGoogleAlt": "Sign in with Google",
"logout": "Изход",
"marketing1Header": "Подобрете навиците си докато играете",
"marketing1Lead1": "Хабитика е видео игра, която Ви помага да подобрите навиците си в истинския живот. Тя превръща живота Ви в игра като преобразява всички Ваши задачи (навици, ежедневни задачи и списъци със задачи за изпълнение) в малки чудовища, които трябва да победите. Колкото по-добре се справяте с тях, толкова повече напредвате в играта. Ако направите грешна стъпка в реалния живот, Вашият герой получава щети в играта.",
@@ -258,8 +259,8 @@
"invalidLoginCredentialsLong": "Опа, потребителското име или паролата е грешна.\n— Уверете се, че потребителското име или е-пощата е написана правилно;\n— Може да сте се вписали чрез Фейсбук, а не чрез е-поща. Проверете това, като опитате да влезете чрез Фейсбук;\n— Ако сте забравили паролата си, щракнете „Забравена парола“.",
"invalidCredentials": "Няма профил, който използва тези данни за вход.",
"accountSuspended": "Профилът беше временно блокиран. Моля, свържете се с leslie@habitica.com за помощ, посочвайки своя потребителски идентификатор: „<%= userId %>“.",
"onlyFbSupported": "В момента се поддържа само Фейсбук.",
"cantDetachFb": "Профилът няма друг начин за удостоверяване, така че Фейсбук не може да бъде разкачен.",
"unsupportedNetwork": "This network is not currently supported.",
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",
"onlySocialAttachLocal": "Местното удостоверяване може да бъде добавено само към профил от социална мрежа.",
"invalidReqParams": "Грешни параметри на заявката.",
"memberIdRequired": "„member“ трябва да бъде правилно форматиран идентификатор UUID.",

View File

@@ -166,14 +166,14 @@
"weaponSpecialSummer2016MageNotes": "Цялата мощ на моретата е съсредоточена в този скиптър. Увеличава интелигентността с <%= int %> и усета с <%= per %>. Ограничена серия: Лятна екипировка 2016 г.",
"weaponSpecialSummer2016HealerText": "Лечебен тризъбец",
"weaponSpecialSummer2016HealerNotes": "Един шип наранява, друг лекува. Увеличава интелигентността с <%= int %>. Ограничена серия: Лятна екипировка 2016 г.",
"weaponSpecialFall2016RogueText": "Spiderbite Dagger",
"weaponSpecialFall2016RogueNotes": "Feel the sting of the spider's bite! Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
"weaponSpecialFall2016WarriorText": "Attacking Roots",
"weaponSpecialFall2016WarriorNotes": "Attack your tasks with these twisting roots! Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
"weaponSpecialFall2016MageText": "Ominous Orb",
"weaponSpecialFall2016MageNotes": "Don't ask this orb to tell your future... Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
"weaponSpecialFall2016HealerText": "Venomous Serpent",
"weaponSpecialFall2016HealerNotes": "One bite harms, and another bite heals. Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
"weaponSpecialFall2016RogueText": "Паякова кама",
"weaponSpecialFall2016RogueNotes": "Усетете отровата на захапката на паяка! Увеличава силата с <%= str %>. Ограничена серия: Есенна екипировка 2016 г.",
"weaponSpecialFall2016WarriorText": "Нападателни корени",
"weaponSpecialFall2016WarriorNotes": "Нападнете задачите си с тези усукани корени! Увеличава силата с <%= str %>. Ограничена серия: Есенна екипировка 2016 г.",
"weaponSpecialFall2016MageText": "Злокобно кълбо",
"weaponSpecialFall2016MageNotes": "Не се опитвайте да видите бъдещето си в това кълбо… Увеличава интелигентността с <%= int %> и усета с <%= per %>. Ограничена серия: Есенна екипировка 2016 г.",
"weaponSpecialFall2016HealerText": "Отровна змия",
"weaponSpecialFall2016HealerNotes": "Едно ухапване ранява, друго лекува. Увеличава интелигентността с <%= int %>. Ограничена серия: Есенна екипировка 2016 г.",
"weaponMystery201411Text": "Вилица на изобилието",
"weaponMystery201411Notes": "Наръгайте враговете си или си боцнете от любимата храна — тази универсална вилица може всичко! не променя атрибутите. Предмет за абонати: ноември 2014 г.",
"weaponMystery201502Text": "Блестящият крилат скиптър на любовта и истината",
@@ -220,6 +220,8 @@
"weaponArmoireCannonNotes": "Грр! Насочете се към целите си с увереност. Увеличава силата с <%= str %>. Омагьосан гардероб: Артилерийски комплект (предмет 1 от 3).",
"weaponArmoireVermilionArcherBowText": "Цинобърен стрелкови лък",
"weaponArmoireVermilionArcherBowNotes": "Стрелата Ви ще се изстрелва от този лък като падаща звезда! Увеличава силата с <%= str %>. Омагьосан гардероб: Цинобърен стрелкови комплект (предмет 1 от 3).",
"weaponArmoireOgreClubText": "Огрова тояга",
"weaponArmoireOgreClubNotes": "Тази тояга е отмъкната от пещера на истински огър. Увеличава силата с <%= str %>. Омагьосан гардероб: комплект „Огър“ (предмет 2 от 3).",
"armor": "броня",
"armorCapitalized": "Броня",
"armorBase0Text": "Обикновени дрехи",
@@ -370,14 +372,14 @@
"armorSpecialSummer2016MageNotes": "Тези хлъзгави одежди превръщат собственика си си в истински делфин-магьосник! Увеличава интелигентността с <%= int %>. Ограничена серия: Лятна екипировка 2016 г.",
"armorSpecialSummer2016HealerText": "Опашка на морско конче",
"armorSpecialSummer2016HealerNotes": "Тези бодливи одежди превръщат собственика си в истинско морско конче-лечител! Увеличава якостта с <%= con %>. Ограничена серия: Лятна екипировка 2016 г.",
"armorSpecialFall2016RogueText": "Black Widow Armor",
"armorSpecialFall2016RogueNotes": "The eyes on this armor are constantly blinking. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
"armorSpecialFall2016WarriorText": "Slime-Streaked Armor",
"armorSpecialFall2016WarriorNotes": "Mysteriously moist and mossy! Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
"armorSpecialFall2016MageText": "Cloak of Wickedness",
"armorSpecialFall2016MageNotes": "When your cloak flaps, you hear the sound of cackling laughter. Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
"armorSpecialFall2016HealerText": "Gorgon Robes",
"armorSpecialFall2016HealerNotes": "These robes are actually made of stone. How are they so comfortable? Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
"armorSpecialFall2016RogueText": "Броня на черна вдовица",
"armorSpecialFall2016RogueNotes": "Очите на тази броня мигат постоянно. Увеличава усета с <%= per %>. Ограничена серия: Есенна екипировка 2016 г.",
"armorSpecialFall2016WarriorText": "Броня със слузести следи",
"armorSpecialFall2016WarriorNotes": "Мистериозно влажна и мъхеста! Увеличава якостта с <%= con %>. Ограничена серия: Есенна екипировка 2016 г.",
"armorSpecialFall2016MageText": "Наметало на порочността",
"armorSpecialFall2016MageNotes": "Когато наметалото Ви изплющява, се чува зловещо кикотене. Увеличава интелигентността с <%= int %>. Ограничена серия: Есенна екипировка 2016 г.",
"armorSpecialFall2016HealerText": "Горгонски одежди",
"armorSpecialFall2016HealerNotes": "Тези одежди всъщност са направени от камък. Как така са толкова удобни? Увеличава якостта с <%= con %>. Ограничена серия: Есенна екипировка 2016 г.",
"armorMystery201402Text": "Одежди на вестоносец",
"armorMystery201402Notes": "Блестяща и здрава, тази дреха има много джобове за носене на писма. Не променя атрибутите. Предмет за абонати: февруари 2014 г.",
"armorMystery201403Text": "Броня на горски бродник",
@@ -422,8 +424,8 @@
"armorMystery201606Notes": "Тази силна опашка блести като разбиваща се в брега морска пяна. Не променя показателите. Предмет за абонати: юни 2016 г.",
"armorMystery201607Text": "Дънна мошеническа броня",
"armorMystery201607Notes": "Слейте се с морското дъно с тази потайна броня. Не променя атрибутите. Предмет за абонати: юли 2016 г.",
"armorMystery201609Text": "Cow Armor",
"armorMystery201609Notes": "Fit in with the rest of the herd in this snuggly armor! Confers no benefit. September 2016 Subscriber Item.",
"armorMystery201609Text": "Кравешка броня",
"armorMystery201609Notes": "Слейте се със стадото, с тази удобна броня! Не променя атрибутите. Предмет за абонати: септември 2016 г.",
"armorMystery301404Text": "Изтънчен костюм",
"armorMystery301404Notes": "Спретнат и елегантен! Не променя показателите. Предмет за абонати: февруари 3015 г.",
"armorArmoireLunarArmorText": "Успокояваща лунна броня",
@@ -464,6 +466,8 @@
"armorArmoireFalconerArmorNotes": "Пазете се от нокти с тази здрава броня! Увеличава якостта с <%= con %>. Омагьосан гардероб: Соколарски комплект (предмет 1 от 3).",
"armorArmoireVermilionArcherArmorText": "Цинобърна стрелкова броня",
"armorArmoireVermilionArcherArmorNotes": "Тази броня е изкована от специално омагьосан червен метал, за максимална защита, минимално ограничение на движението и максимален блясък! Увеличава усета с <%= per %>. Омагьосан гардероб: Цинобърен стрелкови комплект (предмет 2 от 3).",
"armorArmoireOgreArmorText": "Огрова броня",
"armorArmoireOgreArmorNotes": "Тази броня наподобява дебелата кожа на огър, но има втъкана вълна, за да е по-удобна за носене от хора!. Увеличава якостта с <%= con %>. Омагьосан гардероб: комплект „Огър“ (предмет 3 от 3).",
"headgear": "защита за главата",
"headgearCapitalized": "Защита за главата",
"headBase0Text": "Няма шлем",
@@ -612,14 +616,14 @@
"headSpecialSummer2016MageNotes": "Вълшебна вода струи неспирно от тази шапка. Увеличава усета с <%= per %>. Ограничена серия: Лятна екипировка 2016 г.",
"headSpecialSummer2016HealerText": "Шлем на морско конче",
"headSpecialSummer2016HealerNotes": "Този шлем показва, че собственикът му е бил обучен от вълшебните морски кончета-лечители от Мудноград. Увеличава интелигентността с <%= int %>. Ограничена серия: Лятна екипировка 2016 г.",
"headSpecialFall2016RogueText": "Black Widow Helm",
"headSpecialFall2016RogueNotes": "The legs on this helm are constantly twitching. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
"headSpecialFall2016WarriorText": "Gnarled Bark Helm",
"headSpecialFall2016WarriorNotes": "This swamp-sogged helm is covered with bits of bog. Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
"headSpecialFall2016MageText": "Hood of Wickedness",
"headSpecialFall2016MageNotes": "Conceal your plotting beneath this shadowy hood. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
"headSpecialFall2016HealerText": "Medusa's Crown",
"headSpecialFall2016HealerNotes": "Woe to anyone who looks you in the eyes... Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
"headSpecialFall2016RogueText": "Шлем на черна вдовица",
"headSpecialFall2016RogueNotes": "Краката на този шлем потрепват постоянно. Увеличава усета с <%= per %>. Ограничена серия: Есенна екипировка 2016 г.",
"headSpecialFall2016WarriorText": "Шлем от груба кора",
"headSpecialFall2016WarriorNotes": "Този подгизнал шлем е покрит с блатна мръсотия. Увеличава силата с <%= str %>. Ограничена серия: Есенна екипировка 2016 г.",
"headSpecialFall2016MageText": "Качулка на порочността",
"headSpecialFall2016MageNotes": "Прикрийте тайнствените си кроежи с тази сенчеста качулка. Увеличава усета с <%= per %>. Ограничена серия: Есенна екипировка 2016 г.",
"headSpecialFall2016HealerText": "Короната на Медуза",
"headSpecialFall2016HealerNotes": "Горко на онзи, който Ви погледне в очите… Увеличава интелигентността с <%= int %>. Ограничена серия: Есенна екипировка 2016 г.",
"headSpecialGaymerxText": "Боен шлем с цветовете на дъгата",
"headSpecialGaymerxNotes": "В чест на конференцията GaymerX, този специален шлем е оцветен с шарка на дъга! GaymerX е игрално изложение в чест на ЛГБТ културата и игрите, и е отворено за всички.",
"headMystery201402Text": "Крилат шлем",
@@ -664,8 +668,8 @@
"headMystery201607Notes": "Водораслите, растящи върху този шлем, са част от маскировката Ви. Не променя атрибутите. Предмет за абонати: юли 2016 г.",
"headMystery201608Text": "Светкавичен шлем",
"headMystery201608Notes": "Този пращящ шлем провежда електричество! Не променя атрибутите. Предмет за абонати: август 2016 г.",
"headMystery201609Text": "Cow Hat",
"headMystery201609Notes": "You'll never want to remooooove this cow hat. Confers no benefit. September 2016 Subscriber Item.",
"headMystery201609Text": "Кравешка шапка",
"headMystery201609Notes": "Няма да искате да свалите тази кравешка шапка. Не променя атрибутите. Предмет за абонати: септември 2016 г.",
"headMystery301404Text": "Украсен цилиндър",
"headMystery301404Notes": "Украсен цилиндър за най-изтънчените и високопоставени членове на обществото. Не променя атрибутите. Предмет за абонати: януари 3015 г.",
"headMystery301405Text": "Обикновен цилиндър",
@@ -724,6 +728,8 @@
"headArmoireFalconerCapNotes": "Тази весела шапка Ви помага да разбирате по-добре езика на птиците. Увеличава интелигентността с <%= int %>. Омагьосан гардероб: Соколарски комплект (предмет 2 от 3).",
"headArmoireVermilionArcherHelmText": "Цинобърен стрелкови шлем",
"headArmoireVermilionArcherHelmNotes": "Магическият рубин на този шлем ще Ви помага да се прицелвате като с лазер! Увеличава усета с <%= per %>. Омагьосан гардероб: Цинобърен стрелкови комплект (предмет 3 от 3).",
"headArmoireOgreMaskText": "Огрова маска",
"headArmoireOgreMaskNotes": "Враговете Ви ще бягат когато видят, че към тях се задава огър! Увеличава якостта, якостта и силата с по <%= attrs %>. Омагьосан гардероб: комплект „Огър“ (предмет 1 от 3).",
"offhand": "предмет за защитната ръка",
"offhandCapitalized": "Предмет за защитната ръка",
"shieldBase0Text": "Няма предмет в защитната ръка",
@@ -822,12 +828,12 @@
"shieldSpecialSummer2016WarriorNotes": "Захапете трудните задачи с този приличащ на зъб щит! Увеличава якостта с <%= con %>. Ограничена серия: Лятна екипировка 2016 г.",
"shieldSpecialSummer2016HealerText": "Звезден морски щит",
"shieldSpecialSummer2016HealerNotes": "Понякога неправилно наричан „щит-морска звезда“. Увеличава якостта с <%= con %>. Ограничена серия: Лятна екипировка 2016 г.",
"shieldSpecialFall2016RogueText": "Spiderbite Dagger",
"shieldSpecialFall2016RogueNotes": "Feel the sting of the spider's bite! Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
"shieldSpecialFall2016WarriorText": "Defensive Roots",
"shieldSpecialFall2016WarriorNotes": "Defend against Dailies with these writhing roots! Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
"shieldSpecialFall2016HealerText": "Gorgon Shield",
"shieldSpecialFall2016HealerNotes": "Don't admire your own reflection in this. Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
"shieldSpecialFall2016RogueText": "Паякова кама",
"shieldSpecialFall2016RogueNotes": "Усетете отровата на захапката на паяка! Увеличава силата с <%= str %>. Ограничена серия: Есенна екипировка 2016 г.",
"shieldSpecialFall2016WarriorText": "Защитни корени",
"shieldSpecialFall2016WarriorNotes": "Защитете се от ежедневните си задачи, с тези оплетени корени! Увеличава якостта с <%= con %>. Ограничена серия: Есенна екипировка 2016 г.",
"shieldSpecialFall2016HealerText": "Горгонски щит",
"shieldSpecialFall2016HealerNotes": "Не се оглеждайте в този щит. Увеличава якостта с <%= con %>. Ограничена серия: Есенна екипировка 2016 г.",
"shieldMystery201601Text": "Решителен убиец",
"shieldMystery201601Notes": "Това острие може да отблъсне всички разсейващи Ви неща. Не променя атрибутите. Предмет за абонати: януари 2016 г.",
"shieldMystery301405Text": "Часовников щит",

View File

@@ -3,6 +3,7 @@
"stringNotFound": "Текстът „<%= string %>“ не е намерен.",
"titleIndex": "Хабитика | Животът Ви, превърнат в ролева игра",
"habitica": "Хабитика",
"habiticaLink": "<a href='http://habitica.wikia.com/wiki/Habitica' target='_blank'>Habitica</a>",
"titleTasks": "Задачи",
"titleAvatar": "Герой",
"titleBackgrounds": "Фонови изображения",
@@ -75,6 +76,8 @@
"gems": "Диаманти",
"gemButton": "Имате <%= number %> диаманта.",
"moreInfo": "Повече информация",
"moreInfoChallengesURL": "http://habitica.wikia.com/wiki/Challenges",
"moreInfoTagsURL": "http://habitica.wikia.com/wiki/Tags",
"showMoreMore": "(повече)",
"showMoreLess": "(по-малко)",
"gemsWhatFor": "Щракнете за закупуване на диаманти! Диамантите служат за купуване на специални неща като мисии, персонализиране на героя и сезонна екипировка.",

View File

@@ -6,11 +6,12 @@
"innTextBroken": "Вие почивате в странноприемницата, предполагам… Докато сте вътре, ежедневните Ви задачи няма да Ви нараняват в края на деня, но ще продължат да се опресняват всеки ден… Ако участвате в мисия срещу главатар, той ще Ви наранява, когато членовете на групата Ви не изпълняват ежедневните си задачи… освен ако всички те не са също в странноприемницата! Освен това, докато не напуснете странноприемницата, Вашите щети срещу главатаря няма да бъдат прилагани, както и няма да получите събраните си предмети… толкова съм уморен…",
"lfgPosts": "Публикации за търсене на група",
"tutorial": "Инструктаж",
"glossary": "Речник",
"glossary": "<a target='_blank' href='http://habitica.wikia.com/wiki/Glossary'>Glossary</a>",
"wiki": "Уики",
"wikiLink": "<a target='_blank' href='http://habitica.wikia.com/'>Wiki</a>",
"reportAP": "Докладване на проблем",
"requestAF": "Предлагане на функционалност",
"community": "Форум на общността",
"community": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Community Forum</a>",
"dataTool": "Инструмент за показване на данните",
"resources": "Материали",
"askQuestionNewbiesGuild": "Задаване на въпрос (Новобранската гилдия)",
@@ -73,6 +74,7 @@
"createGuild": "Създаване на гилдия",
"guild": "Гилдия",
"guilds": "Гилдии",
"guildsLink": "<a href='http://habitica.wikia.com/wiki/Guilds' target='_blank'>Guilds</a>",
"sureKick": "Наистина ли искате да премахнете този член от групата/гилдията?",
"optionalMessage": "Незадължително съобщение",
"yesRemove": "Да, нека бъдат премахнати",
@@ -203,7 +205,7 @@
"exportInbox": "Изнасяне на съобщенията",
"exportInboxPopoverTitle": "Изнасяне на съобщенията Ви във формат HTML.",
"exportInboxPopoverBody": "Форматът HTML Ви позволява лесно да четете съобщенията си в браузър. Ако се нуждаете от формат, удобен за машинна обработка, използвайте Данни > Изнасяне на данни",
"to": "To:",
"from": "From:",
"to": "До:",
"from": "От:",
"desktopNotificationsText": "Нуждаем се от разрешението Ви да включим известията на работния плот за новите съобщения в груповия чат! Следвайте инструкциите на браузъра си, за да ги включите.<br><br>Ще получавате тези известия само когато страницата на Хабитика е отворена. Ако решите, че не Ви харесват, можете да ги изключите от настройките на браузъра си.<br><br>Тази кутийка ще се затвори автоматично след като вземете решение."
}

View File

@@ -75,10 +75,10 @@
"shipSoothsayerSet": "Корабен гадател (магьосник)",
"strappingSailorSet": "Намотаващ моряк (лечител)",
"reefRenegadeSet": "Рифов ренегат (мошеник)",
"scarecrowWarriorSet": "Scarecrow Warrior (Warrior)",
"stitchWitchSet": "Stitch Witch (Mage)",
"potionerSet": "Potioner (Healer)",
"battleRogueSet": "Bat-tle Rogue (Rogue)",
"scarecrowWarriorSet": "Плашило (воин)",
"stitchWitchSet": "Шиеща вещица (магьосник)",
"potionerSet": "Отвараджия (лечител)",
"battleRogueSet": "Мошеник с вратовръзка (мошеник)",
"fallEventAvailability": "Налично за купуване до 31-ви октомври.",
"winterEventAvailability": "Налично за купуване до 31-ви декември.",
"springEventAvailability": "Налично за купуване до 31-ви май.",

View File

@@ -62,9 +62,9 @@
"autoAllocate": "Автоматично разпределяне",
"autoAllocateText": "Ако автоматичното разпределение е избрано, героят Ви получава атрибути автоматично според атрибутите на задачите Ви, които можете да настроите в <strong>ЗАДАЧА > Редактиране > Разширени > Атрибути</strong>. Например: ако често посещавате фитнеса и към ежедневната Ви задача „Фитнес“ е заден атрибут „сила“, ще получавате сила автоматично.",
"spells": "Заклинания",
"spellsText": "Вече можете да отключвате класово-специфични заклинания. Ще видите първото си на ниво 11. Маната Ви се възстановява с по 10 точки на ден, плюс още по 1 точка за всяка завършена",
"spellsText": "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed <a target='_blank' href='http://habitica.wikia.com/wiki/Todos'>To-Do</a>.",
"toDo": "Задача",
"moreClass": "За повече информация относно класовете, вижте",
"moreClass": "For more information on the class-system, see <a href='http://habitica.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
"tourWelcome": "Добре дошли в Хабитика! Това е Вашият списък със задачи. Отметнете задача, за да продължите!",
"tourExp": "Добра работа! Отмятането на задача Ви носи опит и злато!",
"tourDailies": "Тази колона е за ежедневните задачи. За да продължите, добавете нещо, което трябва да правите всеки ден! <strong>Примерни ежедневни задачи</strong>: <strong>Да си оправя леглото</strong>, <strong>Да си изчистя зъбите с конец</strong>, <strong>Да проверя работната си е-поща</strong> и т.н.",
@@ -98,6 +98,7 @@
"tourHabitsBrief": "<strong>Добри и лоши навици</strong><ul><li>Добрите навици носят злато и опит;</li><li>Лошите навици отнемат здраве.</li></ul>",
"tourHabitsProceed": "Има логика!",
"tourRewardsBrief": "<strong>Списък с награди</strong><ul><li>Харчете спечеленото с труд злато тук!</li><li>Купувайте екипировка за героя си или създайте свои собствени награди.</li></ul>",
"tourRewardsArmoire": "<strong>Списък с награди</strong><ul><li>Харчете спечеленото с труд злато тук!</li><li>Купувайте екипировка за героя си, или вземете специална награда от Омагьосания гардероб, или създайте свои собствени награди.</li></ul>",
"tourRewardsProceed": "Това е всичко!",
"welcomeToHabit": "Добре дошли в Хабитика!",
"welcome1": "Създайте си обикновен герой.",

View File

@@ -26,6 +26,8 @@
"pending": "В очакване",
"questStart": "След като всички членове приемат или откажат, мисията започва. Само тези, които са приели, ще могат да участват в мисията и да получат плячка. Ако някои се бавят твърде много, притежателят на свитъка може да започне без тях като натисне „Започване“. Притежателят на свитъка също така може да прекрати мисията като натисне „Отказ“, при което ще си запази свитъка.",
"questStartBroken": "След като всички членове приемат или откажат, мисията започва… Само тези, които са приели, ще могат да участват в мисията и да получат плячка… Ако някои се бавят твърде много, притежателят на свитъка може да започне без тях като натисне „Започване“… Притежателят на свитъка също така може да прекрати мисията като натисне „Отказ“, при което ще си запази свитъка…",
"questCollection": "Намерени предмети от мисия: +<%= val %>",
"questDamage": "Щети за главатаря: +<%= val %>",
"begin": "Започване",
"bossHP": "Здраве на главатаря",
"bossStrength": "Сила на главатаря",

View File

@@ -91,8 +91,8 @@
"passwordSuccess": "Паролата е променена успешно",
"usernameSuccess": "Потребителското име е променено успешно",
"emailSuccess": "Е-пощата е променена успешно",
"detachFacebook": "Премахване на връзката с Фейсбук",
"detachedFacebook": "Връзката с Фейсбук беше премахната успешно от профила Ви",
"detachSocial": "De-register <%= network %>",
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
"addedLocalAuth": "Местното удостоверяване беше добавено успешно",
"data": "Данни",
"exportData": "Изнасяне на данни",
@@ -101,7 +101,8 @@
"emailChange3": "като упоменете стария и новия адрес на е-пощата си, както и потребителския си идентификатор.",
"usernameOrEmail": "Потребителско име или е-поща",
"email": "Е-поща",
"registeredWithFb": "Вие сте се регистрирали чрез Фейсбук",
"registerWithSocial": "Register with <%= network %>",
"registeredWithSocial": "Registered with <%= network %>",
"loginNameDescription1": "Това е името, което използвате за влизане в Хабитика. Отидете в",
"loginNameDescription2": "Потребител->Профил",
"loginNameDescription3": ", за да промените името, което се показва върху героя Ви и в съобщенията в чата.",

View File

@@ -111,7 +111,7 @@
"mysterySet201606": "Комплект одежди на селки",
"mysterySet201607": "Комплект на дънния мошеник",
"mysterySet201608": "Комплект на буреносника",
"mysterySet201609": "Cow Costume Set",
"mysterySet201609": "Комплект-костюм на крава",
"mysterySet301404": "Стандартен изтънчен комплект",
"mysterySet301405": "Комплект изтънчени принадлежности",
"mysterySetwondercon": "Wondercon",

View File

@@ -195,5 +195,12 @@
"backgroundFarmhouseText": "Statek",
"backgroundFarmhouseNotes": "Řekni ahoj zvířátkům po cestě na statek.",
"backgroundOrchardText": "Orchard",
"backgroundOrchardNotes": "Pick ripe fruit in an Orchard."
"backgroundOrchardNotes": "Pick ripe fruit in an Orchard.",
"backgrounds102016": "SET 29: Released October 2016",
"backgroundSpiderWebText": "Spider Web",
"backgroundSpiderWebNotes": "Get snagged in a Spider Web.",
"backgroundStrangeSewersText": "Strange Sewers",
"backgroundStrangeSewersNotes": "Slither through the Strange Sewers.",
"backgroundRainyCityText": "Rainy City",
"backgroundRainyCityNotes": "Splash through a Rainy City."
}

View File

@@ -11,6 +11,7 @@
"unsubChallenge": "Nefunkční odkaz na výzvu: tento úkol byl součástí výzvy, ze které jsi se odepsal. Co chceš dělat s osiřelými úkoly?",
"challengeWinner": "Stal se výhercem následujících výzev",
"challenges": "Výzvy",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"noChallenges": "Zatím nemáš žádné výzvy. Navštiv",
"toCreate": "abys nějakou vytvořil.",
"selectWinner": "Zvolit vítěze a zavřít výzvu:",
@@ -63,7 +64,7 @@
"hurray": "Hurá!",
"noChallengeOwner": "bez majitele",
"noChallengeOwnerPopover": "Tato Výzva nemá majitele, jelikož uživatel, který ji vytvořil, si smazal účet.",
"challengeMemberNotFound": "Uživatel nenalezen mezi členy výzvy",
"challengeMemberNotFound": "Uživatel nenalezen mezi členy skupiny.",
"onlyGroupLeaderChal": "Pouze vůdce družiny může začít výzvy",
"tavChalsMinPrize": "Cena za výzvu v krčmě musí být alespoň 1 drahokam.",
"cantAfford": "Nemůžete zadat tuto odměnu. Kupte si více drahokamů nebo snižte odměnu.",

View File

@@ -162,7 +162,7 @@
"commGuideLink01description": "cech pro nové uživatele, kde se mohou ptát na vše!",
"commGuideLink02": "Cech zadního koutku",
"commGuideLink02description": "cech pro dlouhé diskuze nebo diskuze na citlivá témata.",
"commGuideLink03": "Wiki",
"commGuideLink03": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>",
"commGuideLink03description": "největší sbírka informací o Habitica.",
"commGuideLink04": "GitHub",
"commGuideLink04description": "pro hlášení chyb a kódování programů!",

View File

@@ -54,8 +54,10 @@
"playerTiers": "Úrovně hráče",
"tier": "Úroveň",
"visitHeroes": "Navštiv Sál hrdinů (pomocníci a přispěvatelé)",
"conLearn": "Dozvi se více o odměnách přispěvatelům.",
"conLearn": "<a href='http://habitica.wikia.com/wiki/Contributor_Rewards' target='_blank'>Learn more about contributor rewards</a>",
"conLearnHow": "Jak přispět programu Habitica",
"conLearnURL": "http://habitica.wikia.com/wiki/Contributing_to_Habitica",
"conRewardsURL": "http://habitica.wikia.com/wiki/Contributor_Rewards",
"surveysSingle": "Pomohl zemi Habitica růst vyplněním dotazníků nebo usilovným testováním. Děkujeme vám!",
"surveysMultiple": "<%= surveys %> krát pomohl zemi Habitica růst vyplněním dotazníků nebo usilovným testováním. Děkujeme vám!",
"currentSurvey": "Aktuální dotazník",

View File

@@ -20,17 +20,17 @@
"chores": "Domácí práce",
"clearBrowserData": "Vyčistit data v prohlížeči",
"communityBug": "Nahlásit chybu",
"communityExtensions": "Dodatky a rozšíření",
"communityExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Add-ons & Extensions</a>",
"communityFacebook": "Facebook",
"communityFeature": "Zažádat o funkci",
"communityForum": "Fórum",
"communityForum": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Forum</a>",
"communityKickstarter": "Kickstarter",
"communityReddit": "Reddit",
"companyAbout": "Jak to funguje",
"companyBlog": "Blog",
"devBlog": "Vývojářský Blog",
"companyDonate": "Přispět",
"companyExtensions": "Rozšíření",
"companyExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Extensions</a>",
"companyPrivacy": "Soukromí",
"companyTerms": "Podmínky",
"companyVideos": "Videa",
@@ -95,7 +95,8 @@
"leadText": "Program Habitica je aplikace na vytváření zvyků a udržení produktivity, která ti z reálného života udělá hru. Díky odměnám a trestům budeš motivován, a silná sociální síť tě bude inspirovat. Habitica ti pomůže dosáhnout tvých cílů, ať už chceš být zdravý, pilný, nebo šťastný.",
"login": "Přihlásit",
"loginAndReg": "Přihlásit / Registrovat",
"loginFacebookAlt": "Přihlásit / Registrovat pomocí Facebooku",
"loginFacebookAlt": "Sign in with Facebook",
"loginGoogleAlt": "Sign in with Google",
"logout": "Odhlásit",
"marketing1Header": "Zlepšete své návyky hraním hry",
"marketing1Lead1": "Program Habitica je internetová hra, která zlepšuje návyky v reálném životě. Mění tvůj život v hru tím, že všechny tvé úkoly (zvyky, denní úkoly a úkoly v úkolníčku) přemění na malá \"monstra\", která musíš porazit. Čím lepší v tom budeš, tím dále budeš postupovat ve hře. Pokud se nebudeš snažit, tvá postava začne chřadnout.",
@@ -258,8 +259,8 @@
"invalidLoginCredentialsLong": "Uh-oh - your username or password is incorrect.\n- Make sure your username or email is typed correctly.\n- You may have signed up with Facebook, not email. Double-check by trying Facebook login.\n- If you forgot your password, click \"Forgot Password\".",
"invalidCredentials": "There is no account that uses those credentials.",
"accountSuspended": "Account has been suspended, please contact leslie@habitica.com with your User ID \"<%= userId %>\" for assistance.",
"onlyFbSupported": "Nyní je podporovaný pouze Facebook.",
"cantDetachFb": "Account lacks another authentication method, can't detach Facebook.",
"unsupportedNetwork": "This network is not currently supported.",
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",
"onlySocialAttachLocal": "Local authentication can be added to only a social account.",
"invalidReqParams": "Invalid request parameters.",
"memberIdRequired": "\"member\" musí být platné UUID.",

View File

@@ -220,6 +220,8 @@
"weaponArmoireCannonNotes": "Arr! Set your aim with determination. Increases Strength by <%= str %>. Enchanted Armoire: Cannoneer Set (Item 1 of 3).",
"weaponArmoireVermilionArcherBowText": "Vermilion Archer Bow",
"weaponArmoireVermilionArcherBowNotes": "Your arrow will fly like a shooting star from this brilliant red bow! Increases Strength by <%= str %>. Enchanted Armoire: Vermilion Archer Set (Item 1 of 3).",
"weaponArmoireOgreClubText": "Ogre Club",
"weaponArmoireOgreClubNotes": "This club was salvaged from an actual Ogre's lair. Increases Strength by <%= str %>. Enchanted Armoire: Ogre Outfit (Item 2 of 3).",
"armor": "zbroj",
"armorCapitalized": "Zbroj",
"armorBase0Text": "Obyčejné oblečení",
@@ -464,6 +466,8 @@
"armorArmoireFalconerArmorNotes": "Keep away talon attacks with this sturdy armor! Increases Constitution by <%= con %>. Enchanted Armoire: Falconer Set (Item 1 of 3).",
"armorArmoireVermilionArcherArmorText": "Vermilion Archer Armor",
"armorArmoireVermilionArcherArmorNotes": "This armor is made of a specially enchanted red metal for maximum protection, minimal restriction, and maximum flair! Increases Perception by <%= per %>. Enchanted Armoire: Vermilion Archer Set (Item 2 of 3).",
"armorArmoireOgreArmorText": "Ogre Armor",
"armorArmoireOgreArmorNotes": "This armor imitates an Ogre's tough skin, but it's lined with fleece for human comfort! Increases Constitution by <%= con %>. Enchanted Armoire: Ogre Outfit (Item 3 of 3).",
"headgear": "Pokrývka hlavy",
"headgearCapitalized": "Headgear",
"headBase0Text": "Žádná přilba",
@@ -724,6 +728,8 @@
"headArmoireFalconerCapNotes": "This jaunty cap helps you better understand birds of prey. Increases Intelligence by <%= int %>. Enchanted Armoire: Falconer Set (Item 2 of 3).",
"headArmoireVermilionArcherHelmText": "Vermilion Archer Helm",
"headArmoireVermilionArcherHelmNotes": "The magic ruby in this helm will help you aim with laser focus! Increases Perception by <%= per %>. Enchanted Armoire: Vermilion Archer Set (Item 3 of 3).",
"headArmoireOgreMaskText": "Ogre Mask",
"headArmoireOgreMaskNotes": "Your enemies will run for the hills when they see an Ogre coming their way! Increases Constitution and Strength by <%= attrs %> each. Enchanted Armoire: Ogre Outfit (Item 1 of 3).",
"offhand": "štít v ruce",
"offhandCapitalized": "Shield-Hand Item",
"shieldBase0Text": "Bez štítu v ruce",

View File

@@ -3,6 +3,7 @@
"stringNotFound": "Řetězec '<%= string %>' nenalezen.",
"titleIndex": "Habitica | Hra tvého života",
"habitica": "Habitica",
"habiticaLink": "<a href='http://habitica.wikia.com/wiki/Habitica' target='_blank'>Habitica</a>",
"titleTasks": "Úkoly",
"titleAvatar": "Postava",
"titleBackgrounds": "Pozadí",
@@ -75,6 +76,8 @@
"gems": "Drahokamy",
"gemButton": "Máš <%= number %> Drahokamy/Drahokamů",
"moreInfo": "Více informací",
"moreInfoChallengesURL": "http://habitica.wikia.com/wiki/Challenges",
"moreInfoTagsURL": "http://habitica.wikia.com/wiki/Tags",
"showMoreMore": "(zobrazit více)",
"showMoreLess": "(zobrazit méně)",
"gemsWhatFor": "Klikni pro nákup drahokamů! Za drahokamy si můžeš koupit speciální předměty jako Výpravy, vybavení avataru a sezónní vybavení.",

View File

@@ -6,11 +6,12 @@
"innTextBroken": "Odpočíváš v Hostinci, asi... Zatímco tu budeš, tvé Denní úkoly ti na konci dne nijak neublíží, ale vždy se resetují... Pokud jsi v boji s příšerou, ublíží ti nesplněné úkoly tvých přátel v družině... Pokud také nejsou v Hostinci... Navíc, jakákoliv újma, kterou uštědříš příšeře (nebo nasbírané předměty) se ti nepřipíšou dokud se z Hostince neodhlásíš... Jsem tak unavený...",
"lfgPosts": "Hledá se skupina (družina)",
"tutorial": "Průvodce",
"glossary": "Slovník",
"glossary": "<a target='_blank' href='http://habitica.wikia.com/wiki/Glossary'>Glossary</a>",
"wiki": "Wiki",
"wikiLink": "<a target='_blank' href='http://habitica.wikia.com/'>Wiki</a>",
"reportAP": "Nahlásit problém",
"requestAF": "Zažádat o funkci",
"community": "Fórum",
"community": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Community Forum</a>",
"dataTool": "Nástroj zobrazení dat",
"resources": "Zdroje",
"askQuestionNewbiesGuild": "Položit otázku (Cech nováčků - Newbies Guild)",
@@ -73,6 +74,7 @@
"createGuild": "Vytvořit cech",
"guild": "Cech",
"guilds": "Cechy",
"guildsLink": "<a href='http://habitica.wikia.com/wiki/Guilds' target='_blank'>Guilds</a>",
"sureKick": "Opravdu chceš tohoto člena vykopnout z družiny/cechu?",
"optionalMessage": "Nepovinná zpráva",
"yesRemove": "Ano, odstraň je",

View File

@@ -62,9 +62,9 @@
"autoAllocate": "Připisovat automaticky",
"autoAllocateText": "If 'automatic allocation' is checked, your avatar gains stats automatically based on your tasks' attributes, which you can find in <strong>TASK > Edit > Advanced > Attributes</strong>. Eg, if you hit the gym often, and your 'Gym' Daily is set to 'Strength', you'll gain Strength automatically.",
"spells": "Kouzla",
"spellsText": "Nyní můžeš odemknout kouzla specifická pro toto povolání. První uvidíš po dosažení úrovně 11. Tvá mana se dobíjí o 10 bodů denně, plus 1 bod při splnění",
"spellsText": "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed <a target='_blank' href='http://habitica.wikia.com/wiki/Todos'>To-Do</a>.",
"toDo": "úkolu",
"moreClass": "Pro více informací o systému povolání, přejdi na",
"moreClass": "For more information on the class-system, see <a href='http://habitica.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
"tourWelcome": "Vítej v zemi Habitica! Tohle tvůj Úkolníček. Odškrtni si úkol abys mohl pokračovat!",
"tourExp": "Skvělá práce! Odškrtnutí úkolu ti přidává Zkušenost a Zlaťáky!",
"tourDailies": "Tento sloupec je pro denní úkoly. Přidej sem úkol, který bys měl plnit každý den! <strong>Příklady denních úkolů</strong>: <strong>Ustlat postel</strong>, <strong>Použít dentální nit</strong>, <strong>Zkontrolovat pracovní e-mail</strong>",
@@ -98,6 +98,7 @@
"tourHabitsBrief": "<strong>Dobré zvyky a zlozvyky</strong><ul><li>Za splnění dobrých zvyků získáš Zlaťáky a Zkušenost.</li><li>Zlozvyky ti ublíží.</li></ul>",
"tourHabitsProceed": "To dává smysl!",
"tourRewardsBrief": "<strong>Seznam odměn</strong><ul><li>Tady můžeš utratit své těžce vydělané Zlaťáky!</li><li>Nakup si vybavení pro svého avatara, nebo si můžeš přidat své vlastní odměny.</li></ul>",
"tourRewardsArmoire": "<strong>Reward List</strong><ul><li>Spend your hard-earned Gold here!</li><li>Purchase Equipment for your avatar, get a random prize from the Enchanted Armoire, or set custom Rewards.</li></ul>",
"tourRewardsProceed": "To je vše!",
"welcomeToHabit": "Vítej v zemi Habitica!",
"welcome1": "Vytvoř si základní postavu.",

View File

@@ -26,6 +26,8 @@
"pending": "Nerozhodnuto",
"questStart": "Výprava začíná jakmile všichni členové výzvu přijmou či odmítnou. Pouze ti, kteří klikli na \"Přijmout\" se mohou výpravy zúčastnit a obdrží ceny. Pokud to některým uživatelům trvá příliš dlouho (nejsou aktivní?), majitel výpravy může začít bez nich kliknutím na \"Začít\". Majitel výpravy začal také může výpravu přerušit a získat tak zpět svitek výpravy kliknutím na \"Zrušit\".",
"questStartBroken": "Výprava začíná jakmile všichni členové výzvu přijmou či odmítnou... Pouze ti, kteří klikli na \"Přijmout\" se mohou výpravy zúčastnit a obdrží ceny... Pokud to některým uživatelům trvá příliš dlouho (nejsou aktivní?), majitel výpravy může začít bez nich kliknutím na \"Začít\"... Majitel výpravy začal také může výpravu přerušit a získat tak zpět svitek výpravy kliknutím na \"Zrušit\"...",
"questCollection": "+<%= val %> quest item(s) found",
"questDamage": "+<%= val %> damage to boss",
"begin": "Začít",
"bossHP": "Zdraví příšery",
"bossStrength": "Síla příšery",

View File

@@ -91,8 +91,8 @@
"passwordSuccess": "Heslo úspěšně změněno",
"usernameSuccess": "Přihlašovací jméno úspěšně změněno",
"emailSuccess": "Email úspěšně změněn",
"detachFacebook": "Odregistruj Facebook",
"detachedFacebook": "Facebook byl z tvého účtu úspěšně odstraněn",
"detachSocial": "De-register <%= network %>",
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
"addedLocalAuth": "Lokální ověření úspěšně přidáno",
"data": "Data",
"exportData": "Export dat",
@@ -101,7 +101,8 @@
"emailChange3": "spolu s tvým starým a novým emailem a tvým uživatelským ID.",
"usernameOrEmail": "Přihlašovací jméno nebo email",
"email": "Email",
"registeredWithFb": "Registrovaný přes Facebook",
"registerWithSocial": "Register with <%= network %>",
"registeredWithSocial": "Registered with <%= network %>",
"loginNameDescription1": "Tohle použiješ k přihlášení do země Habitica. Jdi na",
"loginNameDescription2": "Uživatel -> Profil",
"loginNameDescription3": "aby sis změnil jméno, které se objevuje u tvého avataru a zpráv v chatu.",

View File

@@ -195,5 +195,12 @@
"backgroundFarmhouseText": "Farmhouse",
"backgroundFarmhouseNotes": "Say hello to the animals on your way to the Farmhouse.",
"backgroundOrchardText": "Orchard",
"backgroundOrchardNotes": "Pick ripe fruit in an Orchard."
"backgroundOrchardNotes": "Pick ripe fruit in an Orchard.",
"backgrounds102016": "SET 29: Released October 2016",
"backgroundSpiderWebText": "Spider Web",
"backgroundSpiderWebNotes": "Get snagged in a Spider Web.",
"backgroundStrangeSewersText": "Strange Sewers",
"backgroundStrangeSewersNotes": "Slither through the Strange Sewers.",
"backgroundRainyCityText": "Rainy City",
"backgroundRainyCityNotes": "Splash through a Rainy City."
}

View File

@@ -11,6 +11,7 @@
"unsubChallenge": "Defekt udfordringslink: denne opgave var en del af en udfordring, som du ikke længere abonnerer på. Hvad vil du gøre med de gruppeløse opgaver?",
"challengeWinner": "Blev vinderen i de følgende udfordringer",
"challenges": "Udfordringer",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"noChallenges": "Ingen udfordringer endnu, besøg",
"toCreate": "for at oprette en.",
"selectWinner": "Vælg en vinder og luk udfordringen:",

View File

@@ -162,7 +162,7 @@
"commGuideLink01description": "en klan hvor nye brugere kan stille spørgsmål!",
"commGuideLink02": "Det Bagerste Hjørnes Klan",
"commGuideLink02description": "en klan til at diskutere lange eller følsomme emner.",
"commGuideLink03": "Wikien",
"commGuideLink03": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>",
"commGuideLink03description": "den største samling af information omkring Habitica",
"commGuideLink04": "GitHub",
"commGuideLink04description": "til fejlmeldinger eller hjælp med at kode programmer!",

View File

@@ -54,8 +54,10 @@
"playerTiers": "Spillertrin",
"tier": "Trin",
"visitHeroes": "Besøg Heltenes Sal (bidragsydere og støtter)",
"conLearn": "Lær mere om bidragsyderbelønninger",
"conLearn": "<a href='http://habitica.wikia.com/wiki/Contributor_Rewards' target='_blank'>Learn more about contributor rewards</a>",
"conLearnHow": "Lær hvordan du kan bidrage til Habitica",
"conLearnURL": "http://habitica.wikia.com/wiki/Contributing_to_Habitica",
"conRewardsURL": "http://habitica.wikia.com/wiki/Contributor_Rewards",
"surveysSingle": "Helped Habitica grow, either by filling out a survey or helping with a major testing effort. Thank you!",
"surveysMultiple": "Helped Habitica grow on <%= surveys %> occasions, either by filling out a survey or helping with a major testing effort. Thank you!",
"currentSurvey": "Nuværende Spørgeskema",

View File

@@ -20,17 +20,17 @@
"chores": "Pligter",
"clearBrowserData": "Ryd browserdata",
"communityBug": "Meddel fejl",
"communityExtensions": "Tilføjelser og udvidelser",
"communityExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Add-ons & Extensions</a>",
"communityFacebook": "Facebook",
"communityFeature": "Anmod om en funktion",
"communityForum": "Forum",
"communityForum": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Forum</a>",
"communityKickstarter": "Kickstarter",
"communityReddit": "Reddit",
"companyAbout": "Hvordan det Virker",
"companyBlog": "Blog",
"devBlog": "Developer Blog",
"companyDonate": "Donér",
"companyExtensions": "Udvidelser",
"companyExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Extensions</a>",
"companyPrivacy": "Fortrolighed",
"companyTerms": "Vilkår",
"companyVideos": "Videoer",
@@ -95,7 +95,8 @@
"leadText": "Habitica er en gratis app, der opbygger vaner og produktivitet ved at behandle dit liv som et spil. Habitica belønner og straffer dig i spillet så du bliver motiveret, og det levende sociale netværk inspirerer dig til at opnå dine mål og blive sund, hårdtarbejdende og lykkelig.",
"login": "Log ind",
"loginAndReg": "Log ind/ Registrer",
"loginFacebookAlt": "Log ind / registrer gennem Facebook",
"loginFacebookAlt": "Sign in with Facebook",
"loginGoogleAlt": "Sign in with Google",
"logout": "Log Ud",
"marketing1Header": "Forbedr dine vaner ved at spille et spil.",
"marketing1Lead1": "Habitica er et computerspil, der hjælper med at forbedre dine vaner i virkeligheden. Det gør dit liv til et spil ved at lave alle dine opgaver (Vaner, Daglige og To-Dos) indtil små monstre, du skal besejre. Jo bedre du er til dette, desto større fremskridt vil du gøre i spillet. Hvis du begår fejl i livet vil din karakter gå tilbage i spillet.",
@@ -258,8 +259,8 @@
"invalidLoginCredentialsLong": "Uh-oh - your username or password is incorrect.\n- Make sure your username or email is typed correctly.\n- You may have signed up with Facebook, not email. Double-check by trying Facebook login.\n- If you forgot your password, click \"Forgot Password\".",
"invalidCredentials": "There is no account that uses those credentials.",
"accountSuspended": "Account has been suspended, please contact leslie@habitica.com with your User ID \"<%= userId %>\" for assistance.",
"onlyFbSupported": "Only Facebook is supported currently.",
"cantDetachFb": "Account lacks another authentication method, can't detach Facebook.",
"unsupportedNetwork": "This network is not currently supported.",
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",
"onlySocialAttachLocal": "Local authentication can be added to only a social account.",
"invalidReqParams": "Invalid request parameters.",
"memberIdRequired": "\"member\" must be a valid UUID.",

View File

@@ -220,6 +220,8 @@
"weaponArmoireCannonNotes": "Arr! Set your aim with determination. Increases Strength by <%= str %>. Enchanted Armoire: Cannoneer Set (Item 1 of 3).",
"weaponArmoireVermilionArcherBowText": "Vermilion Archer Bow",
"weaponArmoireVermilionArcherBowNotes": "Your arrow will fly like a shooting star from this brilliant red bow! Increases Strength by <%= str %>. Enchanted Armoire: Vermilion Archer Set (Item 1 of 3).",
"weaponArmoireOgreClubText": "Ogre Club",
"weaponArmoireOgreClubNotes": "This club was salvaged from an actual Ogre's lair. Increases Strength by <%= str %>. Enchanted Armoire: Ogre Outfit (Item 2 of 3).",
"armor": "rustning",
"armorCapitalized": "Armor",
"armorBase0Text": "Almindeligt tøj",
@@ -464,6 +466,8 @@
"armorArmoireFalconerArmorNotes": "Keep away talon attacks with this sturdy armor! Increases Constitution by <%= con %>. Enchanted Armoire: Falconer Set (Item 1 of 3).",
"armorArmoireVermilionArcherArmorText": "Vermilion Archer Armor",
"armorArmoireVermilionArcherArmorNotes": "This armor is made of a specially enchanted red metal for maximum protection, minimal restriction, and maximum flair! Increases Perception by <%= per %>. Enchanted Armoire: Vermilion Archer Set (Item 2 of 3).",
"armorArmoireOgreArmorText": "Ogre Armor",
"armorArmoireOgreArmorNotes": "This armor imitates an Ogre's tough skin, but it's lined with fleece for human comfort! Increases Constitution by <%= con %>. Enchanted Armoire: Ogre Outfit (Item 3 of 3).",
"headgear": "hovedbeklædning",
"headgearCapitalized": "Headgear",
"headBase0Text": "Ingen Hjelm",
@@ -724,6 +728,8 @@
"headArmoireFalconerCapNotes": "This jaunty cap helps you better understand birds of prey. Increases Intelligence by <%= int %>. Enchanted Armoire: Falconer Set (Item 2 of 3).",
"headArmoireVermilionArcherHelmText": "Vermilion Archer Helm",
"headArmoireVermilionArcherHelmNotes": "The magic ruby in this helm will help you aim with laser focus! Increases Perception by <%= per %>. Enchanted Armoire: Vermilion Archer Set (Item 3 of 3).",
"headArmoireOgreMaskText": "Ogre Mask",
"headArmoireOgreMaskNotes": "Your enemies will run for the hills when they see an Ogre coming their way! Increases Constitution and Strength by <%= attrs %> each. Enchanted Armoire: Ogre Outfit (Item 1 of 3).",
"offhand": "skjoldhånds-udstyr",
"offhandCapitalized": "Shield-Hand Item",
"shieldBase0Text": "Intet Skjoldhånds-udstyr",

View File

@@ -3,6 +3,7 @@
"stringNotFound": "Strengen '<%= string %>' blev ikke fundet.",
"titleIndex": "Habitica | Dit Liv Som Rollespil",
"habitica": "Habitica",
"habiticaLink": "<a href='http://habitica.wikia.com/wiki/Habitica' target='_blank'>Habitica</a>",
"titleTasks": "Opgaver",
"titleAvatar": "Avatar",
"titleBackgrounds": "Baggrunde",
@@ -75,6 +76,8 @@
"gems": "Ædelsten",
"gemButton": "Du har <%= number %> Ædelsten.",
"moreInfo": "Mere Information",
"moreInfoChallengesURL": "http://habitica.wikia.com/wiki/Challenges",
"moreInfoTagsURL": "http://habitica.wikia.com/wiki/Tags",
"showMoreMore": "(vis mere)",
"showMoreLess": "(vis mindre)",
"gemsWhatFor": "Klik for at købe Ædelsten! Ædelsten giver dig mulighed for at købe specielle ting, såsom Quests, ændringer til din Avatar og sæson-udstyr.",

View File

@@ -6,11 +6,12 @@
"innTextBroken": "Du hviler på Kroen, går jeg ud fra... Mens du hviler på Kroen, tager du ikke skade fra daglige opgaver, men de bliver stadig nulstillet hver dag... Hvis du deltager i en Boss Quest, vil du stadig tage skade fra de daglige opgaver de andre i gruppen ikke får udført, med mindre de også er på Kroen... Derudover kan du ikke skade Bossen eller samle ting, før du forlader Kroen... du er så træt...",
"lfgPosts": "Leder efter Gruppe (Gruppe Søges) Poster",
"tutorial": "Vejledning",
"glossary": "Ordliste",
"glossary": "<a target='_blank' href='http://habitica.wikia.com/wiki/Glossary'>Glossary</a>",
"wiki": "Wiki",
"wikiLink": "<a target='_blank' href='http://habitica.wikia.com/'>Wiki</a>",
"reportAP": "Rapportér et Problem",
"requestAF": "Anmod om en Funktion",
"community": "Fællesskabsforum",
"community": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Community Forum</a>",
"dataTool": "Datavisningsværktøj",
"resources": "Ressourcer",
"askQuestionNewbiesGuild": "Stil et spørgsmål (Newbies Guild)",
@@ -73,6 +74,7 @@
"createGuild": "Opret Klan",
"guild": "Klan",
"guilds": "Klaner",
"guildsLink": "<a href='http://habitica.wikia.com/wiki/Guilds' target='_blank'>Guilds</a>",
"sureKick": "Vil du virkelig fjerne dette medlem fra gruppen/klanen?",
"optionalMessage": "Valgfri besked",
"yesRemove": "Ja, fjern dem",

View File

@@ -62,9 +62,9 @@
"autoAllocate": "Tildel automatisk",
"autoAllocateText": "If 'automatic allocation' is checked, your avatar gains stats automatically based on your tasks' attributes, which you can find in <strong>TASK > Edit > Advanced > Attributes</strong>. Eg, if you hit the gym often, and your 'Gym' Daily is set to 'Strength', you'll gain Strength automatically.",
"spells": "Fortryllelser",
"spellsText": "Du kan nu låse op for klasse-specifikke fortryllelser. Du vil se din første ved niveau 11. Dit mana vil blive genopfyldt med 10 point per dag, samt 1 point per færdiggjort",
"spellsText": "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed <a target='_blank' href='http://habitica.wikia.com/wiki/Todos'>To-Do</a>.",
"toDo": "To-Do",
"moreClass": "For mere information om klassesystemet, se",
"moreClass": "For more information on the class-system, see <a href='http://habitica.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
"tourWelcome": "Velkommen til Habitica! Dette er din To-Do-liste. Markér en opgave for at fortsætte!",
"tourExp": "Godt klaret! Når du markerer en opgave får du Erfaring og Guld!",
"tourDailies": "This column is for Daily tasks. To proceed, enter a task you should do every day! <strong>Sample Dailies</strong>: <strong>Make Bed</strong>, <strong>Floss</strong>, <strong>Check Work Email</strong>",
@@ -98,6 +98,7 @@
"tourHabitsBrief": "<strong>Gode og Dårlige Vaner</strong><ul><li>Gode Vaner giver guld og erfaring.</li><li>Dårlige Vaner giver skade.</li></ul>",
"tourHabitsProceed": "Det giver mening!",
"tourRewardsBrief": "<strong>Belønninger</strong><ul><li>Brug dit hårdt optjente guld her!</li><li>Køb udstyr til din avatar eller lav dine egne Belønninger.</li></ul>",
"tourRewardsArmoire": "<strong>Reward List</strong><ul><li>Spend your hard-earned Gold here!</li><li>Purchase Equipment for your avatar, get a random prize from the Enchanted Armoire, or set custom Rewards.</li></ul>",
"tourRewardsProceed": "Det var alt!",
"welcomeToHabit": "Velkommen til Habitica!",
"welcome1": "Lav en basis-avatar.",

View File

@@ -26,6 +26,8 @@
"pending": "Afventer",
"questStart": "Når alle medlemmer har enten accepteret eller afvist vil questen begynde. Kun dem, der har klikket \"acceptér\" vil kunne deltage i questen og modtage præmierne. Hvis medlemmer afventer for længe (måske er de inaktive?) kan quest-lederen starte questen uden dem ved at klikke \"Begynd\". Quest-lederen kan også afbryde questen og få quest-skriftrullen tilbage ved at klikke \"Afbryd\"",
"questStartBroken": "Når alle medlemmer har enten accepteret eller afvist vil questen begynde... Kun dem, der har klikket \"acceptér\" vil kunne deltage i questen og modtage præmierne. Hvis medlemmer afventer for længe (måske er de inaktive?) kan quest-lederen starte questen uden dem ved at klikke \"Begynd\"... Quest-lederen kan også afbryde questen og få quest-skriftrullen tilbage ved at klikke \"Afbryd\"...",
"questCollection": "+<%= val %> quest item(s) found",
"questDamage": "+<%= val %> damage to boss",
"begin": "Begynd",
"bossHP": "Boss Liv",
"bossStrength": "Boss-styrke",

View File

@@ -91,8 +91,8 @@
"passwordSuccess": "Dit Kodeord er skiftet",
"usernameSuccess": "Dit Loginnavn er nu ændret",
"emailSuccess": "Din Email er skiftet",
"detachFacebook": "Afregistrér Facebook",
"detachedFacebook": "Facebook er nu fjernet fra din konto",
"detachSocial": "De-register <%= network %>",
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
"addedLocalAuth": "Lokal godkendelse er nu aktiveret",
"data": "Data",
"exportData": "Eksportér Data",
@@ -101,7 +101,8 @@
"emailChange3": "hvor du inkluderer både din gamle og nye email-adresse, samt tid BrugerID",
"usernameOrEmail": "Loginnavn eller Email",
"email": "Email",
"registeredWithFb": "Registreret via Facebook",
"registerWithSocial": "Register with <%= network %>",
"registeredWithSocial": "Registered with <%= network %>",
"loginNameDescription1": "Dette er hvad du bruger til at logge ind på Habitica. Gå til",
"loginNameDescription2": "Bruger->Profil",
"loginNameDescription3": "for at ændre det navn, der vises på din avatar og i dine chatbeskeder.",

View File

@@ -195,5 +195,12 @@
"backgroundFarmhouseText": "Bauernhaus",
"backgroundFarmhouseNotes": "Schau auf dem Weg zum Bauernhaus bei den Tieren vorbei.",
"backgroundOrchardText": "Obstgarten",
"backgroundOrchardNotes": "Pflücke reife Früchte in einem Obstgarten."
"backgroundOrchardNotes": "Pflücke reife Früchte in einem Obstgarten.",
"backgrounds102016": "Set 29: Veröffentlicht im Oktober 2016",
"backgroundSpiderWebText": "Spinnennetz",
"backgroundSpiderWebNotes": "Hänge ein bisschen in einem Spinnennetz herum",
"backgroundStrangeSewersText": "Seltsame Kanalisation",
"backgroundStrangeSewersNotes": "Durch die Seltsame Kanalisation schlittern.",
"backgroundRainyCityText": "Verregnete Stadt",
"backgroundRainyCityNotes": "Durch die Verregnete Stadt planschen."
}

View File

@@ -11,6 +11,7 @@
"unsubChallenge": "Toter Wettbewerb-Link: Diese Aufgabe war Teil eines Wettbewerbs, aber Du hast aufgehört an diesem Wettbewerb teilzunehmen. Was soll mit den verwaisten Aufgaben geschehen?",
"challengeWinner": "Hat die folgenden Wettbewerbe gewonnen",
"challenges": "Wettbewerbe",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"noChallenges": "Keine Wettbewerbe gefunden, besuche",
"toCreate": "um einen Wettbewerb zu erstellen.",
"selectWinner": "Wähle einen Gewinner und beende den Wettbewerb.",

View File

@@ -162,7 +162,7 @@
"commGuideLink01description": "eine Gilde für neue Nutzer, um Fragen zu stellen!",
"commGuideLink02": "Die Back Corner-Gilde",
"commGuideLink02description": "eine Gilde für das Diskutieren von langen oder sensiblen Themen",
"commGuideLink03": "Das Wiki",
"commGuideLink03": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>",
"commGuideLink03description": "die größte Sammlung von Informationen über Habitica.",
"commGuideLink04": "GitHub",
"commGuideLink04description": "für Fehlermeldungen oder Hilfe Programme zu entwickeln!",

View File

@@ -54,8 +54,10 @@
"playerTiers": "Spielerstufen",
"tier": "Level",
"visitHeroes": "Besuche die Halle der Helden (Mitwirkende und Träger)",
"conLearn": "Erfahre mehr über Belohnungen für Mitwirkende",
"conLearn": "<a href='http://habitica.wikia.com/wiki/Contributor_Rewards' target='_blank'>Learn more about contributor rewards</a>",
"conLearnHow": "Erfahre, wie Du bei Habitica mitwirken kannst.",
"conLearnURL": "http://habitica.wikia.com/wiki/Contributing_to_Habitica",
"conRewardsURL": "http://habitica.wikia.com/wiki/Contributor_Rewards",
"surveysSingle": "Half Habitica zu wachsen, entweder durch das Ausfüllen einer Umfrage oder durch große Hilfe beim Testen. Danke!",
"surveysMultiple": "Half Habitica <%= surveys %> mal zu wachsen, durch das Ausfüllen einer Umfrage oder durch große Hilfe beim Testen. Danke!",
"currentSurvey": "Aktuelle Umfrage",

View File

@@ -20,17 +20,17 @@
"chores": "Arbeiten im Haushalt",
"clearBrowserData": "Browserdaten löschen",
"communityBug": "Bug mitteilen",
"communityExtensions": "Add-ons & Erweiterungen",
"communityExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Add-ons & Extensions</a>",
"communityFacebook": "Facebook",
"communityFeature": "Nach Feature fragen",
"communityForum": "Forum",
"communityForum": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Forum</a>",
"communityKickstarter": "Kickstarter",
"communityReddit": "Reddit",
"companyAbout": "Wie es funktioniert",
"companyBlog": "Blog",
"devBlog": "Entwicklerblog",
"companyDonate": "Spenden",
"companyExtensions": "Erweiterungen",
"companyExtensions": "<a href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations' target='_blank'>Extensions</a>",
"companyPrivacy": "Datenschutz",
"companyTerms": "AGB",
"companyVideos": "Videos",
@@ -95,7 +95,8 @@
"leadText": "Habitica ist eine kostenlose Anwendung zur Gewohnheitsbildung und Steigerung der Produktivität, die Dein Leben wie ein Spiel behandelt. Mit Belohnungen und Bestrafungen als Motivation und einem starken sozialen Netzwerk als Inspiration kann Habitica Dir helfen, Deine Ziele zu erreichen und gesund, fleißig und glücklich zu werden.",
"login": "Einloggen",
"loginAndReg": "Anmelden / Registrieren",
"loginFacebookAlt": "Anmelden / Registrieren mit Facebook",
"loginFacebookAlt": "Sign in with Facebook",
"loginGoogleAlt": "Sign in with Google",
"logout": "Abmelden",
"marketing1Header": "Verbessere Deine Lebensführung Durch Ein Spiel",
"marketing1Lead1": "Habitica ist ein Videospiel, welches Dir dabei hilft. Deine Gewohnheiten im realen Leben zu verbessern. Es \"gamifiziert\" Dein Leben, indem es all Deine Aufgaben (Gewohnheiten, tägliche Aufgaben und To-Dos) in kleine Monster verwandelt, die Du besiegen musst. Je besser Du Dich dabei anstellst, umso weiter kommst Du im Spiel. Wenn Du in Deinem realen Leben nachlässt, beginnt Dein Charakter im Spiel zurückzufallen.",
@@ -258,8 +259,8 @@
"invalidLoginCredentialsLong": "Hoppla - Dein Benutzername oder Passwort ist nicht korrekt.\n- überprüfe die korrekte Schreibweise Deines Benutzernamens oder Deiner E-Mail-Adresse.\n-Es ist möglich, dass Du Dich mit Facebook statt mit Deiner E-Mail registriert hast. Probier Dich mit Deinem Facebook-Login anzumelden.\n- Wenn Du Dein Passwort vergessen hast, klicke auf \"Passwort vergessen.\"",
"invalidCredentials": "Es gibt kein Konto, das diese Anmeldedaten verwendet.",
"accountSuspended": "Account wurde stillgelegt. Bitte kontaktiere leslie@habitica.com mit Deiner Benutzer-ID \"<%= userId %>\" für Unterstützung.",
"onlyFbSupported": "Im Moment wird nur Facebook unterstützt.",
"cantDetachFb": "Ohne eine andere Anmelde-Methode kann Facebook nicht von diesem Konto gelöst werden.",
"unsupportedNetwork": "This network is not currently supported.",
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",
"onlySocialAttachLocal": "Lokale Authentifizierung kann nur zu einem Social-Media-Konto hinzugefügt werden.",
"invalidReqParams": "Ungültige Anfrageparameter.",
"memberIdRequired": "\"member\" muss eine gültige UUID sein.",

View File

@@ -220,6 +220,8 @@
"weaponArmoireCannonNotes": "Arr! Erfülle Dein Ziel mit Entschlossenheit. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Kanonier Set (Gegenstand 1 von 3).",
"weaponArmoireVermilionArcherBowText": "Zinnoberroter Schützenbogen",
"weaponArmoireVermilionArcherBowNotes": "Dein Pfeil wird von diesem brillianten roten Bogen wir ein Komet fliegen! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Zinnoberrotes Bogenschützenset (Gegenstand 1 von 3).",
"weaponArmoireOgreClubText": "Ogerkeule",
"weaponArmoireOgreClubNotes": "Diese Keule wurde in einer Ogerhöhle gefunden. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Oger Outfit (Gegenstand 2 von 3).",
"armor": "Rüstung",
"armorCapitalized": "Rüstung",
"armorBase0Text": "Schlichte Kleidung",
@@ -464,6 +466,8 @@
"armorArmoireFalconerArmorNotes": "Halte Dich mit dieser robusten Rüstung von Klauenangriffen fern! Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Falkner Set (Gegenstand 1 von 3).",
"armorArmoireVermilionArcherArmorText": "Zinnoberrote Schützenrüstung",
"armorArmoireVermilionArcherArmorNotes": "Diese Rüstung ist aus einem speziell verzauberten roten Metall gemacht für höchsten Schutz, minimale Bewegungseinschränkungen und maximales Flair! Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Zinnoberrotes Bogenschützenset (Gegenstand 2 von 3).",
"armorArmoireOgreArmorText": "Ogerrüstung",
"armorArmoireOgreArmorNotes": "Diese Rüstung ist so widerstandsfähig wie Ogerhaut. Für den Komfort wurde sie mit Fell beschichtet. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Oger Outfit (Gegenstand 3 von 3)",
"headgear": "Kopfschutz",
"headgearCapitalized": "Kopfschutz",
"headBase0Text": "Kein Helm.",
@@ -724,6 +728,8 @@
"headArmoireFalconerCapNotes": "Diese lustige Kappe lässt Dich Greifvögel besser verstehen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Falkner Set (Gegenstand 2 von 3). ",
"headArmoireVermilionArcherHelmText": "Zinnoberroter Schützenhelm",
"headArmoireVermilionArcherHelmNotes": "Der magische Rubin in diesem Helm wird Dir zur Zielgenauigkeit eines Lasers verhelfen! Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Zinnoberrotes Bogenschützenset (Gegenstand 3 von 3).",
"headArmoireOgreMaskText": "Ogermaske",
"headArmoireOgreMaskNotes": "Deine Feinde werden um ihr Leben rennen, wenn sie einen Oger auf sie zukommen sehen. Erhöht Ausdauer und Stärke jeweils um <%= attrs %>. Verzauberter Schrank: Oger Outfit (Gegenstand 1 von 3)",
"offhand": "Schildhand-Gegenstand",
"offhandCapitalized": "Schildhand-Gegenstand",
"shieldBase0Text": "Keine Schildhand-Ausrüstung",

View File

@@ -3,6 +3,7 @@
"stringNotFound": "String '<%= string %>' nicht gefunden.",
"titleIndex": "Habitica | Dein Leben, das Rollenspiel",
"habitica": "Habitica",
"habiticaLink": "<a href='http://habitica.wikia.com/wiki/Habitica' target='_blank'>Habitica</a>",
"titleTasks": "Aufgaben",
"titleAvatar": "Avatar",
"titleBackgrounds": "Ambiente",
@@ -75,6 +76,8 @@
"gems": "Edelsteine",
"gemButton": "Du hast <%= number %> Edelsteine.",
"moreInfo": "Mehr Informationen",
"moreInfoChallengesURL": "http://habitica.wikia.com/wiki/Challenges",
"moreInfoTagsURL": "http://habitica.wikia.com/wiki/Tags",
"showMoreMore": "(mehr anzeigen)",
"showMoreLess": "(weniger anzeigen)",
"gemsWhatFor": "Klicke hier um Edelsteine zu kaufen! Edelsteine kannst Du gegen besondere Gegestände wie Quests, Avataranpassungen oder saisonale Ausrüstung eintauschen.",

View File

@@ -6,11 +6,12 @@
"innTextBroken": "Du erholst Dich im Gasthaus, schätze ich ... Während Du dort verweilst, werden Dir Deine täglichen Aufgaben keinen Schaden zufügen, aber trotzdem täglich aktualisiert ... Wenn Du an einem Bosskampf teilnimmst, erhältst Du weiterhin Schaden für die verpassten Aufgaben Deiner Gruppenmitglieder ... sofern sich diese nicht auch im Gasthaus befinden ... Außerdem wird Dein Schaden am Boss (oder gesammelte Gegenstände) nicht berücksichtigt, bis Du das Gasthaus verlässt ... So müde ...",
"lfgPosts": "Nach Gruppeneinträgen suchen",
"tutorial": "Anleitung",
"glossary": "Nomenklatur",
"glossary": "<a target='_blank' href='http://habitica.wikia.com/wiki/Glossary'>Glossary</a>",
"wiki": "Wiki",
"wikiLink": "<a target='_blank' href='http://habitica.wikia.com/'>Wiki</a>",
"reportAP": "Problem melden",
"requestAF": "Feature vorschlagen",
"community": "Community-Forum",
"community": "<a target='_blank' href='http://habitica.wikia.com/wiki/Special:Forum'>Community Forum</a>",
"dataTool": "Werkzeug zur Datenanzeige",
"resources": "Ressourcen",
"askQuestionNewbiesGuild": "Stelle eine Frage (Die Newbies-Gilde)",
@@ -73,6 +74,7 @@
"createGuild": "Gilde gründen",
"guild": "Gilde",
"guilds": "Gilden",
"guildsLink": "<a href='http://habitica.wikia.com/wiki/Guilds' target='_blank'>Guilds</a>",
"sureKick": "Willst Du dieses Mitglied wirklich aus der Gruppe/Gilde entfernen?",
"optionalMessage": "Optionale Nachricht",
"yesRemove": "Ja, entferne sie",

View File

@@ -62,9 +62,9 @@
"autoAllocate": "Automatische Verteilung",
"autoAllocateText": "Falls Du eine automatische Verteilung wählst, werden die Punkte automatisch vergeben, abhängig von den Attributen Deiner Aufgaben, die Du unter <strong>Aufgabe > Bearbeiten > Erweiterte Optionen > Attribute</strong> finden kannst. Ein Beispiel: Wenn Du oft im Fitnessstudio bist und die entsprechende Aufgabe auf \"körperlich\" gesetzt ist, bekommst Du automatisch Stärke.",
"spells": "Fähigkeiten",
"spellsText": "Du kannst klassenspezifische Fähigkeiten freischalten. Du wirst die erste mit Level 11 kennenlernen. Dein Mana regeneriert sich 10 Punkte pro Tag plus 1 Punkt pro erfüllte",
"spellsText": "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed <a target='_blank' href='http://habitica.wikia.com/wiki/Todos'>To-Do</a>.",
"toDo": "To-Do",
"moreClass": "Für mehr Informationen über das Klassensystem klicke",
"moreClass": "For more information on the class-system, see <a href='http://habitica.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
"tourWelcome": "Willkommen in Habitica! Dies ist Deine Aufgabenliste. Hake eine Aufgabe ab, um weiterzumachen!",
"tourExp": "Gut gemacht! Eine Aufgabe abzuhaken bringt Dir Erfahrung und Gold ein!",
"tourDailies": "Diese Spalte ist für tägliche Aufgaben. Um weiterzumachen füge eine Aufgabe hinzu, die Du jeden Tag erledigen möchtest. <b>Beispiele für tägliche Aufgaben sind</b>: <b>Das Bett machen</b>, <b>Zahnseide benutzen</b>, <b>Geschäfts-E-Mails durchschauen</b>",
@@ -98,6 +98,7 @@
"tourHabitsBrief": "<strong>Gute & Schlechte Gewohnheiten</strong><ul><li>Gute Gewohnheiten gewähren Gold & Erfahrung.</li><li>Schlechte Gewohnheiten ziehen Lebenspunkte ab.</li></ul>",
"tourHabitsProceed": "Das leuchtet ein!",
"tourRewardsBrief": "<strong>Liste der Belohnungen</strong><ul><li>Gib Dein hart verdientes Gold hier aus!</li><li>Kaufe Ausrüstung für Deinen Avatar oder führe eigene Belohnungen ein.</li></ul>",
"tourRewardsArmoire": "<strong>Liste der Belohnungen</strong><ul><li>Gib Dein hart verdientes Gold hier aus!</li><li>Kaufe Ausrüstung für Deinen Avatar, erhalte zufällige Gegenstände aus dem Verzauberten Schrank oder erstelle eigene Belohnungen.</li></ul>",
"tourRewardsProceed": "Das war's!",
"welcomeToHabit": "Willkommen in Habitica!",
"welcome1": "Erstelle einen einfachen Avatar.",

View File

@@ -26,6 +26,8 @@
"pending": "Ausstehend",
"questStart": "Sobald alle Mitglieder die Einladung entweder angenommen oder abgelehnt haben beginnt die Quest. Nur diejenigen, die die Einladung \"angenommen\" haben können an der Quest teilnehmen und die Belohnungen kassieren. Wenn Mitglieder zu lange überlegen (inaktiv?), kannst Du die Quest ohne sie starten indem Du auf \"Beginnen\" klickst. Der Quest-Besitzer kann die Quest auch abbrechen und die Questrolle zurückerhalten indem er \"Abbrechen\" klickt.",
"questStartBroken": "Sobald alle Mitglieder die Einladung entweder angenommen oder abgelehnt haben beginnt die Quest … Nur diejenigen, die die Einladung \"angenommen\" haben können an der Quest teilnehmen und die Belohnungen kassieren … Wenn Mitglieder zu lange überlegen (inaktiv?), kann der Quest-Besitzer die Quest ohne sie starten indem er auf \"Beginnen\" klickt … Der Quest-Besitzer kann die Quest auch abbrechen und die Questschriftrolle zurückerhalten indem er auf \"Abbrechen\" klickt ...",
"questCollection": "+<%= val %> Quest Gegenstände gefunden",
"questDamage": "+<%= val %> Schaden gegen den Boss",
"begin": "Beginnen",
"bossHP": "Boss-Lebenspunkte",
"bossStrength": "Boss-Stärke",

View File

@@ -91,8 +91,8 @@
"passwordSuccess": "Das Passwort wurde erfolgreich geändert",
"usernameSuccess": "Dein Anmeldename wurde erfolgreich geändert!",
"emailSuccess": "Die E-Mail-Adresse wurde erfolgreich geändert",
"detachFacebook": "Facebook-Registrierung löschen",
"detachedFacebook": "Facebook erfolgreich von Deinem Konto entfernt",
"detachSocial": "De-register <%= network %>",
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
"addedLocalAuth": "Lokale Authentifizierung erfolgreich hinzugefügt",
"data": "Daten",
"exportData": "Daten exportieren",
@@ -101,7 +101,8 @@
"emailChange3": "Bitte gib sowohl Deine alte und neue E-Mail-Adresse, als auch Deine Benutzer-ID an.",
"usernameOrEmail": "Anmeldename oder E-Mail-Adresse",
"email": "E-Mail",
"registeredWithFb": "Mit Facebook registriert",
"registerWithSocial": "Register with <%= network %>",
"registeredWithSocial": "Registered with <%= network %>",
"loginNameDescription1": "Dies hier benutzt Du, um Dich bei Habitica einzuloggen. Gehe zu",
"loginNameDescription2": "Benutzer->Profil",
"loginNameDescription3": "um den Namen, der bei Deinem Avatar und bei Deinen Chat-Nachrichten steht zu ändern.",

View File

@@ -11,6 +11,7 @@
"unsubChallenge": "Broken Challenge Link: this task was part of a challenge, but you have unsubscribed from the challenge. What to do with the orphan tasks?",
"challengeWinner": "Was the winner in the following challenges",
"challenges": "Challenges",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"noChallenges": "No challenges yet, visit",
"toCreate": "to create one.",
"selectWinner": "Select a winner and close the challenge:",

Some files were not shown because too many files have changed in this diff Show More