Merge branch 'develop' into party-chat-translations

This commit is contained in:
Mateus Etto
2018-07-21 16:06:38 +09:00
286 changed files with 9915 additions and 8661 deletions

View File

@@ -78,6 +78,9 @@
"PUSH_CONFIGS": { "PUSH_CONFIGS": {
"GCM_SERVER_API_KEY": "", "GCM_SERVER_API_KEY": "",
"APN_ENABLED": "false", "APN_ENABLED": "false",
"APN_KEY_ID": "xxxxxxxxxx",
"APN_KEY": "xxxxxxxxxx",
"APN_TEAM_ID": "aaabbbcccd",
"FCM_SERVER_API_KEY": "" "FCM_SERVER_API_KEY": ""
}, },
"SITE_HTTP_AUTH": { "SITE_HTTP_AUTH": {

155
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "habitica", "name": "habitica",
"version": "4.51.2", "version": "4.52.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -801,13 +801,25 @@
} }
}, },
"apn": { "apn": {
"version": "1.7.8", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/apn/-/apn-1.7.8.tgz", "resolved": "https://registry.npmjs.org/apn/-/apn-2.2.0.tgz",
"integrity": "sha1-Hp2kKPtXr6lX5UIjvvc0LALCTNo=", "integrity": "sha512-YIypYzPVJA9wzNBLKZ/mq2l1IZX/2FadPvwmSv4ZeR0VH7xdNITQ6Pucgh0Uw6ZZKC+XwheaJ57DFZAhJ0FvPg==",
"requires": { "requires": {
"debug": "2.6.9", "debug": "3.1.0",
"node-forge": "0.6.49", "http2": "https://github.com/node-apn/node-http2/archive/apn-2.1.4.tar.gz",
"q": "1.5.1" "jsonwebtoken": "8.3.0",
"node-forge": "0.7.5",
"verror": "1.10.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
} }
}, },
"append-buffer": { "append-buffer": {
@@ -5036,6 +5048,11 @@
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
"integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74="
}, },
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"buffer-fill": { "buffer-fill": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
@@ -8792,6 +8809,14 @@
"jsbn": "0.1.1" "jsbn": "0.1.1"
} }
}, },
"ecdsa-sig-formatter": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz",
"integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=",
"requires": {
"safe-buffer": "5.1.2"
}
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -13292,6 +13317,10 @@
"sshpk": "1.14.1" "sshpk": "1.14.1"
} }
}, },
"http2": {
"version": "https://github.com/node-apn/node-http2/archive/apn-2.1.4.tar.gz",
"integrity": "sha512-ad4u4I88X9AcUgxCRW3RLnbh7xHWQ1f5HbrXa7gEy2x4Xgq+rq+auGx5I+nUDE2YYuqteGIlbxrwQXkIaYTfnQ=="
},
"httpntlm": { "httpntlm": {
"version": "1.6.1", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz",
@@ -14768,6 +14797,29 @@
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk="
}, },
"jsonwebtoken": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz",
"integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==",
"requires": {
"jws": "3.1.5",
"lodash.includes": "4.3.0",
"lodash.isboolean": "3.0.3",
"lodash.isinteger": "4.0.4",
"lodash.isnumber": "3.0.3",
"lodash.isplainobject": "4.0.6",
"lodash.isstring": "4.0.1",
"lodash.once": "4.1.1",
"ms": "2.1.1"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"jsprim": { "jsprim": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -14806,6 +14858,25 @@
"integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==",
"dev": true "dev": true
}, },
"jwa": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz",
"integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.10",
"safe-buffer": "5.1.2"
}
},
"jws": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz",
"integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==",
"requires": {
"jwa": "1.1.6",
"safe-buffer": "5.1.2"
}
},
"kareem": { "kareem": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.1.0.tgz", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.1.0.tgz",
@@ -16418,6 +16489,11 @@
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
}, },
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
},
"lodash.initial": { "lodash.initial": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.initial/-/lodash.initial-4.1.1.tgz", "resolved": "https://registry.npmjs.org/lodash.initial/-/lodash.initial-4.1.1.tgz",
@@ -16433,16 +16509,36 @@
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
}, },
"lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
},
"lodash.isequal": { "lodash.isequal": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
}, },
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
},
"lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
},
"lodash.isplainobject": { "lodash.isplainobject": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
}, },
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.istypedarray": { "lodash.istypedarray": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz",
@@ -16484,6 +16580,11 @@
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",
"integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==" "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ=="
}, },
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
"lodash.pairs": { "lodash.pairs": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz", "resolved": "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz",
@@ -18033,11 +18134,6 @@
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.4.1.tgz", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.4.1.tgz",
"integrity": "sha512-NNY/MpBkALb9jJmjpBlIi6GRoLveLUM0pJzgbp9vY9F7IQEb/HREC/nxrixechcQwd1NevOhJnWWV8QQQRE+OA==" "integrity": "sha512-NNY/MpBkALb9jJmjpBlIi6GRoLveLUM0pJzgbp9vY9F7IQEb/HREC/nxrixechcQwd1NevOhJnWWV8QQQRE+OA=="
}, },
"mpns": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mpns/-/mpns-2.1.3.tgz",
"integrity": "sha512-gPLNoVqwYoKUmNYZ2shMSdaE2XvHSRxWNzyG4DUi6Av7MSujyeOw/nj61nnQeuV/vke5E0Dni468xn0qxTHIZQ=="
},
"mquery": { "mquery": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz",
@@ -18457,9 +18553,9 @@
} }
}, },
"node-forge": { "node-forge": {
"version": "0.6.49", "version": "0.7.5",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.49.tgz", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
"integrity": "sha1-8e6V1ddGI5OP4Z1piqWibVTS9g8=" "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ=="
}, },
"node-gcm": { "node-gcm": {
"version": "0.14.10", "version": "0.14.10",
@@ -18655,9 +18751,9 @@
} }
}, },
"node-rdkafka": { "node-rdkafka": {
"version": "2.3.3", "version": "2.3.4",
"resolved": "https://registry.npmjs.org/node-rdkafka/-/node-rdkafka-2.3.3.tgz", "resolved": "https://registry.npmjs.org/node-rdkafka/-/node-rdkafka-2.3.4.tgz",
"integrity": "sha512-2J54zC9+Zj0iRQttmQs1Ubv8aHhmh04XjP3vk39uco7l6tp8BYYHG4XRsoqKOGGKjBLctGpFHr9g97WBE1pTbg==", "integrity": "sha512-ilaAOrEpDF3TGTlItsxU5pQXG+qjN1gKbhSvs9CoLXZaItt2EN6oU+kEdO6UkRQLKO6/Kv4m296cBrr0JCmiTw==",
"optional": true, "optional": true,
"requires": { "requires": {
"bindings": "1.3.0", "bindings": "1.3.0",
@@ -20335,11 +20431,6 @@
"pinkie": "2.0.4" "pinkie": "2.0.4"
} }
}, },
"pipe-event": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/pipe-event/-/pipe-event-0.1.0.tgz",
"integrity": "sha1-pfXgPlqXsrdJPUsqBgzYPazLmmE="
},
"pixelsmith": { "pixelsmith": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/pixelsmith/-/pixelsmith-2.2.1.tgz", "resolved": "https://registry.npmjs.org/pixelsmith/-/pixelsmith-2.2.1.tgz",
@@ -22718,19 +22809,6 @@
} }
} }
}, },
"push-notify": {
"version": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
"requires": {
"apn": "1.7.8",
"bluebird": "3.5.1",
"lodash": "4.17.10",
"mpns": "2.1.3",
"node-gcm": "0.14.10",
"pipe-event": "0.1.0",
"q": "1.5.1",
"wns": "0.5.3"
}
},
"pusher": { "pusher": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/pusher/-/pusher-1.5.1.tgz", "resolved": "https://registry.npmjs.org/pusher/-/pusher-1.5.1.tgz",
@@ -27870,11 +27948,6 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"wns": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/wns/-/wns-0.5.3.tgz",
"integrity": "sha1-APToXPz44zg9y9gYmJBvH2rUhF8="
},
"wordwrap": { "wordwrap": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",

View File

@@ -1,7 +1,7 @@
{ {
"name": "habitica", "name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.", "description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.51.2", "version": "4.52.2",
"main": "./website/server/index.js", "main": "./website/server/index.js",
"dependencies": { "dependencies": {
"@slack/client": "^3.8.1", "@slack/client": "^3.8.1",
@@ -11,6 +11,7 @@
"apidoc": "^0.17.5", "apidoc": "^0.17.5",
"autoprefixer": "^8.5.0", "autoprefixer": "^8.5.0",
"aws-sdk": "^2.239.1", "aws-sdk": "^2.239.1",
"apn": "^2.2.0",
"axios": "^0.18.0", "axios": "^0.18.0",
"axios-progress-bar": "^1.2.0", "axios-progress-bar": "^1.2.0",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
@@ -78,7 +79,6 @@
"postcss-easy-import": "^3.0.0", "postcss-easy-import": "^3.0.0",
"ps-tree": "^1.0.0", "ps-tree": "^1.0.0",
"pug": "^2.0.3", "pug": "^2.0.3",
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
"pusher": "^1.3.0", "pusher": "^1.3.0",
"rimraf": "^2.4.3", "rimraf": "^2.4.3",
"sass-loader": "^7.0.0", "sass-loader": "^7.0.0",

View File

@@ -1,6 +1,6 @@
import { model as User } from '../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
import pushNotify from 'push-notify'; import apn from 'apn/mock';
import nconf from 'nconf'; import nconf from 'nconf';
import gcmLib from 'node-gcm'; // works with FCM notifications too import gcmLib from 'node-gcm'; // works with FCM notifications too
@@ -24,7 +24,7 @@ describe('pushNotifications', () => {
sandbox.stub(gcmLib.Sender.prototype, 'send').callsFake(fcmSendSpy); sandbox.stub(gcmLib.Sender.prototype, 'send').callsFake(fcmSendSpy);
sandbox.stub(pushNotify, 'apn').returns({ sandbox.stub(apn.Provider.prototype, 'send').returns({
on: () => null, on: () => null,
send: apnSendSpy, send: apnSendSpy,
}); });
@@ -104,10 +104,7 @@ describe('pushNotifications', () => {
}, },
}; };
sendPushNotification(user, details); const expectedNotification = new apn.Notification({
expect(apnSendSpy).to.have.been.calledOnce;
expect(apnSendSpy).to.have.been.calledWithMatch({
token: '123',
alert: message, alert: message,
sound: 'default', sound: 'default',
category: 'fun', category: 'fun',
@@ -117,6 +114,10 @@ describe('pushNotifications', () => {
b: true, b: true,
}, },
}); });
sendPushNotification(user, details);
expect(apnSendSpy).to.have.been.calledOnce;
expect(apnSendSpy).to.have.been.calledWithMatch(expectedNotification, '123');
expect(fcmSendSpy).to.not.have.been.called; expect(fcmSendSpy).to.not.have.been.called;
}); });
}); });

