mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-23 14:17:05 +00:00
Merge branch 'develop' into release
This commit is contained in:
commit
0f2d2ddad6
73 changed files with 3861 additions and 1620 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -37,6 +37,7 @@ yarn.lock
|
|||
.elasticbeanstalk/*
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
/.vscode
|
||||
|
||||
# webstorm fake webpack for path intellisense
|
||||
webpack.webstorm.config
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@ test/**
|
|||
*.swp
|
||||
*.swx
|
||||
website/raw_sprites/**
|
||||
content_cache/**
|
||||
|
|
|
|||
|
|
@ -75,5 +75,9 @@
|
|||
"WEB_CONCURRENCY": 1,
|
||||
"SKIP_SSL_CHECK_KEY": "key",
|
||||
"ENABLE_STACKDRIVER_TRACING": "false",
|
||||
"APPLE_AUTH_PRIVATE_KEY": "",
|
||||
"APPLE_TEAM_ID": "",
|
||||
"APPLE_AUTH_CLIENT_ID": "",
|
||||
"APPLE_AUTH_KEY_ID": "",
|
||||
"BLOCKED_IPS": ""
|
||||
}
|
||||
|
|
|
|||
477
package-lock.json
generated
477
package-lock.json
generated
|
|
@ -1472,6 +1472,15 @@
|
|||
"defer-to-connect": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@types/body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
|
||||
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
|
||||
"requires": {
|
||||
"@types/connect": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/cacheable-request": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
|
||||
|
|
@ -1489,11 +1498,56 @@
|
|||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/connect": {
|
||||
"version": "3.4.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
|
||||
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.4.tgz",
|
||||
"integrity": "sha512-DO1L53rGqIDUEvOjJKmbMEQ5Z+BM2cIEPy/eV3En+s166Gz+FeuzRerxcab757u/U4v4XF4RYrZPmqKa+aY/2w==",
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/qs": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-jwt": {
|
||||
"version": "0.0.42",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.42.tgz",
|
||||
"integrity": "sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag==",
|
||||
"requires": {
|
||||
"@types/express": "*",
|
||||
"@types/express-unless": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.3.tgz",
|
||||
"integrity": "sha512-sHEsvEzjqN+zLbqP+8OXTipc10yH1QLR+hnr5uw29gi9AhCAAAdri8ClNV7iMdrJrIzXIQtlkPvq8tJGhj3QJQ==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-unless": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.1.tgz",
|
||||
"integrity": "sha512-5fuvg7C69lemNgl0+v+CUxDYWVPSfXHhJPst4yTLcqi4zKJpORCxnDrnnilk3k0DTq/WrAUdvXFs01+vUqUZHw==",
|
||||
"requires": {
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/form-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.5.0.tgz",
|
||||
|
|
@ -1533,6 +1587,11 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
|
||||
"integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw=="
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||
|
|
@ -1570,6 +1629,16 @@
|
|||
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
|
||||
"optional": true
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz",
|
||||
"integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw=="
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
|
||||
},
|
||||
"@types/responselike": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
|
||||
|
|
@ -1583,6 +1652,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
|
||||
},
|
||||
"@types/serve-static": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
|
||||
"integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
|
||||
"requires": {
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/mime": "*"
|
||||
}
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-5.1.2.tgz",
|
||||
|
|
@ -2029,6 +2107,16 @@
|
|||
"default-require-extensions": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"apple-auth": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/apple-auth/-/apple-auth-1.0.5.tgz",
|
||||
"integrity": "sha512-EbMm0rqWyUANxHJfiNGrvLkS3acdBfAj0TJ1hnA/jxq7+l9GTd2br5ajgjBjcHT5bbN6CsvuZFAdYofzn1J/6A==",
|
||||
"requires": {
|
||||
"axios": "^0.19.0",
|
||||
"express": "^4.17.1",
|
||||
"jsonwebtoken": "^8.5.1"
|
||||
}
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
|
|
@ -2298,9 +2386,9 @@
|
|||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||
},
|
||||
"aws-sdk": {
|
||||
"version": "2.648.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.648.0.tgz",
|
||||
"integrity": "sha512-b+PdZmCFvZBisqXEH68jO4xB30LrDHQMWrEX6MJoZaOlxPJfpOqRFUH3zsiAXF5Q2jTdjYLtS5bs3vcIwRzi3Q==",
|
||||
"version": "2.653.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.653.0.tgz",
|
||||
"integrity": "sha512-vtpHfoAKoudNa5kknUgQeXzdnmkI63hqKYHuk5u7mx0HelP8iybTxmKfKENlOvkfKtBdCEbcmJRa3DxZUbQPHQ==",
|
||||
"requires": {
|
||||
"buffer": "4.9.1",
|
||||
"events": "1.1.1",
|
||||
|
|
@ -2353,7 +2441,6 @@
|
|||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
}
|
||||
|
|
@ -2938,6 +3025,11 @@
|
|||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
|
||||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||
|
|
@ -6051,22 +6143,26 @@
|
|||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"optional": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"delegates": "^1.0.0",
|
||||
|
|
@ -6075,12 +6171,14 @@
|
|||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
|
|
@ -6089,32 +6187,38 @@
|
|||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"optional": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
|
|
@ -6122,22 +6226,26 @@
|
|||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"optional": true
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"optional": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
|
|
@ -6145,12 +6253,14 @@
|
|||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"optional": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"aproba": "^1.0.3",
|
||||
|
|
@ -6165,7 +6275,8 @@
|
|||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
|
|
@ -6178,12 +6289,14 @@
|
|||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"optional": true
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
|
|
@ -6191,7 +6304,8 @@
|
|||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimatch": "^3.0.4"
|
||||
|
|
@ -6199,7 +6313,8 @@
|
|||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
|
|
@ -6208,17 +6323,20 @@
|
|||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
|
|
@ -6226,12 +6344,14 @@
|
|||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"optional": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
|
|
@ -6239,12 +6359,14 @@
|
|||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
|
|
@ -6253,7 +6375,8 @@
|
|||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
|
|
@ -6261,7 +6384,8 @@
|
|||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
|
|
@ -6269,12 +6393,14 @@
|
|||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"optional": true
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.3.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.0",
|
||||
|
|
@ -6284,7 +6410,8 @@
|
|||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"detect-libc": "^1.0.2",
|
||||
|
|
@ -6301,7 +6428,8 @@
|
|||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"abbrev": "1",
|
||||
|
|
@ -6310,12 +6438,14 @@
|
|||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
|
||||
"optional": true
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ignore-walk": "^3.0.1",
|
||||
|
|
@ -6324,7 +6454,8 @@
|
|||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"are-we-there-yet": "~1.1.2",
|
||||
|
|
@ -6335,17 +6466,20 @@
|
|||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"optional": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
|
|
@ -6353,17 +6487,20 @@
|
|||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"optional": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"optional": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"os-homedir": "^1.0.0",
|
||||
|
|
@ -6372,17 +6509,20 @@
|
|||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"optional": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"deep-extend": "^0.6.0",
|
||||
|
|
@ -6393,14 +6533,16 @@
|
|||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
|
|
@ -6414,7 +6556,8 @@
|
|||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
|
|
@ -6422,37 +6565,44 @@
|
|||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"optional": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"optional": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"optional": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"optional": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
|
|
@ -6462,7 +6612,8 @@
|
|||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
|
|
@ -6470,7 +6621,8 @@
|
|||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
|
|
@ -6478,12 +6630,14 @@
|
|||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
|
|
@ -6497,12 +6651,14 @@
|
|||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"optional": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"string-width": "^1.0.2 || 2"
|
||||
|
|
@ -6510,12 +6666,14 @@
|
|||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
|
|
@ -8653,6 +8811,125 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jwks-rsa": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.7.0.tgz",
|
||||
"integrity": "sha512-tq7DVJt9J6wTvl9+AQfwZIiPSuY2Vf0F+MovfRTFuBqLB1xgDVhegD33ChEAQ6yBv9zFvUIyj4aiwrSA5VehUw==",
|
||||
"requires": {
|
||||
"@types/express-jwt": "0.0.42",
|
||||
"debug": "^4.1.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"limiter": "^1.1.4",
|
||||
"lru-memoizer": "^2.0.1",
|
||||
"ms": "^2.1.2",
|
||||
"request": "^2.88.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"requires": {
|
||||
"ajv": "^6.5.5",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.3",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"oauth-sign": "~0.9.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"requires": {
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
|
|
@ -8802,6 +9079,11 @@
|
|||
"resolve": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"limiter": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
|
||||
"integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||
|
|
@ -8842,6 +9124,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
},
|
||||
"lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||
},
|
||||
"lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
|
|
@ -8978,6 +9265,31 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"lru-memoizer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.2.tgz",
|
||||
"integrity": "sha512-N5L5xlnVcbIinNn/TJ17vHBZwBMt9t7aJDz2n97moWubjNl6VO9Ao2XuAGBBddkYdjrwR9HfzXbT6NfMZXAZ/A==",
|
||||
"requires": {
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lru-cache": "~4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
|
||||
"integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=",
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.1",
|
||||
"yallist": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
}
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
|
|
@ -9456,9 +9768,9 @@
|
|||
}
|
||||
},
|
||||
"mongoose": {
|
||||
"version": "5.9.6",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.6.tgz",
|
||||
"integrity": "sha512-EfFGO2QUoenf/4eFeF5y2R8aBLKHtqwrMk1pVGgl3OyNWufP5XLLPIuihP006YqR1+6xM1YsBzGpgBjMZkINGA==",
|
||||
"version": "5.9.7",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.7.tgz",
|
||||
"integrity": "sha512-WJOBh9WMvivqBK8my9HFtSzSySKdUxJPNGAwswEakAasWUcPXJl3yHMtZ4ngGnKbwTT9KnAr75xamlt/PouR9w==",
|
||||
"requires": {
|
||||
"bson": "~1.1.1",
|
||||
"kareem": "2.3.1",
|
||||
|
|
@ -9604,11 +9916,6 @@
|
|||
"sliced": "1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
|
||||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
|
|
@ -13873,14 +14180,14 @@
|
|||
}
|
||||
},
|
||||
"winston-loggly-bulk": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/winston-loggly-bulk/-/winston-loggly-bulk-3.0.1.tgz",
|
||||
"integrity": "sha512-C86aohUze/qCRYhOVyxgqTuz3HmDK4mLss3OsVHxb4hfD+gw8jAEl3LEMOsqWHEnoJp/MC0wE1N3PeUcisLi2g==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/winston-loggly-bulk/-/winston-loggly-bulk-3.1.0.tgz",
|
||||
"integrity": "sha512-W03eEzM4JIGSTwUHc50SEgWiDcYg2GWMshjqILqFeDfqHDej4f0YCr3kzDIAp/mSbAsoirGITtaQONDkYBM0qg==",
|
||||
"requires": {
|
||||
"clone": "^2.1.1",
|
||||
"node-loggly-bulk": "^2.0.1",
|
||||
"winston": "^3.0",
|
||||
"winston-transport": "^4.2.0"
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"node-loggly-bulk": "^2.2.4",
|
||||
"winston": "^3.2",
|
||||
"winston-transport": "^4.3.0"
|
||||
}
|
||||
},
|
||||
"winston-transport": {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"amplitude": "^3.5.0",
|
||||
"apidoc": "^0.17.5",
|
||||
"apn": "^2.2.0",
|
||||
"aws-sdk": "^2.648.0",
|
||||
"apple-auth": "^1.0.5",
|
||||
"aws-sdk": "^2.653.0",
|
||||
"bcrypt": "^3.0.8",
|
||||
"body-parser": "^1.18.3",
|
||||
"compression": "^1.7.4",
|
||||
|
|
@ -41,12 +42,14 @@
|
|||
"image-size": "^0.8.3",
|
||||
"in-app-purchase": "^1.11.3",
|
||||
"js2xmlparser": "^4.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jwks-rsa": "^1.7.0",
|
||||
"lodash": "^4.17.15",
|
||||
"merge-stream": "^2.0.0",
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.24.0",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.9.6",
|
||||
"mongoose": "^5.9.7",
|
||||
"morgan": "^1.10.0",
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^1.0.2",
|
||||
|
|
@ -69,7 +72,7 @@
|
|||
"validator": "^11.0.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"winston": "^3.2.1",
|
||||
"winston-loggly-bulk": "^3.0.1",
|
||||
"winston-loggly-bulk": "^3.1.0",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
"private": true,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@ function getUser () {
|
|||
value: 'email@facebook',
|
||||
}],
|
||||
},
|
||||
google: {
|
||||
emails: [{
|
||||
value: 'email@google',
|
||||
}],
|
||||
},
|
||||
apple: {
|
||||
emails: [{
|
||||
value: 'email@apple',
|
||||
}],
|
||||
},
|
||||
},
|
||||
profile: {
|
||||
name: 'profile name',
|
||||
|
|
@ -58,6 +68,8 @@ describe('emails', () => {
|
|||
const user = getUser();
|
||||
delete user.profile.name;
|
||||
delete user.auth.local.email;
|
||||
delete user.auth.google.emails;
|
||||
delete user.auth.apple.emails;
|
||||
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
|
|
@ -67,12 +79,48 @@ describe('emails', () => {
|
|||
expect(data).to.have.property('canSend', true);
|
||||
});
|
||||
|
||||
it('returns correct user data [google users]', () => {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
delete user.profile.name;
|
||||
delete user.auth.local.email;
|
||||
delete user.auth.facebook.emails;
|
||||
delete user.auth.apple.emails;
|
||||
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.google.emails[0].value);
|
||||
expect(data).to.have.property('_id', user._id);
|
||||
expect(data).to.have.property('canSend', true);
|
||||
});
|
||||
|
||||
it('returns correct user data [apple users]', () => {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
delete user.profile.name;
|
||||
delete user.auth.local.email;
|
||||
delete user.auth.google.emails;
|
||||
delete user.auth.facebook.emails;
|
||||
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.apple.emails[0].value);
|
||||
expect(data).to.have.property('_id', user._id);
|
||||
expect(data).to.have.property('canSend', true);
|
||||
});
|
||||
|
||||
it('has fallbacks for missing data', () => {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
delete user.auth.local.email;
|
||||
delete user.auth.facebook;
|
||||
delete user.auth.google;
|
||||
delete user.auth.apple;
|
||||
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
|
|
|
|||
|
|
@ -346,4 +346,23 @@ describe('DELETE /user', () => {
|
|||
await expect(checkExistence('users', user._id)).to.eventually.eql(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('user with Apple auth', async () => {
|
||||
beforeEach(async () => {
|
||||
user = await generateUser({
|
||||
auth: {
|
||||
apple: {
|
||||
id: 'apple-id',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes a Apple user', async () => {
|
||||
await user.del('/user', {
|
||||
password: DELETE_CONFIRMATION,
|
||||
});
|
||||
await expect(checkExistence('users', user._id)).to.eventually.eql(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -95,4 +95,42 @@ describe('DELETE social registration', () => {
|
|||
expect(user.auth.goodl).to.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
context('Apple', () => {
|
||||
it('fails if user does not have an alternative registration method', async () => {
|
||||
await user.update({
|
||||
'auth.apple.id': 'some-apple-id',
|
||||
'auth.local': { ok: true },
|
||||
});
|
||||
await expect(user.del('/user/auth/social/apple')).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('cantDetachSocial'),
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds if user has a local registration', async () => {
|
||||
await user.update({
|
||||
'auth.apple.id': 'some-apple-id',
|
||||
});
|
||||
|
||||
const response = await user.del('/user/auth/social/apple');
|
||||
expect(response).to.eql({});
|
||||
await user.sync();
|
||||
expect(user.auth.apple).to.be.undefined;
|
||||
});
|
||||
|
||||
it('succeeds if user has a facebook registration', async () => {
|
||||
await user.update({
|
||||
'auth.apple.id': 'some-apple-id',
|
||||
'auth.facebook.id': 'some-facebook-id',
|
||||
'auth.local': { ok: true },
|
||||
});
|
||||
|
||||
const response = await user.del('/user/auth/social/apple');
|
||||
expect(response).to.eql({});
|
||||
await user.sync();
|
||||
expect(user.auth.goodl).to.be.undefined;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
getProperty,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import * as appleAuth from '../../../../../../website/server/libs/auth/apple';
|
||||
|
||||
describe('GET /user/auth/apple', () => {
|
||||
let api;
|
||||
let user;
|
||||
const appleEndpoint = '/user/auth/apple';
|
||||
|
||||
before(async () => {
|
||||
const expectedResult = { id: 'appleId', name: 'an apple user' };
|
||||
sandbox.stub(appleAuth, 'appleProfile').returns(Promise.resolve(expectedResult));
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
api = requester();
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('registers a new user', async () => {
|
||||
const response = await api.get(appleEndpoint);
|
||||
|
||||
expect(response.apiToken).to.exist;
|
||||
expect(response.id).to.exist;
|
||||
expect(response.newUser).to.be.true;
|
||||
await expect(getProperty('users', response.id, 'auth.apple.id')).to.eventually.equal('appleId');
|
||||
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('an apple user');
|
||||
});
|
||||
|
||||
it('logs an existing user in', async () => {
|
||||
const registerResponse = await api.get(appleEndpoint);
|
||||
|
||||
const response = await api.get(appleEndpoint);
|
||||
|
||||
expect(response.apiToken).to.eql(registerResponse.apiToken);
|
||||
expect(response.id).to.eql(registerResponse.id);
|
||||
expect(response.newUser).to.be.false;
|
||||
});
|
||||
|
||||
it('add social auth to an existing user', async () => {
|
||||
const response = await user.get(appleEndpoint);
|
||||
|
||||
expect(response.apiToken).to.exist;
|
||||
expect(response.id).to.exist;
|
||||
expect(response.newUser).to.be.false;
|
||||
});
|
||||
});
|
||||
|
|
@ -492,6 +492,74 @@ describe('POST /user/auth/local/register', () => {
|
|||
});
|
||||
});
|
||||
|
||||
context('attach to google user', () => {
|
||||
let user;
|
||||
const email = 'some@email-google.net';
|
||||
const username = 'some-username-google';
|
||||
const password = 'some-password';
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
it('checks onlySocialAttachLocal', async () => {
|
||||
await expect(user.post('/user/auth/local/register', {
|
||||
email,
|
||||
username,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('onlySocialAttachLocal'),
|
||||
});
|
||||
});
|
||||
it('succeeds', async () => {
|
||||
await user.update({ 'auth.google.id': 'some-google-id', 'auth.local': { ok: true } });
|
||||
await user.post('/user/auth/local/register', {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(username);
|
||||
expect(user.auth.local.email).to.eql(email);
|
||||
});
|
||||
});
|
||||
|
||||
context('attach to apple user', () => {
|
||||
let user;
|
||||
const email = 'some@email-apple.net';
|
||||
const username = 'some-username-apple';
|
||||
const password = 'some-password';
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
it('checks onlySocialAttachLocal', async () => {
|
||||
await expect(user.post('/user/auth/local/register', {
|
||||
email,
|
||||
username,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('onlySocialAttachLocal'),
|
||||
});
|
||||
});
|
||||
it('succeeds', async () => {
|
||||
await user.update({ 'auth.apple.id': 'some-apple-id', 'auth.local': { ok: true } });
|
||||
await user.post('/user/auth/local/register', {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(username);
|
||||
expect(user.auth.local.email).to.eql(email);
|
||||
});
|
||||
});
|
||||
|
||||
context('login is already taken', () => {
|
||||
let username; let email; let
|
||||
api;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ describe('POST /user/auth/social', () => {
|
|||
|
||||
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a facebook user');
|
||||
await expect(getProperty('users', response.id, 'auth.local.lowerCaseUsername')).to.exist;
|
||||
await expect(getProperty('users', response.id, 'auth.facebook.id')).to.eventually.equal(facebookId);
|
||||
});
|
||||
|
||||
it('logs an existing user in', async () => {
|
||||
|
|
@ -106,6 +107,7 @@ describe('POST /user/auth/social', () => {
|
|||
expect(response.apiToken).to.exist;
|
||||
expect(response.id).to.exist;
|
||||
expect(response.newUser).to.be.true;
|
||||
await expect(getProperty('users', response.id, 'auth.google.id')).to.eventually.equal(googleId);
|
||||
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a google user');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -457,6 +457,74 @@ describe('POST /user/auth/local/register', () => {
|
|||
});
|
||||
});
|
||||
|
||||
context('attach to google user', () => {
|
||||
let user;
|
||||
const email = 'some-google@email.net';
|
||||
const username = 'some-username-google';
|
||||
const password = 'some-password';
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
it('checks onlySocialAttachLocal', async () => {
|
||||
await expect(user.post('/user/auth/local/register', {
|
||||
email,
|
||||
username,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('onlySocialAttachLocal'),
|
||||
});
|
||||
});
|
||||
it('succeeds', async () => {
|
||||
await user.update({ 'auth.google.id': 'some-google-id', 'auth.local': { ok: true } });
|
||||
await user.post('/user/auth/local/register', {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(username);
|
||||
expect(user.auth.local.email).to.eql(email);
|
||||
});
|
||||
});
|
||||
|
||||
context('attach to apple user', () => {
|
||||
let user;
|
||||
const email = 'some-apple@email.net';
|
||||
const username = 'some-username-apple';
|
||||
const password = 'some-password';
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
it('checks onlySocialAttachLocal', async () => {
|
||||
await expect(user.post('/user/auth/local/register', {
|
||||
email,
|
||||
username,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('onlySocialAttachLocal'),
|
||||
});
|
||||
});
|
||||
it('succeeds', async () => {
|
||||
await user.update({ 'auth.apple.id': 'some-apple-id', 'auth.local': { ok: true } });
|
||||
await user.post('/user/auth/local/register', {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
confirmPassword: password,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(username);
|
||||
expect(user.auth.local.email).to.eql(email);
|
||||
});
|
||||
});
|
||||
|
||||
context('login is already taken', () => {
|
||||
let username; let email; let
|
||||
api;
|
||||
|
|
|
|||
3512
website/client/package-lock.json
generated
3512
website/client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -13,23 +13,23 @@
|
|||
"test:unit": "vue-cli-service test:unit --require ./tests/unit/helpers.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.2.3",
|
||||
"@vue/cli-plugin-eslint": "^4.2.3",
|
||||
"@vue/cli-plugin-router": "^4.2.3",
|
||||
"@vue/cli-plugin-unit-mocha": "^4.2.3",
|
||||
"@vue/cli-service": "^4.2.3",
|
||||
"@storybook/addon-actions": "^5.3.17",
|
||||
"@storybook/addon-knobs": "^5.3.17",
|
||||
"@storybook/addon-links": "^5.3.17",
|
||||
"@storybook/addon-notes": "^5.3.17",
|
||||
"@storybook/vue": "^5.3.17",
|
||||
"@vue/cli-plugin-babel": "^4.3.0",
|
||||
"@vue/cli-plugin-eslint": "^4.3.0",
|
||||
"@vue/cli-plugin-router": "^4.3.0",
|
||||
"@vue/cli-plugin-unit-mocha": "^4.3.0",
|
||||
"@vue/cli-service": "^4.3.0",
|
||||
"@storybook/addon-actions": "^5.3.18",
|
||||
"@storybook/addon-knobs": "^5.3.18",
|
||||
"@storybook/addon-links": "^5.3.18",
|
||||
"@storybook/addon-notes": "^5.3.18",
|
||||
"@storybook/vue": "^5.3.18",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"amplitude-js": "^5.10.0",
|
||||
"axios": "^0.19.2",
|
||||
"axios-progress-bar": "^1.2.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"bootstrap": "^4.4.1",
|
||||
"bootstrap-vue": "^2.9.0",
|
||||
"bootstrap-vue": "^2.10.1",
|
||||
"chai": "^4.1.2",
|
||||
"core-js": "^3.6.4",
|
||||
"eslint": "^6.8.0",
|
||||
|
|
|
|||
4
website/client/src/assets/svg/apple.svg
Normal file
4
website/client/src/assets/svg/apple.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="170px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170 170" version="1.1" height="170px">
|
||||
<path d="m150.37 130.25c-2.45 5.66-5.35 10.87-8.71 15.66-4.58 6.53-8.33 11.05-11.22 13.56-4.48 4.12-9.28 6.23-14.42 6.35-3.69 0-8.14-1.05-13.32-3.18-5.197-2.12-9.973-3.17-14.34-3.17-4.58 0-9.492 1.05-14.746 3.17-5.262 2.13-9.501 3.24-12.742 3.35-4.929 0.21-9.842-1.96-14.746-6.52-3.13-2.73-7.045-7.41-11.735-14.04-5.032-7.08-9.169-15.29-12.41-24.65-3.471-10.11-5.211-19.9-5.211-29.378 0-10.857 2.346-20.221 7.045-28.068 3.693-6.303 8.606-11.275 14.755-14.925s12.793-5.51 19.948-5.629c3.915 0 9.049 1.211 15.429 3.591 6.362 2.388 10.447 3.599 12.238 3.599 1.339 0 5.877-1.416 13.57-4.239 7.275-2.618 13.415-3.702 18.445-3.275 13.63 1.1 23.87 6.473 30.68 16.153-12.19 7.386-18.22 17.731-18.1 31.002 0.11 10.337 3.86 18.939 11.23 25.769 3.34 3.17 7.07 5.62 11.22 7.36-0.9 2.61-1.85 5.11-2.86 7.51zm-31.26-123.01c0 8.1021-2.96 15.667-8.86 22.669-7.12 8.324-15.732 13.134-25.071 12.375-0.119-0.972-0.188-1.995-0.188-3.07 0-7.778 3.386-16.102 9.399-22.908 3.002-3.446 6.82-6.3113 11.45-8.597 4.62-2.2516 8.99-3.4968 13.1-3.71 0.12 1.0831 0.17 2.1663 0.17 3.2409z" fill="#FFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
55
website/client/src/assets/svg/apple_black.svg
Normal file
55
website/client/src/assets/svg/apple_black.svg
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1000"
|
||||
viewBox="0 0 1000 1187.198"
|
||||
version="1.1"
|
||||
height="1187.198"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Apple_1998.svg">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.1767767"
|
||||
inkscape:cx="-1066.5045"
|
||||
inkscape:cy="964.94669"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<path
|
||||
d="m 979.04184,925.18785 c -17.95397,41.47737 -39.20563,79.65705 -63.82824,114.75895 -33.56298,47.8528 -61.04356,80.9761 -82.22194,99.3698 -32.83013,30.192 -68.00529,45.6544 -105.67203,46.5338 -27.04089,0 -59.6512,-7.6946 -97.61105,-23.3035 -38.08442,-15.5358 -73.08371,-23.2303 -105.08578,-23.2303 -33.56296,0 -69.55888,7.6945 -108.06101,23.2303 -38.5608,15.6089 -69.62484,23.7432 -93.37541,24.5493 -36.12049,1.5389 -72.1237,-14.3632 -108.06101,-47.7796 -22.93711,-20.0059 -51.62684,-54.3017 -85.99592,-102.8874 C 92.254176,984.54592 61.937588,924.38175 38.187028,855.7902 12.750995,781.70252 0,709.95986 0,640.50361 0,560.94181 17.191859,492.32094 51.626869,434.81688 78.689754,388.62753 114.69299,352.19192 159.75381,325.44413 c 45.06086,-26.74775 93.74914,-40.37812 146.18212,-41.25019 28.68971,0 66.3125,8.8744 113.06613,26.31542 46.62174,17.49964 76.55727,26.37404 89.68198,26.37404 9.8124,0 43.06758,-10.37669 99.4431,-31.06405 53.31237,-19.18512 98.30724,-27.12887 135.16787,-23.99975 99.8828,8.06098 174.92313,47.43518 224.82789,118.37174 -89.33023,54.12578 -133.51903,129.93556 -132.63966,227.18753 0.8061,75.75115 28.28668,138.78795 82.2952,188.8393 24.47603,23.23022 51.81008,41.18421 82.22186,53.93522 -6.59525,19.12648 -13.557,37.44688 -20.95846,55.03446 z M 749.96366,23.751237 c 0,59.37343 -21.69138,114.810233 -64.92748,166.121963 -52.17652,60.99961 -115.28658,96.24803 -183.72426,90.68597 -0.87204,-7.12298 -1.37769,-14.61967 -1.37769,-22.49743 0,-56.99843 24.81315,-117.99801 68.87738,-167.873453 21.99909,-25.25281 49.978,-46.25018 83.90738,-63.00018 C 686.57507,10.688027 718.59913,1.5631274 748.71783,5.2734376e-4 749.59727,7.9378274 749.96366,15.875627 749.96366,23.750467 Z"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="form">
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="col-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('facebook')"
|
||||
|
|
@ -15,7 +15,9 @@
|
|||
: $t('loginWithSocial', {social: 'Facebook'}) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
</div>
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('google')"
|
||||
|
|
@ -30,6 +32,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('apple')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon apple-icon"
|
||||
v-html="icons.appleIcon"
|
||||
></div>
|
||||
<span>{{ registering
|
||||
? $t('signUpWithSocial', {social: 'Apple'})
|
||||
: $t('loginWithSocial', {social: 'Apple'}) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="registering"
|
||||
class="form-group"
|
||||
|
|
@ -199,7 +217,11 @@
|
|||
height: 18px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: .2em;
|
||||
margin-top: .1em;
|
||||
}
|
||||
|
||||
.apple-icon {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
small.form-text {
|
||||
|
|
@ -219,10 +241,11 @@
|
|||
import hello from 'hellojs';
|
||||
import debounce from 'lodash/debounce';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import { setUpAxios } from '@/libs/auth';
|
||||
import { setUpAxios, buildAppleAuthUrl } from '@/libs/auth';
|
||||
import { MINIMUM_PASSWORD_LENGTH } from '@/../../common/script/constants';
|
||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||
import googleIcon from '@/assets/svg/google.svg';
|
||||
import appleIcon from '@/assets/svg/apple_black.svg';
|
||||
|
||||
export default {
|
||||
name: 'AuthForm',
|
||||
|
|
@ -239,6 +262,7 @@ export default {
|
|||
data.icons = Object.freeze({
|
||||
facebookIcon: facebookSquareIcon,
|
||||
googleIcon,
|
||||
appleIcon,
|
||||
});
|
||||
|
||||
return data;
|
||||
|
|
@ -307,27 +331,31 @@ export default {
|
|||
}, 500),
|
||||
// @TODO: Abstract hello in to action or lib
|
||||
async socialAuth (network) {
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
if (network === 'apple') {
|
||||
window.location.href = buildAppleAuthUrl();
|
||||
} else {
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
|
||||
try {
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
try {
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
await this.finishAuth();
|
||||
} catch (err) {
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
// logout the user
|
||||
await hello(network).logout();
|
||||
this.socialAuth(network); // login again
|
||||
await this.finishAuth();
|
||||
} catch (err) {
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
// logout the user
|
||||
await hello(network).logout();
|
||||
this.socialAuth(network); // login again
|
||||
}
|
||||
}
|
||||
},
|
||||
async register () {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="col-12 col-md-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('facebook')"
|
||||
|
|
@ -54,7 +54,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
</div>
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12 col-md-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('google')"
|
||||
|
|
@ -73,6 +75,29 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row text-center">
|
||||
<div class="col-12 col-md-12">
|
||||
<div
|
||||
class="btn btn-secondary social-button"
|
||||
@click="socialAuth('apple')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon"
|
||||
v-html="icons.appleIcon"
|
||||
></div>
|
||||
<div
|
||||
class="text"
|
||||
>
|
||||
{{ registering
|
||||
? $t('signUpWithSocial', {social: 'Apple'})
|
||||
: $t('loginWithSocial', {social: 'Apple'}) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="strike">
|
||||
<span>{{ $t('or') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="registering"
|
||||
class="form-group"
|
||||
|
|
@ -496,12 +521,13 @@
|
|||
}
|
||||
|
||||
.social-icon {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: .2em;
|
||||
margin-top: .1em;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -581,6 +607,42 @@
|
|||
.exclamation {
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.strike {
|
||||
display: block;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.strike > span {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
line-height: 1.14;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.strike > span:before,
|
||||
.strike > span:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 9999px;
|
||||
height: 1px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.strike > span:before {
|
||||
right: 100%;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.strike > span:after {
|
||||
left: 100%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
|
@ -589,6 +651,7 @@ import hello from 'hellojs';
|
|||
import moment from 'moment';
|
||||
import debounce from 'lodash/debounce';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import { buildAppleAuthUrl } from '../../libs/auth';
|
||||
|
||||
import { MINIMUM_PASSWORD_LENGTH } from '@/../../common/script/constants';
|
||||
import exclamation from '@/assets/svg/exclamation.svg';
|
||||
|
|
@ -596,6 +659,7 @@ import gryphon from '@/assets/svg/gryphon.svg';
|
|||
import habiticaIcon from '@/assets/svg/habitica-logo.svg';
|
||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||
import googleIcon from '@/assets/svg/google.svg';
|
||||
import appleIcon from '@/assets/svg/apple_black.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
|
|
@ -618,6 +682,7 @@ export default {
|
|||
habiticaIcon,
|
||||
facebookIcon: facebookSquareIcon,
|
||||
googleIcon,
|
||||
appleIcon,
|
||||
});
|
||||
|
||||
return data;
|
||||
|
|
@ -799,35 +864,39 @@ export default {
|
|||
},
|
||||
// @TODO: Abstract hello in to action or lib
|
||||
async socialAuth (network) {
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
// explicitly pass the redirect url or it might redirect to /home
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
let redirectTo;
|
||||
|
||||
if (this.$route.query.redirectTo) {
|
||||
redirectTo = this.$route.query.redirectTo;
|
||||
if (network === 'apple') {
|
||||
window.location.href = buildAppleAuthUrl();
|
||||
} else {
|
||||
redirectTo = '/';
|
||||
}
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
|
||||
// @TODO do not reload entire page
|
||||
// problem is that app.vue created hook should be called again
|
||||
// after user is logged in / just signed up
|
||||
// ALSO it's the only way to make sure language data
|
||||
// is reloaded and correct for the logged in user
|
||||
window.location.href = redirectTo;
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
// explicitly pass the redirect url or it might redirect to /home
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
let redirectTo;
|
||||
|
||||
if (this.$route.query.redirectTo) {
|
||||
redirectTo = this.$route.query.redirectTo;
|
||||
} else {
|
||||
redirectTo = '/';
|
||||
}
|
||||
|
||||
// @TODO do not reload entire page
|
||||
// problem is that app.vue created hook should be called again
|
||||
// after user is logged in / just signed up
|
||||
// ALSO it's the only way to make sure language data
|
||||
// is reloaded and correct for the logged in user
|
||||
window.location.href = redirectTo;
|
||||
}
|
||||
},
|
||||
handleSubmit () {
|
||||
if (this.registering) {
|
||||
|
|
|
|||
|
|
@ -561,6 +561,8 @@ import { SUPPORTED_SOCIAL_NETWORKS } from '@/../../common/script/constants';
|
|||
import changeClass from '@/../../common/script/ops/changeClass';
|
||||
import notificationsMixin from '../../mixins/notifications';
|
||||
import sounds from '../../libs/sounds';
|
||||
import { buildAppleAuthUrl } from '../../libs/auth';
|
||||
|
||||
// @TODO: this needs our window.env fix
|
||||
// import { availableLanguages } from '../../../server/libs/i18n';
|
||||
|
||||
|
|
@ -837,13 +839,17 @@ export default {
|
|||
this.text(this.$t('detachedSocial', { network: network.name }));
|
||||
},
|
||||
async socialAuth (network) {
|
||||
const auth = await hello(network).login({ scope: 'email' });
|
||||
if (network === 'apple') {
|
||||
window.location.href = buildAppleAuthUrl();
|
||||
} else {
|
||||
const auth = await hello(network).login({ scope: 'email' });
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
window.location.href = '/';
|
||||
window.location.href = '/';
|
||||
}
|
||||
},
|
||||
async changeClassForUser (confirmationNeeded) {
|
||||
if (confirmationNeeded && !window.confirm(this.$t('changeClassConfirmCost'))) return;
|
||||
|
|
|
|||
35
website/client/src/components/static/appleRedirect.vue
Normal file
35
website/client/src/components/static/appleRedirect.vue
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div class="static-view">
|
||||
<p>Redirecting...</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '~@/assets/scss/static.scss';
|
||||
.static-view {
|
||||
height: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.static-view p {
|
||||
padding-top: 100px;
|
||||
font-size: 2em
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
async mounted () {
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
const reqParams = { code: urlParams.get('code') };
|
||||
if (urlParams.has('name')) {
|
||||
reqParams.name = urlParams.get('name');
|
||||
}
|
||||
await this.$store.dispatch('auth:appleAuth', reqParams);
|
||||
|
||||
window.location.href = '/';
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -28,31 +28,6 @@
|
|||
<h3 class="text-center">
|
||||
{{ $t('singUpForFree') }}
|
||||
</h3>
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="social-button"
|
||||
@click="socialAuth('facebook')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon"
|
||||
v-html="icons.facebookIcon"
|
||||
></div>
|
||||
<span>{{ $t('signUpWithSocial', {social: 'Facebook'}) }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="social-button"
|
||||
@click="socialAuth('google')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon"
|
||||
v-html="icons.googleIcon"
|
||||
></div>
|
||||
<span>{{ $t('signUpWithSocial', {social: 'Google'}) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="strike">
|
||||
<span>{{ $t('or') }}</span>
|
||||
</div>
|
||||
<form
|
||||
class="form"
|
||||
@submit.prevent.stop="register()"
|
||||
|
|
@ -127,6 +102,41 @@
|
|||
{{ $t('signup') }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="strike">
|
||||
<span>{{ $t('or') }}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="social-button"
|
||||
@click="socialAuth('facebook')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon"
|
||||
v-html="icons.facebookIcon"
|
||||
></div>
|
||||
<span>{{ $t('signUpWithSocial', {social: 'Facebook'}) }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="social-button"
|
||||
@click="socialAuth('google')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon"
|
||||
v-html="icons.googleIcon"
|
||||
></div>
|
||||
<span>{{ $t('signUpWithSocial', {social: 'Google'}) }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="social-button"
|
||||
@click="socialAuth('apple')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon social-icon apple-icon"
|
||||
v-html="icons.appleIcon"
|
||||
></div>
|
||||
<span>{{ $t('signUpWithSocial', {social: 'Apple'}) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div
|
||||
|
|
@ -450,17 +460,17 @@
|
|||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.social-button {
|
||||
border-radius: 2px;
|
||||
border: solid 2px #bda8ff;
|
||||
width: 48%;
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding: .5em;
|
||||
background: transparent;
|
||||
margin-right: .5em;
|
||||
margin-bottom: .5em;
|
||||
color: #bda8ff;
|
||||
transition: .5s;
|
||||
|
||||
|
|
@ -481,7 +491,11 @@
|
|||
height: 18px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: .2em;
|
||||
margin-top: .1em;
|
||||
}
|
||||
|
||||
.apple-icon {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.strike {
|
||||
|
|
@ -781,6 +795,7 @@
|
|||
import hello from 'hellojs';
|
||||
import debounce from 'lodash/debounce';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import { buildAppleAuthUrl } from '../../libs/auth';
|
||||
import googlePlay from '@/assets/images/home/google-play-badge.svg';
|
||||
import iosAppStore from '@/assets/images/home/ios-app-store.svg';
|
||||
import iphones from '@/assets/images/home/iphones.svg';
|
||||
|
|
@ -790,6 +805,7 @@ import pixelHorizontal2 from '@/assets/images/home/pixel-horizontal-2.svg';
|
|||
import pixelHorizontal3 from '@/assets/images/home/pixel-horizontal-3.svg';
|
||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||
import googleIcon from '@/assets/svg/google.svg';
|
||||
import appleIcon from '@/assets/svg/apple.svg';
|
||||
import cnet from '@/assets/svg/cnet.svg';
|
||||
import fastCompany from '@/assets/svg/fast-company.svg';
|
||||
import discover from '@/assets/images/home/discover.svg';
|
||||
|
|
@ -814,6 +830,7 @@ export default {
|
|||
pixelHorizontal3,
|
||||
facebookIcon: facebookSquareIcon,
|
||||
googleIcon,
|
||||
appleIcon,
|
||||
cnet,
|
||||
fastCompany,
|
||||
discover,
|
||||
|
|
@ -885,9 +902,9 @@ export default {
|
|||
});
|
||||
|
||||
hello.init({
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -946,22 +963,26 @@ export default {
|
|||
},
|
||||
// @TODO: Abstract hello in to action or lib
|
||||
async socialAuth (network) {
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
if (network === 'apple') {
|
||||
window.location.href = buildAppleAuthUrl();
|
||||
} else {
|
||||
try {
|
||||
await hello(network).logout();
|
||||
} catch (e) {} // eslint-disable-line
|
||||
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
// explicitly pass the redirect url or it might redirect to /home
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
// explicitly pass the redirect url or it might redirect to /home
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
window.location.href = '/';
|
||||
window.location.href = '/';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@
|
|||
class="col-12 col-md-3"
|
||||
>
|
||||
<div class="box white row col-12">
|
||||
<div class="col-9">
|
||||
<div class="col-9 text-nowrap">
|
||||
<div :class="stat">
|
||||
{{ $t(stats[stat].title) }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,3 +21,8 @@ export function setUpAxios (AUTH_SETTINGS) { // eslint-disable-line import/prefe
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function buildAppleAuthUrl () {
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}/api/v4/user/auth/apple`;
|
||||
return `https://appleid.apple.com/auth/authorize?response_mode=form_post&scope=name%20email&response_type=code&version=2&redirect_uri=${redirectUrl}&client_id=${process.env.APPLE_AUTH_CLIENT_ID}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const StaticWrapper = () => import(/* webpackChunkName: "entry" */'@/components/
|
|||
const HomePage = () => import(/* webpackChunkName: "entry" */'@/components/static/home');
|
||||
|
||||
const AppPage = () => import(/* webpackChunkName: "static" */'@/components/static/app');
|
||||
const AppleRedirectPage = () => import(/* webpackChunkName: "static" */'@/components/static/appleRedirect');
|
||||
const ClearBrowserDataPage = () => import(/* webpackChunkName: "static" */'@/components/static/clearBrowserData');
|
||||
const CommunityGuidelinesPage = () => import(/* webpackChunkName: "static" */'@/components/static/communityGuidelines');
|
||||
const ContactPage = () => import(/* webpackChunkName: "static" */'@/components/static/contact');
|
||||
|
|
@ -272,6 +273,9 @@ const router = new VueRouter({
|
|||
{
|
||||
name: 'app', path: 'app', component: AppPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'appleRedirect', path: 'apple-redirect', component: AppleRedirectPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'clearBrowserData', path: 'clear-browser-data', component: ClearBrowserDataPage, meta: { requiresLogin: false },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -82,6 +82,27 @@ export async function socialAuth (store, params) {
|
|||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
}
|
||||
|
||||
export async function appleAuth (store, params) {
|
||||
const url = '/api/v4/user/auth/apple';
|
||||
const result = await axios.get(url, {
|
||||
params: {
|
||||
code: params.code,
|
||||
name: params.name,
|
||||
},
|
||||
});
|
||||
|
||||
const user = result.data.data;
|
||||
|
||||
const userLocalData = JSON.stringify({
|
||||
auth: {
|
||||
apiId: user.id,
|
||||
apiToken: user.apiToken,
|
||||
},
|
||||
});
|
||||
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
}
|
||||
|
||||
export function logout (store, options = {}) {
|
||||
localStorage.clear();
|
||||
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const envVars = [
|
|||
'STRIPE_PUB_KEY',
|
||||
'FACEBOOK_KEY',
|
||||
'GOOGLE_CLIENT_ID',
|
||||
'APPLE_AUTH_CLIENT_ID',
|
||||
'AMPLITUDE_KEY',
|
||||
'LOGGLY_CLIENT_TOKEN',
|
||||
// TODO necessary? if yes how not to mess up with vue cli? 'NODE_ENV'
|
||||
|
|
|
|||
|
|
@ -2051,5 +2051,26 @@
|
|||
"weaponArmoireBaseballBatText": "Baseballschläger",
|
||||
"shieldArmoireBaseballGloveNotes": "Perfekt für das große Turnier oder ein freundschaftliches Fangspiel zwischen zwei Aufgaben. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Baseball-Set (Gegenstand 4 von 4).",
|
||||
"armorArmoireBaseballUniformNotes": "Nadelstreifen kommen nie aus der Mode. Erhöht Ausdauer und Stärke um jeweils <%= attrs %>. Verzauberter Schrank: Baseball-Set (Gegenstand 2 von 4).",
|
||||
"weaponArmoireBaseballBatNotes": "Hol Dir einen Homerun für die guten Gewohnheiten! Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Baseball-Set (Gegenstand 3 von 4)."
|
||||
"weaponArmoireBaseballBatNotes": "Hol Dir einen Homerun für die guten Gewohnheiten! Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Baseball-Set (Gegenstand 3 von 4).",
|
||||
"headAccessoryMystery202004Text": "Mächtige Monarchfalterfühler",
|
||||
"backMystery202004Text": "Mächtige Monarchfalterflügel",
|
||||
"shieldSpecialSpring2020HealerText": "Duftschild",
|
||||
"shieldSpecialSpring2020WarriorText": "Irisierender Schild",
|
||||
"headSpecialSpring2020HealerText": "Iris-Fascinator",
|
||||
"headSpecialSpring2020WarriorText": "Käferhelm",
|
||||
"headSpecialSpring2020RogueText": "Lapislazuli Kabuto-Helm",
|
||||
"armorSpecialSpring2020HealerText": "Beschützendes Blütenblatt",
|
||||
"armorSpecialSpring2020MageText": "Whirlpfützenumhang",
|
||||
"armorSpecialSpring2020WarriorNotes": "Diese harte Schale kann Dich selbst vor den vernichtendsten Attacken schützen. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"armorSpecialSpring2020WarriorText": "Exoskelettrüstung",
|
||||
"armorSpecialSpring2020RogueNotes": "Die Farbe der Dämmerung, einer Vielzahl wertvoller Steine, der tiefsten Stelle des Meeres! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"armorSpecialSpring2020RogueText": "Ultramarinblaue Rüstung",
|
||||
"weaponSpecialSpring2020HealerNotes": "Eine Iris ist schön, aber ihre Blätter sind scharf wie Schwerter... lass Dich nicht von den Blumen in die Irre führen, dieser Stab ist hart wie Stahl! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2020HealerText": "Schwertlilienstab",
|
||||
"weaponSpecialSpring2020MageNotes": "Sie fallen Dir unaufhörlich auf den Kopf! Aber Du wirst sie nie aufhalten, indem Du Dich beklagst. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2020MageText": "Regentropfen",
|
||||
"weaponSpecialSpring2020WarriorNotes": "Kämpfen oder Fliehen, dieser Flügel wird Dir einen guten Dienst erweisen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2020WarriorText": "Geschliffener Flügel",
|
||||
"weaponSpecialSpring2020RogueNotes": "Du wirst so schnell zuschlagen, dass sie NOCH blauer aussehen wird! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2020 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2020RogueText": "Lapislazuli Klinge"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "Schlüpfelixier",
|
||||
"noHatchingPotions": "Du hast im Moment keine Schlüpfelixiere.",
|
||||
"inventoryText": "Klicke auf ein Ei um die anwendbaren Elixiere grün hervorgehoben zu sehen. Klicke dann auf ein hervorgehobenes Elixier, um Dein Haustier auszubrüten. Falls kein Elixier hervorgehoben wird, klicke auf das Ei um es abzuwählen und klicke diesmal zuerst auf das Elixier, um die Eier hervorzuheben. Du kannst überflüssige Gegenstände auch an Alexander den Händler verkaufen.",
|
||||
"haveHatchablePet": "Du hast ein <%= potion %> Schlüpfelixier und ein <%= egg %>-Ei, um dieses Haustier auszubrüten! <b>Klicke</b> auf den Pfotenabdruck, damit es schlüpft.",
|
||||
"haveHatchablePet": "Du hast ein <%= potion %> Schlüpfelixier und ein <%= egg %>-Ei, um dieses Haustier auszubrüten! <b>Klicke</b>, damit es schlüpft.",
|
||||
"quickInventory": "Schnell-Inventar",
|
||||
"foodText": "Futter",
|
||||
"food": "Futter und magische Sättel",
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@
|
|||
|
||||
"questButterflyText": "Bye, Bye, Butterfry",
|
||||
"questButterflyNotes": "Your gardener friend @Megan sends you an invitation: “These warm days are the perfect time to visit Habitica’s butterfly garden in the Taskan countryside. Come see the butterflies migrate!” When you arrive, however, the garden is in shambles -- little more than scorched grass and dried-out weeds. It’s been so hot that the Habiticans haven’t come out to water the flowers, and the dark-red Dailies have turned it into a dry, sun-baked, fire-hazard. There's only one butterfly there, and there's something odd about it...<br><br>“Oh no! This is the perfect hatching ground for the Flaming Butterfry,” cries @Leephon.<br><br>“If we don’t catch it, it’ll destroy everything!” gasps @Eevachu.<br><br>Time to say bye, bye to Butterfry!",
|
||||
"questButterflyCompletion": "After a blazing battle, the Flaming Butterfry is captured. “Great job catching the that would-be arsonist,” says @Megan with a sigh of relief. “Still, it’s hard to vilify even the vilest butterfly. We’d better free this Butterfry someplace safe…like the desert.”<br><br>One of the other gardeners, @Beffymaroo, comes up to you, singed but smiling. “Will you help raise these foundling chrysalises we found? Perhaps next year we’ll have a greener garden for them.”",
|
||||
"questButterflyCompletion": "After a blazing battle, the Flaming Butterfry is captured. “Great job catching that would-be arsonist,” says @Megan with a sigh of relief. “Still, it’s hard to vilify even the vilest butterfly. We’d better free this Butterfry someplace safe…like the desert.”<br><br>One of the other gardeners, @Beffymaroo, comes up to you, singed but smiling. “Will you help raise these foundling chrysalises we found? Perhaps next year we’ll have a greener garden for them.”",
|
||||
"questButterflyBoss": "Flaming Butterfry",
|
||||
"questButterflyDropButterflyEgg": "Caterpillar (Egg)",
|
||||
"questButterflyUnlockText": "Unlocks Caterpillar Eggs for purchase in the Market",
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundSucculentGardenNotes": "Take in the arid beauty of a Succulent Garden.",
|
||||
"backgroundSucculentGardenText": "Succulent Garden",
|
||||
"backgroundButterflyGardenNotes": "Party with pollinators in a Butterfly Garden.",
|
||||
"backgroundButterflyGardenText": "Butterfly Garden"
|
||||
"backgroundButterflyGardenText": "Butterfly Garden",
|
||||
"backgroundRainyBarnyardNotes": "Take a soggy splashy stroll through a Rainy Barnyard.",
|
||||
"backgroundRainyBarnyardText": "Rainy Barnyard",
|
||||
"backgroundHeatherFieldNotes": "Enjoy the aroma of a Field of Heather.",
|
||||
"backgroundHeatherFieldText": "Heather Field",
|
||||
"backgroundAnimalCloudsNotes": "Exercise your imagination finding Animal shapes in the Clouds.",
|
||||
"backgroundAnimalCloudsText": "Animal Clouds",
|
||||
"backgrounds042020": "SET 71: Released April 2020"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2083,5 +2083,11 @@
|
|||
"headAccessoryMystery202004Notes": "They twitch just a bit if the scent of flowers drifts by--use them to find a pretty garden! Confers no benefit. April 2020 Subscriber Item.",
|
||||
"headAccessoryMystery202004Text": "Mighty Monarch Antennae",
|
||||
"backMystery202004Notes": "Make a quick flutter to the nearest flowery meadow or migrate across the continent with these beautiful wings! Confers no benefit. April 2020 Subscriber Item.",
|
||||
"backMystery202004Text": "Mighty Monarch Wings"
|
||||
"backMystery202004Text": "Mighty Monarch Wings",
|
||||
"shieldArmoireHobbyHorseNotes": "Ride your handsome hobby-horse steed toward your just Rewards! Increases Perception and Constitution by <%= attrs %> each. Enchanted Armoire: Paper Knight Set (Item 2 of 3).",
|
||||
"shieldArmoireHobbyHorseText": "Hobby Horse",
|
||||
"armorArmoireBoxArmorNotes": "Box Armor: It fits, therefore you sits... uh, therefore you wear it into battle, like the bold knight you are! Increases Perception and Constitution by <%= attrs %> each. Enchanted Armoire: Paper Knight Set (Item 3 of 3). ",
|
||||
"armorArmoireBoxArmorText": "Box Armor",
|
||||
"weaponArmoirePaperCutterNotes": "This may not look fearsome, but have you never had a papercut? Increases Strength by <%= str %>. Enchanted Armoire: Paper Knight Set (Item 1 of 3).",
|
||||
"weaponArmoirePaperCutterText": "Paper Cutter"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "hatching potion",
|
||||
"noHatchingPotions": "You don't have any hatching potions.",
|
||||
"inventoryText": "Click an egg to see usable potions highlighted in green and then click one of the highlighted potions to hatch your pet. If no potions are highlighted, click that egg again to deselect it, and instead click a potion first to have the usable eggs highlighted. You can also sell unwanted drops to Alexander the Merchant.",
|
||||
"haveHatchablePet": "You have a <%= potion %> hatching potion and <%= egg %> egg to hatch this pet! <b>Click</b> the paw print to hatch.",
|
||||
"haveHatchablePet": "You have a <%= potion %> hatching potion and <%= egg %> egg to hatch this pet! <b>Click</b> to hatch!",
|
||||
"quickInventory": "Quick Inventory",
|
||||
"foodText": "food",
|
||||
"food": "Pet Food and Saddles",
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundButterflyGardenText": "Jardin à papillons",
|
||||
"backgroundAmongGiantFlowersNotes": "Badinez parmi les fleurs géantes.",
|
||||
"backgroundAmongGiantFlowersText": "Parmi les fleurs géantes",
|
||||
"backgrounds032020": "Ensemble 70 : sorti en mars 2020"
|
||||
"backgrounds032020": "Ensemble 70 : sorti en mars 2020",
|
||||
"backgroundRainyBarnyardNotes": "Faites une promenade détrempée et éclaboussante dans une basse-cour pluvieuse.",
|
||||
"backgroundRainyBarnyardText": "Basse-cour pluvieuse",
|
||||
"backgroundHeatherFieldNotes": "Appréciez les arômes d'un champ de bruyère.",
|
||||
"backgroundHeatherFieldText": "Champ de bruyère",
|
||||
"backgroundAnimalCloudsNotes": "Entraînez votre imagination à reconnaître les formes des animaux dans les nuages.",
|
||||
"backgroundAnimalCloudsText": "Nuages en formes d'animaux",
|
||||
"backgrounds042020": "Ensemble 71 : sorti en avril 2020"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2079,5 +2079,15 @@
|
|||
"weaponSpecialSpring2020WarriorNotes": "En vol ou au sol, ces ailes vous serviront bien ! Augmente la force de <%= str %>. Équipement en édition limitée du printemps 2020.",
|
||||
"weaponSpecialSpring2020WarriorText": "Ailes affutées",
|
||||
"weaponSpecialSpring2020RogueNotes": "Vous frapperez si vite que aura l'air encore PLUS bleu ! Augmente la force de <%= str %>. Équipement en édition limitée du printemps 2020.",
|
||||
"weaponSpecialSpring2020RogueText": "Épée de Lazurite"
|
||||
"weaponSpecialSpring2020RogueText": "Épée de Lazurite",
|
||||
"headAccessoryMystery202004Notes": "Elles se trémoussent juste un peu si l'odeur des fleurs passe devant elles : utilisez-les pour trouver un joli jardin ! Ne confère aucun bonus. Équipement d'abonnement d'avril 2020.",
|
||||
"headAccessoryMystery202004Text": "Antennes de merveilleux monarque",
|
||||
"backMystery202004Notes": "Faites un vol rapide vers la prairie fleurie la plus proche ou migrez à travers le continent avec ces jolies ailes ! Ne confère aucun bonus. Équipement d'abonnement d'avril 2020.",
|
||||
"backMystery202004Text": "Ailes de merveilleux monarque",
|
||||
"shieldArmoireHobbyHorseNotes": "Chevauchez votre magnifique monture de jeu vers vos récompenses méritées ! Augmente la perception et la constitution de <%= attrs %> chacune. Armoire enchantée : ensemble de chevalerie de papier (objet 2 de 3).",
|
||||
"shieldArmoireHobbyHorseText": "Cheval de jeu",
|
||||
"armorArmoireBoxArmorNotes": "Attention, un chat y dort peut-être... mais ça ne vous empêchera pas de porter cette armure au combat, avec l'audace qui vous caractérise ! Augmente la perception et la constitution de <%= attrs %> chacune. Armoire enchantée : ensemble de chevalerie de papier (objet 3 de 3). ",
|
||||
"armorArmoireBoxArmorText": "Armure boite",
|
||||
"weaponArmoirePaperCutterNotes": "Ca n'a pas l'air terrible, mais vous êtes vous déjà coupé avec une feuille de papier ? Augmente la force de <%= str %>. Armoire enchantée : ensemble de chevalerie de papier (objet 1 de 3).",
|
||||
"weaponArmoirePaperCutterText": "Coupe papier"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "potion d'éclosion",
|
||||
"noHatchingPotions": "Vous n'avez pas de potion d'éclosion.",
|
||||
"inventoryText": "Cliquez sur un œuf pour voir les potions utilisables surlignées en vert, puis cliquez sur une des potions surlignées pour faire éclore votre familier. Si aucune potion n'est surlignée, cliquez à nouveau sur l’œuf pour le désélectionner et cliquez plutôt sur une potion d'abord pour voir les œufs utilisables. Vous pouvez aussi vendre votre surplus d'objets à Alexander le marchand.",
|
||||
"haveHatchablePet": "Vous avez une potion d'éclosion <%= potion %> et un œuf de <%= egg %> qui peuvent faire éclore ce familier ! <b>Cliquez</b> sur l'empreinte pour le faire naître.",
|
||||
"haveHatchablePet": "Vous avez une potion d'éclosion <%= potion %> et un œuf de <%= egg %> qui peuvent faire éclore ce familier ! <b>Cliquez</b> pour le faire naître !",
|
||||
"quickInventory": "Inventaire rapide",
|
||||
"foodText": "nourriture",
|
||||
"food": "Nourriture de familiers et selles",
|
||||
|
|
|
|||
|
|
@ -247,5 +247,6 @@
|
|||
"monthlyMysteryItems": "Objets mystère mensuels",
|
||||
"subscribersReceiveBenefits": "Les personnes abonnées reçoivent ces bénéfices utiles !",
|
||||
"mysterySet202003": "Ensemble de combat barbelé",
|
||||
"giftASubscription": "Offrez un abonnement"
|
||||
"giftASubscription": "Offrez un abonnement",
|
||||
"mysterySet202004": "Ensemble du merveilleux monarque"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundHolidayMarketNotes": "Vind de perfecte cadeaus en versieringen bij een Feestdagen Markt.",
|
||||
"backgroundHolidayMarketText": "Feestdagen Markt",
|
||||
"backgrounds122019": "SET 67: Uitgebracht December 2019",
|
||||
"backgroundPotionShopNotes": "Vind een elixer tegen een kwaal in een Uitbroeddrankenwinkel."
|
||||
"backgroundPotionShopNotes": "Vind een elixer tegen een kwaal in een Uitbroeddrankenwinkel.",
|
||||
"backgroundRainyBarnyardNotes": "Maak een drassige, spetterende wandeling door een Regenachtige Boerenerf.",
|
||||
"backgroundRainyBarnyardText": "Regenachtige boerenerf",
|
||||
"backgroundHeatherFieldNotes": "Geniet van de geur van een Heather Veld.",
|
||||
"backgroundHeatherFieldText": "Heather Veld",
|
||||
"backgroundAnimalCloudsNotes": "Oefen je fantasie door dierenvormen in de wolken te vinden.",
|
||||
"backgroundAnimalCloudsText": "Dierlijke Wolken",
|
||||
"backgrounds042020": "SET 71: Uitgekomen April 2020"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"jsDisabledHeading": "Helaas! Je browser heeft Javascript niet geactiveerd",
|
||||
"jsDisabledHeadingFull": "Helaas! Je browser heeft Javascript niet geactiveerd en zonder dat kan Habitica niet goed werken",
|
||||
"jsDisabledHeading": "Helaas! Je browser heeft JavaScript niet geactiveerd",
|
||||
"jsDisabledHeadingFull": "Helaas! Je browser heeft JavaScript niet geactiveerd en zonder dat kan Habitica niet goed werken",
|
||||
"jsDisabledText": "Habitica kan zonder dat de site niet goed weergeven!",
|
||||
"jsDisabledLink": "Activeer alsjeblieft Javascript om door te gaan!"
|
||||
}
|
||||
"jsDisabledLink": "Activeer alsjeblieft JavaScript om door te gaan!"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"randomize": "Randomiseren",
|
||||
"mattBoch": "Matt Boch",
|
||||
"mattShall": "Zal ik je je ros brengen, <%= name %>? Als je een Huisdier genoeg voedsel hebt gevoerd om het in een Rijdier te veranderen, zal het hier verschijnen. Klik op een rijdier om het te zadelen!",
|
||||
"mattBochText1": "Welkom in de Stal! Ik ben Matt, de Dierenmeester. Na niveau 3 kun je huisdieren laten uitkomen door middel van eieren en toverdranken. Als je een dier laat uitkomen in de markt, zal het hier verschijnen! Klik op de afbeelding van een huisdier om het aan je avatar toe te voegen! Voeder je huisdieren met het voedsel dat je vindt na niveau 3, zodat ze uitgroeien tot krachtige rijdieren.",
|
||||
"mattBochText1": "Welkom in de Stal! Ik ben Matt, de dierenmeester. Iedere keer als je een taak voltooid, heb je een willekeurige kans om een Ei of een Uitbroedtoverdrankje te ontvangen om Huisdieren uit te broeden. Als je een Huisdier uitbroedt, verschijnt het hier! Klik op de afbeelding van een Huisdier om het toe te voegen aan je Avatar. Voer ze met Voedsel voor Huisdieren en ze zullen uitgroeien tot stevige Rijdieren.",
|
||||
"welcomeToTavern": "Welkom bij de Herberg!",
|
||||
"sleepDescription": "Heb je een pauze nodig? Neem een kijkje in Daniel's Herberg om enkele van de moeilijkere spelmechanismen te pauzeren:",
|
||||
"sleepBullet1": "Gemiste Dagtaken zullen je niet beschadigen",
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
"unlocked": "Voorwerpen zijn ontgrendeld",
|
||||
"alreadyUnlocked": "Volledige set is al ontgrendeld.",
|
||||
"alreadyUnlockedPart": "Volledige set is al gedeeltelijk ontgrendeld.",
|
||||
"invalidQuantity": "Hoeveelheid om te kopen moet een nummer zijn.",
|
||||
"invalidQuantity": "Hoeveelheid om te kopen moet een positief heel getal zijn.",
|
||||
"USD": "(USD)",
|
||||
"newStuff": "Nieuwe informatie van Bailey",
|
||||
"newBaileyUpdate": "Nieuwe update van Bailey!",
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
"donationDesc": "20 Edelstenen, donatie aan Habitica",
|
||||
"payWithCard": "Betaal met creditcard",
|
||||
"payNote": "Opmerking: PayPal doet er soms lang over om een betaling te verwerken. We raden je aan te betalen met een creditcard.",
|
||||
"card": "CreditCard (met Stripe)",
|
||||
"card": "Creditcard",
|
||||
"amazonInstructions": "Klik op de knop om te betalen via de Amazon Betaaldienst",
|
||||
"paymentMethods": "Koop met",
|
||||
"paymentSuccessful": "Je betaling van succesvol!",
|
||||
|
|
@ -138,9 +138,9 @@
|
|||
"tourPartyPage": "Jouw gezelschap helpt je verantwoordelijk te blijven. Nodig je vrienden uit en speel een queeste-perkamentrol vrij!",
|
||||
"tourGuildsPage": "Gilden zijn chatgroepen met gezamenlijke interesses; gemaakt door de spelers, voor de spelers. Zoek door de lijst en word lid van de gilden die je interesseren. Kijk eens bij het populaire Habitica Help: Ask a Question gilde, waar iedereen vragen kan stellen over Habitica!",
|
||||
"tourChallengesPage": "Uitdagingen zijn takenlijsten met een thema, aangemaakt door andere gebruikers! Als je meedoet aan een uitdaging worden de bijbehorende taken toegevoegd aan je account. Wedijver met andere gebruikers om edelstenen te winnen!",
|
||||
"tourMarketPage": "Vanaf niveau 3 kun je eieren en uitbroeddranken vinden als je een taak afvinkt. Ze verschijnen hier - gebruik ze om huisdieren uit te broeden! Je kunt ook voorwerpen kopen in de markt.",
|
||||
"tourMarketPage": "Iedere keer als je een taak voltooid, heb je een willekeurige kans om een Ei, Uitbroedtoverdrank of een stuk Voedsel voor Dieren te vinden. Je kunt deze voorwerpen ook hier kopen.",
|
||||
"tourHallPage": "Welkom in de Hal der Helden, waar mensen die een bijdrage leveren aan Habitica worden geëerd. Door programmeren, kunst, muziek, schrijven, of zelfs door behulpzaam te zijn hebben zij edelstenen, exclusieve uitrusting en prestigieuze titels verdiend. Als je wilt, kun jij ook bijdragen aan Habitica!",
|
||||
"tourPetsPage": "Dit is de Stal! Na niveau 3 verzamel je eieren en toverdranken tijdens het voltooien van taken. Als je een huisdier laat uitkomen in de markt, verschijnt het hier! Klik op het plaatje van een huisdier om het aan je avatar toe te voegen. Voer je huisdieren met het voedsel dat je na niveau 3 vindt om ze te laten uitgroeien tot krachtige rijdieren.",
|
||||
"tourPetsPage": "Welkom in de Stal! Iedere keer als je een taak voltooid, heb je een willekeurige kans om een Ei of een Uitbroedtoverdrankje te ontvangen om Huisdieren uit te broeden. Als je een Huisdier uitbroedt, verschijnt het hier! Klik op de afbeelding van een Huisdier om het toe te voegen aan je Avatar. Voer ze met Voedsel voor Huisdieren en ze zullen uitgroeien tot stevige Rijdieren.",
|
||||
"tourMountsPage": "Als je een huisdier genoeg gevoerd hebt en het in een rijdier verandert, verschijnt het hier. Klik op een rijdier om op te zadelen!",
|
||||
"tourEquipmentPage": "This is where your Equipment is stored! Your Battle Gear affects your Stats. If you want to show different Equipment on your avatar without changing your Stats, click \"Enable Costume.\"",
|
||||
"equipmentAlreadyOwned": "Je bezit dat stuk uitrusting al",
|
||||
|
|
@ -167,5 +167,9 @@
|
|||
"welcome4": "Vermijd slechte gewoontes die je gezondheid (HP) verminderen, want anders gaat je avatar dood!",
|
||||
"welcome5": "Nu kun je je avatar aanpassen en je taken instellen...",
|
||||
"imReady": "Betreed Habitica",
|
||||
"limitedOffer": "Beschikbaar tot <%= date %>"
|
||||
"limitedOffer": "Beschikbaar tot <%= date %>",
|
||||
"paymentSubBillingWithMethod": "Je abonnement zal afgeschreven worden: <strong>$<%= amount %></strong> elke <strong><%= months %> maanden</strong> via <strong><%= paymentMethod %></strong>.",
|
||||
"paymentCanceledDisputes": "We hebben een annuleringsbevestiging gestuurd naar je e-mailadres. Als je deze mail niet ziet, neem dan alsjeblieft contact met ons op om geschillen over toekomstige rekeningen te voorkomen.",
|
||||
"paymentAutoRenew": "Dit abonnement zal automatisch vernieuwd worden totdat het wordt geannuleerd. Als het nodig is je abonnement op te zeggen, kun je dat doen in je instellingen.",
|
||||
"cannotUnpinItem": "Dit voorwerp kan niet losgekoppeld worden."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
"step2": "Stap 2: Verdien punten door dingen te doen in het echte leven",
|
||||
"webStep2Text": "Begin nu met het tackelen van de doelen op je lijst! Als je taken voltooit en ze afstreept in Habitica krijg je [Ervaringspunten](https://habitica.fandom.com/nl/wiki/Ervaringspunten), die je helpen om niveaus omhoog te gaan, en [Goud](https://habitica.fandom.com/nl/wiki/Goud), waarmee je beloningen kunt kopen. Als je terugvalt in slechte gewoontes of dagelijkse taken mist, zul je [Levenspunten](https://habitica.fandom.com/nl/wiki/Levenspunten) verliezen. Op deze manier zijn de ervaringsbalk en gezondheidsbalk een leuke indicator van je vooruitgang ten opzichte van je doelen. Je zult zien dat je echte leven verbetert naarmate je personage in het spel vooruit gaat.",
|
||||
"step3": "Stap 3: Bewerk en verken Habitica",
|
||||
"webStep3Text": "Zodra je wat meer vertrouwd bent met de basis, kun je nog meer uit Habitica halen met deze vernuftige functies: \n * Organiseer je taken met [labels](http://habitica.fandom.com/wiki/Tags) (wijzig de taak om labels toe te voegen).\n * Pas je [avatar] aan (http://habitica.fandom.com/wiki/Avatar) door te klikken op het gebruikersicoon in de hoek rechtsboven. \n * Koop je [Uitrusting](http://habitica.fandom.com/wiki/Equipment) in de Beloningensectie of in de [Winkels](<%= shopUrl %>), en verander het via [Boedel> Uitrusting](<%= equipUrl %>).\n * Bouw een band op met andere gebruikers in de [Herberg](http://habitica.fandom.com/wiki/Tavern).\n * Vanaf niveau 3, broedt [Huisdieren] uit (http://habitica.fandom.com/wiki/Pets) door [Eieren] (http://habitica.fandom.com/wiki/Eggs) en [Uitbroeddrankjes](http://habitica.fandom.com/wiki/Hatching_Potions) te verzamelen. [Voed](http://habitica.fandom.com/wiki/Food) ze om ze te laten uitgroeien tot [Rijdieren](http://habitica.fandom.com/wiki/Mounts).\n * Op niveau 10: Kies een specifieke [Klasse](http://habitica.fandom.com/wiki/Class_System) en gebruik de klassespecifieke [vaardigheden](http://habitica.fandom.com/wiki/Skills) (levels 11 to 14).\n * Vorm een gezelschap met je vrienden (door te klikken op [Gezelschap](<%= partyUrl %>) in de navigatiebalk) en zo verantwoording af te leggen en om Queesterollen te verdienen.\n * Versla Monsters en verzamel voorwerpen op [queesten](http://habitica.fandom.com/wiki/Quests) (Je ontvangt een Queeste op niveau 15).",
|
||||
"webStep3Text": "Zodra je wat meer vertrouwd bent met de basis, kun je nog meer uit Habitica halen met deze vernuftige functies: \n * Organiseer je taken met [labels](http://habitica.fandom.com/wiki/Tags) (wijzig de taak om labels toe te voegen).\n * Pas je [avatar] aan (http://habitica.fandom.com/wiki/Avatar) door te klikken op het gebruikersicoon in de hoek rechtsboven. \n * Koop je [Uitrusting](http://habitica.fandom.com/wiki/Equipment) in de Beloningensectie of in de [Winkels](<%= shopUrl %>), en verander het via [Boedel> Uitrusting](<%= equipUrl %>).\n * Bouw een band op met andere gebruikers in de [Herberg](http://habitica.fandom.com/wiki/Tavern).\n * Broedt [Huisdieren] uit (http://habitica.fandom.com/wiki/Pets) door [Eieren] (http://habitica.fandom.com/wiki/Eggs) en [Uitbroeddrankjes](http://habitica.fandom.com/wiki/Hatching_Potions) te verzamelen. [Voed](http://habitica.fandom.com/wiki/Food) ze om ze te laten uitgroeien tot [Rijdieren](http://habitica.fandom.com/wiki/Mounts).\n * Op niveau 10: Kies een specifieke [Klasse](http://habitica.fandom.com/wiki/Class_System) en gebruik de klassespecifieke [vaardigheden](http://habitica.fandom.com/wiki/Skills) (levels 11 to 14).\n * Vorm een gezelschap met je vrienden (door te klikken op [Gezelschap](<%= partyUrl %>) in de navigatiebalk) en zo verantwoording af te leggen en om Queesterollen te verdienen.\n * Versla Monsters en verzamel voorwerpen op [queesten](http://habitica.fandom.com/wiki/Quests) (Je ontvangt een Queeste op niveau 15).",
|
||||
"overviewQuestions": "Heb je vragen? Bekijk de [FAQ](<%= faqUrl %>)! Als dat je vraag niet beantwoordt, dan kun je hulp zoeken bij het [Habitica Help guild](<%= helpGuildUrl %>).\n\n Veel succes met je taken!"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "uitbroeddrank",
|
||||
"noHatchingPotions": "Je hebt geen uitbroeddranken.",
|
||||
"inventoryText": "Klik op een ei om bruikbare drankjes in het groen gemarkeerd te zien en klik dan op één van de gemarkeerde drankjes om een dier uit te broeden. Als er geen drankjes zijn gemarkeerd, klik dan opnieuw op het ei om de selectie te verwijderen; klik in plaats daarvan op een drankje om te zien of er bruikbare eieren gemarkeerd worden. Je kunt ongewenste voorwerpen ook verkopen aan Alexander de Koopman.",
|
||||
"haveHatchablePet": "Je hebt een <%= potion %>uitbroeddrank en een <%= egg %>ei om dit huisdier te laten uitbroeden! <b>Click</b> op de pootafdruk om uit te broeden.",
|
||||
"haveHatchablePet": "Je hebt een <%= potion %>uitbroeddrank en een <%= egg %>ei om dit huisdier te laten uitbroeden! <b>Click</b> om uit te broeden.",
|
||||
"quickInventory": "Snelle boedel",
|
||||
"foodText": "voedsel",
|
||||
"food": "Huisdieren voedsel en zadels",
|
||||
|
|
@ -123,9 +123,9 @@
|
|||
"foodWikiText": "Wat eet mijn huisdier graag?",
|
||||
"foodWikiUrl": "http://habitica.fandom.com/wiki/Food_Preferences",
|
||||
"welcomeStable": "Welkom in de stal!",
|
||||
"welcomeStableText": "Ik ben Matt, de Dierenmeester. Na niveau 3 kun je huisdieren laten uitkomen door middel van eieren en toverdranken die je vind! Wanneer je een dier laat uitkomen vanaf je Boedel, zal deze hier verschijnen! Klik op de afbeelding van een huisdier om het aan je avatar toe te voegen. Geef je huisdieren te eten met het voedsel dat je vindt na niveau 3, zodat ze uitgroeien tot krachtige rijdieren.",
|
||||
"welcomeStableText": "Welkom bij de stal! Ik ben Matt, de beestmeester. Elke keer dat je een taak voltooit, heb je een willekeurige kans om een ei of een uitkomstdrankje te ontvangen om huisdieren uit te laten komen. Wanneer je een huisdier uitbroedt, zal het hier verschijnen! Klik op de afbeelding van een huisdier om deze toe te voegen aan je avatar. Voer ze met het dierenvoedsel dat je vindt en ze zullen uitgroeien tot winterharde rijdieren.",
|
||||
"petLikeToEat": "Wat eet mijn huisdier graag?",
|
||||
"petLikeToEatText": "Het maakt niet uit wat je huisdieren voert om ze te laten groeien, maar ze zullen sneller groeien als je ze hun favoriete Voedsel voert. Experimenteer om uit te vinden wat het patroon is, of zie het antwoord hier: <br/><a href=\"http://habitica.fandom.com/wiki/Food_Preferences\" target=\"_blank\">http://habitica.fandom.com/wiki/Food_Preferences</a>",
|
||||
"petLikeToEatText": "Het maakt niet uit wat je huisdieren voert om ze te laten groeien, maar ze zullen sneller groeien als je ze hun favoriete voedsel voert. Experimenteer om uit te vinden wat het patroon is, of zie het antwoord hier: <br/><a href=\"http://habitica.fandom.com/wiki/Food_Preferences\" target=\"_blank\">http://habitica.fandom.com/wiki/Food_Preferences</a>",
|
||||
"filterByStandard": "Standaard",
|
||||
"filterByMagicPotion": "Magisch drankje",
|
||||
"filterByQuest": "Queeste",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
"rebirthOrb": "Heeft een Bol der Hergeboorte gebruikt om opnieuw te beginnen na het bereiken van Niveau <%= level %>.",
|
||||
"rebirthOrb100": "Heeft een Bol der Hergeboorte gebruikt om opnieuw te beginnen na het bereiken van Niveau 100 of hoger.",
|
||||
"rebirthOrbNoLevel": "Heeft een Bol der Hergeboorte gebruikt om opnieuw te beginnen.",
|
||||
"rebirthPop": "Herstart je personage direct als een Niveau 1 Krijger zonder je prestaties, verzamelobjecten en uitrusting te verliezen. Je taken en hun geschiedenis zal hetzelfde blijven maar ze worden gereset naar geel. Je series worden verwijderd behalve bij taken van uitdagingen. Je Goud, Ervaring, Mana en de effecten van al je Vaardigheden gaan verloren. Dit alles gaat direct in werking. Voor meer informatie zie de pagina van de <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Bol der Hergeboorte</a>.",
|
||||
"rebirthPop": "Herstart je personage direct als een Niveau 1 Krijger zonder je prestaties, verzamelobjecten en uitrusting te verliezen. Je taken - behalve taken die horen uitdagingen of onderdeel zijn van een groepsplan - en hun geschiedenis zal hetzelfde blijven maar ze worden gereset naar een gele kleur en de series worden verwijderd. Je Goud, Ervaring, Mana en de effecten van al je Vaardigheden gaan verloren. Dit alles gaat direct in werking. Voor meer informatie zie de pagina van de <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Bol der Hergeboorte</a>.",
|
||||
"rebirthName": "Bol der Hergeboorte",
|
||||
"reborn": "Herboren, maximale Niveau <%= reLevel %>",
|
||||
"confirmReborn": "Weet je het zeker?",
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@
|
|||
"mysterySet301703": "Pauw steampunkset",
|
||||
"mysterySet301704": "Fazant steampunkset",
|
||||
"mysterySetwondercon": "Wondercon",
|
||||
"subUpdateCard": "Creditcard aanpassen",
|
||||
"subUpdateCard": "Creditcard gegevens aanpassen",
|
||||
"subUpdateTitle": "Aanpassen",
|
||||
"subUpdateDescription": "Verander welke creditcard gebruikt wordt.",
|
||||
"notEnoughHourglasses": "Je hebt niet genoeg mystieke zandlopers.",
|
||||
|
|
@ -247,5 +247,6 @@
|
|||
"monthlyMysteryItems": "Maandelijkse mysterie-voorwerpen",
|
||||
"subscribersReceiveBenefits": "Abonnees ontvangen deze handige voordelen!",
|
||||
"subCanceledTitle": "Abonnement opgezegd",
|
||||
"backgroundAlreadyOwned": "Achtergrond al in bezit."
|
||||
"backgroundAlreadyOwned": "Achtergrond al in bezit.",
|
||||
"mysterySet202004": "Machtige Vorsten Set"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundButterflyGardenText": "Jardim de borboleta",
|
||||
"backgroundAmongGiantFlowersNotes": "Divirta-se entre flores gigantes.",
|
||||
"backgroundAmongGiantFlowersText": "Entre flores gigantes",
|
||||
"backgrounds032020": "Conjunto 70: lançado em Março de 2020"
|
||||
"backgrounds032020": "Conjunto 70: lançado em Março de 2020",
|
||||
"backgroundRainyBarnyardNotes": "Encharque-se enquanto faz um passeio por um curral chuvoso.",
|
||||
"backgroundRainyBarnyardText": "Curral chuvoso",
|
||||
"backgroundHeatherFieldNotes": "Aproveite o perfume de um campo de urzes.",
|
||||
"backgroundHeatherFieldText": "Campo de urzes",
|
||||
"backgroundAnimalCloudsNotes": "Exercite sua imaginação encontrando formas de animais nas nuvens.",
|
||||
"backgroundAnimalCloudsText": "Nuvens de animais",
|
||||
"backgrounds042020": "Conjunto 71: lançado em Abril de 2020"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2066,15 +2066,15 @@
|
|||
"headSpecialSpring2020RogueNotes": "Tão vibrante e valioso que você será tentado a roubá-lo de sua própria cabeça. Aumenta a percepção em <% = per %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020HealerNotes": "Envolva-se em folhas e pétalas de íris macias para enganar os inimigos e subestimar o seu poder de cura. Aumenta a Constituição em <%= con %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020HealerText": "Pétalas de proteção",
|
||||
"armorSpecialSpring2020MageNotes": "Se você não consegue resistir a pisar nos restos das tempestades, esta armadura é para você! Transforme um impulso infantil em uma exibição de arte mística. Aumenta a Inteligência em <%= int%>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020MageNotes": "Se você não consegue resistir a pisar nos restos das tempestades, esta armadura é para você! Transforme um impulso infantil em uma exibição de arte mística. Aumenta a Inteligência em <%= int %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020MageText": "Vestido de redemoinho",
|
||||
"armorSpecialSpring2020WarriorNotes": "Essa carapaça rígida pode mantê-lo seguro até dos ataques mais esmagadores. Aumenta a Constituição em <%= con %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020WarriorText": "Armadura de exoesqueleto",
|
||||
"armorSpecialSpring2020RogueNotes": "A cor do crepúsculo, de uma infinidade de pedras preciosas, do mar mais profundo! Aumenta a Percepção em <%= per %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"armorSpecialSpring2020RogueText": "Armadura ultramarina",
|
||||
"weaponSpecialSpring2020HealerNotes": "Uma íris é linda, mas as folhas são como espadas ... não se deixe enganar pelas flores, esse cajado é duro como aço! Aumenta a Inteligência em <% =int %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"weaponSpecialSpring2020HealerNotes": "Uma íris é linda, mas as folhas são como espadas ... não se deixe enganar pelas flores, esse cajado é duro como aço! Aumenta a Inteligência em <%= int %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"weaponSpecialSpring2020HealerText": "Cajado da espada-lírio",
|
||||
"weaponSpecialSpring2020MageNotes": "Eles continuam caindo em sua cabeça! Mas você nunca os impedirá reclamando. Aumenta a Inteligência em <%= int %> e a Percepção em <%=per %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"weaponSpecialSpring2020MageNotes": "Eles continuam caindo em sua cabeça! Mas você nunca os impedirá reclamando. Aumenta a Inteligência em <%= int %> e a Percepção em <%=per %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"weaponSpecialSpring2020MageText": "Pingos de chuva",
|
||||
"weaponSpecialSpring2020WarriorNotes": "Lutar ou voar, esta asa irá te atender bem! Aumenta a Força em <%= str %>. Equipamento de edição limitada da primavera de 2020.",
|
||||
"weaponSpecialSpring2020WarriorText": "Asa afiada",
|
||||
|
|
@ -2082,6 +2082,12 @@
|
|||
"weaponSpecialSpring2020RogueText": "Lâmina de lazurita",
|
||||
"headAccessoryMystery202004Notes": "Elas tremem um pouco se o perfume das flores passa perto -- use-as para encontrar um belo jardim! Não confere benefícios. Item de assinante, Abril de 2020.",
|
||||
"headAccessoryMystery202004Text": "Antenas do(a) Monarca poderoso(a)",
|
||||
"backMystery202004Notes": "Faça um movimento rápido para o prado florido mais próximo ou migre pelo continente com essas lindas asas! Não confere benefícios. Item de assinante, Abril de 2020.",
|
||||
"backMystery202004Text": "Asas do(a) Monarca poderoso(a)"
|
||||
"backMystery202004Notes": "Faça um movimento rápido para o prado florido mais próximo ou migre pelo continente com essas lindas asas! Não confere benefícios. Item de assinante, Abril de 2020.",
|
||||
"backMystery202004Text": "Asas do(a) Monarca poderoso(a)",
|
||||
"shieldArmoireHobbyHorseNotes": "Monte seu belo cavalo do passatempo em direção às suas justas Recompensas! Aumenta Percepção e Constituição em <%= attrs %>, cada. Armário Encantado: Conjunto do Cavaleiro de papel (Item 2 de 3).",
|
||||
"shieldArmoireHobbyHorseText": "Cavalo do passatempo",
|
||||
"armorArmoireBoxArmorNotes": "Armadura de caixa de papelão: se couber, portanto, você senta... ops, portanto você o usa em batalha, como o cavaleiro ousado que você é! Aumenta Percepção e Constituição em <%= attrs %> , cada. Armário Encantado: Conjunto do Cavaleiro de papel (Item 3 de 3). ",
|
||||
"armorArmoireBoxArmorText": "Armadura de caixa de papelão",
|
||||
"weaponArmoirePaperCutterNotes": "Isso pode não parecer assustador, mas você nunca teve um cortador de papel? Aumenta Força em <%= str %>. Armário Encantado: Conjunto do Cavaleiro de papel (Item 1 de 3).",
|
||||
"weaponArmoirePaperCutterText": "Cortador de papel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "poção de eclosão",
|
||||
"noHatchingPotions": "Você não possui poções de eclosão.",
|
||||
"inventoryText": "Clique num ovo para ver as poções utilizáveis destacadas em verde e depois clique em uma das poções destacadas para incubar seu mascote. Se nenhuma poção estiver destacada, clique no ovo novamente para desmarcá-lo, e em vez do ovo, clique na poção primeiro para ver os ovos utilizáveis marcados em verde. Você também pode vender itens indesejados para Alexander, o Comerciante.",
|
||||
"haveHatchablePet": "Você tem a Poção de Eclosão <%= potion %> e o ovo <%= egg %> para chocar este mascote! <b>Clique</b> na pata para chocar.",
|
||||
"haveHatchablePet": "Você tem a poção de eclosão <%= potion %> e o ovo <%= egg %> para chocar este mascote! <b>Clique</b>para chocar!",
|
||||
"quickInventory": "Inventário Rápido",
|
||||
"foodText": "comida",
|
||||
"food": "Comida para mascotes e Selas",
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
"noPhoto": "Acest Habitican nu și-a adăugat o poză.",
|
||||
"other": "Altele",
|
||||
"fullName": "Numele complet",
|
||||
"displayName": "Display name",
|
||||
"changeDisplayName": "Change Display Name",
|
||||
"newDisplayName": "New Display Name",
|
||||
"displayName": "Nume Afișat",
|
||||
"changeDisplayName": "Schimbă Numele Afișat",
|
||||
"newDisplayName": "Nume Afișat Nou",
|
||||
"displayPhoto": "Poză",
|
||||
"displayBlurb": "Prezentare",
|
||||
"displayBlurbPlaceholder": "Te rugăm să te prezinți",
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
"beard": "Barbă",
|
||||
"mustache": "Mustață",
|
||||
"flower": "Floare",
|
||||
"accent": "Accent",
|
||||
"accent": "Accesorii",
|
||||
"headband": "Bentiță",
|
||||
"wheelchair": "Scaun cu rotile",
|
||||
"extra": "Altele",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
"autoEquipPopoverText": "Selectează opțiunea de a îmbrăca echipament automat la cumpărarea acestuia.",
|
||||
"costumeDisabled": "Ți-ai dezactivat costumul.",
|
||||
"gearAchievement": "Ai câștigat trofeul „Armura Maximală” pentru că ai continuat să modernizezi până ai ajuns la setul maxim pentru o clasă! Ai obținut următoarele seturi complete:",
|
||||
"gearAchievementNotification": "You have earned the \"Ultimate Gear\" Achievement for upgrading to the maximum gear set for a class!",
|
||||
"gearAchievementNotification": "Ați obținut Realizarea „Ultimate Gear” pentru actualizarea la maxim a setului de echipamentul pentru o clasă!",
|
||||
"moreGearAchievements": "Pentru a obține mai multe insigne de Echipament Maximal, schimbă clasele din <a href='/user/settings/site' target='_blank'>Setări > pagina Site-ului</a> și cumpără echipament pentru noua ta clasă!",
|
||||
"armoireUnlocked": "Pentru mai mult echipament, verifică <strong>Cufărul Fermecat!</strong> Dă click pe Recompensa din Cufărul Fermecat pentru o șansă la un Echipament special random! E de asemenea posibil să primești aleator XP sau hrană.",
|
||||
"ultimGearName": "Echipament Maximal - <%= ultClass %>",
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
"allocatePerPop": "Adaugă un Punct la Percepție",
|
||||
"allocateInt": "Puncte atribuite la INT:",
|
||||
"allocateIntPop": "Adaugă un Punct la Inteligență",
|
||||
"noMoreAllocate": "Acum că ai atins nivelul 100, nu vei mai primi Puncte de Status suplimentare. Poți continua să îți crești nivelul, sau să începi o nouă aventură de la nivelul 1, folosind <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Globul Renașterii</a>, acum disponibil gratis în Târg.",
|
||||
"noMoreAllocate": "Acum că ai atins nivelul 100, nu vei mai primi Puncte de Status suplimentare. Poți continua să îți crești nivelul, sau să începi o nouă aventură de la nivelul 1, folosind <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Globul Renașterii</a>!",
|
||||
"stats": "Status",
|
||||
"achievs": "Realizari",
|
||||
"strength": "Forță",
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
"optOutOfClasses": "Refuză",
|
||||
"optOutOfPMs": "Refuză",
|
||||
"chooseClass": "Alege-ți Clasa",
|
||||
"chooseClassLearnMarkdown": "[Află mai multe despre sistemul de clase Habitica](http://habitica.fandom.com/wiki/Class_System)",
|
||||
"chooseClassLearnMarkdown": "[Află mai multe despre sistemul de clase Habitica](https://habitica.fandom.com/wiki/Class_System)",
|
||||
"optOutOfClassesText": "Nu ai chef de clase? Vrei să alegi mai târziu? Refuză - vei fi un războinic fără abilități speciale. Poți citi despre sistemul de clase mai târziu pe wiki și poți activa clasele oricând din Icon-ul de Utilizator > Setări.",
|
||||
"selectClass": "Selectează <%= heroClass %>",
|
||||
"select": "Alege",
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
"lostHealth": "Ai pierdut niște Sănătate",
|
||||
"lostExperience": "Ai pierdut niște Experiență",
|
||||
"displayNameDescription1": "This is what appears in messages you post in the Tavern, guilds, and party chat, along with what is displayed on your avatar. To change it, click the Edit button above. If instead you want to change your username, go to",
|
||||
"displayNameDescription2": "Settings->Site",
|
||||
"displayNameDescription2": "Setări->Site",
|
||||
"displayNameDescription3": "și uită-te la secțiunea de Înregistrare.",
|
||||
"unequipBattleGear": "Unequip Battle Gear",
|
||||
"unequipCostume": "Unequip Costume",
|
||||
|
|
@ -224,5 +224,6 @@
|
|||
"mainHand": "Mână dominantă",
|
||||
"offHand": "Mână nedominantă",
|
||||
"statPoints": "Stat Points",
|
||||
"pts": "pcte"
|
||||
"pts": "pcte",
|
||||
"purchasePetItemConfirm": "Această achiziție ar depăși numărul de articole de care aveți nevoie pentru a ecloza toate animalele de companie <% = itemText%> posibile. Esti sigur?"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"lostAllHealth": "Ai rămas fără sănătate!",
|
||||
"dontDespair": "Nu dispera",
|
||||
"dontDespair": "Nu dispera!",
|
||||
"deathPenaltyDetails": "Ai pierdut un nivel, aurul și o piesă de echipament, dar le poți obține înapoi prin muncă susținută! Mult noroc -- o să fie bine.",
|
||||
"refillHealthTryAgain": "Realimentează cu sănătate și încearcă din nou.",
|
||||
"refillHealthTryAgain": "Realimentează cu Sănătate și Încearcă din Nou",
|
||||
"dyingOftenTips": "Se întâmplă des? <a href='http://habitica.fandom.com/wiki/Death_Mechanics#Strategies_for_Staying_Alive' target='_blank'>Aici sunt niște indicii!</a>",
|
||||
"losingHealthWarning": "Atenție - pierzi din sănătate!",
|
||||
"losingHealthWarning2": "Nu lăsa sănătatea să scadă la zero! Dacă faci asta, vei pierde un nivel, tot aurul și o piesă de echipament.",
|
||||
|
|
@ -10,8 +10,8 @@
|
|||
"lowHealthTips1": "Avansează un nivel pentru a te vindeca complet!",
|
||||
"lowHealthTips2": "Cumpără o licoare de sănătate din Coloana de răsplăți pentru a restaura 15 puncte de sănătate.",
|
||||
"losingHealthQuickly": "Pierzi sănătate prea rapid?",
|
||||
"lowHealthTips3": "Sarcini zilnice necompletate te rănesc peste noapte, așa că ai grijă să nu adaugi prea multe la început.",
|
||||
"lowHealthTips3": "Sarcini zilnice necompletate te rănesc peste noapte, așa că ai grijă să nu adaugi prea multe la început!",
|
||||
"lowHealthTips4": "Dacă o sarcină zilnică nu trebuie realizată ziua respectivă, o poți dezactiva printr-un clic pe iconița cu creion.",
|
||||
"goodLuck": "Baftă!",
|
||||
"cannotRevive": "Nu poți reînvia fără a fi mort"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,5 +330,6 @@
|
|||
"signup": "Sign Up",
|
||||
"getStarted": "Get Started!",
|
||||
"mobileApps": "Mobile Apps",
|
||||
"learnMore": "Learn More"
|
||||
"learnMore": "Learn More",
|
||||
"communityInstagram": "Instagram"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,38 @@
|
|||
{
|
||||
"tipTitle": "Pont #<%= tipNumber %>",
|
||||
"tip1": "Verifică-ți sarcinile departe de casă cu aplicațiile mobile Habitica.",
|
||||
"tip2": "Click any equipment to see a preview, or equip it instantly by clicking the star in its upper-left corner!",
|
||||
"tip3": "Puteți să vă personalizați sarcinile prin întrebuințarea ideogramelor emoji.",
|
||||
"tip4": "Scrie simbolul # înaintea denumirii unei sarcini, și aceasta va avea un font uriaș!",
|
||||
"tip5": "Este recomandat să folosești abilitățile dimineața, pentru a le face să dureze mai mult.",
|
||||
"tip6": "Hover over a task and click the dots to access advanced task controls, such as the ability to push tasks to the top/bottom of your list.",
|
||||
"tip7": "Some backgrounds connect perfectly if Party members use the same background. Ex: Mountain Lake, Pagodas, and Rolling Hills.",
|
||||
"tip8": "Trimite un Mesaj cuiva dând click pe numele lor în chat și apoi apăsând pe pictograma cu plicul din susul profilului lor!",
|
||||
"tip9": "Use the filters + search bar in the Inventories, Shops, Guilds, and Challenges to quickly find what you want.",
|
||||
"tip10": "Poți câștiga nestemate luând parte la Provocări. Acestea sunt adăugate în fiecare zi!",
|
||||
"tip11": "Having more than four Party members increases accountability!",
|
||||
"tip12": "Adaugă liste de bifare la Activitățile tale De-Făcut pentru a-ți multiplica recompensele!",
|
||||
"tip13": "Apasă pe ”Etichete” pe pagina ta cu sarcini pentru a transforma o listă cu sarcini greu de controlat într-una foarte controlabilă!",
|
||||
"tip14": "You can add headers or inspirational quotes to your list as Habits with no (+/-).",
|
||||
"tip15": "Complete all the Masterclasser Quest-lines to learn about Habitica’s secret lore.",
|
||||
"tip16": "Click the link to the Data Display Tool in the footer for valuable insights on your progress.",
|
||||
"tip17": "Use the mobile apps to set reminders for your tasks.",
|
||||
"tip18": "Habits that are just positive or just negative gradually “fade” and return to yellow.",
|
||||
"tip19": "Boost your Intelligence Stat to gain more experience when you complete a task.",
|
||||
"tip20": "Boost your Perception Stat to get more drops and gold.",
|
||||
"tip21": "Boost your Strength Stat to do more boss damage or get critical hits.",
|
||||
"tip22": "Boost your Constitution Stat to lessen the damage from incomplete Dailies.",
|
||||
"tip23": "Reach level 100 to unlock the Orb of Rebirth for free and start a new adventure!",
|
||||
"tip24": "Have a question? Ask in the Habitica Help Guild!",
|
||||
"tip25": "The four seasonal Grand Galas start near the solstices and equinoxes.",
|
||||
"tip26": "You can look for a Party or find Party members in the Party Wanted Guild!",
|
||||
"tip27": "Did a Daily yesterday, but forgot to check it off? Don't worry! With Record Yesterday's Activity, you'll have a chance to record what you did before starting your new day.",
|
||||
"tip28": "Set a Custom Day Start under User Icon > Settings to control when your day restarts.",
|
||||
"tip29": "Complete all your Dailies to get a Perfect Day Buff that increases your Stats!",
|
||||
"tip30": "You can invite people to Guilds, not just Parties.",
|
||||
"tip31": "Check out the pre-made lists in the Library of Tasks and Challenges Guild for example tasks.",
|
||||
"tip32": "Lots of Habitica’s code, art, and writing is made by volunteer contributors! Head to the Aspiring Legends Guild to help.",
|
||||
"tip33": "Check out The Bulletin Board Guild for news about Guilds, Challenges, and other player-created events - and announce your own there!",
|
||||
"tip34": "Occasionally re-evaluate your tasks to make sure they’re up-to-date!",
|
||||
"tip35": "Users who are part of a Group Plan gain the ability to assign tasks to other users in that Group for extra task management and accountability."
|
||||
"tipTitle": "Pont #<%= tipNumber %>",
|
||||
"tip1": "Verifică-ți sarcinile departe de casă cu aplicațiile mobile Habitica.",
|
||||
"tip2": "Faceți clic pe orice echipament pentru a vedea o previzualizare sau echipați-l instantaneu făcând clic pe steaua din colțul din stânga sus!",
|
||||
"tip3": "Puteți să vă personalizați sarcinile prin întrebuințarea ideogramelor emoji.",
|
||||
"tip4": "Scrie simbolul # înaintea denumirii unei sarcini, și aceasta va avea un font uriaș!",
|
||||
"tip5": "Este recomandat să folosești abilitățile dimineața, pentru a le face să dureze mai mult.",
|
||||
"tip6": "Treceți peste o sarcină și faceți clic pe puncte pentru a accesa controale avansate ale sarcinilor, cum ar fi posibilitatea de a muta sarcinile la începutul/sfârșitul listei.",
|
||||
"tip7": "Unele fundaluri se conectează perfect dacă membrii Echipei folosesc același fundal. Ex: Lacul de Munte, Pagode și Dealuri Domoale.",
|
||||
"tip8": "Trimite un Mesaj cuiva dând click pe numele lor în chat și apoi apăsând pe pictograma cu plicul din susul profilului lor!",
|
||||
"tip9": "Utilizați filtrele + bara de căutare din Inventar, Magazine, Guilde și Provocări pentru a găsi rapid ceea ce doriți.",
|
||||
"tip10": "Poți câștiga nestemate luând parte la Provocări. Acestea sunt adăugate în fiecare zi!",
|
||||
"tip11": "A avea mai mult de patru membri în Echipă crește responsabilitatea!",
|
||||
"tip12": "Adaugă liste de bifare la Activitățile tale De-Făcut pentru a-ți multiplica recompensele!",
|
||||
"tip13": "Apasă pe ”Etichete” pe pagina ta cu sarcini pentru a transforma o listă cu sarcini greu de controlat într-una foarte controlabilă!",
|
||||
"tip14": "Puteți adăuga antete sau citate de inspirație la lista dvs. ca Obiceiuri fără (+/-).",
|
||||
"tip15": "Completați toată linia de Aventuri Masterclasser pentru a afla mai multe despre secretele din Habitica.",
|
||||
"tip16": "Faceți clic pe linkul Unealtă de Afișare a Datelor din subsol pentru informații importante despre progresul dvs.",
|
||||
"tip17": "Utilizați aplicațiile mobile pentru a seta mementouri pentru sarcinile dvs.",
|
||||
"tip18": "Obiceiurile care sunt doar pozitive sau doar negative se „estompează” treptat și revin la galben.",
|
||||
"tip19": "Îmbunătățește-ți Statul de Informații pentru a câștiga mai multă experiență atunci când finalizați o sarcină.",
|
||||
"tip20": "Îmbunătățește-ți Statul de Percepție pentru a obține mai multe recompense și aur.",
|
||||
"tip21": "Îmbunătățește-ți Statul de Forță pentru a face mai multe daune Căpcăunului sau a primi lovituri critice.",
|
||||
"tip22": "Îmbunătățește-ți Statul de Constituție pentru a reduce daunele cauzate de Cotidienele incomplete.",
|
||||
"tip23": "Atinge nivelul 100 pentru a debloca gratuit Globului Renașterii și începe o nouă aventură!",
|
||||
"tip24": "Ai o intrebare? Întreabă în Ghilda Habitica Help!",
|
||||
"tip25": "Cele patru Grand Galas sezoniere încep în apropierea solstițiilor și echinocțiilor.",
|
||||
"tip26": "Puteți căuta o Echipă sau puteți găsi membri ai Echipei în Ghildul Party Wanted!",
|
||||
"tip27": "Ai făcut o Cotidiană ieri, dar ai uitat să o înregistrezi? Nu-ți face griji! Cu Înregistrați Activitatea de Ieri, vei avea șansa să înregistrezi ceea ce ai făcut înainte de a începe noua ta zi.",
|
||||
"tip28": "Setați un Început de Zi Personalizat sub pictograma Utilizator > Setări pentru a controla când începe ziua.",
|
||||
"tip29": "Completează toate Cotidienele tale pentru a obține un Spor Zi Perfectă care îți crește statisticile!",
|
||||
"tip30": "Puteți invita oamenii în Ghildă, nu doar în Echipe.",
|
||||
"tip31": "Consultați listele pre-făcute în Ghildul Library of Tasks and Challenges pentru exemple de sarcini.",
|
||||
"tip32": "O mulțime de cod, artă și scriere de la Habitica sunt realizate de colaboratori voluntari! Mergeți spre Ghildul Aspiring Legends ca să ajutați.",
|
||||
"tip33": "Vezi Ghildul The Bulletin Board pentru noutăți despre Ghilde, Provocările și alte evenimente create de jucători și anunță-l pe al tău acolo!",
|
||||
"tip34": "Re-evaluați ocazional sarcinile pentru a vă asigura că sunt la zi!",
|
||||
"tip35": "Utilizatorii care fac parte dintr-un Plan de Grup câștigă capacitatea de a atribui sarcini altor utilizatori din Grupul respectiv pentru gestionare și responsabilitate suplimentară a sarcinilor."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
{
|
||||
"unlockedReward": "Ai primit <%= reward %>",
|
||||
"earnedRewardForDevotion": "You have earned <%= reward %> for being committed to improving your life.",
|
||||
"nextRewardUnlocksIn": "Check-ins until your next prize: <%= numberOfCheckinsLeft %>",
|
||||
"awesome": "Mișto!",
|
||||
"totalCount": "<%= count %> total count",
|
||||
"countLeft": "Check-in-uri până la următoarea recompensă: <%= count %>",
|
||||
"incentivesDescription": "Când vine vorba de formarea obiceiurilor, consistența este elementul cheie. Fiecare zi în care faceți check-in te va aduce mai aproape de un premiu. ",
|
||||
"totalCheckins": "<%= count %>Check-in-uri",
|
||||
"checkinEarned": "Your Check-In Counter went up!",
|
||||
"unlockedCheckInReward": "Ai deblocat un Premiu pentru Check-In!",
|
||||
"totalCheckinsTitle": "Check-In-uri totale",
|
||||
"checkinProgressTitle": "Progres până la următorul",
|
||||
"incentiveBackgroundsUnlockedWithCheckins": "Imaginile de Background simple blocate se vor debloca odată cu check-in-urile zilnice.",
|
||||
"checkinReceivedAllRewardsMessage": "Ai primit toate premiile disponibile pentru Check-In-uri! Felicitări!",
|
||||
"oneOfAllPetEggs": "Câte un Ou standard din fiecare",
|
||||
"twoOfAllPetEggs": "two of each standard Pet Egg",
|
||||
"threeOfAllPetEggs": "three of each standard Pet Egg",
|
||||
"oneOfAllHatchingPotions": "one of each standard Hatching Potion",
|
||||
"threeOfEachFood": "three of each standard Pet Food",
|
||||
"fourOfEachFood": "four of each standard Pet Food",
|
||||
"twoSaddles": "two Saddles",
|
||||
"threeSaddles": "three Saddles",
|
||||
"incentiveAchievement": "the Royally Loyal achievement",
|
||||
"royallyLoyal": "Royally Loyal",
|
||||
"royallyLoyalText": "This user has checked in over 500 times, and has earned every Check-In Prize!",
|
||||
"checkInRewards": "Check-In Rewards",
|
||||
"backloggedCheckInRewards": "You received Check-In Prizes! Visit your Inventory and Equipment to see what's new."
|
||||
"unlockedReward": "Ai primit <%= reward %>",
|
||||
"earnedRewardForDevotion": "Ai câștigat <%= reward %> pentru că te-ai comis să îți îmbunătățești viața.",
|
||||
"nextRewardUnlocksIn": "Verificări până la următorul premiu: <%= numberOfCheckinsLeft %>",
|
||||
"awesome": "Mișto!",
|
||||
"totalCount": "<%= count %> numărătoare totală",
|
||||
"countLeft": "Check-in-uri până la următoarea recompensă: <%= count %>",
|
||||
"incentivesDescription": "Când vine vorba de formarea obiceiurilor, consistența este elementul cheie. Fiecare zi în care faceți check-in te va aduce mai aproape de un premiu.",
|
||||
"totalCheckins": "<%= count %>Check-in-uri",
|
||||
"checkinEarned": "Contorul tău de înregistrare a crescut!",
|
||||
"unlockedCheckInReward": "Ai deblocat un Premiu pentru Check-In!",
|
||||
"totalCheckinsTitle": "Check-In-uri totale",
|
||||
"checkinProgressTitle": "Progres până la următorul",
|
||||
"incentiveBackgroundsUnlockedWithCheckins": "Imaginile de Background simple blocate se vor debloca odată cu check-in-urile zilnice.",
|
||||
"checkinReceivedAllRewardsMessage": "Ai primit toate premiile disponibile pentru Check-In-uri! Felicitări!",
|
||||
"oneOfAllPetEggs": "câte un Ou standard din fiecare",
|
||||
"twoOfAllPetEggs": "câte două Ouă de Animale de Companie standard din fiecare",
|
||||
"threeOfAllPetEggs": "câte trei Ouă de Animale de Companie standard din fiecare",
|
||||
"oneOfAllHatchingPotions": "câte o Poțiune de Eclozat standard din fiecare",
|
||||
"threeOfEachFood": "câte trei Mâncare pentru Animale standard din fiecare",
|
||||
"fourOfEachFood": "câte patru Mâncare pentru Animale standard din fiecare",
|
||||
"twoSaddles": "două Șei",
|
||||
"threeSaddles": "trei Șei",
|
||||
"incentiveAchievement": "realizarea Sincer Loial (the Royally Loyal)",
|
||||
"royallyLoyal": "Sincer Loial",
|
||||
"royallyLoyalText": "Acest utilizator s-a înregistrat de peste 500 de ori și a obținut fiecare Premiu de Înregistrare!",
|
||||
"checkInRewards": "Premiu de Înregistrare",
|
||||
"backloggedCheckInRewards": "Ai primit Premii de Înregistrare! Accesează Inventarul și Echipamentul pentru a vedea ce este nou."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,14 @@
|
|||
{
|
||||
"merch" : "Marfă",
|
||||
"merchandiseDescription": "Looking for t-shirts, mugs, or stickers to show off your Habitica pride? Click here!",
|
||||
|
||||
"merch-teespring-summary" : "Teespring este o platforma care permit oricui să creeze și să vândă produse de înaltă calitate adorate de clienți, fără costuri sau riscuri asociate. ",
|
||||
"merch-teespring-goto" : "Cumpără un tricou Habitica",
|
||||
|
||||
"merch-teespring-mug-summary" : "Teespring is a platform that makes it easy for anyone to create and sell high-quality products people love, with no cost or risk.",
|
||||
"merch-teespring-mug-goto" : "Cumpără o Cană Habitica",
|
||||
|
||||
"merch-teespring-eu-summary" : "EUROPEAN VERSION : Teespring is a platform that makes it easy for anyone to create and sell high-quality products people love, with no cost or risk.",
|
||||
"merch-teespring-eu-goto" : "Cumpărați un tricou Habitica",
|
||||
|
||||
"merch-teespring-mug-eu-summary" : "EUROPEAN VERSION : Teespring is a platform that makes it easy for anyone to create and sell high-quality products people love, with no cost or risk.",
|
||||
"merch-teespring-mug-eu-goto" : "Cumpără o Cană Habitica (UE)",
|
||||
|
||||
"merch-stickermule-summary" : "Stick proud Melior wherever you (or someone else) need a reminder of both present and future accomplishments!",
|
||||
"merch-stickermule-goto" : "Cumpărați stickere Habitica"
|
||||
|
||||
"merch": "Marfă",
|
||||
"merchandiseDescription": "Căutați tricouri, căni sau autocolante pentru a vă arăta mândria de la Habitica? Click aici!",
|
||||
"merch-teespring-summary": "Teespring este o platforma care permit oricui să creeze și să vândă produse de înaltă calitate adorate de clienți, fără costuri sau riscuri asociate.",
|
||||
"merch-teespring-goto": "Cumpără un tricou Habitica",
|
||||
"merch-teespring-mug-summary": "Teespring este o platformă care ușurează oricui să creeze și să vândă produse de înaltă calitate pe care le iubesc, fără costuri sau riscuri.",
|
||||
"merch-teespring-mug-goto": "Cumpără o Cană Habitica",
|
||||
"merch-teespring-eu-summary": "VERSIUNEA EUROPEANĂ: Teespring este o platformă care facilitează oricui să creeze și să vândă produse de înaltă calitate pe care le iubesc, fără costuri sau riscuri.",
|
||||
"merch-teespring-eu-goto": "Cumpărați un tricou Habitica",
|
||||
"merch-teespring-mug-eu-summary": "VERSIUNEA EUROPEANĂ: Teespring este o platformă care facilitează oricui să creeze și să vândă produse de înaltă calitate pe care le iubesc, fără costuri sau riscuri.",
|
||||
"merch-teespring-mug-eu-goto": "Cumpără o Cană Habitica (UE)",
|
||||
"merch-stickermule-summary": "Lipiți mândru Melior oriunde voi (sau altcineva) aveți nevoie să vă aminti atât de realizările prezente, cât și de cele viitoare!",
|
||||
"merch-stickermule-goto": "Cumpărați stickere Habitica"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +1,59 @@
|
|||
{
|
||||
"spellWizardFireballText": "Rafală de flăcări",
|
||||
"spellWizardFireballNotes": "You summon XP and deal fiery damage to Bosses! (Based on: INT)",
|
||||
"spellWizardFireballNotes": "Convocați Experiență și faceți daune înflăcărate Căpcăunului! (Bazat pe: INT)",
|
||||
"spellWizardMPHealText": "Val eteric",
|
||||
"spellWizardMPHealNotes": "You sacrifice Mana so the rest of your Party, except Mages, gains MP! (Based on: INT)",
|
||||
"spellWizardMPHealNotes": "Sacrifici Mana astfel încât restul Echipei tale, cu excepția Magilor, câștigă Puncte Mana! (Bazat pe: INT)",
|
||||
"spellWizardEarthText": "Cutremur",
|
||||
"spellWizardEarthNotes": "Your mental power shakes the earth and buffs your Party's Intelligence! (Based on: Unbuffed INT)",
|
||||
"spellWizardEarthNotes": "Puterea ta mentală zdruncină pământul și sporește Inteligența Echipei! (Bazat pe: INT Nesporită)",
|
||||
"spellWizardFrostText": "Ger aprig",
|
||||
"spellWizardFrostNotes": "Cu o singură vrajă, toate șirurile tale sunt înghețate, astfel încât nu se vor mai reseta mâine!",
|
||||
"spellWizardFrostAlreadyCast": "Ai folosit deja această vrajă astăzi. Șirurile tale sunt înghețate deja, deci nu este nevoie să faci aceeași vrajă din nou. ",
|
||||
"spellWizardFrostNotes": "Cu o singură vrajă, toate șirurile tale sunt înghețate, astfel încât nu se vor mai reseta mâine! ",
|
||||
"spellWizardFrostAlreadyCast": " Ai folosit deja această vrajă astăzi. Șirurile tale sunt înghețate deja, deci nu este nevoie să faci aceeași vrajă din nou.",
|
||||
"spellWarriorSmashText": "Izbitură brutală",
|
||||
"spellWarriorSmashNotes": "You make a task more blue/less red and deal extra damage to Bosses! (Based on: STR)",
|
||||
"spellWarriorSmashNotes": "Faceți o sarcină mai albastră/mai puțin roșie și faceți daune suplimentare Căpcăunului! (Bazat pe: FOR)",
|
||||
"spellWarriorDefensiveStanceText": "Postură defensivă",
|
||||
"spellWarriorDefensiveStanceNotes": "You crouch low and gain a buff to Constitution! (Based on: Unbuffed CON)",
|
||||
"spellWarriorDefensiveStanceNotes": "Vă ghemuți jos și obțineți un spor la Constituție! (Bazat pe: CON nesporit)",
|
||||
"spellWarriorValorousPresenceText": "Tovărășie vitejească",
|
||||
"spellWarriorValorousPresenceNotes": "Your boldness buffs your whole Party's Strength! (Based on: Unbuffed STR)",
|
||||
"spellWarriorValorousPresenceNotes": "Îndrăzneala ta îmbunătățește întreaga Forță a Echipei! (Bazat pe: Forța Nesporită)",
|
||||
"spellWarriorIntimidateText": "Privire intimidantă",
|
||||
"spellWarriorIntimidateNotes": "Your fierce stare buffs your whole Party's Constitution! (Based on: Unbuffed CON)",
|
||||
"spellWarriorIntimidateNotes": "Privirea ta înverșunată îmbunătățește întreaga Constituție a Echipei! (Bazat pe: CON nesporit)",
|
||||
"spellRoguePickPocketText": "Pungaș",
|
||||
"spellRoguePickPocketNotes": "You rob a nearby task and gain gold! (Based on: PER)",
|
||||
"spellRoguePickPocketNotes": "Tu jefuiești o sarcină din apropiere și câștigi aur! (Pe baza: PER)",
|
||||
"spellRogueBackStabText": "Înjunghiere",
|
||||
"spellRogueBackStabNotes": "You betray a foolish task and gain gold and XP! (Based on: STR)",
|
||||
"spellRogueBackStabNotes": "Trădează o sarcină prostească și câștigi aur și XP! (Bazat pe: FOR)",
|
||||
"spellRogueToolsOfTradeText": "Sculele meseriei",
|
||||
"spellRogueToolsOfTradeNotes": "Your tricky talents buff your whole Party's Perception! (Based on: Unbuffed PER)",
|
||||
"spellRogueToolsOfTradeNotes": "Talentele tale complicate păstrează Percepția întregii Echipe! (Bazat pe: PER nesporit)",
|
||||
"spellRogueStealthText": "Discreție",
|
||||
"spellRogueStealthNotes": "With each cast, a few of your undone Dailies won't cause damage tonight. Their streaks and colors won't change. (Based on: PER)",
|
||||
"spellRogueStealthDaliesAvoided": "<%= originalText %> Number of dailies avoided: <%= number %>.",
|
||||
"spellRogueStealthMaxedOut": "You have already avoided all your dailies; there's no need to cast this again.",
|
||||
"spellRogueStealthNotes": "Cu fiecare aruncare a vrăjii, câteva dintre Cotidianele voastre nefăcute nu vor provoca daune în această seară. Șirulși culorile lor nu se vor schimba. (Pe baza: PER)",
|
||||
"spellRogueStealthDaliesAvoided": "<%= originalText %> Numumărul de Cotidiene evitate: <%= number %>.",
|
||||
"spellRogueStealthMaxedOut": " You have already avoided all your dailies; there's no need to cast this again.",
|
||||
"spellHealerHealText": "Lumină vindecătoare",
|
||||
"spellHealerHealNotes": "Shining light restores your health! (Based on: CON and INT)",
|
||||
"spellHealerHealNotes": "Lumina strălucitoare îți restabilește sănătatea! (Bazat pe: CON și INT)",
|
||||
"spellHealerBrightnessText": "Strălucire mistuitoare",
|
||||
"spellHealerBrightnessNotes": "A burst of light makes your tasks more blue/less red! (Based on: INT)",
|
||||
"spellHealerBrightnessNotes": "O explozie de lumină îți face sarcinile mai albastre/mai puțin roșii! (Bazat pe: INT)",
|
||||
"spellHealerProtectAuraText": "Aură protectoare",
|
||||
"spellHealerProtectAuraNotes": "You shield your Party by buffing their Constitution! (Based on: Unbuffed CON)",
|
||||
"spellHealerProtectAuraNotes": "Îți protejezi Echipa prin sporirea Constituției! (Bazat pe: CON nesporită)",
|
||||
"spellHealerHealAllText": "Binecuvântare",
|
||||
"spellHealerHealAllNotes": "Your soothing spell restores your whole Party's health! (Based on: CON and INT)",
|
||||
"spellHealerHealAllNotes": "Vraja ta liniștitoare restabilește sănătatea întregii tale Echipe! (Bazat pe: CON și INT)",
|
||||
"spellSpecialSnowballAuraText": "Bulgăre de zăpadă",
|
||||
"spellSpecialSnowballAuraNotes": "Turn a friend into a frosty snowman!",
|
||||
"spellSpecialSnowballAuraNotes": "Transformă un prieten într-un om de zăpadă înghețat!",
|
||||
"spellSpecialSaltText": "Sare",
|
||||
"spellSpecialSaltNotes": "Reverse the spell that made you a snowman.",
|
||||
"spellSpecialSpookySparklesText": "Spooky Sparkles",
|
||||
"spellSpecialSpookySparklesNotes": "Turn your friend into a transparent pal!",
|
||||
"spellSpecialSaltNotes": "Inversează vraja care te-a făcut om de zăpadă.",
|
||||
"spellSpecialSpookySparklesText": "Fantoma Sclipicioasă",
|
||||
"spellSpecialSpookySparklesNotes": "Transformă-ți prietenul într-un prieten transparent!",
|
||||
"spellSpecialOpaquePotionText": "Poțiune opacă",
|
||||
"spellSpecialOpaquePotionNotes": "Reverse the spell that made you transparent.",
|
||||
"spellSpecialShinySeedText": "Shiny Seed",
|
||||
"spellSpecialShinySeedNotes": "Turn a friend into a joyous flower!",
|
||||
"spellSpecialPetalFreePotionText": "Petal-Free Potion",
|
||||
"spellSpecialPetalFreePotionNotes": "Reverse the spell that made you a flower.",
|
||||
"spellSpecialSeafoamText": "Seafoam",
|
||||
"spellSpecialSeafoamNotes": "Turn a friend into a sea creature!",
|
||||
"spellSpecialSandText": "Sand",
|
||||
"spellSpecialSandNotes": "Reverse the spell that made you a sea star.",
|
||||
"partyNotFound": "Party not found",
|
||||
"targetIdUUID": "\"targetId\" must be a valid User ID.",
|
||||
"challengeTasksNoCast": "Casting a skill on challenge tasks is not allowed.",
|
||||
"groupTasksNoCast": "Casting a skill on group tasks is not allowed.",
|
||||
"spellNotOwned": "You don't own this skill.",
|
||||
"spellLevelTooHigh": "You must be level <%= level %> to use this skill."
|
||||
}
|
||||
"spellSpecialOpaquePotionNotes": "Inversează vraja care te-a făcut transparent.",
|
||||
"spellSpecialShinySeedText": "Semința Strălucitoare",
|
||||
"spellSpecialShinySeedNotes": "Transformă un prieten într-o floare veselă!",
|
||||
"spellSpecialPetalFreePotionText": "Poțiune Fără Petale",
|
||||
"spellSpecialPetalFreePotionNotes": "Inversați vraja care v-a făcut floare.",
|
||||
"spellSpecialSeafoamText": "Spumă de Mare",
|
||||
"spellSpecialSeafoamNotes": "Transformă un prieten într-o creatură de mare!",
|
||||
"spellSpecialSandText": "Nisip",
|
||||
"spellSpecialSandNotes": "Inversează vraja care te-a făcut o stea de mare.",
|
||||
"partyNotFound": "Echipa nu a fost găsită",
|
||||
"targetIdUUID": "\"targetId\" trebuie să fie un ID de utilizator valid.",
|
||||
"challengeTasksNoCast": "Aplicarea unei abilități în sarcinile de la provocări nu este permisă.",
|
||||
"groupTasksNoCast": "Nu este permisă aplicarea unei abilități în sarcinile grupului.",
|
||||
"spellNotOwned": "Nu dețineți această abilitate.",
|
||||
"spellLevelTooHigh": "Pentru a utiliza această abilitate trebuie să fiți nivelul <%= level %>."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"lotOfToDos": "Cele mai recente 30 de activități De-Făcut completate apar aici. Le poți vedea pe cele mai vechi din Data > Data Display Tool sau Data > Export Data > User Data.",
|
||||
"deleteToDosExplanation": "Dacă apeși butonul de mai jos, toate activitățile tale De-Făcut completate și cele arhivate vor fi șterse permanent, cu excepția celor din provocări în desfășurare și din Planurile de Grup. Exportă-le întâi dacă vrei să ții o evidență a lor.",
|
||||
"addMultipleTip": "<strong>Sfat</strong> Pentru a adăuga multiple <%= taskType %>, separă-le pe fiecare utilizând o linie de pauză (Shift + Enter) și apoi apasă ”Enter.”",
|
||||
"addsingle": "Add Single",
|
||||
"addsingle": "Adaugă Individual",
|
||||
"addATask": "Adaugă un/o <%= type %>",
|
||||
"editATask": "Editează un/o <%= type %>",
|
||||
"createTask": "Crează <%= type %>",
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
"habit": "Obicei",
|
||||
"habits": "Obiceiuri",
|
||||
"newHabit": "Obicei nou",
|
||||
"newHabitBulk": "New Habits (one per line)",
|
||||
"newHabitBulk": "Obiceiuri noi (câte unul pe linie)",
|
||||
"habitsDesc": "Obiceiurile nu au un program rigid. Le poți bifa de mai multe ori pe zi.",
|
||||
"positive": "Positiv",
|
||||
"negative": "Negativ",
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
"newChecklistItem": "Obiect nou în listă",
|
||||
"expandChecklist": "Extinde Lista",
|
||||
"collapseChecklist": "Pliază Checklist-ul",
|
||||
"text": "Title",
|
||||
"text": "Titlu",
|
||||
"extraNotes": "Alte note",
|
||||
"notes": "Notițe",
|
||||
"direction/Actions": "Direcție/Acțiuni",
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
"taskAliasPopoverWarning": "ATENȚIE: Schimbarea acestei valor iva schimba orice integrare a unei partiții terțe care se bazează pe acest alias sarcină.",
|
||||
"difficulty": "Dificultate",
|
||||
"difficultyHelp": "Dificultatea descrie cât de solicitantă este completarea unui Obicei, a unei Cotidiene sau a unui lucru De-Făcut. Cu cât dificultatea este mai înaltă, cu atât recompensele de completare a sarcinii vor fi mai mari, dar de asemenea vor determina deteriorare mai mare atunci când o Cotidiană este ratată sau un Obicei negativ este apăsat.",
|
||||
"trivial": "Trivial",
|
||||
"trivial": "Banal",
|
||||
"easy": "Ușor",
|
||||
"medium": "Mediu",
|
||||
"hard": "Greu",
|
||||
|
|
@ -52,20 +52,20 @@
|
|||
"daily": "Activitate Zilnică",
|
||||
"dailies": "Cotidiene",
|
||||
"newDaily": "Cotidiană nouă",
|
||||
"newDailyBulk": "New Dailies (one per line)",
|
||||
"newDailyBulk": "O nouă activitate zilnică (câte una pe fiecare linie)",
|
||||
"dailysDesc": "Cotidienele se repetă regulat. Alege-ți programul care funcționează cel mai bine pentru tine!",
|
||||
"streakCounter": "Contor șir",
|
||||
"repeat": "Repetă",
|
||||
"repeats": "Se repetă",
|
||||
"repeatEvery": "Repeat Every",
|
||||
"repeatEvery": "Repetă la fiecare",
|
||||
"repeatOn": "Se repetă pe",
|
||||
"repeatHelpTitle": "How often should this task be repeated?",
|
||||
"dailyRepeatHelpContent": "This task will be due every X days. You can set that value below.",
|
||||
"weeklyRepeatHelpContent": "This task will be due on the highlighted days below. Click on a day to activate/deactivate it.",
|
||||
"repeatDays": "Every X Days",
|
||||
"repeatWeek": "On Certain Days of the Week",
|
||||
"repeatHelpTitle": "Cât de des ar trebui să se repete această sarcină?",
|
||||
"dailyRepeatHelpContent": "Această sarcină se va efectua la fiecare X zile. Poți seta această valoare mai jos.",
|
||||
"weeklyRepeatHelpContent": "Această sarcină se va efectua în zilele evidențiate mai jos. Faceți clic pe o zi pentru a o activa/dezactiva.",
|
||||
"repeatDays": "La fiecare X Zile",
|
||||
"repeatWeek": "În anumite zile ale săptămânii",
|
||||
"day": "Day",
|
||||
"days": "Days",
|
||||
"days": "Zile",
|
||||
"restoreStreak": "Ajustează Șirul",
|
||||
"resetStreak": "Resetează Șirul",
|
||||
"todo": "De-Făcut",
|
||||
|
|
@ -75,23 +75,23 @@
|
|||
"todosDesc": "Lucrurile De-Făcut trebuie completate o singură dată. Adaugă o bife acestora pentru a le crește valoarea.",
|
||||
"dueDate": "Dată limită",
|
||||
"remaining": "Active",
|
||||
"complete": "Done",
|
||||
"complete": "Terminat",
|
||||
"complete2": "Complet",
|
||||
"dated": "Dated",
|
||||
"dated": "Datat",
|
||||
"today": "Astăzi",
|
||||
"dueIn": "Termen limită <%= dueIn %>",
|
||||
"due": "Scadente",
|
||||
"notDue": "Not Due",
|
||||
"notDue": "Realizate",
|
||||
"grey": "Gri",
|
||||
"score": "Score",
|
||||
"reward": "Recompensă",
|
||||
"rewards": "Recompense",
|
||||
"rewardsDesc": "Recompensele sunt o modalitate grozavă de a utiliza Habitica și a-ți completa sarcinile. Încearcă să adaugi câteva astăzi!",
|
||||
"ingamerewards": "Equipment & Skills",
|
||||
"ingamerewards": "Echipament & Abilități",
|
||||
"gold": "Aur",
|
||||
"silver": "Argint (100 Arginți = 1 Aur)",
|
||||
"newReward": "Răsplată nouă",
|
||||
"newRewardBulk": "New Rewards (one per line)",
|
||||
"newRewardBulk": "Recompense noi (una pe linie)",
|
||||
"price": "Preț",
|
||||
"tags": "Etichete",
|
||||
"editTags": "Modifică",
|
||||
|
|
@ -102,13 +102,13 @@
|
|||
"editTags2": "Editează Etichetele",
|
||||
"toRequired": "Trebuie să oferi o caracteristică ”to”",
|
||||
"startDate": "Start Date",
|
||||
"startDateHelpTitle": "When should this task start?",
|
||||
"startDateHelp": "Set the date for which this task takes effect. Will not be due on earlier days.",
|
||||
"startDateHelpTitle": "Când ar trebui să înceapă această sarcină?",
|
||||
"startDateHelp": "Setați data pentru care această sarcină are efect. Nu va fi scadent în zilele anterioare.",
|
||||
"streaks": "Realizări legate de Șir",
|
||||
"streakName": "<%= count %> Realizări legate de Șir",
|
||||
"streakText": "A îndeplinit <%= count %> șiruri a câte 21 de zile în Cotidiene",
|
||||
"streakSingular": "Înșiruitor",
|
||||
"streakSingularText": "A îndeplinit 21 de zile în șir o Cotidiană",
|
||||
"streakSingularText": "A îndeplinit 21 de zile în șir o Cotidiană",
|
||||
"perfectName": "<%= count %> Zile Perfecte",
|
||||
"perfectText": "A completat toate Cotidienele în <%= count %> zile. Cu această realizare primești +nivel/2 sporuri pentru toate atributele în ziua următoare. Nivelele mai mari de 100 nu au niciun spor suplimentar.",
|
||||
"perfectSingular": "Zi perfectă",
|
||||
|
|
@ -125,25 +125,25 @@
|
|||
"streakCoins": "Bonus de realizare în șir!",
|
||||
"taskToTop": "Mergi sus",
|
||||
"taskToBottom": "Mergi jos",
|
||||
"emptyTask": "Enter the task's title first.",
|
||||
"dailiesRestingInInn": "You're Resting in the Inn! Your Dailies will NOT hurt you tonight, but they WILL still refresh every day. If you're in a quest, you won't deal damage/collect items until you check out of the Inn, but you can still be injured by a Boss if your Party mates skip their own Dailies.",
|
||||
"habitHelp1": "Good Habits are things that you do often. They award Gold and Experience every time you click the <%= plusIcon %>.",
|
||||
"habitHelp2": "Bad Habits are things you want to avoid doing. They remove Health every time you click the <%= minusIcon %>.",
|
||||
"habitHelp3": "For inspiration, check out these <a href='http://habitica.fandom.com/wiki/Sample_Habits' target='_blank'>sample Habits</a>!",
|
||||
"emptyTask": "Introduceți mai întâi titlul sarcinii.",
|
||||
"dailiesRestingInInn": "Te odihnești în han! Cotidienele tale NU te vor răni în această seară, dar ele SE VOR reînnoi în fiecare zi. Dacă ești într-o aventură, nu vei suferi daune/colecta obiecte până nu pleci de la Han, dar poți fi în continuare rănit de un Căpcăun dacă membrii Echipei tale sar peste propriile Cotidiene.",
|
||||
"habitHelp1": "Obiceiuri Bune sunt lucruri pe care le faci des. Ele acordă Aur și Experiență de fiecare dată când faceți clic pe <%= plusIcon %>.",
|
||||
"habitHelp2": "Obiceiurile Rele sunt lucruri pe care doriți să le evitați. Acestea elimină Sănătate de fiecare dată când faceți clic pe <%= minusIcon %>.",
|
||||
"habitHelp3": "Pentru inspirație, consultați aceste <a href='http://habitica.fandom.com/wiki/Sample_Habits' target='_blank'>exemple de Obiceiuri</a>!",
|
||||
"newbieGuild": "Ai alte întrebări? Întreabă în <%= linkStart %> Habitica Help Guild<%= linkEnd %>!",
|
||||
"dailyHelp1": "Dailies repeat <%= emphasisStart %>every day<%= emphasisEnd %> that they are active. Click the <%= pencilIcon %> to change the days a Daily is active.",
|
||||
"dailyHelp2": "If you don't complete active Dailies, you lose Health when your day rolls over.",
|
||||
"dailyHelp3": "Dailies turn <%= emphasisStart %>redder<%= emphasisEnd %> when you miss them, and <%= emphasisStart %>bluer<%= emphasisEnd %> when you complete them. The redder the Daily, the more it will reward you... or hurt you.",
|
||||
"dailyHelp4": "To change when your day rolls over, go to <%= linkStart %> Settings > Site<%= linkEnd %> > Custom Day Start.",
|
||||
"dailyHelp5": "For inspiration, check out these <a href='http://habitica.fandom.com/wiki/Sample_Dailies' target='_blank'>sample Dailies</a>!",
|
||||
"toDoHelp1": "To-Dos start yellow, and get redder (more valuable) the longer it takes to complete them.",
|
||||
"toDoHelp2": "To-Dos never hurt you! They only award Gold and Experience.",
|
||||
"toDoHelp3": "Breaking a To-Do down into a checklist of smaller items will make it less scary, and will increase your points!",
|
||||
"toDoHelp4": "For inspiration, check out these <a href='http://habitica.fandom.com/wiki/Sample_To-Dos' target='_blank'>sample To-Dos</a>!",
|
||||
"rewardHelp1": "The Equipment you buy for your avatar is stored in <%= linkStart %>Inventory > Equipment<%= linkEnd %>.",
|
||||
"dailyHelp1": "Zilnicele repetă <%= emphasisStart %> în fiecare zi<%= emphasisEnd %> că sunt active. Faceți clic pe <%= pencilIcon %> pentru a schimba zilele în care sunt activate Zilnicele.",
|
||||
"dailyHelp2": "Dacă nu completați Zilnicele active, pierdeți Sănătate atunci când ziua ta se va termina.",
|
||||
"dailyHelp3": "Cotidienele devin <%= emphasisStart %>mai roși<%= emphasisEnd %> când le lipsești și <%= emphasisStart %>mai albastre<%= emphasisEnd %> când le completezi. Cu cât este mai roșu Cotidianul, cu atât te va răsplăti mai mult ... sau te va răni.",
|
||||
"dailyHelp4": "Pentru a vă schimba când ziua dvs. se va trece, mergeți la <%= linkStart %> Setări > Site<%= linkEnd %> > Când Începe Ziua.",
|
||||
"dailyHelp5": "Pentru inspirație, verificați acestea <a href='http://habitica.fandom.com/wiki/Sample_Dailies' target='_blank'>exemple de Cotidiene (sau Zilnice)</a>!",
|
||||
"toDoHelp1": "Sarcinile De-Făcut încep galbene și devine mai roșu (mai valoroase) cu cât durează mai mult pentru a le completa.",
|
||||
"toDoHelp2": "Sarcinile De-Făcut nu te rănesc niciodată! Ele acordă doar Aur și Experiență.",
|
||||
"toDoHelp3": "Spargerea unei sarcini De-Făcut într-o listă cu articole mai mici o va face mai puțin înfricoșător și vă va crește punctele!",
|
||||
"toDoHelp4": "Pentru inspirație, verificați acestea <a href='http://habitica.fandom.com/wiki/Sample_To-Dos' target='_blank'>exemple de Sarcini De-Făcut</a>!",
|
||||
"rewardHelp1": "Echipamentul pe care îl cumperi pentru avatarul tău este depozitat în <%= linkStart %>Inventar > Echipament<%= linkEnd %>.",
|
||||
"rewardHelp2": "Echipamentul îți influențează Statisticile (<%= linkStart %>Avatar > Stats<%= linkEnd %>).",
|
||||
"rewardHelp3": "Special equipment will appear here during World Events.",
|
||||
"rewardHelp4": "Don't be afraid to set custom Rewards! Check out <a href='http://habitica.fandom.com/wiki/Sample_Custom_Rewards' target='_blank'>some samples here</a>.",
|
||||
"rewardHelp3": "Echipamente speciale vor apărea aici în timpul Evenimentelor Mondiale.",
|
||||
"rewardHelp4": "Nu vă fie teamă să setați Recompense personalizate! Verifică <a href='http://habitica.fandom.com/wiki/Sample_Custom_Rewards' target='_blank'>câteva exemple aici</a>.",
|
||||
"clickForHelp": "Click for help",
|
||||
"taskAliasAlreadyUsed": "Aliasul sarcinii este deja utilizat pentru o alta.",
|
||||
"taskNotFound": "Sarcina nu a putut fi găsită.",
|
||||
|
|
@ -173,7 +173,7 @@
|
|||
"habitCounterDown": "Counter Negativ (Se resetează <%= frequency %>)",
|
||||
"taskRequiresApproval": "Această sarcină trebuie aprobată înainte să o poți completa. Aprobarea a fost deja solicitată",
|
||||
"taskApprovalHasBeenRequested": "Aprobarea a fost solicitată",
|
||||
"taskApprovalWasNotRequested": "Numai o sarcină așteaptă aprobare și poate fi marcată ca necesitând treabă suplimentară",
|
||||
"taskApprovalWasNotRequested": "Nu a fost solicitată aprobarea pentru această sarcină.",
|
||||
"approvals": "Aprobări",
|
||||
"approvalRequired": "Necesită Aprobare",
|
||||
"repeatZero": "Cotidenele nu au niciodată termen limită",
|
||||
|
|
|
|||
|
|
@ -504,5 +504,7 @@
|
|||
"backgroundHallOfHeroesText": "Зал героев",
|
||||
"backgrounds022020": "Набор 69: Выпущен в феврале 2020",
|
||||
"backgroundElegantBallroomText": "Элегантный бальный зал",
|
||||
"backgrounds032020": "Набор 70: Выпущен в марте 2020"
|
||||
"backgrounds032020": "Набор 70: Выпущен в марте 2020",
|
||||
"backgroundSucculentGardenText": "Суккулентный сад",
|
||||
"backgroundButterflyGardenText": "Сад бабочек"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2038,5 +2038,7 @@
|
|||
"weaponArmoireLivelyMatchText": "Искрящиеся спичка",
|
||||
"shieldArmoireBaseballGloveText": "Бейсбольная перчатка",
|
||||
"headArmoireBaseballCapText": "Бейсболка",
|
||||
"weaponArmoireBaseballBatText": "Бейсбольная бита"
|
||||
"weaponArmoireBaseballBatText": "Бейсбольная бита",
|
||||
"armorSpecialSpring2020RogueText": "Ультрамариновые доспехи",
|
||||
"weaponSpecialSpring2020MageText": "Капли дождя"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,40 +90,40 @@
|
|||
"grandMalkinSet": "Великий Малкин (Маг)",
|
||||
"cleverDogSet": "Мудрый Пёс (Вор)",
|
||||
"braveMouseSet": "Храбрая мышь (Воин)",
|
||||
"summer2016SharkWarriorSet": "Воин-акула (Воин)",
|
||||
"summer2016DolphinMageSet": "Маг-дельфин (Маг)",
|
||||
"summer2016SeahorseHealerSet": "Целитель - морской конёк (Целитель)",
|
||||
"summer2016EelSet": "Разбойник-угорь (Разбойник)",
|
||||
"summer2016SharkWarriorSet": "Акула (Воин)",
|
||||
"summer2016DolphinMageSet": "Дельфин (Маг)",
|
||||
"summer2016SeahorseHealerSet": "Морской конёк (Целитель)",
|
||||
"summer2016EelSet": "Угорь (Разбойник)",
|
||||
"fall2016SwampThingSet": "Болотная тварь (Воин)",
|
||||
"fall2016WickedSorcererSet": "Злой колдун (Маг)",
|
||||
"fall2016GorgonHealerSet": "Горгона-целитель (Целитель)",
|
||||
"fall2016BlackWidowSet": "Черная вдова-разбойница (Разбойник)",
|
||||
"fall2016GorgonHealerSet": "Горгона (Целитель)",
|
||||
"fall2016BlackWidowSet": "Черная вдова (Разбойник)",
|
||||
"winter2017IceHockeySet": "Хоккейная клюшка (воин)",
|
||||
"winter2017WinterWolfSet": "Зимний волк (Маг)",
|
||||
"winter2017SugarPlumSet": "Сахарная слива (Целитель)",
|
||||
"winter2017FrostyRogueSet": "Морозный разбойник (Разбойник)",
|
||||
"spring2017FelineWarriorSet": "Кошачий воин (воин)",
|
||||
"spring2017FelineWarriorSet": "Кошачий (воин)",
|
||||
"spring2017CanineConjurorSet": "Собачий заклинатель(маг)",
|
||||
"spring2017FloralMouseSet": "Цветочная мышь (Целитель)",
|
||||
"spring2017SneakyBunnySet": "Скрытный кролик (Разбойник)",
|
||||
"summer2017SandcastleWarriorSet": "Воин песчаного замка (Воин)",
|
||||
"summer2017WhirlpoolMageSet": "Маг водоворота (Маг)",
|
||||
"summer2017SandcastleWarriorSet": "Песчаный замок (Воин)",
|
||||
"summer2017WhirlpoolMageSet": "Водоворот (Маг)",
|
||||
"summer2017SeashellSeahealerSet": "Целитель морской ракушки (Целитель)",
|
||||
"summer2017SeaDragonSet": "Морской дракон (Разбойник)",
|
||||
"fall2017HabitoweenSet": "Привычкоуинский воин",
|
||||
"fall2017MasqueradeSet": "Маскарадный маг (Маг)",
|
||||
"fall2017HauntedHouseSet": "Целитель Проклятого Дома (Целитель)",
|
||||
"fall2017HabitoweenSet": "Привычкоуин (Воин)",
|
||||
"fall2017MasqueradeSet": "Маскарад (Маг)",
|
||||
"fall2017HauntedHouseSet": "Проклятый Дом (Целитель)",
|
||||
"fall2017TrickOrTreatSet": "Кошелек или жизнь (Разбойник)",
|
||||
"winter2018ConfettiSet": "Маг Конфетти",
|
||||
"winter2018GiftWrappedSet": "Подарочно-упакованный воин",
|
||||
"winter2018MistletoeSet": "Омела Целитель",
|
||||
"winter2018ReindeerSet": "Оленеразбойник",
|
||||
"spring2018SunriseWarriorSet": "Воин восходящего солнца (Воин)",
|
||||
"spring2018TulipMageSet": "Тюльпанный маг (Маг)",
|
||||
"spring2018GarnetHealerSet": "Гранатово-красный целитель (Целитель)",
|
||||
"spring2018DucklingRogueSet": "Гадкий утёнок (Разбойник)",
|
||||
"summer2018BettaFishWarriorSet": "Воин бойцовской рыбы (Воин)",
|
||||
"summer2018LionfishMageSet": "Маг-крылатка (Маг)",
|
||||
"winter2018ConfettiSet": "Конфетти (Маг)",
|
||||
"winter2018GiftWrappedSet": "Подарочно-упакованный (Воин)",
|
||||
"winter2018MistletoeSet": "Омела (Целитель)",
|
||||
"winter2018ReindeerSet": "Олень (Разбойник)",
|
||||
"spring2018SunriseWarriorSet": "Утренняя заря (Воин)",
|
||||
"spring2018TulipMageSet": "Тюльпан (Маг)",
|
||||
"spring2018GarnetHealerSet": "Гранат (Целитель)",
|
||||
"spring2018DucklingRogueSet": "Утёнок (Разбойник)",
|
||||
"summer2018BettaFishWarriorSet": "Бойцовая рыбка петушок (Воин)",
|
||||
"summer2018LionfishMageSet": "Крылатка (Маг)",
|
||||
"summer2018MerfolkMonarchSet": "Амфибия (Целитель)",
|
||||
"summer2018FisherRogueSet": "Рыбак-разбойник (Разбойник)",
|
||||
"fall2018MinotaurWarriorSet": "Минотавр (Воин)",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "инкубационный эликсир",
|
||||
"noHatchingPotions": "У вас нет инкубационных эликсиров.",
|
||||
"inventoryText": "Выберите яйцо, чтобы посмотреть эликсиры, которые можно использовать с ним — они подсветятся зеленым, затем выберите один из этих эликсиров, чтобы вырастить питомца. Если ни один эликсир не будет выделен подсветкой, щелкните яйцо снова, чтобы снять выбор, а затем выберите сначала эликсир, чтобы выделить подсветкой яйца, которые можно использовать с ним. Ненужные вам предметы можно продать Торговцу Александру.",
|
||||
"haveHatchablePet": "У вас имеется <%= potion %> инкубационный эликсир и <%= egg %> яйцо для выращивания этого питомца! <b>Нажмите</b> на значек лапы чтобы вырастить его.",
|
||||
"haveHatchablePet": "У вас имеется <%= potion %> инкубационный эликсир и <%= egg %> яйцо для выращивания этого питомца! <b>Нажмите</b> чтобы вырастить его!",
|
||||
"quickInventory": "Инвентаризация запасов",
|
||||
"foodText": "еда",
|
||||
"food": "Корм и сёдла",
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundButterflyGardenText": "蝴蝶花园",
|
||||
"backgroundAmongGiantFlowersNotes": "玩弄在巨花之中。",
|
||||
"backgroundAmongGiantFlowersText": "在巨花之中",
|
||||
"backgrounds032020": "第70组:2020年3月推出"
|
||||
"backgrounds032020": "第70组:2020年3月推出",
|
||||
"backgroundRainyBarnyardNotes": "漫步在多雨的农家庭院。",
|
||||
"backgroundRainyBarnyardText": "多雨的农家庭院",
|
||||
"backgroundHeatherFieldNotes": "享受石南属田的香气。",
|
||||
"backgroundHeatherFieldText": "石南属田",
|
||||
"backgroundAnimalCloudsNotes": "发挥你的想象力,找动物形的云朵。",
|
||||
"backgroundAnimalCloudsText": "动物型的云朵",
|
||||
"backgrounds042020": "第71组:2020年4月推出"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@
|
|||
"weaponArmoireMiningPickaxNotes": "从你的任务中挖取最大量的金币!增加<%= per %>点感知。魔法衣橱:采矿者套装(3/3)。",
|
||||
"weaponArmoireBasicLongbowText": "基础长弓",
|
||||
"weaponArmoireBasicLongbowNotes": "一把有用的传下来的弓。增加<%= str %>点力量。魔法衣橱:基础射手套装(1/3)。",
|
||||
"weaponArmoireHabiticanDiplomaText": "Habitica村民毕业证书",
|
||||
"weaponArmoireHabiticanDiplomaText": "Habitica居民毕业证书",
|
||||
"weaponArmoireHabiticanDiplomaNotes": "重大成就的一个证书 -- 干的好!增加<%= int %>点智力。魔法衣橱:毕业生套装(1/3)。",
|
||||
"weaponArmoireSandySpadeText": "沙铲",
|
||||
"weaponArmoireSandySpadeNotes": "挖掘工具,也能用沙子攻击敌方怪兽的眼睛。增加<%= str %>点力量。魔法衣橱:海滨套装(1/3)。",
|
||||
|
|
@ -675,7 +675,7 @@
|
|||
"armorMystery201604Text": "叶子护甲",
|
||||
"armorMystery201604Notes": "你的身周喷发着许多小但是可怕的叶子。没有属性加成。2016年4月订阅者物品。",
|
||||
"armorMystery201605Text": "吟游诗人制服",
|
||||
"armorMystery201605Notes": "不像传统的吟游诗人参加冒险派对,参加Habitic村民游行乐队的吟游诗人因宏大的游行而不是因地牢突击被众所周知。没有属性加成。2016年5月订阅者物品。",
|
||||
"armorMystery201605Notes": "不像传统的吟游诗人参加冒险派对,参加Habitica居民游行乐队的吟游诗人因宏大的游行而不是因地牢突击被众所周知。没有属性加成。2016年5月订阅者物品。",
|
||||
"armorMystery201606Text": "海豹的尾巴",
|
||||
"armorMystery201606Notes": "这条有力的尾巴闪闪发光,就像大海的泡沫撞碎在岸上。没有属性加成。2016年6月订阅者物品。",
|
||||
"armorMystery201607Text": "海底盗贼护甲",
|
||||
|
|
@ -2081,5 +2081,13 @@
|
|||
"armorSpecialSpring2020MageText": "旋风长袍",
|
||||
"armorSpecialSpring2020HealerText": "防护的花瓣",
|
||||
"headAccessoryMystery202004Text": "强大的君主斑蝶触角",
|
||||
"backMystery202004Text": "强大的君主斑蝶翅膀"
|
||||
"backMystery202004Text": "强大的君主斑蝶翅膀",
|
||||
"headAccessoryMystery202004Notes": "如果花朵的香味飘过,它们只会抽搐一下--用它们找到一个漂亮的花园!没有属性加成。2020年4月订阅者物品。",
|
||||
"backMystery202004Notes": "用这些美丽的翅膀快速地飞向最近绚丽的草地,或在整个大陆上迁移!没有属性加成。2020年4月订阅者物品。",
|
||||
"shieldArmoireHobbyHorseNotes": "骑着你的俊美的爱好马迈向你的奖励!增加感知、体质各<%= attrs %>点。魔法衣橱:纸骑士套装(2/3)。",
|
||||
"shieldArmoireHobbyHorseText": "爱好马",
|
||||
"armorArmoireBoxArmorNotes": "盒装甲:它适合你,所以你可以坐在... 嗯,所以你可以穿上战斗吧,像勇敢的骑士一样!增加感知、体质各<%= attrs %>点。魔法衣橱:纸骑士套装(3/3)。 ",
|
||||
"armorArmoireBoxArmorText": "盒装甲",
|
||||
"weaponArmoirePaperCutterNotes": "这可能看起来并不可怕,但你有没有被纸割伤过吗?增加<%= str %>点力量。魔法衣橱:纸骑士套装(1/3)。",
|
||||
"weaponArmoirePaperCutterText": "裁纸器"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@
|
|||
"guildSummaryPlaceholder": "写一个简短的描述将你的公会展示给其他Habitica居民。你的公会的主要目的是什么?为什么大家要加入呢?尝试在概要中包含有用的关键字,以便Habitica居民在搜索时可以轻松找到它!",
|
||||
"groupDescription": "详细描述",
|
||||
"guildDescriptionPlaceholder": "在这里输入公会会员应该了解公会的所有内容。有用的提示,有帮助的链接和激励人心的标语都在这里!",
|
||||
"markdownFormattingHelp": "[Markdown语法帮助](http://habitica.fandom.com/wiki/Markdown_Cheat_Sheet)",
|
||||
"markdownFormattingHelp": "[Markdown语法帮助](http://habitica.fandom.com/zh/wiki/Markdown格式帮助)",
|
||||
"partyDescriptionPlaceholder": "这是我们队伍的描述。它描述了我们在这个队伍里做什么。如果你想了解更多关于我们在这个队伍所做的事,请阅读说明。派对继续。",
|
||||
"guildGemCostInfo": "花费宝石促进高质量的公会,宝石会转移到您的公会的银行。",
|
||||
"noGuildsTitle": "你不是任何公会的成员。",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "孵化药水",
|
||||
"noHatchingPotions": "你没有任何孵化药水。",
|
||||
"inventoryText": "点选一颗蛋后,可使用的药水会亮起绿色的背景,然后点击药水来孵化出宠物。如果没有药水亮起绿色背景,再点击一次蛋来取消点选它,然后先点击药水看看可使用的宠物蛋,它们同样会亮起绿色背景。你也可以在商人Alexander那里卖掉不想要的物品。",
|
||||
"haveHatchablePet": "你有一个<%= potion %>孵化药水和<%= egg %>蛋去孵化这只宠物!<b>点击</b>爪子印孵化它。",
|
||||
"haveHatchablePet": "你有一个<%= potion %>孵化药水和<%= egg %>蛋去孵化这只宠物!<b>点击</b>印孵化它!",
|
||||
"quickInventory": "物品栏",
|
||||
"foodText": "食物",
|
||||
"food": "宠物食品和鞍",
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@
|
|||
"questBewilderBossRageDescription": "当这个量槽被填满,迷失怪就会在Habitica释放他的欺骗攻击!",
|
||||
"questBewilderDropBumblebeePet": "魔法蜜蜂(宠物)",
|
||||
"questBewilderDropBumblebeeMount": "魔法蜜蜂(坐骑)",
|
||||
"questBewilderBossRageMarket": "`迷失怪运用了 欺骗打击!`\n\n噢不!尽管我们努力了,我们迷失怪迷人的幻觉还是让我们分心,忘掉了一些每日任务!伴随着咯咯的叫喊声,华丽的鸟儿扇动着翅膀,扇起了一大团薄雾围绕着商人Alex。当雾消失,他已经着魔了!“有一些免费的样品!”他兴高采烈地喊着,开始丢出爆炸的蛋和药水朝向逃跑的Habitica村民。诚然,不是最优惠的销售。\n\n快!让我们保持关注我们的每日任务在它占据其他人之前打败这个怪物。",
|
||||
"questBewilderBossRageMarket": "`迷失怪运用了 欺骗打击!`\n\n噢不!尽管我们努力了,我们迷失怪迷人的幻觉还是让我们分心,忘掉了一些每日任务!伴随着咯咯的叫喊声,华丽的鸟儿扇动着翅膀,扇起了一大团薄雾围绕着商人Alex。当雾消失,他已经着魔了!“有一些免费的样品!”他兴高采烈地喊着,开始丢出爆炸的蛋和药水朝向逃跑的Habitica居民。诚然,不是最优惠的销售。\n\n快!让我们保持关注我们的每日任务在它占据其他人之前打败这个怪物。",
|
||||
"questBewilderBossRageStables": "`迷失怪运用了 欺骗打击!` \n \n啊!!!迷失怪再次让我们目眩神迷以至于忽视了我们的每日任务,现在它已经攻击了驯兽师Matt!一阵烟雾后,Matt竟然变成了可怕的飞行怪兽,所有的宠物和坐骑都在兽栏中痛苦地嚎叫。快!专注于你的每日任务来打败这个卑鄙的怪物!",
|
||||
"questBewilderBossRageBailey": "`迷失怪运用了 欺骗打击!`\n\n小心!在报导新闻中,公告员Bailey已经被迷失怪占据了!她放出了一个恶魔,她随意的大叫声升上了天空。现在我们该怎么办?\n\n不要放弃...我们就快要击败这个讨厌的大鸟了,一劳永逸!",
|
||||
"questFalconText": "掠食明天之鸟",
|
||||
|
|
|
|||
|
|
@ -513,5 +513,12 @@
|
|||
"backgroundButterflyGardenText": "蝴蝶花園",
|
||||
"backgroundAmongGiantFlowersNotes": "玩弄在巨花之中。",
|
||||
"backgroundAmongGiantFlowersText": "在巨花之中",
|
||||
"backgrounds032020": "第70組:2020年3月推出"
|
||||
"backgrounds032020": "第70組:2020年3月推出",
|
||||
"backgroundRainyBarnyardNotes": "漫步在多雨的农家庭院。",
|
||||
"backgroundRainyBarnyardText": "多雨的农家庭院",
|
||||
"backgroundHeatherFieldNotes": "享受石南屬田的香氣。",
|
||||
"backgroundHeatherFieldText": "石南屬田",
|
||||
"backgroundAnimalCloudsNotes": "發揮你的想像力,找動物形的雲朵。",
|
||||
"backgroundAnimalCloudsText": "動物型的雲朵",
|
||||
"backgrounds042020": "第71組:2020年4月推出"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2079,5 +2079,15 @@
|
|||
"weaponSpecialSpring2020WarriorNotes": "在戰鬥時或逃跑時,這支翅膀會為你服務!增加<%= str %>點力量。 2020年春季限定版裝備。",
|
||||
"weaponSpecialSpring2020WarriorText": "鋒利的翅膀",
|
||||
"weaponSpecialSpring2020RogueNotes": "你會擊打得這麼快,任務會看起來更藍!增加<%= str %>點力量。 2020年春季限定版裝備。",
|
||||
"weaponSpecialSpring2020RogueText": "青金石刀"
|
||||
"weaponSpecialSpring2020RogueText": "青金石刀",
|
||||
"headAccessoryMystery202004Notes": "如果花朵的香味飄過,它們只會抽搐一下--用它們找到一個漂亮的花園!沒有屬性加成。 2020年4月訂閱者物品。",
|
||||
"headAccessoryMystery202004Text": "強大的君主斑蝶觸角",
|
||||
"backMystery202004Notes": "用這些美麗的翅膀快速地飛向最近絢麗的草地,或在整個大陸上遷移!沒有屬性加成。 2020年4月訂閱者物品。",
|
||||
"backMystery202004Text": "強大的君主斑蝶翅膀",
|
||||
"shieldArmoireHobbyHorseNotes": "騎著你的俊美的愛好馬邁向你的獎勵!增加感知、體質各<%= attrs %>點。魔法衣櫥:紙騎士套裝(2/3)。",
|
||||
"shieldArmoireHobbyHorseText": "愛好馬",
|
||||
"armorArmoireBoxArmorNotes": "盒裝甲:它適合你,所以你可以坐在... 嗯,所以你可以穿上戰鬥吧,像勇敢的騎士一樣!增加感知、體質各<%= attrs %>點。魔法衣櫥:紙騎士套裝(3/3)。 ",
|
||||
"armorArmoireBoxArmorText": "盒裝甲",
|
||||
"weaponArmoirePaperCutterNotes": "這可能看起來並不可怕,但你有沒有被紙割傷過嗎?增加<%= str %>點力量。魔法衣櫥:紙騎士套裝(1/3)。",
|
||||
"weaponArmoirePaperCutterText": "裁紙器"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"hatchingPotion": "孵化藥水",
|
||||
"noHatchingPotions": "你沒有任何孵化藥水。",
|
||||
"inventoryText": "點選一顆蛋後,可使用的藥水會亮起綠色的背景,然後點擊藥水,來孵化出寵物。如果沒有藥水亮起綠色背景,再點擊一次蛋,可以取消點選。然後先點擊藥水,看看可使用的寵物蛋,它們同樣會亮起綠色背景。你也可以在商人Alexander那裡,賣掉不想要的物品。",
|
||||
"haveHatchablePet": "你擁有一瓶<%= potion %>孵化藥水和一顆<%= egg %>蛋,可以孵化出這隻寵物!<b>點擊</b>爪印來孵化牠。",
|
||||
"haveHatchablePet": "你有一個<%= potion %>孵化藥水和<%= egg %>蛋去孵化這隻寵物! <b>點擊</b>印孵化它!",
|
||||
"quickInventory": "快捷背包",
|
||||
"foodText": "食物",
|
||||
"food": "寵物食品和鞍",
|
||||
|
|
|
|||
|
|
@ -247,5 +247,6 @@
|
|||
"cancelYourSubscription": "取消您的訂閱?",
|
||||
"cancelSubAlternatives": "如果您遇到技術問題或Habitica不能滿足您的要求,請考慮<a href='mailto:admin@habitica.com'>與我們聯繫</a>。我們希望幫助您從Habitica獲得最大的收益。",
|
||||
"mysterySet202003": "倒刺鬥士套裝",
|
||||
"giftASubscription": "贈送訂閱"
|
||||
"giftASubscription": "贈送訂閱",
|
||||
"mysterySet202004": "強大的君主斑蝶套裝"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const CHAT_FLAG_FROM_SHADOW_MUTE = 10;
|
|||
export const SUPPORTED_SOCIAL_NETWORKS = [
|
||||
{ key: 'facebook', name: 'Facebook' },
|
||||
{ key: 'google', name: 'Google' },
|
||||
{ key: 'apple', name: 'Apple' },
|
||||
];
|
||||
|
||||
export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when using pagination
|
||||
|
|
@ -27,6 +28,7 @@ export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when u
|
|||
export const PARTY_LIMIT_MEMBERS = 30;
|
||||
|
||||
export const MINIMUM_PASSWORD_LENGTH = 8;
|
||||
|
||||
export const TRANSFORMATION_DEBUFFS_LIST = {
|
||||
snowball: 'salt',
|
||||
spookySparkles: 'opaquePotion',
|
||||
|
|
|
|||
|
|
@ -146,6 +146,41 @@ api.loginSocial = {
|
|||
},
|
||||
};
|
||||
|
||||
// Called by apple for web authentication.
|
||||
api.redirectApple = {
|
||||
method: 'POST',
|
||||
middlewares: [authWithHeaders({
|
||||
optional: true,
|
||||
})],
|
||||
url: '/user/auth/apple',
|
||||
async handler (req, res) {
|
||||
if (req.body.id_token) {
|
||||
req.body.network = 'apple';
|
||||
return loginSocial(req, res);
|
||||
}
|
||||
let url = `/static/apple-redirect?code=${req.body.code}`;
|
||||
if (req.body.user) {
|
||||
const { name } = JSON.parse(req.body.user);
|
||||
url += `&name=${name.firstName} ${name.lastName}`;
|
||||
}
|
||||
return res.redirect(303, url);
|
||||
},
|
||||
};
|
||||
|
||||
// Called as a callback by Apple. Internal route
|
||||
// Can be passed `code` and `name` as query parameters
|
||||
api.loginApple = {
|
||||
method: 'GET',
|
||||
middlewares: [authWithHeaders({
|
||||
optional: true,
|
||||
})],
|
||||
url: '/user/auth/apple',
|
||||
async handler (req, res) {
|
||||
req.body.network = 'apple';
|
||||
return loginSocial(req, res);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {put} /api/v3/user/auth/update-username Update username
|
||||
* @apiDescription Update and verify the user's username
|
||||
|
|
|
|||
52
website/server/libs/auth/apple.js
Normal file
52
website/server/libs/auth/apple.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import AppleAuth from 'apple-auth';
|
||||
import nconf from 'nconf';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import jwksClient from 'jwks-rsa';
|
||||
import util from 'util';
|
||||
|
||||
const APPLE_PRIVATE_KEY = nconf.get('APPLE_AUTH_PRIVATE_KEY');
|
||||
const APPLE_AUTH_CLIENT_ID = nconf.get('APPLE_AUTH_CLIENT_ID');
|
||||
const APPLE_TEAM_ID = nconf.get('APPLE_TEAM_ID');
|
||||
const APPLE_AUTH_KEY_ID = nconf.get('APPLE_AUTH_KEY_ID');
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
const appleAuth = new AppleAuth(JSON.stringify({
|
||||
client_id: APPLE_AUTH_CLIENT_ID, // eslint-disable-line camelcase
|
||||
team_id: APPLE_TEAM_ID, // eslint-disable-line camelcase
|
||||
key_id: APPLE_AUTH_KEY_ID, // eslint-disable-line camelcase
|
||||
redirect_uri: `${BASE_URL}/api/v4/user/auth/apple`, // eslint-disable-line camelcase
|
||||
scope: 'name email',
|
||||
}), APPLE_PRIVATE_KEY, 'text');
|
||||
|
||||
const APPLE_PUBLIC_KEYS_URL = 'https://appleid.apple.com/auth/keys';
|
||||
|
||||
const appleJwksClient = jwksClient({
|
||||
jwksUri: APPLE_PUBLIC_KEYS_URL,
|
||||
});
|
||||
|
||||
const getAppleSigningKey = util.promisify(appleJwksClient.getSigningKey);
|
||||
|
||||
export async function appleProfile (req) {
|
||||
const code = req.body.code ? req.body.code : req.query.code;
|
||||
const passedToken = req.body.id_token ? req.body.id_token : req.query.id_token;
|
||||
let idToken;
|
||||
|
||||
if (code) {
|
||||
const response = await appleAuth.accessToken(code);
|
||||
idToken = response.id_token;
|
||||
} else if (passedToken) {
|
||||
idToken = passedToken;
|
||||
}
|
||||
|
||||
const decodedToken = jwt.decode(idToken, { complete: true });
|
||||
const signingKey = await getAppleSigningKey(decodedToken.header.kid);
|
||||
const applePublicKey = signingKey.getPublicKey();
|
||||
|
||||
const verifiedPayload = await jwt.verify(idToken, applePublicKey, { algorithms: 'RS256' });
|
||||
|
||||
return {
|
||||
id: verifiedPayload.sub,
|
||||
emails: [{ value: verifiedPayload.email }],
|
||||
name: verifiedPayload.name || req.body.name || req.query.name,
|
||||
};
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import {
|
|||
generateUsername,
|
||||
loginRes,
|
||||
} from './utils';
|
||||
import { appleProfile } from './apple';
|
||||
import { model as User } from '../../models/user';
|
||||
import { model as EmailUnsubscription } from '../../models/emailUnsubscription';
|
||||
import { sendTxn as sendTxnEmail } from '../email';
|
||||
|
|
@ -24,14 +25,21 @@ function _passportProfile (network, accessToken) {
|
|||
|
||||
export async function loginSocial (req, res) { // eslint-disable-line import/prefer-default-export
|
||||
const existingUser = res.locals.user;
|
||||
const accessToken = req.body.authResponse.access_token;
|
||||
const { network } = req.body;
|
||||
|
||||
const isSupportedNetwork = common.constants.SUPPORTED_SOCIAL_NETWORKS
|
||||
.find(supportedNetwork => supportedNetwork.key === network);
|
||||
if (!isSupportedNetwork) throw new BadRequest(res.t('unsupportedNetwork'));
|
||||
|
||||
const profile = await _passportProfile(network, accessToken);
|
||||
let profile = {};
|
||||
if (network === 'apple') {
|
||||
profile = await appleProfile(req);
|
||||
} else {
|
||||
const accessToken = req.body.authResponse.access_token;
|
||||
profile = await _passportProfile(network, accessToken);
|
||||
}
|
||||
|
||||
if (!profile.id) throw new BadRequest(res.t('invalidData'));
|
||||
|
||||
let user = await User.findOne({
|
||||
[`auth.${network}.id`]: profile.id,
|
||||
|
|
@ -80,7 +88,7 @@ export async function loginSocial (req, res) { // eslint-disable-line import/pre
|
|||
user.newUser = true;
|
||||
}
|
||||
|
||||
loginRes(user, req, res);
|
||||
const response = loginRes(user, req, res);
|
||||
|
||||
// Clean previous email preferences
|
||||
if (
|
||||
|
|
@ -114,5 +122,5 @@ export async function loginSocial (req, res) { // eslint-disable-line import/pre
|
|||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import nconf from 'nconf';
|
||||
import shortid from 'short-uuid';
|
||||
import url from 'url';
|
||||
|
||||
import { NotAuthorized } from '../errors';
|
||||
|
||||
|
|
@ -18,6 +19,11 @@ export function loginRes (user, req, res) {
|
|||
{ communityManagerEmail: COMMUNITY_MANAGER_EMAIL, userId: user._id },
|
||||
));
|
||||
}
|
||||
const urlPath = url.parse(req.url).pathname;
|
||||
if (req.headers['x-client'] === 'habitica-android' && urlPath.includes('apple')) {
|
||||
// This is a workaround for android not being able to handle sign in with apple better.
|
||||
return res.redirect(`/?id=${user._id}&key=${user.apiToken}&newUser=${user.newUser || false}`);
|
||||
}
|
||||
|
||||
const responseData = {
|
||||
id: user._id,
|
||||
|
|
@ -25,6 +31,5 @@ export function loginRes (user, req, res) {
|
|||
newUser: user.newUser || false,
|
||||
username: user.auth.local.username,
|
||||
};
|
||||
|
||||
return res.respond(200, responseData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export default new Schema({
|
|||
$type: Schema.Types.Mixed,
|
||||
default: () => ({}),
|
||||
},
|
||||
apple: { $type: Schema.Types.Mixed, default: () => ({}) },
|
||||
local: {
|
||||
email: {
|
||||
$type: String,
|
||||
|
|
|
|||
Loading…
Reference in a new issue