View File

@@ -388,6 +388,23 @@ describe('POST /chat', () => {
expect(groupMessages[0].id).to.exist; expect(groupMessages[0].id).to.exist;
}); });
it('creates a chat with a max length of 3000 chars', async () => {
const veryLongMessage = `
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789.
THIS PART WON'T BE IN THE MESSAGE (over 3000)
`;
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: veryLongMessage});
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
expect(newMessage.message.id).to.exist;
expect(groupMessages[0].id).to.exist;
expect(newMessage.message.text.length).to.eql(3000);
expect(newMessage.message.text).to.not.contain('MESSAGE');
expect(groupMessages[0].text.length).to.eql(3000);
});
it('creates a chat with user styles', async () => { it('creates a chat with user styles', async () => {
const mount = 'test-mount'; const mount = 'test-mount';
const pet = 'test-pet'; const pet = 'test-pet';

View File

@@ -23,6 +23,17 @@ describe('GET /export/userdata.xml', () => {
]); ]);
// add pinnedItem
await user.get('/user/toggle-pinned-item/marketGear/gear.flat.shield_rogue_5');
// add a private message
let receiver = await generateUser();
user.post('/members/send-private-message', {
message: 'Your first message, hi!',
toUserId: receiver._id,
});
let response = await user.get('/export/userdata.xml'); let response = await user.get('/export/userdata.xml');
let {user: res} = await parseStringAsync(response, {explicitArray: false}); let {user: res} = await parseStringAsync(response, {explicitArray: false});

View File

@@ -140,4 +140,89 @@ describe('POST /tasks/:id/approve/:userId', () => {
message: t('canOnlyApproveTaskOnce'), message: t('canOnlyApproveTaskOnce'),
}); });
}); });
it('completes master task when single-completion task is approved', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: true,
sharedCompletion: 'singleCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`);
let groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(true);
});
it('deletes other assigned user tasks when single-completion task is approved', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: true,
sharedCompletion: 'singleCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`);
let member2Tasks = await member2.get('/tasks/user');
let syncedTask2 = find(member2Tasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
expect(syncedTask2).to.equal(undefined);
});
it('does not complete master task when not all user tasks are approved if all assigned must complete', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: true,
sharedCompletion: 'allAssignedCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`);
let groupTasks = await user.get(`/tasks/group/${guild._id}`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(false);
});
it('completes master task when all user tasks are approved if all assigned must complete', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: true,
sharedCompletion: 'allAssignedCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member2._id}`);
let groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(true);
});
}); });

View File

@@ -125,7 +125,7 @@ describe('POST /tasks/:id/score/:direction', () => {
}); });
}); });
it('allows a user to score an apporoved task', async () => { it('allows a user to score an approved task', async () => {
let memberTasks = await member.get('/tasks/user'); let memberTasks = await member.get('/tasks/user');
let syncedTask = find(memberTasks, findAssignedTask); let syncedTask = find(memberTasks, findAssignedTask);
@@ -137,4 +137,112 @@ describe('POST /tasks/:id/score/:direction', () => {
expect(updatedTask.completed).to.equal(true); expect(updatedTask.completed).to.equal(true);
expect(updatedTask.dateCompleted).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type expect(updatedTask.dateCompleted).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type
}); });
it('completes master task when single-completion task is completed', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: false,
sharedCompletion: 'singleCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
let memberTasks = await member.get('/tasks/user');
let syncedTask = find(memberTasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
await member.post(`/tasks/${syncedTask._id}/score/up`);
let groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(true);
});
it('deletes other assigned user tasks when single-completion task is completed', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: false,
sharedCompletion: 'singleCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
let memberTasks = await member.get('/tasks/user');
let syncedTask = find(memberTasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
await member.post(`/tasks/${syncedTask._id}/score/up`);
let member2Tasks = await member2.get('/tasks/user');
let syncedTask2 = find(member2Tasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
expect(syncedTask2).to.equal(undefined);
});
it('does not complete master task when not all user tasks are completed if all assigned must complete', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: false,
sharedCompletion: 'allAssignedCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
let memberTasks = await member.get('/tasks/user');
let syncedTask = find(memberTasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
await member.post(`/tasks/${syncedTask._id}/score/up`);
let groupTasks = await user.get(`/tasks/group/${guild._id}`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(false);
});
it('completes master task when all user tasks are completed if all assigned must complete', async () => {
let sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, {
text: 'shared completion todo',
type: 'todo',
requiresApproval: false,
sharedCompletion: 'allAssignedCompletion',
});
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`);
await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`);
let memberTasks = await member.get('/tasks/user');
let member2Tasks = await member2.get('/tasks/user');
let syncedTask = find(memberTasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
let syncedTask2 = find(member2Tasks, (memberTask) => {
return memberTask.group.taskId === sharedCompletionTask._id;
});
await member.post(`/tasks/${syncedTask._id}/score/up`);
await member2.post(`/tasks/${syncedTask2._id}/score/up`);
let groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`);
let masterTask = find(groupTasks, (groupTask) => {
return groupTask._id === sharedCompletionTask._id;
});
expect(masterTask.completed).to.equal(true);
});
}); });

View File

@@ -62,7 +62,11 @@ module.exports = {
target: DEV_BASE_URL, target: DEV_BASE_URL,
changeOrigin: true, changeOrigin: true,
}, },
'/logout': { '/logout-server': {
target: DEV_BASE_URL,
changeOrigin: true,
},
'/export': {
target: DEV_BASE_URL, target: DEV_BASE_URL,
changeOrigin: true, changeOrigin: true,
}, },

View File

@@ -105,7 +105,7 @@ div
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
/* @TODO: The modal-open class is not being removed. Let's try this for now */ /* @TODO: The modal-open class is not being removed. Let's try this for now */
.modal, .modal-open { .modal {
overflow-y: scroll !important; overflow-y: scroll !important;
} }
@@ -331,9 +331,33 @@ export default {
]; ];
if (notificationNotFoundMessage.indexOf(errorMessage) !== -1) snackbarTimeout = true; if (notificationNotFoundMessage.indexOf(errorMessage) !== -1) snackbarTimeout = true;
let errorsToShow = [];
let usernameCheck = false;
let emailCheck = false;
let passwordCheck = false;
// show only the first error for each param
if (errorData.errors) {
for (let e of errorData.errors) {
if (!usernameCheck && e.param === 'username') {
errorsToShow.push(e.message);
usernameCheck = true;
}
if (!emailCheck && e.param === 'email') {
errorsToShow.push(e.message);
emailCheck = true;
}
if (!passwordCheck && e.param === 'password') {
errorsToShow.push(e.message);
passwordCheck = true;
}
}
} else {
errorsToShow.push(errorMessage);
}
// dispatch as one snackbar notification
this.$store.dispatch('snackbars:add', { this.$store.dispatch('snackbars:add', {
title: 'Habitica', title: 'Habitica',
text: errorMessage, text: errorsToShow.join(' '),
type: 'error', type: 'error',
timeout: snackbarTimeout, timeout: snackbarTimeout,
}); });
@@ -475,8 +499,16 @@ export default {
}); });
this.$root.$on('bv::modal::hidden', (bvEvent) => { this.$root.$on('bv::modal::hidden', (bvEvent) => {
const modalId = bvEvent.target && bvEvent.target.id; let modalId = bvEvent.target && bvEvent.target.id;
if (!modalId) return;
// sometimes the target isn't passed to the hidden event, fallback is the vueTarget
if (!modalId) {
modalId = bvEvent.vueTarget && bvEvent.vueTarget.id;
}
if (!modalId) {
return;
}
const modalStack = this.$store.state.modalStack; const modalStack = this.$store.state.modalStack;
@@ -493,6 +525,7 @@ export default {
// Get previous modal // Get previous modal
const modalBefore = modalOnTop ? modalOnTop.prev : undefined; const modalBefore = modalOnTop ? modalOnTop.prev : undefined;
if (modalBefore) this.$root.$emit('bv::show::modal', modalBefore, {fromRoot: true}); if (modalBefore) this.$root.$emit('bv::show::modal', modalBefore, {fromRoot: true});
}); });
}, },

View File

@@ -1,66 +1,78 @@
.promo_aquatic_glass_potions { .promo_aquatic_glass_potions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -720px 0px; background-position: -853px 0px;
width: 141px; width: 141px;
height: 441px; height: 441px;
} }
.promo_armoire_backgrounds_201807 { .promo_armoire_backgrounds_201807 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -720px -442px; background-position: -853px -442px;
width: 141px; width: 141px;
height: 441px; height: 441px;
} }
.promo_ios { .promo_ios {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -394px 0px; background-position: -477px 0px;
width: 325px; width: 375px;
height: 336px; height: 361px;
} }
.promo_mystery_201806 { .promo_mystery_201806 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -862px -442px; background-position: -995px -442px;
width: 121px; width: 121px;
height: 114px; height: 114px;
} }
.promo_seafoam { .promo_seafoam {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -862px 0px; background-position: -995px 0px;
width: 141px; width: 141px;
height: 441px; height: 441px;
} }
.promo_seaserpent {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px;
width: 476px;
height: 364px;
}
.promo_seasonal_shop_summer { .promo_seasonal_shop_summer {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -518px -370px; background-position: -401px -552px;
width: 162px; width: 162px;
height: 138px; height: 138px;
} }
.promo_splashy_skins { .promo_splashy_skins {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -142px -370px; background-position: -142px -365px;
width: 375px; width: 375px;
height: 186px; height: 186px;
} }
.customize-option.promo_splashy_skins { .customize-option.promo_splashy_skins {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -167px -385px; background-position: -167px -380px;
width: 60px; width: 60px;
height: 60px; height: 60px;
} }
.promo_summer_splash_2018 { .promo_summer_splash_2018 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -370px; background-position: 0px -365px;
width: 141px; width: 141px;
height: 588px; height: 588px;
} }
.promo_take_this { .promo_take_this {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -862px -557px; background-position: -995px -557px;
width: 96px; width: 96px;
height: 69px; height: 69px;
} }
.scene_party_healing { .promo_unconventional_armor {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px; background-position: -518px -365px;
width: 393px; width: 180px;
height: 369px; height: 180px;
}
.scene_pomodoro {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -142px -552px;
width: 258px;
height: 258px;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -1,13 +1,22 @@
.markdown { .markdown {
> p { p {
margin-bottom: 0px; margin-bottom: 8px;
} }
h1 { h1 {
margin-bottom: 10px;
margin-top: 14px;
line-height: 1.17; line-height: 1.17;
} }
h2 {
margin-bottom: 6px;
margin-top: 10px;
}
h3 { h3 {
margin-bottom: 4px;
margin-top: 6px;
color: $gray-10; color: $gray-10;
} }

View File

@@ -0,0 +1,13 @@
<script>
export default {
components: {},
methods: {
async logout () {
return await this.$store.dispatch('auth:logout');
},
},
created () {
this.logout();
},
};
</script>

View File

@@ -402,11 +402,6 @@ export default {
window.location.href = redirectTo; window.location.href = redirectTo;
}, },
async login () { async login () {
if (!this.username) {
alert('Email is required');
return;
}
await this.$store.dispatch('auth:login', { await this.$store.dispatch('auth:login', {
username: this.username, username: this.username,
// email: this.email, // email: this.email,

View File

@@ -3,7 +3,7 @@
challenge-modal(v-on:updatedChallenge='updatedChallenge') challenge-modal(v-on:updatedChallenge='updatedChallenge')
leave-challenge-modal(:challengeId='challenge._id') leave-challenge-modal(:challengeId='challenge._id')
close-challenge-modal(:members='members', :challengeId='challenge._id') close-challenge-modal(:members='members', :challengeId='challenge._id')
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id') challenge-member-progress-modal(:challengeId='challenge._id')
.col-12.col-md-8.standard-page .col-12.col-md-8.standard-page
.row .row
.col-12.col-md-6 .col-12.col-md-6
@@ -231,7 +231,6 @@ export default {
creatingTask: {}, creatingTask: {},
workingTask: {}, workingTask: {},
taskFormPurpose: 'create', taskFormPurpose: 'create',
progressMemberId: '',
searchTerm: '', searchTerm: '',
memberResults: [], memberResults: [],
}; };
@@ -345,6 +344,7 @@ export default {
this.tasksByType[task.type].splice(index, 1); this.tasksByType[task.type].splice(index, 1);
}, },
showMemberModal () { showMemberModal () {
// @TODO: Change these to options and add a custom event to members modal
this.$store.state.memberModalOptions.challengeId = this.challenge._id; this.$store.state.memberModalOptions.challengeId = this.challenge._id;
this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings
this.$store.state.memberModalOptions.group = this.group; this.$store.state.memberModalOptions.group = this.group;
@@ -374,8 +374,9 @@ export default {
Object.assign(this.challenge, eventData.challenge); Object.assign(this.challenge, eventData.challenge);
}, },
openMemberProgressModal (member) { openMemberProgressModal (member) {
this.progressMemberId = member._id; this.$root.$emit('habitica:challenge:member-progress', {
this.$root.$emit('bv::show::modal', 'challenge-member-modal'); progressMemberId: member._id,
});
}, },
async exportChallengeCsv () { async exportChallengeCsv () {
// let response = await this.$store.dispatch('challenges:exportChallengeCsv', { // let response = await this.$store.dispatch('challenges:exportChallengeCsv', {

View File

@@ -1,5 +1,8 @@
<template lang="pug"> <template lang="pug">
b-modal#challenge-member-modal(title="User Progress", size='lg') b-modal#challenge-member-modal(title="User Progress", size='lg')
.row.award-row
.col-12.text-center
button.btn.btn-primary(v-once, @click='closeChallenge()') {{ $t('awardWinners') }}
.row .row
task-column.col-6( task-column.col-6(
v-for="column in columns", v-for="column in columns",
@@ -8,12 +11,19 @@
:taskListOverride='tasksByType[column]') :taskListOverride='tasksByType[column]')
</template> </template>
<style scoped>
.award-row {
padding-top: 1rem;
padding-bottom: 1rem;
}
</style>
<script> <script>
import axios from 'axios'; import axios from 'axios';
import Column from '../tasks/column'; import Column from '../tasks/column';
export default { export default {
props: ['challengeId', 'memberId'], props: ['challengeId'],
components: { components: {
TaskColumn: Column, TaskColumn: Column,
}, },
@@ -26,8 +36,19 @@ export default {
todo: [], todo: [],
reward: [], reward: [],
}, },
memberId: '',
}; };
}, },
mounted () {
this.$root.$on('habitica:challenge:member-progress', (data) => {
if (!data.progressMemberId) return;
this.memberId = data.progressMemberId;
this.$root.$emit('bv::show::modal', 'challenge-member-modal');
});
},
beforeDestroy () {
this.$root.$off('habitica:challenge:member-progress');
},
watch: { watch: {
async memberId (id) { async memberId (id) {
if (!id) return; if (!id) return;
@@ -45,5 +66,14 @@ export default {
}); });
}, },
}, },
methods: {
async closeChallenge () {
this.challenge = await this.$store.dispatch('challenges:selectChallengeWinner', {
challengeId: this.challengeId,
winnerId: this.memberId,
});
this.$router.push('/challenges/myChallenges');
},
},
}; };
</script> </script>

View File

@@ -317,14 +317,17 @@ export default {
methods: { methods: {
async shown () { async shown () {
this.groups = await this.$store.dispatch('guilds:getMyGuilds'); this.groups = await this.$store.dispatch('guilds:getMyGuilds');
await this.$store.dispatch('party:getParty');
const party = this.$store.state.party.data; if (this.user.party && this.user.party._id) {
if (party._id) { await this.$store.dispatch('party:getParty');
this.groups.push({ const party = this.$store.state.party.data;
name: party.name, if (party._id) {
_id: party._id, this.groups.push({
privacy: 'private', name: party.name,
}); _id: party._id,
privacy: 'private',
});
}
} }
this.groups.push({ this.groups.push({

View File

@@ -100,6 +100,7 @@ export default {
if (!data.message || !data.groupId) return; if (!data.message || !data.groupId) return;
this.abuseObject = data.message; this.abuseObject = data.message;
this.groupId = data.groupId; this.groupId = data.groupId;
this.reportComment = '';
this.$root.$emit('bv::show::modal', 'report-flag'); this.$root.$emit('bv::show::modal', 'report-flag');
}); });
}, },

View File

@@ -80,6 +80,7 @@
:key="column", :key="column",
:taskListOverride='tasksByType[column]', :taskListOverride='tasksByType[column]',
v-on:editTask="editTask", v-on:editTask="editTask",
v-on:loadGroupCompletedTodos="loadGroupCompletedTodos",
:group='group', :group='group',
:searchText="searchText") :searchText="searchText")
</template> </template>
@@ -384,6 +385,20 @@ export default {
this.$root.$emit('bv::show::modal', 'task-modal'); this.$root.$emit('bv::show::modal', 'task-modal');
}); });
}, },
async loadGroupCompletedTodos () {
const completedTodos = await this.$store.dispatch('tasks:getCompletedGroupTasks', {
groupId: this.searchId,
});
completedTodos.forEach((task) => {
const existingTaskIndex = findIndex(this.tasksByType.todo, (todo) => {
return todo._id === task._id;
});
if (existingTaskIndex === -1) {
this.tasksByType.todo.push(task);
}
});
},
createTask (type) { createTask (type) {
this.taskFormPurpose = 'create'; this.taskFormPurpose = 'create';
this.creatingTask = taskDefaults({type, text: ''}); this.creatingTask = taskDefaults({type, text: ''});

View File

@@ -9,8 +9,10 @@
:class='{"user-entry": newMessage}', :class='{"user-entry": newMessage}',
@keydown='updateCarretPosition', @keydown='updateCarretPosition',
@keyup.ctrl.enter='sendMessageShortcut()', @keyup.ctrl.enter='sendMessageShortcut()',
@paste='disableMessageSendShortcut()' @paste='disableMessageSendShortcut()',
maxlength='3000'
) )
span {{ currentLength }} / 3000
autocomplete( autocomplete(
:text='newMessage', :text='newMessage',
v-on:select="selectedAutocomplete", v-on:select="selectedAutocomplete",
@@ -62,6 +64,11 @@
}, },
}; };
}, },
computed: {
currentLength () {
return this.newMessage.length;
},
},
methods: { methods: {
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a // https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
getCoord (e, text) { getCoord (e, text) {

View File

@@ -53,6 +53,9 @@ div
span.dropdown-icon-item span.dropdown-icon-item
.svg-icon.inline(v-html="icons.removeIcon") .svg-icon.inline(v-html="icons.removeIcon")
span.text {{$t('removeManager2')}} span.text {{$t('removeManager2')}}
b-dropdown-item(@click='viewProgress(member)')
span.dropdown-icon-item
span.text {{ $t('viewProgress') }}
.row(v-if='isLoadMoreAvailable') .row(v-if='isLoadMoreAvailable')
.col-12.text-center .col-12.text-center
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }} button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
@@ -475,6 +478,11 @@ export default {
groupData.leader = member; groupData.leader = member;
this.$root.$emit('updatedGroup', groupData); this.$root.$emit('updatedGroup', groupData);
}, },
viewProgress (member) {
this.$root.$emit('habitica:challenge:member-progress', {
progressMemberId: member._id,
});
},
}, },
}; };
</script> </script>

View File

@@ -48,7 +48,6 @@
.member-stats { .member-stats {
padding-left: 12px; padding-left: 12px;
padding-right: 24px; padding-right: 24px;
margin-right: 1px;
opacity: 1; opacity: 1;
transition: width 0.15s ease-out; transition: width 0.15s ease-out;
} }
@@ -148,6 +147,7 @@
right: 100%; right: 100%;
height: calc(100% + 18px); height: calc(100% + 18px);
margin-top: -9px; margin-top: -9px;
margin-right: 1px;
padding-top: 9px; padding-top: 9px;
padding-bottom: 24px; padding-bottom: 24px;
padding-right: 16px; padding-right: 16px;

View File

@@ -485,7 +485,9 @@ export default {
break; break;
case 'CHALLENGE_JOINED_ACHIEVEMENT': case 'CHALLENGE_JOINED_ACHIEVEMENT':
this.playSound('Achievement_Unlocked'); this.playSound('Achievement_Unlocked');
this.$root.$emit('bv::show::modal', 'joined-challenge'); this.text(`${this.$t('achievement')}: ${this.$t('joinedChallenge')}`, () => {
this.$root.$emit('bv::show::modal', 'joined-challenge');
}, false);
break; break;
case 'INVITED_FRIEND_ACHIEVEMENT': case 'INVITED_FRIEND_ACHIEVEMENT':
this.playSound('Achievement_Unlocked'); this.playSound('Achievement_Unlocked');

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
transition(name="fade") transition(name="fade")
.notification.callout.animated(:class="classes", v-if='show', @click='show = false') .notification.callout.animated(:class="classes", v-if='show', @click='handleOnClick()')
.row(v-if='notification.type === "error"') .row(v-if='notification.type === "error"')
.text.col-12 .text.col-12
div(v-html='notification.text') div(v-html='notification.text')
@@ -50,6 +50,10 @@ transition(name="fade")
.error { .error {
background-color: #f74e52; background-color: #f74e52;
border-radius: 60px;
width: 320px !important;
padding: 10px 5px;
margin-left: 0;
color: #fff; color: #fff;
} }
@@ -142,6 +146,15 @@ export default {
beforeDestroy () { beforeDestroy () {
clearTimeout(this.timer); clearTimeout(this.timer);
}, },
methods: {
handleOnClick () {
if (typeof this.notification.onClick === 'function') {
this.notification.onClick();
}
this.show = false;
},
},
watch: { watch: {
show () { show () {
this.$store.dispatch('snackbars:remove', this.notification); this.$store.dispatch('snackbars:remove', this.notification);

View File

@@ -1,18 +1,36 @@
<template lang="pug"> <template lang="pug">
.container-fluid .container-fluid(role="tablist")
.row .row
.col-12.col-md-6.offset-md-3 .col-12.col-md-6.offset-md-3
h1 {{ $t('frequentlyAskedQuestions') }} h1#faq-heading {{ $t('frequentlyAskedQuestions') }}
.faq-question(v-for='(heading, index) in headings') .faq-question(v-for='(heading, index) in headings', :key="index")
h2.accordion(@click='setActivePage(heading)') {{ $t(`faqQuestion${index}`) }} h2(role="tab", v-b-toggle="heading", @click="handleClick($event)", variant="info") {{ $t(`faqQuestion${index}`) }}
div(v-if='pageState[heading]', v-markdown="$t('webFaqAnswer' + index, replacements)") b-collapse(:id="heading", :visible="isVisible(heading)", accordion="faq", role="tabpanel")
div.card-body(v-markdown="$t('webFaqAnswer' + index, replacements)")
hr hr
p(v-markdown="$t('webFaqStillNeedHelp')") p(v-markdown="$t('webFaqStillNeedHelp')")
</template> </template>
<style lang='scss' scoped> <style lang='scss' scoped>
.faq-question { .card-body {
margin-bottom: 1em; margin-bottom: 1em;
}
.faq-question h2 {
cursor: pointer;
}
.faq-question .card-body {
padding: 0;
}
.static-wrapper .faq-question h2 {
margin: 0 0 16px 0;
}
.faq-question a {
text-decoration: none;
color: #4F2A93;
} }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
@@ -25,6 +43,7 @@
<script> <script>
// @TODO: env.EMAILS.TECH_ASSISTANCE_EMAIL // @TODO: env.EMAILS.TECH_ASSISTANCE_EMAIL
const TECH_ASSISTANCE_EMAIL = 'admin@habitica.com'; const TECH_ASSISTANCE_EMAIL = 'admin@habitica.com';
import markdownDirective from 'client/directives/markdown'; import markdownDirective from 'client/directives/markdown';
export default { export default {
@@ -48,19 +67,15 @@
'world-boss', 'world-boss',
]; ];
let pageState = {}; const hash = window.location.hash.replace('#', '');
for (let index in headings) {
let heading = headings[index];
pageState[heading] = false;
}
return { return {
pageState,
headings, headings,
replacements: { replacements: {
techAssistanceEmail: TECH_ASSISTANCE_EMAIL, techAssistanceEmail: TECH_ASSISTANCE_EMAIL,
wikiTechAssistanceEmail: `mailto:${TECH_ASSISTANCE_EMAIL}`, wikiTechAssistanceEmail: `mailto:${TECH_ASSISTANCE_EMAIL}`,
}, },
visible: hash && headings.includes(hash) ? hash : null,
// @TODO webFaqStillNeedHelp: { // @TODO webFaqStillNeedHelp: {
// linkStart: '[', // linkStart: '[',
// linkEnd: '](/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)', // linkEnd: '](/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)',
@@ -69,8 +84,13 @@
}; };
}, },
methods: { methods: {
setActivePage (page) { isVisible (heading) {
this.pageState[page] = !this.pageState[page]; return this.visible && this.visible === heading;
},
handleClick (e) {
if (!e) return;
const heading = e.target.nextElementSibling.id;
history.pushState({}, heading, `#${heading}`);
}, },
}, },
}; };

View File

@@ -616,11 +616,6 @@
}, },
// @TODO this is totally duplicate from the registerLogin component // @TODO this is totally duplicate from the registerLogin component
async register () { async register () {
if (this.password !== this.passwordConfirm) {
alert('Passwords must match');
return;
}
let groupInvite = ''; let groupInvite = '';
if (this.$route.query && this.$route.query.p) { if (this.$route.query && this.$route.query.p) {
groupInvite = this.$route.query.p; groupInvite = this.$route.query.p;

View File

@@ -81,6 +81,10 @@
min-height: 556px; min-height: 556px;
} }
.sortable-tasks {
word-break: break-word;
}
.sortable-tasks + .reward-items { .sortable-tasks + .reward-items {
margin-top: 16px; margin-top: 16px;
} }
@@ -358,7 +362,7 @@ export default {
type: this.type, type: this.type,
filterType: this.activeFilter.label, filterType: this.activeFilter.label,
}) : }) :
this.taskListOverride; this.filterByCompleted(this.taskListOverride, this.activeFilter.label);
let taggedList = this.filterByTagList(filteredTaskList, this.selectedTags); let taggedList = this.filterByTagList(filteredTaskList, this.selectedTags);
let searchedList = this.filterBySearchText(taggedList, this.searchText); let searchedList = this.filterBySearchText(taggedList, this.searchText);
@@ -446,6 +450,7 @@ export default {
if (this.type !== 'todo') return; if (this.type !== 'todo') return;
this.$root.$on('habitica::resync-requested', () => { this.$root.$on('habitica::resync-requested', () => {
if (this.activeFilter.label !== 'complete2') return;
this.loadCompletedTodos(true); this.loadCompletedTodos(true);
}); });
}, },
@@ -551,7 +556,11 @@ export default {
activateFilter (type, filter = '') { activateFilter (type, filter = '') {
// Needs a separate API call as this data may not reside in store // Needs a separate API call as this data may not reside in store
if (type === 'todo' && filter === 'complete2') { if (type === 'todo' && filter === 'complete2') {
this.loadCompletedTodos(); if (this.group && this.group._id) {
this.$emit('loadGroupCompletedTodos');
} else {
this.loadCompletedTodos();
}
} }
// the only time activateFilter is called with filter==='' is when the component is first created // the only time activateFilter is called with filter==='' is when the component is first created
@@ -589,6 +598,13 @@ export default {
} }
}); });
}, },
filterByCompleted (taskList, filter) {
if (!taskList) return [];
return taskList.filter(task => {
if (filter === 'complete2') return task.completed;
return !task.completed;
});
},
filterByTagList (taskList, tagList = []) { filterByTagList (taskList, tagList = []) {
let filteredTaskList = taskList; let filteredTaskList = taskList;
// filter requested tasks by tags // filter requested tasks by tags

View File

@@ -185,6 +185,15 @@
:checked="requiresApproval", :checked="requiresApproval",
@change="updateRequiresApproval" @change="updateRequiresApproval"
) )
.form-group(v-if="task.type === 'todo'")
label(v-once) {{ $t('sharedCompletion') }}
b-dropdown.inline-dropdown(:text="$t(sharedCompletion)")
b-dropdown-item(
v-for="completionOption in ['recurringCompletion', 'singleCompletion', 'allAssignedCompletion']",
:key="completionOption",
@click="sharedCompletion = completionOption",
:class="{active: sharedCompletion === completionOption}"
) {{ $t(completionOption) }}
.advanced-settings(v-if="task.type !== 'reward'") .advanced-settings(v-if="task.type !== 'reward'")
.advanced-settings-toggle.d-flex.justify-content-between.align-items-center(@click = "showAdvancedOptions = !showAdvancedOptions") .advanced-settings-toggle.d-flex.justify-content-between.align-items-center(@click = "showAdvancedOptions = !showAdvancedOptions")
@@ -691,6 +700,7 @@ export default {
calendar: calendarIcon, calendar: calendarIcon,
}), }),
requiresApproval: false, // We can't set task.group fields so we use this field to toggle requiresApproval: false, // We can't set task.group fields so we use this field to toggle
sharedCompletion: 'recurringCompletion',
members: [], members: [],
memberNamesById: {}, memberNamesById: {},
assignedMembers: [], assignedMembers: [],
@@ -811,6 +821,7 @@ export default {
}); });
this.assignedMembers = []; this.assignedMembers = [];
if (this.task.group && this.task.group.assignedUsers) this.assignedMembers = this.task.group.assignedUsers; if (this.task.group && this.task.group.assignedUsers) this.assignedMembers = this.task.group.assignedUsers;
if (this.task.group) this.sharedCompletion = this.task.group.sharedCompletion || 'recurringCompletion';
} }
// @TODO: This whole component is mutating a prop and that causes issues. We need to not copy the prop similar to group modals // @TODO: This whole component is mutating a prop and that causes issues. We need to not copy the prop similar to group modals
@@ -892,10 +903,13 @@ export default {
async submit () { async submit () {
if (this.newChecklistItem) this.addChecklistItem(); if (this.newChecklistItem) this.addChecklistItem();
// TODO Fix up permissions on task.group so we don't have to keep doing these hacks
if (this.groupId) { if (this.groupId) {
this.task.group.assignedUsers = this.assignedMembers; this.task.group.assignedUsers = this.assignedMembers;
this.task.requiresApproval = this.requiresApproval; this.task.requiresApproval = this.requiresApproval;
this.task.group.approval.required = this.requiresApproval; this.task.group.approval.required = this.requiresApproval;
this.task.sharedCompletion = this.sharedCompletion;
this.task.group.sharedCompletion = this.sharedCompletion;
} }
if (this.purpose === 'create') { if (this.purpose === 'create') {

View File

@@ -144,7 +144,7 @@
.up(v-if='user.stats.points', @click='allocate(stat)') .up(v-if='user.stats.points', @click='allocate(stat)')
div div
.down(@click='deallocate(stat)', v-if='user.stats.points') .down(@click='deallocate(stat)', v-if='user.stats.points')
.row.save-row .row.save-row(v-if='showStatsSave')
.col-12.col-md-6.offset-md-3.text-center .col-12.col-md-6.offset-md-3.text-center
button.btn.btn-primary(@click='saveAttributes()', :disabled='loading') {{ this.loading ? $t('loading') : $t('save') }} button.btn.btn-primary(@click='saveAttributes()', :disabled='loading') {{ this.loading ? $t('loading') : $t('save') }}
</template> </template>
@@ -238,6 +238,10 @@
userLevel100Plus () { userLevel100Plus () {
return this.user.stats.lvl >= 100; return this.user.stats.lvl >= 100;
}, },
showStatsSave () {
const statsAreBeingUpdated = Object.values(this.statUpdates).find(stat => stat > 0);
return Boolean(this.user.stats.points) || statsAreBeingUpdated;
},
}, },
methods: { methods: {
getGearTitle (key) { getGearTitle (key) {

View File

@@ -1,13 +1,27 @@
export default { export default {
methods: { methods: {
makeGenericPurchase (item, type = 'buyModal', quantity = 1) { async makeGenericPurchase (item, type = 'buyModal', quantity = 1) {
this.$store.dispatch('shops:genericPurchase', { try {
pinType: item.pinType, await this.$store.dispatch('shops:genericPurchase', {
type: item.purchaseType, pinType: item.pinType,
key: item.key, type: item.purchaseType,
currency: item.currency, key: item.key,
quantity, currency: item.currency,
}); quantity,
});
} catch (e) {
if (!e.request) {
// axios request errors already handled by app.vue
this.$store.dispatch('snackbars:add', {
title: '',
text: e.message,
type: 'error',
});
return;
} else {
throw e;
}
}
this.$root.$emit('playSound', 'Reward'); this.$root.$emit('playSound', 'Reward');

View File

@@ -56,9 +56,9 @@ export default {
streak (val) { streak (val) {
this.notify(`${val}`, 'streak'); this.notify(`${val}`, 'streak');
}, },
text (val, onClick) { text (val, onClick, timeout) {
if (!val) return; if (!val) return;
this.notify(val, 'info', null, null, onClick); this.notify(val, 'info', null, null, onClick, timeout);
}, },
sign (number) { sign (number) {
return getSign(number); return getSign(number);
@@ -66,14 +66,19 @@ export default {
round (number, nDigits) { round (number, nDigits) {
return round(number, nDigits); return round(number, nDigits);
}, },
notify (html, type, icon, sign) { notify (html, type, icon, sign, onClick, timeout) {
if (typeof timeout === 'undefined') {
timeout = true;
}
this.$store.dispatch('snackbars:add', { this.$store.dispatch('snackbars:add', {
title: '', title: '',
text: html, text: html,
type, type,
icon, icon,
sign, sign,
timeout: true, onClick,
timeout,
}); });
}, },
}, },

View File

@@ -27,6 +27,7 @@ const PrivacyPage = () => import(/* webpackChunkName: "static" */'./components/s
const TermsPage = () => import(/* webpackChunkName: "static" */'./components/static/terms'); const TermsPage = () => import(/* webpackChunkName: "static" */'./components/static/terms');
const RegisterLoginReset = () => import(/* webpackChunkName: "auth" */'./components/auth/registerLoginReset'); const RegisterLoginReset = () => import(/* webpackChunkName: "auth" */'./components/auth/registerLoginReset');
const Logout = () => import(/* webpackChunkName: "auth" */'./components/auth/logout');
// User Pages // User Pages
// const StatsPage = () => import(/* webpackChunkName: "user" */'./components/userMenu/stats'); // const StatsPage = () => import(/* webpackChunkName: "user" */'./components/userMenu/stats');
@@ -105,6 +106,7 @@ const router = new VueRouter({
routes: [ routes: [
{ name: 'register', path: '/register', component: RegisterLoginReset, meta: {requiresLogin: false} }, { name: 'register', path: '/register', component: RegisterLoginReset, meta: {requiresLogin: false} },
{ name: 'login', path: '/login', component: RegisterLoginReset, meta: {requiresLogin: false} }, { name: 'login', path: '/login', component: RegisterLoginReset, meta: {requiresLogin: false} },
{ name: 'logout', path: '/logout', component: Logout },
{ name: 'resetPassword', path: '/reset-password', component: RegisterLoginReset, meta: {requiresLogin: false} }, { name: 'resetPassword', path: '/reset-password', component: RegisterLoginReset, meta: {requiresLogin: false} },
{ name: 'tasks', path: '/', component: UserTasks }, { name: 'tasks', path: '/', component: UserTasks },
{ {

View File

@@ -68,5 +68,5 @@ export async function socialAuth (store, params) {
export function logout () { export function logout () {
localStorage.removeItem(LOCALSTORAGE_AUTH_KEY); localStorage.removeItem(LOCALSTORAGE_AUTH_KEY);
localStorage.removeItem(LOCALSTORAGE_SOCIAL_AUTH_KEY); localStorage.removeItem(LOCALSTORAGE_SOCIAL_AUTH_KEY);
window.location.href = '/logout'; window.location.href = '/logout-server';
} }

View File

@@ -176,6 +176,11 @@ export async function getGroupTasks (store, payload) {
return response.data.data; return response.data.data;
} }
export async function getCompletedGroupTasks (store, payload) {
let response = await axios.get(`/api/v4/tasks/group/${payload.groupId}?type=completedTodos`);
return response.data.data;
}
export async function createGroupTasks (store, payload) { export async function createGroupTasks (store, payload) {
let response = await axios.post(`/api/v4/tasks/group/${payload.groupId}`, payload.tasks); let response = await axios.post(`/api/v4/tasks/group/${payload.groupId}`, payload.tasks);
return response.data.data; return response.data.data;

View File

@@ -131,6 +131,7 @@
"locationRequired": "Мястото на предизвикателството е задължително („Добавяне в“)", "locationRequired": "Мястото на предизвикателството е задължително („Добавяне в“)",
"categoiresRequired": "Задължително е да бъде избрана поне една категория", "categoiresRequired": "Задължително е да бъде избрана поне една категория",
"viewProgressOf": "Преглед на напредъка на", "viewProgressOf": "Преглед на напредъка на",
"viewProgress": "View Progress",
"selectMember": "Изберете член", "selectMember": "Изберете член",
"confirmKeepChallengeTasks": "Искате ли да задържите задачите от предизвикателството?", "confirmKeepChallengeTasks": "Искате ли да задържите задачите от предизвикателството?",
"selectParticipant": "Изберете участник" "selectParticipant": "Изберете участник"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Катерица", "questEggSquirrelText": "Катерица",
"questEggSquirrelMountText": "Катерица", "questEggSquirrelMountText": "Катерица",
"questEggSquirrelAdjective": "рунтава", "questEggSquirrelAdjective": "рунтава",
"questEggSeaSerpentText": "Морски змей",
"questEggSeaSerpentMountText": "Морски змей",
"questEggSeaSerpentAdjective": "блещукащ",
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Нормален цвят", "hatchingPotionBase": "Нормален цвят",
"hatchingPotionWhite": "Бял цвят", "hatchingPotionWhite": "Бял цвят",

View File

@@ -1162,7 +1162,7 @@
"headArmoireBigWigNotes": "Някои напудрени перуки придават авторитет, но тази е само за смях! Увеличава силата с <%= str %>. Омагьосан гардероб: независим предмет.", "headArmoireBigWigNotes": "Някои напудрени перуки придават авторитет, но тази е само за смях! Увеличава силата с <%= str %>. Омагьосан гардероб: независим предмет.",
"headArmoireGlassblowersHatText": "Шапка на стъклодухач", "headArmoireGlassblowersHatText": "Шапка на стъклодухач",
"headArmoireGlassblowersHatNotes": "Тази шапка просто си отива с останалото защитно облекло на стъклодухач! Увеличава усета с <%= per %>. Омагьосан гардероб: комплект „Стъклодухач“ (предмет 3 от 4).", "headArmoireGlassblowersHatNotes": "Тази шапка просто си отива с останалото защитно облекло на стъклодухач! Увеличава усета с <%= per %>. Омагьосан гардероб: комплект „Стъклодухач“ (предмет 3 от 4).",
"headArmoirePiraticalPrincessHeaddressText": "Piratical Princess Headdress", "headArmoirePiraticalPrincessHeaddressText": "Украса за глава на пиратска принцеса",
"headArmoirePiraticalPrincessHeaddressNotes": "Пиратите са известни с причудливите неща, които носят на главите си! Увеличава усета и интелигентността с по <%= attrs %>. Омагьосан гардероб: комплект „Пиратска принцеса“ (предмет 1 от 4).", "headArmoirePiraticalPrincessHeaddressNotes": "Пиратите са известни с причудливите неща, които носят на главите си! Увеличава усета и интелигентността с по <%= attrs %>. Омагьосан гардероб: комплект „Пиратска принцеса“ (предмет 1 от 4).",
"offhand": "страничен предмет", "offhand": "страничен предмет",
"offhandCapitalized": "Страничен предмет", "offhandCapitalized": "Страничен предмет",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Наистина ли искате да одобрите тази задача?", "confirmApproval": "Наистина ли искате да одобрите тази задача?",
"confirmNeedsWork": "Наистина ли искате да отбележите, че тази задача се нуждае от още работа?", "confirmNeedsWork": "Наистина ли искате да отбележите, че тази задача се нуждае от още работа?",
"userRequestsApproval": "<%= userName %> иска одобрение", "userRequestsApproval": "<%= userName %> иска одобрение",
"userCountRequestsApproval": "<%= userCount %> потребители искат одобрение", "userCountRequestsApproval": "<%= userCount %> членове искат одобрение",
"youAreRequestingApproval": "Вие искате одобрение", "youAreRequestingApproval": "Вие искате одобрение",
"chatPrivilegesRevoked": "Не можете да направите това, защото привилегиите Ви в чата са Ви били отнети.", "chatPrivilegesRevoked": "Не можете да направите това, защото привилегиите Ви в чата са Ви били отнети.",
"cannotCreatePublicGuildWhenMuted": "Не можете да създадете обществена гилдия, защото привилегиите Ви в чата са Ви били отнети.", "cannotCreatePublicGuildWhenMuted": "Не можете да създадете обществена гилдия, защото привилегиите Ви в чата са Ви били отнети.",
@@ -380,6 +380,7 @@
"bronzeTier": "Бронзово ниво", "bronzeTier": "Бронзово ниво",
"privacySettings": "Настройки за поверителността", "privacySettings": "Настройки за поверителността",
"onlyLeaderCreatesChallenges": "Само водачът може да създава предизвикателства", "onlyLeaderCreatesChallenges": "Само водачът може да създава предизвикателства",
"onlyLeaderCreatesChallengesDetail": "Ако това е избрано, обикновените членове на групата няма да могат да създават предизвикателства.",
"privateGuild": "Частна гилдия", "privateGuild": "Частна гилдия",
"charactersRemaining": "Оставащи знаци: <%= characters %>", "charactersRemaining": "Оставащи знаци: <%= characters %>",
"guildSummary": "Резюме", "guildSummary": "Резюме",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Пакет мисии „Пухкави приятелчета“", "cuddleBuddiesText": "Пакет мисии „Пухкави приятелчета“",
"cuddleBuddiesNotes": "Съдържа: „Зайчето-убиец“, „Нечестивият пор“ и „Бандата на морските свинчета“. Наличен до 31 май.", "cuddleBuddiesNotes": "Съдържа: „Зайчето-убиец“, „Нечестивият пор“ и „Бандата на морските свинчета“. Наличен до 31 май.",
"aquaticAmigosText": "Пакет мисии „Водни дружки“", "aquaticAmigosText": "Пакет мисии „Водни дружки“",
"aquaticAmigosNotes": "Съдържа: „Вълшебният саламандър“, „Кракенът на незавършеността“ и „Зовът на Октотулу“. Наличен до 30 юни." "aquaticAmigosNotes": "Съдържа: „Вълшебният саламандър“, „Кракенът на незавършеността“ и „Зовът на Октотулу“. Наличен до 30 юни.",
"questSeaSerpentText": "Опасност в дълбините: Нападението на морския змей!",
"questSeaSerpentNotes": "С всичките си серии се чувстваш като късметлия и сега е идеално време за посещение на хиподрума за морски кончета. Качваш се на подводницата от пристанище Усърдие и се настаняваш удобно за пътуването до Мудноград, но едва се потапяте, когато нещо удря подводницата и запраща всички пътници на пода. „Какво става“ — крещи @AriesFaries?<br><br>Поглеждаш през близкия люк и ужас виждаш как покрай него преминава стена от блестящи люспи. „Морски змей“ — обявява капитан @Witticaster по вътрешното радио! — „Пригответе се, връща се!“ Сграбчвайки подлакътниците на седалката си, виждаш незавършените си задачи да преминават пред погледа ти. „Може би, ако работим заедно и ги завършим“, мислиш си, „ще прогоним чудовището“.",
"questSeaSerpentCompletion": "Сломен от усърдието ви, морският змей отстъпва и изчезва в дълбините. Когато пристигаш в Мудноград, най-после си отдъхваш, и забелязваш, че @*~Seraphina~ се приближава с три яйца. „Ето, вземи ги“ — казва тя. — „Явно знаеш как да се оправяш с морските змейове!“ Когато вземаш яйцата, отново се заричаш да бъдеш по-сериозен със задачите си, за да не се повтори тази случка.",
"questSeaSerpentBoss": "Могъщият морски змей",
"questSeaSerpentDropSeaSerpentEgg": "Морски змей (яйце)",
"questSeaSerpentUnlockText": "Отключва възможността за купуване на яйца на морски змей от пазара."
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "Musí být vybrána jedna nebo více kategorií", "categoiresRequired": "Musí být vybrána jedna nebo více kategorií",
"viewProgressOf": "Zobrazit pokrok", "viewProgressOf": "Zobrazit pokrok",
"viewProgress": "View Progress",
"selectMember": "Vyber člena", "selectMember": "Vyber člena",
"confirmKeepChallengeTasks": "Chceš ponechat úkoly z výzvy?", "confirmKeepChallengeTasks": "Chceš ponechat úkoly z výzvy?",
"selectParticipant": "Zvol účastníka" "selectParticipant": "Zvol účastníka"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Squirrel", "questEggSquirrelText": "Squirrel",
"questEggSquirrelMountText": "Squirrel", "questEggSquirrelMountText": "Squirrel",
"questEggSquirrelAdjective": "bushy-tailed", "questEggSquirrelAdjective": "bushy-tailed",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a to se vylíhne v <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a to se vylíhne v <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Základní", "hatchingPotionBase": "Základní",
"hatchingPotionWhite": "Bílý", "hatchingPotionWhite": "Bílý",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Are you sure you want to approve this task?", "confirmApproval": "Are you sure you want to approve this task?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
"userRequestsApproval": "<%= userName %> requests approval", "userRequestsApproval": "<%= userName %> requests approval",
"userCountRequestsApproval": "<%= userCount %> request approval", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "You are requesting approval", "youAreRequestingApproval": "You are requesting approval",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.",
@@ -380,6 +380,7 @@
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",
"privacySettings": "Privacy Settings", "privacySettings": "Privacy Settings",
"onlyLeaderCreatesChallenges": "Only the Leader can create Challenges", "onlyLeaderCreatesChallenges": "Only the Leader can create Challenges",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Private Guild", "privateGuild": "Private Guild",
"charactersRemaining": "<%= characters %> characters remaining", "charactersRemaining": "<%= characters %> characters remaining",
"guildSummary": "Summary", "guildSummary": "Summary",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle", "cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "One or more categories must be selected", "categoiresRequired": "One or more categories must be selected",
"viewProgressOf": "View Progress Of", "viewProgressOf": "View Progress Of",
"viewProgress": "View Progress",
"selectMember": "Select Member", "selectMember": "Select Member",
"confirmKeepChallengeTasks": "Do you want to keep challenge tasks?", "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?",
"selectParticipant": "Select a Participant" "selectParticipant": "Select a Participant"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Squirrel", "questEggSquirrelText": "Squirrel",
"questEggSquirrelMountText": "Squirrel", "questEggSquirrelMountText": "Squirrel",
"questEggSquirrelAdjective": "bushy-tailed", "questEggSquirrelAdjective": "bushy-tailed",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Almindelig", "hatchingPotionBase": "Almindelig",
"hatchingPotionWhite": "Hvid", "hatchingPotionWhite": "Hvid",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Are you sure you want to approve this task?", "confirmApproval": "Are you sure you want to approve this task?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
"userRequestsApproval": "<%= userName %> requests approval", "userRequestsApproval": "<%= userName %> requests approval",
"userCountRequestsApproval": "<%= userCount %> request approval", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "You are requesting approval", "youAreRequestingApproval": "You are requesting approval",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.",
@@ -380,6 +380,7 @@
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",
"privacySettings": "Privacy Settings", "privacySettings": "Privacy Settings",
"onlyLeaderCreatesChallenges": "Only the Leader can create Challenges", "onlyLeaderCreatesChallenges": "Only the Leader can create Challenges",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Private Guild", "privateGuild": "Private Guild",
"charactersRemaining": "<%= characters %> characters remaining", "charactersRemaining": "<%= characters %> characters remaining",
"guildSummary": "Summary", "guildSummary": "Summary",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle", "cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Zuordnung des Wettbewerbs ist erforderlich (Füge hinzu)", "locationRequired": "Zuordnung des Wettbewerbs ist erforderlich (Füge hinzu)",
"categoiresRequired": "Mindestens eine Kategorie muss ausgewählt sein", "categoiresRequired": "Mindestens eine Kategorie muss ausgewählt sein",
"viewProgressOf": "Fortschritt ansehen von", "viewProgressOf": "Fortschritt ansehen von",
"viewProgress": "View Progress",
"selectMember": "Ein Mitglied auswählen", "selectMember": "Ein Mitglied auswählen",
"confirmKeepChallengeTasks": "Möchtest Du die Wettbewerbsaufgaben behalten?", "confirmKeepChallengeTasks": "Möchtest Du die Wettbewerbsaufgaben behalten?",
"selectParticipant": "Wähle einen Teilnehmer aus" "selectParticipant": "Wähle einen Teilnehmer aus"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Eichörnchen", "questEggSquirrelText": "Eichörnchen",
"questEggSquirrelMountText": "Eichörnchen", "questEggSquirrelMountText": "Eichörnchen",
"questEggSquirrelAdjective": "mit einem flauschigen Schwanz", "questEggSquirrelAdjective": "mit einem flauschigen Schwanz",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein <%= eggAdjective(locale) %> <%= eggText(locale) %> schlüpfen kann.", "eggNotes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein <%= eggAdjective(locale) %> <%= eggText(locale) %> schlüpfen kann.",
"hatchingPotionBase": "Normales", "hatchingPotionBase": "Normales",
"hatchingPotionWhite": "Weißes", "hatchingPotionWhite": "Weißes",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Bist Du sicher, dass Du diese Aufgabe bestätigen möchtest?", "confirmApproval": "Bist Du sicher, dass Du diese Aufgabe bestätigen möchtest?",
"confirmNeedsWork": "Bist Du sicher, dass Du diese Aufgabe auf \"Benötigt Arbeit\" setzen möchtest?", "confirmNeedsWork": "Bist Du sicher, dass Du diese Aufgabe auf \"Benötigt Arbeit\" setzen möchtest?",
"userRequestsApproval": "<%= userName %> beantragt eine Bestätigung", "userRequestsApproval": "<%= userName %> beantragt eine Bestätigung",
"userCountRequestsApproval": "<%= userCount %> beantragen eine Bestätigung", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "Du beantragst eine Bestätigung", "youAreRequestingApproval": "Du beantragst eine Bestätigung",
"chatPrivilegesRevoked": "Du kannst dies nicht tun, da Dir Deine Chat-Privilegien entzogen wurden.", "chatPrivilegesRevoked": "Du kannst dies nicht tun, da Dir Deine Chat-Privilegien entzogen wurden.",
"cannotCreatePublicGuildWhenMuted": "Du kannst keine öffentliche Gilde erstellen, da Dir Deine Chat-Privilegien entzogen wurden.", "cannotCreatePublicGuildWhenMuted": "Du kannst keine öffentliche Gilde erstellen, da Dir Deine Chat-Privilegien entzogen wurden.",
@@ -380,6 +380,7 @@
"bronzeTier": "Bronze", "bronzeTier": "Bronze",
"privacySettings": "Datenschutzeinstellungen", "privacySettings": "Datenschutzeinstellungen",
"onlyLeaderCreatesChallenges": "Nur der Leiter kann Wettbewerbe erstellen", "onlyLeaderCreatesChallenges": "Nur der Leiter kann Wettbewerbe erstellen",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Private Gilde", "privateGuild": "Private Gilde",
"charactersRemaining": "<%= characters %> Zeichen übrig", "charactersRemaining": "<%= characters %> Zeichen übrig",
"guildSummary": "Zusammenfassung", "guildSummary": "Zusammenfassung",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "\"Kuschelkumpel\" Quest-Paket", "cuddleBuddiesText": "\"Kuschelkumpel\" Quest-Paket",
"cuddleBuddiesNotes": "Beinhaltet 'Das Killerkaninchen', 'Das Ruchlose Frettchen' und 'Die Meerschweinchen Gang'. Verfügbar bis zum 31. Mai.", "cuddleBuddiesNotes": "Beinhaltet 'Das Killerkaninchen', 'Das Ruchlose Frettchen' und 'Die Meerschweinchen Gang'. Verfügbar bis zum 31. Mai.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -1,4 +1,5 @@
{ {
"achievement": "Achievement",
"share": "Share", "share": "Share",
"onwards": "Onwards!", "onwards": "Onwards!",
"levelup": "By accomplishing your real life goals, you leveled up and are now fully healed!", "levelup": "By accomplishing your real life goals, you leveled up and are now fully healed!",

View File

@@ -132,6 +132,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "One or more categories must be selected", "categoiresRequired": "One or more categories must be selected",
"viewProgressOf": "View Progress Of", "viewProgressOf": "View Progress Of",
"viewProgress": "View Progress",
"selectMember": "Select Member", "selectMember": "Select Member",
"confirmKeepChallengeTasks": "Do you want to keep challenge tasks?", "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?",
"selectParticipant": "Select a Participant" "selectParticipant": "Select a Participant"

View File

@@ -235,6 +235,10 @@
"questEggSquirrelMountText": "Squirrel", "questEggSquirrelMountText": "Squirrel",
"questEggSquirrelAdjective": "bushy-tailed", "questEggSquirrelAdjective": "bushy-tailed",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Base", "hatchingPotionBase": "Base",

View File

@@ -475,5 +475,9 @@
"howToRequireApprovalDesc2": "Group Leaders and Managers can approve completed Tasks directly from the Task Board or from the Notifications panel.", "howToRequireApprovalDesc2": "Group Leaders and Managers can approve completed Tasks directly from the Task Board or from the Notifications panel.",
"whatIsGroupManager": "What is a Group Manager?", "whatIsGroupManager": "What is a Group Manager?",
"whatIsGroupManagerDesc": "A Group Manager is a user role that do not have access to the group's billing details, but can create, assign, and approve shared Tasks for the Group's members. Promote Group Managers from the Groups member list.", "whatIsGroupManagerDesc": "A Group Manager is a user role that do not have access to the group's billing details, but can create, assign, and approve shared Tasks for the Group's members. Promote Group Managers from the Groups member list.",
"goToTaskBoard": "Go to Task Board" "goToTaskBoard": "Go to Task Board",
"sharedCompletion": "Shared Completion",
"recurringCompletion": "None - Group task does not complete",
"singleCompletion": "Single - Completes when any assigned user finishes",
"allAssignedCompletion": "All - Completes when all assigned users finish"
} }

View File

@@ -700,5 +700,12 @@
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "One or more categories must be selected", "categoiresRequired": "One or more categories must be selected",
"viewProgressOf": "View Progress Of", "viewProgressOf": "View Progress Of",
"viewProgress": "View Progress",
"selectMember": "Select Member", "selectMember": "Select Member",
"confirmKeepChallengeTasks": "Do you want to keep challenge tasks?", "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?",
"selectParticipant": "Select a Participant" "selectParticipant": "Select a Participant"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Squirrel", "questEggSquirrelText": "Squirrel",
"questEggSquirrelMountText": "Squirrel", "questEggSquirrelMountText": "Squirrel",
"questEggSquirrelAdjective": "bushy-tailed", "questEggSquirrelAdjective": "bushy-tailed",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Find ye hatchin' potion to pourrrr on this egg, an' it'll hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Find ye hatchin' potion to pourrrr on this egg, an' it'll hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Base", "hatchingPotionBase": "Base",
"hatchingPotionWhite": "White", "hatchingPotionWhite": "White",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Are you sure you want to approve this task?", "confirmApproval": "Are you sure you want to approve this task?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
"userRequestsApproval": "<%= userName %> requests approval", "userRequestsApproval": "<%= userName %> requests approval",
"userCountRequestsApproval": "<%= userCount %> request approval", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "You are requesting approval", "youAreRequestingApproval": "You are requesting approval",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
"cannotCreatePublicGuildWhenMuted": "Ye cannot create a public guild because yer chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "Ye cannot create a public guild because yer chat privileges have been revoked.",
@@ -380,6 +380,7 @@
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",
"privacySettings": "Privacy Settings", "privacySettings": "Privacy Settings",
"onlyLeaderCreatesChallenges": "Only the Leader can create Challenges", "onlyLeaderCreatesChallenges": "Only the Leader can create Challenges",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Private Guild", "privateGuild": "Private Guild",
"charactersRemaining": "<%= characters %> characters remaining", "charactersRemaining": "<%= characters %> characters remaining",
"guildSummary": "Summary", "guildSummary": "Summary",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle", "cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "One or more categories must be selected", "categoiresRequired": "One or more categories must be selected",
"viewProgressOf": "View Progress Of", "viewProgressOf": "View Progress Of",
"viewProgress": "View Progress",
"selectMember": "Select Member", "selectMember": "Select Member",
"confirmKeepChallengeTasks": "Do you want to keep challenge tasks?", "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?",
"selectParticipant": "Select a Participant" "selectParticipant": "Select a Participant"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Squirrel", "questEggSquirrelText": "Squirrel",
"questEggSquirrelMountText": "Squirrel", "questEggSquirrelMountText": "Squirrel",
"questEggSquirrelAdjective": "bushy-tailed", "questEggSquirrelAdjective": "bushy-tailed",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Base", "hatchingPotionBase": "Base",
"hatchingPotionWhite": "White", "hatchingPotionWhite": "White",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "Are you sure you want to approve this task?", "confirmApproval": "Are you sure you want to approve this task?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
"userRequestsApproval": "<%= userName %> requests approval", "userRequestsApproval": "<%= userName %> requests approval",
"userCountRequestsApproval": "<%= userCount %> request approval", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "You are requesting approval", "youAreRequestingApproval": "You are requesting approval",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.",
@@ -380,6 +380,7 @@
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",
"privacySettings": "Privacy Settings", "privacySettings": "Privacy Settings",
"onlyLeaderCreatesChallenges": "Only the Leader can create Challenges", "onlyLeaderCreatesChallenges": "Only the Leader can create Challenges",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Private Guild", "privateGuild": "Private Guild",
"charactersRemaining": "<%= characters %> characters remaining", "charactersRemaining": "<%= characters %> characters remaining",
"guildSummary": "Summary", "guildSummary": "Summary",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle", "cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "Location of challenge is required ('Add to')", "locationRequired": "Location of challenge is required ('Add to')",
"categoiresRequired": "One or more categories must be selected", "categoiresRequired": "One or more categories must be selected",
"viewProgressOf": "View Progress Of", "viewProgressOf": "View Progress Of",
"viewProgress": "View Progress",
"selectMember": "Select Member", "selectMember": "Select Member",
"confirmKeepChallengeTasks": "¿Deseas mantener las tareas de retos?", "confirmKeepChallengeTasks": "¿Deseas mantener las tareas de retos?",
"selectParticipant": "Elige un participante" "selectParticipant": "Elige un participante"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Ardilla", "questEggSquirrelText": "Ardilla",
"questEggSquirrelMountText": "Ardilla", "questEggSquirrelMountText": "Ardilla",
"questEggSquirrelAdjective": "de cola tupida", "questEggSquirrelAdjective": "de cola tupida",
"questEggSeaSerpentText": "Serpiente marina",
"questEggSeaSerpentMountText": "Serpiente marina",
"questEggSeaSerpentAdjective": "brillante",
"eggNotes": "Encuentra una poción de eclosión para verter en este huevo y eclosionará en <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Encuentra una poción de eclosión para verter en este huevo y eclosionará en <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Base", "hatchingPotionBase": "Base",
"hatchingPotionWhite": "Blanco", "hatchingPotionWhite": "Blanco",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "¿Estás seguro de querer aprobar esta tarea?", "confirmApproval": "¿Estás seguro de querer aprobar esta tarea?",
"confirmNeedsWork": "¿Estás seguro de querer marcar esta tarea como trabajo necesario?", "confirmNeedsWork": "¿Estás seguro de querer marcar esta tarea como trabajo necesario?",
"userRequestsApproval": "<%= userName %>requieren aprobación", "userRequestsApproval": "<%= userName %>requieren aprobación",
"userCountRequestsApproval": "<%= userCount %> requieren aprobación", "userCountRequestsApproval": "<%= userCount %> miembros requieren aprobación",
"youAreRequestingApproval": "Estás solicitando aprobación", "youAreRequestingApproval": "Estás solicitando aprobación",
"chatPrivilegesRevoked": "No puedes hacer eso porque tus privilegios para chatear han sido revocados.", "chatPrivilegesRevoked": "No puedes hacer eso porque tus privilegios para chatear han sido revocados.",
"cannotCreatePublicGuildWhenMuted": "No puedes crear un gremio público porque tus privilegios para chatear han sido revocados.", "cannotCreatePublicGuildWhenMuted": "No puedes crear un gremio público porque tus privilegios para chatear han sido revocados.",
@@ -380,6 +380,7 @@
"bronzeTier": "Nivel Bronce", "bronzeTier": "Nivel Bronce",
"privacySettings": "Ajustes de privacidad", "privacySettings": "Ajustes de privacidad",
"onlyLeaderCreatesChallenges": "Sólo el líder puede crear Retos", "onlyLeaderCreatesChallenges": "Sólo el líder puede crear Retos",
"onlyLeaderCreatesChallengesDetail": "Con esta opción seleccionada, los miembros normales del grupo no pueden crear desafíos para el grupo.",
"privateGuild": "Hermandad privada", "privateGuild": "Hermandad privada",
"charactersRemaining": "<%= characters %> caracteres restantes", "charactersRemaining": "<%= characters %> caracteres restantes",
"guildSummary": "Resumen", "guildSummary": "Resumen",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Lote de Misiones Compañeros Abrazados", "cuddleBuddiesText": "Lote de Misiones Compañeros Abrazados",
"cuddleBuddiesNotes": "Contiene \"El Conejito Asesino\", \"El Hurón Malvado\", y \"La Pandilla de Cobayas\". Disponible hasta el 31 de mayo.", "cuddleBuddiesNotes": "Contiene \"El Conejito Asesino\", \"El Hurón Malvado\", y \"La Pandilla de Cobayas\". Disponible hasta el 31 de mayo.",
"aquaticAmigosText": "Lote de Misiones de Amigos Acuáticos", "aquaticAmigosText": "Lote de Misiones de Amigos Acuáticos",
"aquaticAmigosNotes": "Contiene 'El ajolote mágico', 'El Kraken del Inkompleto' y 'La llamada de Octothulu'. Disponible hasta el 30 de junio." "aquaticAmigosNotes": "Contiene 'El ajolote mágico', 'El Kraken del Inkompleto' y 'La llamada de Octothulu'. Disponible hasta el 30 de junio.",
"questSeaSerpentText": "Peligro en las profundidades: ¡Ataque de la serpiente marina!",
"questSeaSerpentNotes": "Tus manchas te hacen sentir afortunado: es el momento perfecto para un viaje a la pista de carreras de caballitos de mar. Abordas el submarino en Muelles Diligentes y te acomodas para el viaje a Dilatoria, pero apenas te has sumergido cuando un impacto sacude el submarino, haciendo que sus ocupantes caigan.\n ¿Qué está pasando? grita @AriesFaries. <br><br>Miras a través de un ojo de buey cercano y te sorprende la pared de escamas brillantes que pasan por allí.\n¡Serpiente de mar! aclama el capitán @Witticaster a través del intercomunicador. ¡Preparaos, viene otra vez!\nMientras agarras los brazos de tu asiento, tus tareas inconclusas parpadean ante tus ojos. \"Quizás si trabajamos juntos y los completamos\", piensas, \"¡podemos alejar a este monstruo!\"",
"questSeaSerpentCompletion": "Maltrecha por tu compromiso, la serpiente marina huye, desapareciendo en las profundidades. Cuando llegas a Dilatoria, sueltas un suspiro de alivio antes de ver que @*~Seraphina~ se acerca con tres huevos translúcidos acunados en sus brazos. \n Aquí, debes quedarte con esto dice ella. ¡Sabes cómo manejar una serpiente marina!\nAl aceptar los huevos, prometes nuevamente mantenerte firme al completar tus tareas para asegurarte de que no vuelva a ocurrir.",
"questSeaSerpentBoss": "La poderosa serpiente marina",
"questSeaSerpentDropSeaSerpentEgg": "Serpiente marina (huevo)",
"questSeaSerpentUnlockText": "Desbloquear la compra de huevos de serpiente de agua en el Mercado"
} }

View File

@@ -131,6 +131,7 @@
"locationRequired": "La ubicación del reto es necesaria (\"Añadir a\")", "locationRequired": "La ubicación del reto es necesaria (\"Añadir a\")",
"categoiresRequired": "Una o más categorías deben ser seleccionadas", "categoiresRequired": "Una o más categorías deben ser seleccionadas",
"viewProgressOf": "Ver el Progreso de", "viewProgressOf": "Ver el Progreso de",
"viewProgress": "View Progress",
"selectMember": "Seleccionar miembro", "selectMember": "Seleccionar miembro",
"confirmKeepChallengeTasks": "¿Quieres mantener las tareas del reto?", "confirmKeepChallengeTasks": "¿Quieres mantener las tareas del reto?",
"selectParticipant": "Seleccionar un Participante" "selectParticipant": "Seleccionar un Participante"

View File

@@ -170,6 +170,9 @@
"questEggSquirrelText": "Ardilla", "questEggSquirrelText": "Ardilla",
"questEggSquirrelMountText": "Ardilla", "questEggSquirrelMountText": "Ardilla",
"questEggSquirrelAdjective": "de cola tupida", "questEggSquirrelAdjective": "de cola tupida",
"questEggSeaSerpentText": "Sea Serpent",
"questEggSeaSerpentMountText": "Sea Serpent",
"questEggSeaSerpentAdjective": "shimmering",
"eggNotes": "Encuentra una poción de eclosión para verter sobre este huevo y se convertirá en <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "eggNotes": "Encuentra una poción de eclosión para verter sobre este huevo y se convertirá en <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Básico", "hatchingPotionBase": "Básico",
"hatchingPotionWhite": "Blanco", "hatchingPotionWhite": "Blanco",

View File

@@ -255,7 +255,7 @@
"confirmApproval": "¿Estás seguro que quieres aprobar esta tarea?", "confirmApproval": "¿Estás seguro que quieres aprobar esta tarea?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
"userRequestsApproval": "<%= userName %> solicita aprobación", "userRequestsApproval": "<%= userName %> solicita aprobación",
"userCountRequestsApproval": "<%= userCount %> solicitan aprobación", "userCountRequestsApproval": "<%= userCount %> members request approval",
"youAreRequestingApproval": "Estás solicitando aprobación", "youAreRequestingApproval": "Estás solicitando aprobación",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.",
@@ -380,6 +380,7 @@
"bronzeTier": "Nivel Bronce", "bronzeTier": "Nivel Bronce",
"privacySettings": "Ajustes de Privacidad", "privacySettings": "Ajustes de Privacidad",
"onlyLeaderCreatesChallenges": "Solo el Líder puede crear Desafíos", "onlyLeaderCreatesChallenges": "Solo el Líder puede crear Desafíos",
"onlyLeaderCreatesChallengesDetail": "With this option selected, ordinary group members cannot create Challenges for the group.",
"privateGuild": "Gremio Privado", "privateGuild": "Gremio Privado",
"charactersRemaining": "<%= characters %> caracteres restantes", "charactersRemaining": "<%= characters %> caracteres restantes",
"guildSummary": "Resumen", "guildSummary": "Resumen",

View File

@@ -604,5 +604,11 @@
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle", "cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.", "cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31.",
"aquaticAmigosText": "Aquatic Amigos Quest Bundle", "aquaticAmigosText": "Aquatic Amigos Quest Bundle",
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30." "aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'. Available until June 30.",
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
"questSeaSerpentNotes": "Your streaks have you feeling lucky—its the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but youve barely submerged when an impact rocks the sub, sending its occupants tumbling. “Whats going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, its coming round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. Maybe if we work together and complete them, you think, we can drive this monster away!",
"questSeaSerpentCompletion": "Battered by your commitment, the sea serpent flees, disappearing into the depths. When you arrive in Dilatory, you breathe a sigh of relief before noticing @*~Seraphina~ approaching with three translucent eggs cradled in her arms. “Here, you should have these,” she says. “You know how to handle a sea serpent!” As you accept the eggs, you vow anew to remain steadfast in completing your tasks to ensure that theres not a repeat occurrence.",
"questSeaSerpentBoss": "The Mighty Sea Serpent",
"questSeaSerpentDropSeaSerpentEgg": "Sea Serpent (Egg)",
"questSeaSerpentUnlockText": "Unlocks purchasable Sea Serpent eggs in the Market"
} }

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