mirror of
https://github.com/HabitRPG/habitica.git
synced 2026-04-21 03:08:29 -05:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 963b4133ec | |||
| 53999a5b80 | |||
| 4510c90e41 | |||
| 9f97a09b8c | |||
| eccc115b73 | |||
| 2b26eb2bd1 | |||
| 8e042cabc4 | |||
| 8abe167848 | |||
| 3414f962e2 | |||
| 1b68e6d4d3 | |||
| 5dd9711413 | |||
| a542277a41 | |||
| cdf8556fd6 | |||
| 3d93390a7a | |||
| 59f9cfa0f4 | |||
| 80d7804f69 | |||
| 4e5efe09a3 | |||
| d42a597672 | |||
| ea17b2e9c7 | |||
| f56708cd88 | |||
| 005d14f6e8 | |||
| c05a96ce6c | |||
| 8fdbfb9dc6 | |||
| 057a642baa | |||
| 6c522157a7 | |||
| ba9a1ab2a9 | |||
| 4767461c4f | |||
| 847c97dc8f | |||
| 215b26acac | |||
| e223e7821a | |||
| 8134fa7c00 | |||
| 84208f612e | |||
| 57e06334c0 | |||
| be695d25b3 | |||
| 77ee83f467 | |||
| 86556e346b | |||
| 2007a872c6 | |||
| a8348038de | |||
| 87bcd69979 | |||
| 8f8e84d0c7 | |||
| 2c18cb00cc | |||
| daa0fd18c0 | |||
| 5c555cbf88 | |||
| 7379c7b230 | |||
| c055537c38 | |||
| 7559feec8e | |||
| 43808696a8 | |||
| 72fb41c7e0 | |||
| 3bf18e09ed | |||
| 407a901883 | |||
| 81a008906b | |||
| 992a978923 | |||
| a8062ad615 | |||
| 781a904583 | |||
| d87946d912 | |||
| 7456ff2def |
@@ -82,7 +82,7 @@ jobs:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
- run: npm run test:sanity
|
||||
|
||||
|
||||
common:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -129,13 +129,13 @@ jobs:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
- run: npm run test:content
|
||||
|
||||
|
||||
api-unit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [21.x]
|
||||
mongodb-version: [4.2]
|
||||
mongodb-version: [7.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -144,11 +144,13 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Start MongoDB ${{ matrix.mongodb-version }} Replica Set
|
||||
uses: supercharge/mongodb-github-action@1.3.0
|
||||
uses: supercharge/mongodb-github-action@1.11.0
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
@@ -158,15 +160,17 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
|
||||
- run: npm run test:api:unit
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
|
||||
api-v3-integration:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [21.x]
|
||||
mongodb-version: [4.2]
|
||||
mongodb-version: [7.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -176,10 +180,11 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Start MongoDB ${{ matrix.mongodb-version }} Replica Set
|
||||
uses: supercharge/mongodb-github-action@1.3.0
|
||||
uses: supercharge/mongodb-github-action@1.11.0
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
@@ -189,15 +194,18 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
|
||||
- run: npm run test:api-v3:integration
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
|
||||
api-v4-integration:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [21.x]
|
||||
mongodb-version: [4.2]
|
||||
mongodb-version: [7.0]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -207,10 +215,11 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Start MongoDB ${{ matrix.mongodb-version }} Replica Set
|
||||
uses: supercharge/mongodb-github-action@1.3.0
|
||||
uses: supercharge/mongodb-github-action@1.11.0
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
@@ -220,6 +229,7 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
|
||||
- run: npm run test:api-v4:integration
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
|
||||
+1
-1
@@ -47,5 +47,5 @@ webpack.webstorm.config
|
||||
|
||||
# mongodb replica set for local dev
|
||||
mongodb-*.tgz
|
||||
/mongodb-data*
|
||||
/mongodb-*
|
||||
/.nyc_output
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@
|
||||
"MAINTENANCE_MODE": "false",
|
||||
"MONGODB_POOL_SIZE": "10",
|
||||
"MONGODB_SOCKET_TIMEOUT": "20000",
|
||||
"NODE_DB_URI": "mongodb://localhost:27017/habitica-dev?replicaSet=rs",
|
||||
"NODE_DB_URI": "mongodb://localhost:27017/habitica-dev?replicaSet=rs&directConnection=true&readPreference=secondary",
|
||||
"NODE_ENV": "development",
|
||||
"PATH": "bin:node_modules/.bin:/usr/local/bin:/usr/bin:/bin",
|
||||
"PAYPAL_BILLING_PLANS_basic_12mo": "basic_12mo",
|
||||
@@ -90,7 +90,7 @@
|
||||
"STRIPE_API_KEY": "aaaabbbbccccddddeeeeffff00001111",
|
||||
"STRIPE_PUB_KEY": "22223333444455556666777788889999",
|
||||
"STRIPE_WEBHOOKS_ENDPOINT_SECRET": "111111",
|
||||
"TEST_DB_URI": "mongodb://localhost:27017/habitica-test?replicaSet=rs",
|
||||
"TEST_DB_URI": "mongodb://localhost:27017/habitica-test?replicaSet=rs&directConnection=true&readPreference=secondary",
|
||||
"TIME_TRAVEL_ENABLED": "false",
|
||||
"TRUSTED_DOMAINS": "localhost,https://habitica.com",
|
||||
"WEB_CONCURRENCY": 1
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
services:
|
||||
client:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile-Dev
|
||||
command: ["npm", "run", "client:dev"]
|
||||
depends_on:
|
||||
- server
|
||||
environment:
|
||||
- BASE_URL=http://server:3000
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- .:/usr/src/habitica
|
||||
- /usr/src/habitica/node_modules
|
||||
- /usr/src/habitica/website/client/node_modules
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile-Dev
|
||||
command: ["npm", "start"]
|
||||
depends_on:
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- NODE_DB_URI=mongodb://mongo/habitrpg
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .:/usr/src/habitica
|
||||
- /usr/src/habitica/node_modules
|
||||
mongo:
|
||||
image: mongo:5.0.23
|
||||
restart: unless-stopped
|
||||
command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"]
|
||||
healthcheck:
|
||||
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
|
||||
interval: 10s
|
||||
timeout: 30s
|
||||
start_period: 0s
|
||||
start_interval: 1s
|
||||
retries: 30
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
- "27017:27017"
|
||||
networks:
|
||||
habitica:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,23 @@
|
||||
networks:
|
||||
mongodb-network:
|
||||
name: "mongodb-network"
|
||||
driver: bridge
|
||||
services:
|
||||
mongodb:
|
||||
image: "mongo:7.0"
|
||||
container_name: "habitica-mongodb-only"
|
||||
networks:
|
||||
- mongodb-network
|
||||
hostname: "mongodb"
|
||||
ports:
|
||||
- "27017:27017"
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- "./mongodb-data-docker:/data/db"
|
||||
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs" ]
|
||||
healthcheck:
|
||||
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
|
||||
interval: 10s
|
||||
timeout: 30s
|
||||
start_period: 0s
|
||||
retries: 30
|
||||
@@ -0,0 +1,23 @@
|
||||
networks:
|
||||
mongodb-network:
|
||||
name: "mongodb-network"
|
||||
driver: bridge
|
||||
services:
|
||||
mongodb:
|
||||
image: "mongo:7.0"
|
||||
container_name: "habitica-mongodb-test"
|
||||
networks:
|
||||
- mongodb-network
|
||||
hostname: "mongodb"
|
||||
ports:
|
||||
- "27017:27017"
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- "./mongodb-data-docker-testing:/data/db"
|
||||
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs" ]
|
||||
healthcheck:
|
||||
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
|
||||
interval: 10s
|
||||
timeout: 30s
|
||||
start_period: 0s
|
||||
retries: 30
|
||||
+43
-22
@@ -1,35 +1,56 @@
|
||||
version: "3"
|
||||
services:
|
||||
|
||||
client:
|
||||
build: .
|
||||
networks:
|
||||
- habitica
|
||||
environment:
|
||||
- BASE_URL=http://server:3000
|
||||
ports:
|
||||
- "8080:8080"
|
||||
command: ["npm", "run", "client:dev"]
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile-Dev
|
||||
command: ["npm", "run", "client:dev:docker"]
|
||||
depends_on:
|
||||
- server
|
||||
|
||||
server:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- BASE_URL=http://server:3000
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
- "5173:5173"
|
||||
volumes:
|
||||
- .:/usr/src/habitica
|
||||
- /usr/src/habitica/node_modules
|
||||
- /usr/src/habitica/website/client/node_modules
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile-Dev
|
||||
command: ["npm", "start"]
|
||||
depends_on:
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- NODE_DB_URI=mongodb://mongo/habitrpg
|
||||
depends_on:
|
||||
- mongo
|
||||
|
||||
mongo:
|
||||
image: mongo:3.6
|
||||
ports:
|
||||
- "27017:27017"
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .:/usr/src/habitica
|
||||
- /usr/src/habitica/node_modules
|
||||
mongo:
|
||||
image: "mongo:7.0"
|
||||
container_name: "habitica-mongodb"
|
||||
networks:
|
||||
- habitica
|
||||
hostname: "mongodb"
|
||||
ports:
|
||||
- "27017:27017"
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- "./mongodb-data-docker:/data/db"
|
||||
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs" ]
|
||||
healthcheck:
|
||||
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
|
||||
interval: 10s
|
||||
timeout: 30s
|
||||
start_period: 0s
|
||||
retries: 30
|
||||
|
||||
networks:
|
||||
habitica:
|
||||
|
||||
+12
-9
@@ -5,7 +5,7 @@ import path from 'path';
|
||||
import babel from 'gulp-babel';
|
||||
import os from 'os';
|
||||
import fs from 'fs';
|
||||
import spawn from 'cross-spawn'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import spawn from 'cross-spawn';
|
||||
import clean from 'rimraf';
|
||||
|
||||
gulp.task('build:babel:server', () => gulp.src('website/server/**/*.js')
|
||||
@@ -35,7 +35,7 @@ gulp.task('build:prod', gulp.series(
|
||||
// When used on windows `run-rs` must first be run without the `--keep` option
|
||||
// in order to be setup correctly, afterwards it can be used.
|
||||
|
||||
const MONGO_PATH = path.join(__dirname, '/../mongodb-data/');
|
||||
const MONGO_PATH = path.join(__dirname, '/../mongodb-data-docker/');
|
||||
|
||||
gulp.task('build:prepare-mongo', async () => {
|
||||
if (fs.existsSync(MONGO_PATH)) {
|
||||
@@ -51,29 +51,32 @@ gulp.task('build:prepare-mongo', async () => {
|
||||
console.log('MongoDB data folder is missing, setting up.'); // eslint-disable-line no-console
|
||||
|
||||
// use run-rs without --keep, kill it as soon as the replica set starts
|
||||
const runRsProcess = spawn('run-rs', ['-v', '4.1.1', '-l', 'ubuntu1804', '--dbpath', 'mongodb-data', '--number', '1', '--quiet']);
|
||||
const dockerMongoProcess = spawn('npm', ['run', 'docker:mongo:dev']);
|
||||
|
||||
for await (const chunk of runRsProcess.stdout) {
|
||||
let manuallyStopped = false;
|
||||
|
||||
for await (const chunk of dockerMongoProcess.stdout) {
|
||||
const stringChunk = chunk.toString();
|
||||
console.log(stringChunk); // eslint-disable-line no-console
|
||||
// kills the process after the replica set is setup
|
||||
if (stringChunk.includes('Started replica set')) {
|
||||
if (stringChunk.includes('mongod startup complete')) {
|
||||
console.log('MongoDB setup correctly.'); // eslint-disable-line no-console
|
||||
runRsProcess.kill();
|
||||
dockerMongoProcess.kill();
|
||||
manuallyStopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
let error = '';
|
||||
for await (const chunk of runRsProcess.stderr) {
|
||||
for await (const chunk of dockerMongoProcess.stderr) {
|
||||
const stringChunk = chunk.toString();
|
||||
error += stringChunk;
|
||||
}
|
||||
|
||||
const exitCode = await new Promise(resolve => {
|
||||
runRsProcess.on('close', resolve);
|
||||
dockerMongoProcess.on('close', resolve);
|
||||
});
|
||||
|
||||
if (exitCode || error.length > 0) {
|
||||
if (!manuallyStopped && (exitCode || error.length > 0)) {
|
||||
// remove any leftover files
|
||||
clean.sync(MONGO_PATH);
|
||||
|
||||
|
||||
+61
-26
@@ -6,9 +6,21 @@ gulp.task('cache:content', done => {
|
||||
// Requiring at runtime because these files access `common`
|
||||
// code which in production works only if transpiled so after
|
||||
// gulp build:babel:common has run
|
||||
const { CONTENT_CACHE_PATH, getLocalizedContentResponse } = require('../website/server/libs/content'); // eslint-disable-line global-require
|
||||
const {
|
||||
CONTENT_CACHE_PATH,
|
||||
getLocalizedContentResponse,
|
||||
IOS_FILTER,
|
||||
ANDROID_FILTER,
|
||||
buildFilterObject,
|
||||
hashForFilter,
|
||||
} = require('../website/server/libs/content'); // eslint-disable-line global-require
|
||||
const { langCodes } = require('../website/server/libs/i18n'); // eslint-disable-line global-require
|
||||
|
||||
const iosHash = hashForFilter(IOS_FILTER);
|
||||
const iosFilterObj = buildFilterObject(IOS_FILTER);
|
||||
const androidHash = hashForFilter(ANDROID_FILTER);
|
||||
const androidFilterObj = buildFilterObject(ANDROID_FILTER);
|
||||
|
||||
try {
|
||||
// create the cache folder (if it doesn't exist)
|
||||
try {
|
||||
@@ -26,33 +38,56 @@ gulp.task('cache:content', done => {
|
||||
getLocalizedContentResponse(langCode),
|
||||
'utf8',
|
||||
);
|
||||
});
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('cache:i18n', done => {
|
||||
// Requiring at runtime because these files access `common`
|
||||
// code which in production works only if transpiled so after
|
||||
// gulp build:babel:common has run
|
||||
const { BROWSER_SCRIPT_CACHE_PATH, geti18nBrowserScript } = require('../website/server/libs/i18n'); // eslint-disable-line global-require
|
||||
const { langCodes } = require('../website/server/libs/i18n'); // eslint-disable-line global-require
|
||||
|
||||
try {
|
||||
// create the cache folder (if it doesn't exist)
|
||||
try {
|
||||
fs.mkdirSync(BROWSER_SCRIPT_CACHE_PATH);
|
||||
} catch (err) {
|
||||
if (err.code !== 'EEXIST') throw err;
|
||||
}
|
||||
|
||||
// create and save the i18n browser script for each language
|
||||
langCodes.forEach(languageCode => {
|
||||
fs.writeFileSync(
|
||||
`${BROWSER_SCRIPT_CACHE_PATH}${languageCode}.js`,
|
||||
geti18nBrowserScript(languageCode),
|
||||
`${CONTENT_CACHE_PATH}${langCode}${iosHash}.json`,
|
||||
getLocalizedContentResponse(langCode, iosFilterObj),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
`${CONTENT_CACHE_PATH}${langCode}${androidHash}.json`,
|
||||
getLocalizedContentResponse(langCode, androidFilterObj),
|
||||
'utf8',
|
||||
);
|
||||
});
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
|
||||
function safeMkdir (path) {
|
||||
try {
|
||||
fs.mkdirSync(path);
|
||||
} catch (err) {
|
||||
if (err.code !== 'EEXIST') throw err;
|
||||
}
|
||||
}
|
||||
|
||||
gulp.task('cache:i18n', done => {
|
||||
// Requiring at runtime because these files access `common`
|
||||
// code which in production works only if transpiled so after
|
||||
// gulp build:babel:common has run
|
||||
const { BROWSER_SCRIPT_CACHE_PATH, geti18nCoreBrowserScript, geti18nContentBrowserScript } = require('../website/server/libs/i18n'); // eslint-disable-line global-require
|
||||
const { langCodes } = require('../website/server/libs/i18n'); // eslint-disable-line global-require
|
||||
|
||||
try {
|
||||
// create the cache folders (if they doesn't exist)
|
||||
safeMkdir(BROWSER_SCRIPT_CACHE_PATH);
|
||||
safeMkdir(`${BROWSER_SCRIPT_CACHE_PATH}core/`);
|
||||
safeMkdir(`${BROWSER_SCRIPT_CACHE_PATH}content/`);
|
||||
|
||||
// create and save the i18n browser script for each language
|
||||
langCodes.forEach(languageCode => {
|
||||
fs.writeFileSync(
|
||||
`${BROWSER_SCRIPT_CACHE_PATH}core/${languageCode}.js`,
|
||||
geti18nCoreBrowserScript(languageCode),
|
||||
'utf8',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
`${BROWSER_SCRIPT_CACHE_PATH}content/${languageCode}.js`,
|
||||
geti18nContentBrowserScript(languageCode),
|
||||
'utf8',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -53,6 +53,11 @@ gulp.task('test:prepare:mongo', cb => {
|
||||
const mongooseOptions = getDefaultConnectionOptions();
|
||||
const connectionUrl = getDevelopmentConnectionUrl(TEST_DB_URI);
|
||||
|
||||
console.info({
|
||||
mongooseOptions,
|
||||
connectionUrl,
|
||||
});
|
||||
|
||||
mongoose.connect(connectionUrl, mongooseOptions)
|
||||
.then(() => mongoose.connection.dropDatabase())
|
||||
.then(() => mongoose.connection.close()).then(() => {
|
||||
|
||||
+1
-1
Submodule habitica-images updated: 8a96a0ff62...359153997e
Generated
+426
-605
File diff suppressed because it is too large
Load Diff
+10
-5
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.42.3",
|
||||
"version": "5.44.3",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -40,6 +40,7 @@
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
"habitica-markdown": "^3.0.0",
|
||||
"heapdump": "^0.3.15",
|
||||
"helmet": "^4.6.0",
|
||||
"in-app-purchase": "^1.11.3",
|
||||
"js2xmlparser": "^5.0.0",
|
||||
@@ -48,10 +49,12 @@
|
||||
"lodash": "^4.17.21",
|
||||
"merge-stream": "^2.0.0",
|
||||
"method-override": "^3.0.0",
|
||||
"micromustache": "^8.0.3",
|
||||
"moment": "^2.29.4",
|
||||
"moment-recur": "git://github.com/HabitRPG/moment-recur.git#d3e8e6da0806f13b74dd2e4d7d9053e6a63db119",
|
||||
"mongoose": "^8.9.5",
|
||||
"morgan": "^1.10.1",
|
||||
"nan": "^2.25.0",
|
||||
"nconf": "^0.12.1",
|
||||
"node-gcm": "^1.0.5",
|
||||
"on-headers": "^1.1.0",
|
||||
@@ -100,13 +103,16 @@
|
||||
"coverage": "nyc report --reporter=html --report-dir coverage/results; open coverage/results/index.html",
|
||||
"sprites": "gulp sprites:compile",
|
||||
"client:dev": "cd website/client && npm run serve",
|
||||
"client:dev:docker": "cd website/client && npm run serve:docker",
|
||||
"client:build": "cd website/client && npm run build",
|
||||
"client:unit": "cd website/client && npm run test:unit",
|
||||
"start": "node --watch ./website/server/index.js",
|
||||
"start:simple": "node ./website/server/index.js",
|
||||
"debug": "node --watch --inspect ./website/server/index.js",
|
||||
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||
"docker:aio": "docker compose -f docker-compose.yml up",
|
||||
"docker:mongo:dev": "docker compose -f docker-compose.mongo-only.yml up",
|
||||
"docker:mongo:dev:down": "docker compose -f docker-compose.mongo-only.yml down",
|
||||
"docker:mongo:test": "docker compose -f docker-compose.mongo-test-local.yml up",
|
||||
"mongo:test": "node scripts/start-local-mongo.mjs --test-db",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc",
|
||||
"heroku-postbuild": ".heroku/report_deploy.sh"
|
||||
@@ -122,7 +128,6 @@
|
||||
"monk": "^7.3.4",
|
||||
"nyc": "^15.1.0",
|
||||
"require-again": "^2.0.0",
|
||||
"run-rs": "^0.7.7",
|
||||
"sinon-chai": "^3.7.0",
|
||||
"sinon-stub-promise": "^4.0.0"
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
|
||||
xdescribe('GET /export/avatar-:memberId.html', () => {
|
||||
let user;
|
||||
|
||||
before(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('validates req.params.memberId', async () => {
|
||||
await expect(user.get('/export/avatar-:memberId.html')).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('handles non-existing members', async () => {
|
||||
const dummyId = generateUUID();
|
||||
await expect(user.get(`/export/avatar-${dummyId}.html`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('userWithIDNotFound', { userId: dummyId }),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an html page', async () => {
|
||||
const res = await user.get(`/export/avatar-${user._id}.html`);
|
||||
expect(res.substring(0, 100).indexOf('<!DOCTYPE html>')).to.equal(0);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
// TODO how to test this route since it points to a file on AWS s3?
|
||||
|
||||
describe('GET /export/avatar-:memberId.png', () => {});
|
||||
@@ -47,7 +47,7 @@ describe('GET /inbox/messages', () => {
|
||||
it('returns four messages when using page-query ', async () => {
|
||||
const promises = [];
|
||||
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
for (let i = 0; i < 50; i += 1) {
|
||||
promises.push(user.post('/members/send-private-message', {
|
||||
toUserId: user.id,
|
||||
message: 'fourth',
|
||||
|
||||
@@ -65,6 +65,52 @@ describe('POST /user/auth/social', () => {
|
||||
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a google user');
|
||||
});
|
||||
|
||||
it('includes sanitized version of provided username', async () => {
|
||||
const response = await api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
username: 'Google User Name',
|
||||
});
|
||||
|
||||
await expect(getProperty('users', response.id, 'auth.local.username')).to.eventually.equal('GoogleUserName');
|
||||
await expect(getProperty('users', response.id, 'auth.local.lowerCaseUsername')).to.eventually.equal('googleusername');
|
||||
});
|
||||
|
||||
it('generates a random username if provided username contains only disallowed characters', async () => {
|
||||
const response = await api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
username: 'Áîüè',
|
||||
});
|
||||
|
||||
await expect(getProperty('users', response.id, 'auth.local.username')).to.eventually.contain('hb-');
|
||||
await expect(getProperty('users', response.id, 'auth.local.lowerCaseUsername')).to.eventually.contain('hb-');
|
||||
});
|
||||
|
||||
it('generates a random username if provided username contains a disallowed word', async () => {
|
||||
const response = await api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
username: 'i am a TESTPLACEHOLDERSLURWORDHERE',
|
||||
});
|
||||
|
||||
await expect(getProperty('users', response.id, 'auth.local.username')).to.eventually.contain('hb-');
|
||||
await expect(getProperty('users', response.id, 'auth.local.lowerCaseUsername')).to.eventually.contain('hb-');
|
||||
});
|
||||
|
||||
it('generates a random username if sanitized username conflicts with an extant user', async () => {
|
||||
user = await generateUser({ 'auth.local.username': 'GoogleUserName' });
|
||||
|
||||
const response = await api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
username: 'Google User Name',
|
||||
});
|
||||
|
||||
await expect(getProperty('users', response.id, 'auth.local.username')).to.eventually.contain('hb-');
|
||||
await expect(getProperty('users', response.id, 'auth.local.lowerCaseUsername')).to.eventually.contain('hb-');
|
||||
});
|
||||
|
||||
it('fails if allowRegister is false and user does not exist', async () => {
|
||||
await expect(api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('GET /inbox/conversations', () => {
|
||||
it('returns five messages when using page-query ', async () => {
|
||||
const promises = [];
|
||||
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
for (let i = 0; i < 50; i += 1) {
|
||||
promises.push(user.post('/members/send-private-message', {
|
||||
toUserId: user.id,
|
||||
message: 'fourth',
|
||||
|
||||
@@ -20,6 +20,9 @@ describe('shared.ops.unlock', () => {
|
||||
beforeEach(() => {
|
||||
user = generateUser();
|
||||
user.balance = usersStartingGems;
|
||||
user.pinnedItems.push({ type: 'background', path: 'backgrounds.backgrounds042016.giant_florals' });
|
||||
user.pinnedItems.push({ type: 'haircolor', path: 'hair.color.rainbow' });
|
||||
user.pinnedItems.push({ type: 'shirt', path: 'shirt.convict' });
|
||||
clock = sandbox.useFakeTimers(new Date('2024-04-10'));
|
||||
});
|
||||
|
||||
@@ -272,6 +275,7 @@ describe('shared.ops.unlock', () => {
|
||||
});
|
||||
|
||||
it('unlocks an item (appearance)', async () => {
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'shirt')).to.not.equal(-1);
|
||||
const path = unlockPath.split(',')[0];
|
||||
const initialShirts = Object.keys(user.purchased.shirt).length;
|
||||
const [, message] = await unlock(user, { query: { path } });
|
||||
@@ -282,11 +286,12 @@ describe('shared.ops.unlock', () => {
|
||||
);
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'shirt')).to.equal(-1);
|
||||
});
|
||||
|
||||
it('unlocks an item (hair color)', async () => {
|
||||
user.purchased.hair.color = {};
|
||||
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'haircolor')).to.not.equal(-1);
|
||||
const path = hairUnlockPath.split(',')[0];
|
||||
const initialColorHair = Object.keys(user.purchased.hair.color).length;
|
||||
const [, message] = await unlock(user, { query: { path } });
|
||||
@@ -297,6 +302,7 @@ describe('shared.ops.unlock', () => {
|
||||
);
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'haircolor')).to.equal(-1);
|
||||
});
|
||||
|
||||
it('unlocks an item (facial hair)', async () => {
|
||||
@@ -334,6 +340,7 @@ describe('shared.ops.unlock', () => {
|
||||
|
||||
it('unlocks an item (background)', async () => {
|
||||
const initialBackgrounds = Object.keys(user.purchased.background).length;
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'background')).to.not.equal(-1);
|
||||
const [, message] = await unlock(user, {
|
||||
query: { path: backgroundUnlockPath },
|
||||
});
|
||||
@@ -344,6 +351,7 @@ describe('shared.ops.unlock', () => {
|
||||
);
|
||||
expect(get(user.purchased, backgroundUnlockPath)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.75);
|
||||
expect(user.pinnedItems.findIndex(item => item.type === 'background')).to.equal(-1);
|
||||
});
|
||||
|
||||
it('handles an invalid hair path gracefully', async () => {
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { STRING_ERROR_MSG, STRING_DOES_NOT_EXIST_MSG } from '../helpers/content.helper';
|
||||
import { STRING_DOES_NOT_EXIST_MSG } from '../helpers/content.helper';
|
||||
import translator from '../../website/common/script/content/translation';
|
||||
|
||||
describe('Translator', () => {
|
||||
it('returns error message if string is not properly formatted', () => {
|
||||
const improperlyFormattedString = translator('petName', { attr: 0 })();
|
||||
expect(improperlyFormattedString).to.match(STRING_ERROR_MSG);
|
||||
});
|
||||
|
||||
it('returns an error message if string does not exist', () => {
|
||||
const stringDoesNotExist = translator('stringDoesNotExist')();
|
||||
expect(stringDoesNotExist).to.match(STRING_DOES_NOT_EXIST_MSG);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import i18n from '../../website/common/script/i18n';
|
||||
import './globals.helper';
|
||||
import { translations } from '../../website/server/libs/i18n';
|
||||
import { contentTranslations } from '../../website/server/libs/i18n';
|
||||
|
||||
i18n.translations = translations;
|
||||
i18n.translations = contentTranslations;
|
||||
|
||||
export const STRING_ERROR_MSG = /^Error processing the string ".*". Please see Help > Report a Bug.$/;
|
||||
export const STRING_DOES_NOT_EXIST_MSG = /^String '.*' not found.$/;
|
||||
|
||||
@@ -21,6 +21,7 @@ export async function getProperty (collectionName, id, path) {
|
||||
// Specifically helpful for the GET /groups tests,
|
||||
// resets the db to an empty state and creates a tavern document
|
||||
export async function resetHabiticaDB () {
|
||||
console.info('Resetting Habitica DB');
|
||||
const groups = mongoose.connection.db.collection('groups');
|
||||
const users = mongoose.connection.db.collection('users');
|
||||
return mongoose.connection.dropDatabase()
|
||||
|
||||
@@ -32,6 +32,6 @@
|
||||
|
||||
<script type="text/javascript" src="//cloudfront.loggly.com/js/loggly.tracker-latest.min.js" async></script>
|
||||
<!-- Translations -->
|
||||
<script type='text/javascript' src='/api/v4/i18n/browser-script' vite-ignore></script>
|
||||
<script type='text/javascript' src='/api/v4/i18n/core' vite-ignore></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
+4968
-2726
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vite",
|
||||
"serve:docker": "npx vite --host 0.0.0.0",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest run",
|
||||
@@ -33,6 +34,7 @@
|
||||
"jquery": "^3.7.1",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^14.0.0",
|
||||
"micromustache": "^8.0.3",
|
||||
"moment": "^2.29.4",
|
||||
"nconf": "^0.12.1",
|
||||
"sass": "^1.63.4",
|
||||
|
||||
@@ -1060,6 +1060,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_elven_citadel {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_elven_citadel.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_enchanted_music_room {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_enchanted_music_room.png');
|
||||
width: 141px;
|
||||
@@ -1931,6 +1936,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_riding_a_comet {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_riding_a_comet.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_rime_ice {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rime_ice.png');
|
||||
width: 141px;
|
||||
@@ -2427,6 +2437,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_waterfall_with_rainbow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_waterfall_with_rainbow.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_wedding_arch {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_wedding_arch.png');
|
||||
width: 141px;
|
||||
@@ -29800,6 +29815,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_handstandOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_handstandOutfit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_hattersSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_hattersSuit.png');
|
||||
width: 114px;
|
||||
@@ -30075,6 +30095,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_softYellowSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_softYellowSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_springPetalYukata {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_springPetalYukata.png');
|
||||
width: 114px;
|
||||
@@ -30385,6 +30410,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_floppyYellowHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_floppyYellowHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_flutteryWig {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_flutteryWig.png');
|
||||
width: 114px;
|
||||
@@ -30705,6 +30735,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_verdantArmingCap {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_verdantArmingCap.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_vermilionArcherHelm {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_vermilionArcherHelm.png');
|
||||
width: 90px;
|
||||
@@ -31120,6 +31155,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_softYellowPillow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_softYellowPillow.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_spanishGuitar {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_spanishGuitar.png');
|
||||
width: 114px;
|
||||
@@ -31170,6 +31210,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_verdantBanner {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_verdantBanner.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_vikingShield {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_vikingShield.png');
|
||||
width: 90px;
|
||||
@@ -31440,6 +31485,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_handstandOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_handstandOutfit .png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_hattersSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_hattersSuit.png');
|
||||
width: 114px;
|
||||
@@ -31715,6 +31765,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_softYellowSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_softYellowSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_springPetalYukata {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_springPetalYukata.png');
|
||||
width: 114px;
|
||||
@@ -34125,11 +34180,21 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_202605 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_202605.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_mystery_202604 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202604.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202512.png');
|
||||
width: 114px;
|
||||
@@ -34140,11 +34205,31 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202603 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202603.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202604 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202604.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_mystery_202605 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202605.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_mystery_202604 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202604.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202512.png');
|
||||
width: 114px;
|
||||
@@ -34155,6 +34240,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_mystery_202603 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202603.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_201402 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_201402.png');
|
||||
width: 90px;
|
||||
@@ -36275,6 +36365,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_spring2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_spring2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_spring2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_spring2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_spring2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_spring2026Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_spring2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_spring2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_springHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_springHealer.png');
|
||||
width: 90px;
|
||||
@@ -36595,6 +36705,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_spring2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_spring2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_spring2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_spring2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_spring2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_spring2026Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_spring2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_spring2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_springHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_springHealer.png');
|
||||
width: 90px;
|
||||
@@ -36780,6 +36910,21 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_spring2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_spring2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_spring2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_spring2026Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_spring2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_spring2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_springHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_springHealer.png');
|
||||
width: 90px;
|
||||
@@ -37015,6 +37160,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_spring2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_spring2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_spring2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_spring2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_spring2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_spring2026Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_spring2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_spring2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_springHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_springHealer.png');
|
||||
width: 90px;
|
||||
@@ -37255,6 +37420,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_spring2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_spring2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_spring2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_spring2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_spring2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_spring2026Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_spring2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_spring2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_springHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_springHealer.png');
|
||||
width: 90px;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -311,7 +311,7 @@
|
||||
<input
|
||||
id="passwordInput"
|
||||
v-model="password"
|
||||
class="form-control input-with-error"
|
||||
class="form-control dark input-with-error"
|
||||
type="password"
|
||||
:placeholder="$t('password')"
|
||||
:class="{'input-invalid': passwordInvalid, 'input-valid': passwordValid}"
|
||||
@@ -323,7 +323,7 @@
|
||||
{{ $t('minPasswordLength') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group mb-4">
|
||||
<label
|
||||
v-once
|
||||
for="confirmPasswordInput"
|
||||
@@ -331,7 +331,7 @@
|
||||
<input
|
||||
id="confirmPasswordInput"
|
||||
v-model="passwordConfirm"
|
||||
class="form-control input-with-error"
|
||||
class="form-control dark input-with-error"
|
||||
type="password"
|
||||
:placeholder="$t('confirmPasswordPlaceholder')"
|
||||
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
||||
@@ -344,13 +344,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div
|
||||
class="btn btn-info"
|
||||
:enabled="!resetPasswordSetNewOneData.hasError"
|
||||
<button
|
||||
class="btn btn-info w-100"
|
||||
:disabled="!password || !passwordConfirm
|
||||
|| password !== passwordConfirm || resetPasswordSetNewOneData.hasError"
|
||||
@click="resetPasswordSetNewOneLink()"
|
||||
>
|
||||
{{ $t('setNewPass') }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div
|
||||
class="banner d-flex align-items-center justify-content-between py-3 px-4"
|
||||
id="privacy-banner"
|
||||
v-if="!hidden"
|
||||
id="privacy-banner"
|
||||
class="banner d-flex align-items-center justify-content-between py-3 px-4"
|
||||
>
|
||||
<p
|
||||
class="mr-3 mb-0"
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
>
|
||||
<div
|
||||
class="close-x"
|
||||
@click="remove()"
|
||||
@click.stop="remove()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon svg-close"
|
||||
@@ -140,7 +140,7 @@ export default {
|
||||
methods: {
|
||||
remove () {
|
||||
if (this.eventKey) {
|
||||
window.sessionStorage.setItem(`hide-g1g1-${this.eventKey}`, 'true');
|
||||
window.localStorage.setItem(`hide-g1g1-${this.eventKey}`, 'true');
|
||||
}
|
||||
this.$emit('notification-removed');
|
||||
},
|
||||
|
||||
@@ -318,7 +318,7 @@ export default {
|
||||
shouldShowG1g1 () {
|
||||
if (!this.currentG1g1Event) return false;
|
||||
const eventKey = this.g1g1EventKey;
|
||||
if (eventKey && window.sessionStorage.getItem(`hide-g1g1-${eventKey}`) === 'true') {
|
||||
if (eventKey && window.localStorage.getItem(`hide-g1g1-${eventKey}`) === 'true') {
|
||||
return false;
|
||||
}
|
||||
return !this.g1g1Hidden;
|
||||
|
||||
@@ -105,7 +105,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
privacyConsent: true,
|
||||
privacyConsent: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -281,6 +281,11 @@
|
||||
.badge-dialog {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
|
||||
.badge-pin {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@@ -851,10 +856,17 @@ export default {
|
||||
- ownedMounts
|
||||
- ownedItems;
|
||||
|
||||
if (
|
||||
petsRemaining < 0
|
||||
&& !window.confirm(this.$t('purchasePetItemConfirm', { itemText: this.item.text })) // eslint-disable-line no-alert
|
||||
) return;
|
||||
if (petsRemaining < 0) {
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:purchase-confirm', {
|
||||
message: this.$t('purchasePetItemConfirm', { itemText: this.item.text }),
|
||||
currency: this.item.currency,
|
||||
cost: this.item.value * this.selectedAmountToBuy,
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.item.purchaseType === 'customization') {
|
||||
@@ -866,11 +878,14 @@ export default {
|
||||
this.purchased(this.item.text);
|
||||
} else {
|
||||
const shouldConfirmPurchase = this.item.currency === 'gems' || this.item.currency === 'hourglasses';
|
||||
if (
|
||||
shouldConfirmPurchase
|
||||
&& !this.confirmPurchase(this.item.currency, this.item.value * this.selectedAmountToBuy)
|
||||
) {
|
||||
return;
|
||||
if (shouldConfirmPurchase) {
|
||||
const confirmed = await this.confirmPurchase(
|
||||
this.item.currency,
|
||||
this.item.value * this.selectedAmountToBuy,
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.genericPurchase) {
|
||||
if (this.item.key === 'rebirth_orb') {
|
||||
@@ -893,8 +908,8 @@ export default {
|
||||
purchaseGems () {
|
||||
this.$root.$emit('bv::show::modal', 'buy-gems');
|
||||
},
|
||||
togglePinned () {
|
||||
this.isPinned = this.$store.dispatch('user:togglePinnedItem', { type: this.item.pinType, path: this.item.path });
|
||||
async togglePinned () {
|
||||
this.isPinned = await this.$store.dispatch('user:togglePinnedItem', { type: this.item.pinType, path: this.item.path });
|
||||
|
||||
if (!this.isPinned) {
|
||||
this.text(this.$t('unpinnedItem', { item: this.item.text }));
|
||||
|
||||
@@ -76,7 +76,21 @@
|
||||
:empty-item="false"
|
||||
:show-popover="Boolean(ctx.item.text)"
|
||||
@click="selectItem(ctx.item)"
|
||||
/>
|
||||
>
|
||||
<template
|
||||
slot="itemBadge"
|
||||
slot-scope="slotProps"
|
||||
>
|
||||
<span
|
||||
class="badge-top"
|
||||
@click.prevent.stop="togglePinned(slotProps.item)"
|
||||
>
|
||||
<pin-badge
|
||||
:pinned="slotProps.item.pinned"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
</shop-item>
|
||||
</template>
|
||||
</item-rows>
|
||||
</div>
|
||||
@@ -108,6 +122,16 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.market .badge-pin:not(.pinned) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.market .item:hover .badge-pin {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import find from 'lodash/find';
|
||||
import shops from '@/../../common/script/libs/shops';
|
||||
@@ -118,7 +142,9 @@ import Checkbox from '@/components/ui/checkbox';
|
||||
import FilterGroup from '@/components/ui/filterGroup';
|
||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||
import ItemRows from '@/components/ui/itemRows';
|
||||
import PinBadge from '@/components/ui/pinBadge';
|
||||
import ShopItem from '../shopItem';
|
||||
import pinUtils from '@/mixins/pinUtils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -126,8 +152,10 @@ export default {
|
||||
FilterGroup,
|
||||
FilterSidebar,
|
||||
ItemRows,
|
||||
PinBadge,
|
||||
ShopItem,
|
||||
},
|
||||
mixins: [pinUtils],
|
||||
data () {
|
||||
return {
|
||||
searchText: null,
|
||||
@@ -184,8 +212,12 @@ export default {
|
||||
methods: {
|
||||
customizationsItems (options = {}) {
|
||||
const { category, searchBy } = options;
|
||||
return category.items.filter(item => !searchBy
|
||||
|| item.text.toLowerCase().includes(searchBy));
|
||||
return category.items
|
||||
.filter(item => !searchBy || item.text.toLowerCase().includes(searchBy))
|
||||
.map(item => ({
|
||||
...item,
|
||||
pinned: this.isPinned(item),
|
||||
}));
|
||||
},
|
||||
emptyClick (identifier, event) {
|
||||
if (event.target.tagName !== 'A') return;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="purchase-confirm-modal"
|
||||
:hide-footer="true"
|
||||
:hide-header="true"
|
||||
modal-class="purchase-confirm-modal"
|
||||
centered
|
||||
>
|
||||
<div class="modal-content-wrapper">
|
||||
<div class="top-bar"></div>
|
||||
<div class="modal-body-content">
|
||||
<div
|
||||
class="currency-chip"
|
||||
:class="currency"
|
||||
>
|
||||
<span
|
||||
class="svg-icon icon-24"
|
||||
v-html="icons[currency]"
|
||||
></span>
|
||||
<span class="cost-value">{{ cost }}</span>
|
||||
</div>
|
||||
<h2 class="modal-title">
|
||||
{{ $t('confirmPurchase') }}
|
||||
</h2>
|
||||
<p class="modal-subtitle">
|
||||
{{ confirmationMessage }}
|
||||
</p>
|
||||
<div class="button-wrapper">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="confirm()"
|
||||
>
|
||||
{{ $t('confirm') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn-cancel"
|
||||
@click="cancel()"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import svgGem from '@/assets/svg/gem.svg?raw';
|
||||
import svgHourglass from '@/assets/svg/hourglass.svg?raw';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
confirmationMessage: '',
|
||||
currency: 'gems',
|
||||
cost: 0,
|
||||
resolveCallback: null,
|
||||
icons: Object.freeze({
|
||||
gems: svgGem,
|
||||
hourglasses: svgHourglass,
|
||||
}),
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:purchase-confirm', config => {
|
||||
this.confirmationMessage = config.message;
|
||||
this.currency = config.currency || 'gems';
|
||||
this.cost = config.cost || 0;
|
||||
this.resolveCallback = config.resolve;
|
||||
this.$root.$emit('bv::show::modal', 'purchase-confirm-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:purchase-confirm');
|
||||
},
|
||||
methods: {
|
||||
confirm () {
|
||||
if (this.resolveCallback) {
|
||||
this.resolveCallback(true);
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
cancel () {
|
||||
if (this.resolveCallback) {
|
||||
this.resolveCallback(false);
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'purchase-confirm-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
::v-deep .purchase-confirm-modal {
|
||||
.modal-dialog {
|
||||
max-width: 330px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 8px;
|
||||
background-color: $purple-300;
|
||||
}
|
||||
|
||||
.modal-body-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 24px 24px;
|
||||
}
|
||||
|
||||
.currency-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 40px;
|
||||
padding: 8px 20px;
|
||||
border-radius: 20px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
|
||||
&.gems {
|
||||
color: $gems-color;
|
||||
background-color: rgba($green-10, 0.15);
|
||||
}
|
||||
|
||||
&.hourglasses {
|
||||
color: $hourglass-color;
|
||||
background-color: rgba($blue-10, 0.15);
|
||||
}
|
||||
|
||||
.icon-24 {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
color: $purple-300;
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: none;
|
||||
border: none;
|
||||
color: $purple-300;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -180,6 +180,11 @@
|
||||
.badge-dialog {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
|
||||
.badge-pin {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@@ -510,8 +515,12 @@ export default {
|
||||
this.selectedAmountToBuy = 1;
|
||||
this.$emit('change', $event);
|
||||
},
|
||||
buyItem () {
|
||||
if (!this.confirmPurchase(this.item.currency, this.item.value * this.selectedAmountToBuy)) {
|
||||
async buyItem () {
|
||||
const confirmed = await this.confirmPurchase(
|
||||
this.item.currency,
|
||||
this.item.value * this.selectedAmountToBuy,
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
this.makeGenericPurchase(this.item, 'buyQuestModal', this.selectedAmountToBuy);
|
||||
|
||||
@@ -498,8 +498,13 @@ export default {
|
||||
|
||||
await this.triggerGetWorldState();
|
||||
this.currentEvent = _find(this.currentEventList, event => Boolean(event.season));
|
||||
this.imageURLs.background = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_background.png)`;
|
||||
this.imageURLs.npc = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_npc.png)`;
|
||||
if (this.currentEvent.season === 'valentines') {
|
||||
this.imageURLs.background = 'url(/static/npc/spring/seasonal_shop_opened_background.png)';
|
||||
this.imageURLs.npc = 'url(/static/npc/spring/seasonal_shop_opened_npc.png)';
|
||||
} else {
|
||||
this.imageURLs.background = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_background.png)`;
|
||||
this.imageURLs.npc = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_npc.png)`;
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('buyModal::boughtItem');
|
||||
|
||||
@@ -64,9 +64,11 @@
|
||||
<li>sexual orientation; and</li>
|
||||
<li>information collected from a known child.</li>
|
||||
</ul>
|
||||
<p><strong>
|
||||
NOTE: Please do not provide us “sensitive personal information” or “sensitive personal data”, as those terms are defined under applicable privacy laws, unless we directly request that you do so. If you feel, after careful consideration, that it is necessary to provide us certain sensitive personal information or data, please provide us the minimum amount of such information or data that is necessary.
|
||||
</strong></p>
|
||||
<p>
|
||||
<strong>
|
||||
NOTE: Please do not provide us “sensitive personal information” or “sensitive personal data”, as those terms are defined under applicable privacy laws, unless we directly request that you do so. If you feel, after careful consideration, that it is necessary to provide us certain sensitive personal information or data, please provide us the minimum amount of such information or data that is necessary.
|
||||
</strong>
|
||||
</p>
|
||||
<h3 id="section_1_1">
|
||||
1.1 Information You Provide Directly
|
||||
</h3>
|
||||
@@ -617,7 +619,7 @@
|
||||
7. General Audience Services
|
||||
</h2>
|
||||
<p>
|
||||
The Service is intended for users 18 years or older; you are not permitted to access or use the Service if you are younger than 18. We do not knowingly collect personal information from children under the age of 18 through the Service. We encourage parents and legal guardians to monitor their children’s Internet usage and to help enforce our Privacy Policy by instructing their children to never provide personal information without their permission. If you have reason to believe that a child under the age of 18 has provided personal information to us, please contact us at <a href='mailto:privacy@habitica.com'>privacy@habitica.com</a>, and we will delete that information from our databases.
|
||||
The Service is intended for users 18 years or older; you are not permitted to access or use the Service if you are younger than 18. We do not knowingly collect personal information from children under the age of 18 through the Service. We encourage parents and legal guardians to monitor their children’s Internet usage and to help enforce our Privacy Policy by instructing their children to never provide personal information without their permission. If you have reason to believe that a child under the age of 18 has provided personal information to us, please contact us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>, and we will delete that information from our databases.
|
||||
</p>
|
||||
|
||||
<h2 id="section_8">
|
||||
@@ -708,7 +710,7 @@
|
||||
|
||||
<p><strong><u>Nevada Residents</u></strong></p>
|
||||
<p>
|
||||
Nevada residents may opt out of the sale of certain “covered information” collected by operators of websites or online services. We currently do not sell covered information, as “sale” is defined by such law, and do not have plans to do so. In accordance with Nevada law, you may submit to us a verified request instructing us not to sell your covered information by sending an email to <a href='mailto:privacy@habitica.com'>privacy@habitica.com</a>.
|
||||
Nevada residents may opt out of the sale of certain “covered information” collected by operators of websites or online services. We currently do not sell covered information, as “sale” is defined by such law, and do not have plans to do so. In accordance with Nevada law, you may submit to us a verified request instructing us not to sell your covered information by sending an email to <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>.
|
||||
</p>
|
||||
<p><strong><u>Notice to United Kingdom/European/Switzerland Residents.</u></strong></p>
|
||||
<p>
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<router-view />
|
||||
</div>
|
||||
<div
|
||||
id="bottom-background"
|
||||
v-if="loginFlow"
|
||||
id="bottom-background"
|
||||
class="bg-purple-300"
|
||||
>
|
||||
<div class="seamless_mountains_demo_repeat"></div>
|
||||
@@ -31,7 +31,10 @@
|
||||
id="bottom-wrap"
|
||||
class="purple-4"
|
||||
>
|
||||
<div id="bottom-background" v-if="!loginFlow">
|
||||
<div
|
||||
v-if="!loginFlow"
|
||||
id="bottom-background"
|
||||
>
|
||||
<div class="seamless_mountains_demo_repeat"></div>
|
||||
<div class="midground_foreground_extended2"></div>
|
||||
</div>
|
||||
@@ -104,9 +107,10 @@
|
||||
footer, footer a {
|
||||
background: transparent;
|
||||
color: $purple-500;
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -117,10 +121,6 @@
|
||||
border-top-color: $purple-100;
|
||||
}
|
||||
|
||||
.donate-text {
|
||||
color: $purple-500;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: $purple-300;
|
||||
}
|
||||
@@ -129,42 +129,27 @@
|
||||
color: $purple-500;
|
||||
}
|
||||
|
||||
.social .d-flex:hover {
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
svg {
|
||||
fill: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.social-circle {
|
||||
background: $purple-50;
|
||||
color: $purple-500;
|
||||
|
||||
.instagram svg {
|
||||
svg {
|
||||
background-color: $purple-50;
|
||||
fill: $purple-500;
|
||||
&:hover {
|
||||
fill: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.bluesky svg {
|
||||
background-color: $purple-50;
|
||||
fill: $purple-500;
|
||||
&:hover {
|
||||
fill: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.facebook svg {
|
||||
background-color: $purple-50;
|
||||
fill: $purple-500;
|
||||
&:hover {
|
||||
fill: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.tumblr svg {
|
||||
background-color: $purple-50;
|
||||
fill: $purple-500;
|
||||
&:hover {
|
||||
fill: $white;
|
||||
}
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-contribute {
|
||||
background: $white;
|
||||
box-shadow: none;
|
||||
@@ -274,7 +259,8 @@ export default {
|
||||
return 'purple-footer';
|
||||
},
|
||||
loginFlow () {
|
||||
return ['login', 'register', 'username'].indexOf(this.$route.name) !== -1;
|
||||
const loginRoutes = ['forgotPassword', 'login', 'register', 'resetPassword', 'username'];
|
||||
return loginRoutes.indexOf(this.$route.name) !== -1;
|
||||
},
|
||||
showContentWrap () {
|
||||
return this.$route.name !== 'news';
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY:
|
||||
</p>
|
||||
<p>
|
||||
YOU CAN REQUEST A REFUND OF YOUR MOST RECENT PAYMENT TO US BY CONTACTING US AT <a href='mailto:admin@habitica.com'>ADMIN@HABITICA.COM</a>. THE AMOUNT OF YOUR REFUND, IF ANY, WILL BE BASED ON (1) THE AMOUNT OF YOUR PURCHASED BUT UNUSED SUBSCRIPTION BENEFITS AND (2) THE TERMS IMPOSED ON US BY OUR PAYMENT PROCESSING VENDORS (E.G., WITH RESPECT TO THE DURATION OF THE REFUND PERIOD).
|
||||
YOU CAN REQUEST A REFUND OF YOUR MOST RECENT PAYMENT TO US BY CONTACTING US AT <a href="mailto:admin@habitica.com">ADMIN@HABITICA.COM</a>. THE AMOUNT OF YOUR REFUND, IF ANY, WILL BE BASED ON (1) THE AMOUNT OF YOUR PURCHASED BUT UNUSED SUBSCRIPTION BENEFITS AND (2) THE TERMS IMPOSED ON US BY OUR PAYMENT PROCESSING VENDORS (E.G., WITH RESPECT TO THE DURATION OF THE REFUND PERIOD).
|
||||
</p>
|
||||
<p>
|
||||
FOR ANY CUSTOMER WHO PURCHASED PREMIUM IN APPLE INC.'s APP STORE ("APP STORE"), PLEASE CONTACT APPLE INC.'s SUPPORT TEAM: <a
|
||||
|
||||
@@ -1,65 +1,45 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="broken-task-modal"
|
||||
title="Broken Challenge"
|
||||
size="sm"
|
||||
:hide-footer="true"
|
||||
:hide-header="true"
|
||||
modal-class="broken-task-confirm-modal"
|
||||
centered
|
||||
>
|
||||
<div
|
||||
v-if="brokenChallengeTask && brokenChallengeTask.challenge"
|
||||
class="modal-body"
|
||||
class="modal-content-wrapper"
|
||||
>
|
||||
<div
|
||||
v-if="brokenChallengeTask.challenge.broken === 'TASK_DELETED'
|
||||
|| brokenChallengeTask.challenge.broken === 'CHALLENGE_TASK_NOT_FOUND'"
|
||||
>
|
||||
<h2>{{ $t('brokenTask') }}</h2>
|
||||
<div>
|
||||
<div class="top-bar"></div>
|
||||
<div class="modal-body-content">
|
||||
<div
|
||||
class="icon-wrapper"
|
||||
v-html="icons.alertIcon"
|
||||
></div>
|
||||
<h2 class="modal-title">
|
||||
{{ modalTitle }}
|
||||
</h2>
|
||||
<p class="modal-subtitle">
|
||||
{{ modalSubtitle }}
|
||||
</p>
|
||||
<div class="button-wrapper">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="unlink('keep')"
|
||||
@click="keepAction()"
|
||||
>
|
||||
{{ $t('keepIt') }}
|
||||
{{ keepButtonText }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="removeTask(obj)"
|
||||
@click="removeAction()"
|
||||
>
|
||||
{{ $t('removeIt') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="brokenChallengeTask.challenge.broken === 'CHALLENGE_DELETED'">
|
||||
<h2>{{ $t('brokenChallenge') }}</h2>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="unlink('keep-all')"
|
||||
>
|
||||
{{ $t('keepTasks') }}
|
||||
{{ removeButtonText }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="unlink('remove-all')"
|
||||
class="btn-cancel"
|
||||
@click="close()"
|
||||
>
|
||||
{{ $t('removeTasks') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="brokenChallengeTask.challenge.broken === 'CHALLENGE_CLOSED'">
|
||||
<h2 v-html="$t('challengeCompleted', {user: brokenChallengeTask.challenge.winner})"></h2>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="unlink('keep-all')"
|
||||
>
|
||||
{{ $t('keepTasks') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="unlink('remove-all')"
|
||||
>
|
||||
{{ $t('removeTasks') }}
|
||||
{{ $t('cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,23 +47,175 @@
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.modal-body {
|
||||
padding-bottom: 2em;
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
::v-deep .broken-task-confirm-modal {
|
||||
.modal-dialog {
|
||||
max-width: 330px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 8px;
|
||||
background-color: $maroon-100;
|
||||
}
|
||||
|
||||
.modal-body-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 24px 24px;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
margin-top: 40px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
::v-deep svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
path {
|
||||
fill: #DE3F3F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
color: $maroon-100;
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: none;
|
||||
border: none;
|
||||
color: $purple-300;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapActions } from '@/libs/store';
|
||||
import notifications from '@/mixins/notifications';
|
||||
import alertIcon from '@/assets/svg/for-css/alert.svg?raw';
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
data () {
|
||||
return {
|
||||
brokenChallengeTask: {},
|
||||
icons: Object.freeze({
|
||||
alertIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
brokenType () {
|
||||
return this.brokenChallengeTask.challenge?.broken;
|
||||
},
|
||||
isSingleTask () {
|
||||
return this.brokenType === 'TASK_DELETED'
|
||||
|| this.brokenType === 'CHALLENGE_TASK_NOT_FOUND';
|
||||
},
|
||||
brokenChallengeTaskCount () {
|
||||
if (!this.brokenChallengeTask.challenge?.id) return 0;
|
||||
const challengeId = this.brokenChallengeTask.challenge.id;
|
||||
const tasksData = this.$store.state.tasks.data;
|
||||
let count = 0;
|
||||
['habits', 'dailys', 'todos', 'rewards'].forEach(type => {
|
||||
if (tasksData[type]) {
|
||||
count += tasksData[type].filter(
|
||||
t => t.challenge && t.challenge.id === challengeId,
|
||||
).length;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
},
|
||||
modalTitle () {
|
||||
if (this.isSingleTask) {
|
||||
return this.$t('brokenTask');
|
||||
}
|
||||
if (this.brokenType === 'CHALLENGE_CLOSED') {
|
||||
return this.$t('challengeCompleted');
|
||||
}
|
||||
return this.$t('brokenChallenge');
|
||||
},
|
||||
modalSubtitle () {
|
||||
if (this.isSingleTask) {
|
||||
return this.$t('brokenTaskDescription');
|
||||
}
|
||||
if (this.brokenType === 'CHALLENGE_CLOSED') {
|
||||
return this.$t('challengeCompletedDescription', { user: this.brokenChallengeTask.challenge?.winner });
|
||||
}
|
||||
return this.$t('brokenChallengeDescription');
|
||||
},
|
||||
keepButtonText () {
|
||||
if (this.isSingleTask) {
|
||||
return this.$t('keepIt');
|
||||
}
|
||||
return this.$t('keepTasks');
|
||||
},
|
||||
removeButtonText () {
|
||||
if (this.isSingleTask) {
|
||||
return this.$t('removeIt');
|
||||
}
|
||||
return this.$t('removeTasks');
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('handle-broken-task', task => {
|
||||
this.brokenChallengeTask = { ...task };
|
||||
@@ -99,8 +231,36 @@ export default {
|
||||
unlinkOneTask: 'tasks:unlinkOneTask',
|
||||
unlinkAllTasks: 'tasks:unlinkAllTasks',
|
||||
}),
|
||||
keepAction () {
|
||||
if (this.isSingleTask) {
|
||||
this.unlink('keep');
|
||||
} else {
|
||||
this.unlink('keep-all');
|
||||
}
|
||||
},
|
||||
async removeAction () {
|
||||
if (this.isSingleTask) {
|
||||
await this.removeTask();
|
||||
} else {
|
||||
await this.unlink('remove-all');
|
||||
}
|
||||
},
|
||||
async unlink (keepOption) {
|
||||
if (keepOption.indexOf('-all') !== -1) {
|
||||
if (keepOption === 'remove-all') {
|
||||
const count = this.brokenChallengeTaskCount;
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:delete-task-confirm', {
|
||||
title: count === 1 ? this.$t('deleteTask') : this.$t('deleteXTasks', { count }),
|
||||
description: this.$t('brokenChallengeTaskCount', { count }),
|
||||
message: this.$t('confirmDeleteTasks'),
|
||||
buttonText: count === 1 ? this.$t('deleteTask') : this.$t('deleteXTasks', { count }),
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
await this.unlinkAllTasks({
|
||||
challengeId: this.brokenChallengeTask.challenge.id,
|
||||
keep: keepOption,
|
||||
@@ -122,8 +282,14 @@ export default {
|
||||
});
|
||||
this.close();
|
||||
},
|
||||
removeTask () {
|
||||
if (!window.confirm('Are you sure you want to delete this task?')) return; // eslint-disable-line no-alert
|
||||
async removeTask () {
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:delete-task-confirm', {
|
||||
message: this.$t('sureDelete'),
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) return;
|
||||
this.destroyTask(this.brokenChallengeTask);
|
||||
this.close();
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
ref="tasksList"
|
||||
class="sortable-tasks"
|
||||
:disabled="activeFilter.label === 'scheduled' || !canBeDragged()"
|
||||
scrollSensitivity="64"
|
||||
scroll-sensitivity="64"
|
||||
:delay-on-touch-only="true"
|
||||
:delay="100"
|
||||
@update="taskSorted"
|
||||
@@ -348,7 +348,6 @@
|
||||
import throttle from 'lodash/throttle';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import draggable from 'vuedraggable';
|
||||
import { shouldDo } from '@/../../common/script/cron';
|
||||
import inAppRewards from '@/../../common/script/libs/inAppRewards';
|
||||
import taskDefaults from '@/../../common/script/libs/taskDefaults';
|
||||
import Task from './task';
|
||||
@@ -482,25 +481,10 @@ export default {
|
||||
return this.$t('addATask', { type });
|
||||
},
|
||||
badgeCount () {
|
||||
// 0 means the badge will not be shown
|
||||
// It is shown for the all and due views of dailies
|
||||
// and for the active and scheduled views of todos.
|
||||
if (this.type === 'todo' && this.activeFilter.label !== 'complete2') {
|
||||
return this.taskList.length;
|
||||
} if (this.type === 'daily') {
|
||||
if (this.activeFilter.label === 'due') {
|
||||
return this.taskList.length;
|
||||
} if (this.activeFilter.label === 'all') {
|
||||
return this.taskList
|
||||
.reduce(
|
||||
(count, t) => (!t.completed
|
||||
&& shouldDo(new Date(), t, this.getUserPreferences) ? count + 1 : count),
|
||||
0,
|
||||
);
|
||||
}
|
||||
if (this.type === 'reward') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return this.taskList.length;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="delete-task-confirm-modal"
|
||||
:hide-footer="true"
|
||||
:hide-header="true"
|
||||
modal-class="delete-confirm-modal"
|
||||
centered
|
||||
>
|
||||
<div class="modal-content-wrapper">
|
||||
<div class="top-bar"></div>
|
||||
<div class="modal-body-content">
|
||||
<div
|
||||
class="icon-wrapper"
|
||||
v-html="icons.alertIcon"
|
||||
></div>
|
||||
<h2 class="modal-title">
|
||||
{{ displayTitle }}
|
||||
</h2>
|
||||
<p
|
||||
v-if="description"
|
||||
class="modal-description"
|
||||
>
|
||||
{{ description }}
|
||||
</p>
|
||||
<p class="modal-subtitle">
|
||||
{{ confirmationMessage }}
|
||||
</p>
|
||||
<div class="button-wrapper">
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="confirm()"
|
||||
>
|
||||
{{ buttonText }}
|
||||
</button>
|
||||
<button
|
||||
class="btn-cancel"
|
||||
@click="cancel()"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import alertIcon from '@/assets/svg/for-css/alert.svg?raw';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
confirmationMessage: '',
|
||||
taskType: '',
|
||||
description: '',
|
||||
customTitle: '',
|
||||
customButtonText: '',
|
||||
resolveCallback: null,
|
||||
icons: Object.freeze({
|
||||
alertIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
displayTitle () {
|
||||
if (this.customTitle) return this.customTitle;
|
||||
return this.$t('deleteType', { type: this.taskType });
|
||||
},
|
||||
buttonText () {
|
||||
if (this.customButtonText) return this.customButtonText;
|
||||
return this.displayTitle;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:delete-task-confirm', config => {
|
||||
this.confirmationMessage = config.message;
|
||||
this.taskType = config.taskType || '';
|
||||
this.description = config.description || '';
|
||||
this.customTitle = config.title || '';
|
||||
this.customButtonText = config.buttonText || '';
|
||||
this.resolveCallback = config.resolve;
|
||||
this.$root.$emit('bv::show::modal', 'delete-task-confirm-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:delete-task-confirm');
|
||||
},
|
||||
methods: {
|
||||
confirm () {
|
||||
if (this.resolveCallback) {
|
||||
this.resolveCallback(true);
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
cancel () {
|
||||
if (this.resolveCallback) {
|
||||
this.resolveCallback(false);
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'delete-task-confirm-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
::v-deep .delete-confirm-modal {
|
||||
.modal-dialog {
|
||||
max-width: 330px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 8px;
|
||||
background-color: $maroon-100;
|
||||
}
|
||||
|
||||
.modal-body-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 24px 24px;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
margin-top: 40px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
::v-deep svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
path {
|
||||
fill: #DE3F3F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
color: $maroon-100;
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-description {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.modal-description + .modal-subtitle {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: none;
|
||||
border: none;
|
||||
color: $purple-300;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1177,9 +1177,16 @@ export default {
|
||||
moveToBottom () {
|
||||
this.$emit('moveTo', this.task, 'bottom');
|
||||
},
|
||||
destroy () {
|
||||
async destroy () {
|
||||
const type = this.$t(this.task.type);
|
||||
if (!window.confirm(this.$t('sureDeleteType', { type }))) return; // eslint-disable-line no-alert
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:delete-task-confirm', {
|
||||
message: this.$t('sureDeleteType', { type }),
|
||||
taskType: type,
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) return;
|
||||
this.destroyTask(this.task);
|
||||
this.$emit('taskDestroyed', this.task);
|
||||
},
|
||||
|
||||
@@ -150,14 +150,14 @@
|
||||
<button
|
||||
type="button"
|
||||
class="habit-option-container no-transition
|
||||
d-flex flex-column justify-content-center align-items-center"
|
||||
d-flex flex-column justify-content-center align-items-center"
|
||||
:class="!task.up ? cssClass('habit-control-disabled') : ''"
|
||||
:disabled="challengeAccessRequired"
|
||||
@click="toggleUpDirection()"
|
||||
>
|
||||
<div
|
||||
class="habit-option-button no-transition
|
||||
d-flex justify-content-center align-items-center mb-2"
|
||||
d-flex justify-content-center align-items-center mb-2"
|
||||
:class="task.up ? cssClass('bg') : ''"
|
||||
>
|
||||
<div
|
||||
@@ -176,14 +176,14 @@
|
||||
<button
|
||||
type="button"
|
||||
class="habit-option-container no-transition
|
||||
d-flex flex-column justify-content-center align-items-center"
|
||||
d-flex flex-column justify-content-center align-items-center"
|
||||
:class="!task.down ? cssClass('habit-control-disabled') : ''"
|
||||
:disabled="challengeAccessRequired"
|
||||
@click="toggleDownDirection()"
|
||||
>
|
||||
<div
|
||||
class="habit-option-button no-transition
|
||||
d-flex justify-content-center align-items-center mb-2"
|
||||
d-flex justify-content-center align-items-center mb-2"
|
||||
:class="task.down ? cssClass('bg') : ''"
|
||||
>
|
||||
<div
|
||||
@@ -382,6 +382,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showStatAssignment"
|
||||
class="stat-assignment option mt-3"
|
||||
>
|
||||
<div class="form-group row">
|
||||
<label
|
||||
v-once
|
||||
class="col-12 mb-1"
|
||||
>{{ $t('assignedStat') }}</label>
|
||||
<div class="col-12">
|
||||
<div class="stat-dropdown-container">
|
||||
<select-list
|
||||
:items="statOptions"
|
||||
:value="task.attribute"
|
||||
key-prop="key"
|
||||
active-key-prop="key"
|
||||
@select="task.attribute = $event.key"
|
||||
>
|
||||
<template #item="{ item, button }">
|
||||
<div class="stat-option-content">
|
||||
<span
|
||||
class="stat-option-title"
|
||||
:class="item.key"
|
||||
>
|
||||
{{ $t(item.label) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="!button"
|
||||
class="stat-option-description"
|
||||
>
|
||||
{{ $t(item.description) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</select-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="task.type === 'habit' && !groupId"
|
||||
class="option mt-3"
|
||||
@@ -591,7 +630,7 @@
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary btn-footer
|
||||
d-flex align-items-center justify-content-center"
|
||||
d-flex align-items-center justify-content-center"
|
||||
:class="{'btn-disabled': !canSave}"
|
||||
type="button"
|
||||
@click="submit()"
|
||||
@@ -911,6 +950,87 @@
|
||||
.streak-addon path {
|
||||
fill: $gray-200;
|
||||
}
|
||||
|
||||
.stat-dropdown-container {
|
||||
.select-list {
|
||||
.selectListItem {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.selectListItem .dropdown-item {
|
||||
padding: 8px 16px !important;
|
||||
height: auto !important;
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: rgba($purple-600, 0.25) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.stat-option-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.stat-option-title {
|
||||
font-weight: normal;
|
||||
color: $gray-50;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stat-option-content {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
.stat-option-title {
|
||||
display: block;
|
||||
font-family: Roboto;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
line-height: 1.71;
|
||||
text-transform: capitalize;
|
||||
margin-bottom: 4px;
|
||||
|
||||
&.str {
|
||||
color: $maroon-100;
|
||||
}
|
||||
|
||||
&.int {
|
||||
color: $blue-50;
|
||||
}
|
||||
|
||||
&.con {
|
||||
color: $yellow-5;
|
||||
}
|
||||
|
||||
&.per {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-option-description {
|
||||
display: block;
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: $gray-100;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -1023,7 +1143,6 @@
|
||||
.input-group-outer.disabled .input-group-text {
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -1038,6 +1157,7 @@ import SelectMulti from './modal-controls/selectMulti';
|
||||
import selectDifficulty from '@/components/tasks/modal-controls/selectDifficulty';
|
||||
import selectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||
import lockableLabel from '@/components/tasks/modal-controls/lockableLabel';
|
||||
import selectList from '@/components/ui/selectList';
|
||||
|
||||
import syncTask from '../../mixins/syncTask';
|
||||
|
||||
@@ -1061,6 +1181,7 @@ export default {
|
||||
selectTranslatedArray,
|
||||
toggleCheckbox,
|
||||
lockableLabel,
|
||||
selectList,
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
@@ -1094,6 +1215,12 @@ export default {
|
||||
con: 'constitution',
|
||||
per: 'perception',
|
||||
},
|
||||
statOptions: [
|
||||
{ key: 'str', label: 'strength', description: 'strTaskText' },
|
||||
{ key: 'int', label: 'intelligence', description: 'intTaskText' },
|
||||
{ key: 'con', label: 'constitution', description: 'conTaskText' },
|
||||
{ key: 'per', label: 'perception', description: 'perTaskText' },
|
||||
],
|
||||
calendarHighlights: { dates: [new Date()] },
|
||||
};
|
||||
},
|
||||
@@ -1187,6 +1314,12 @@ export default {
|
||||
selectedTags () {
|
||||
return this.getTagsFor(this.task);
|
||||
},
|
||||
showStatAssignment () {
|
||||
return this.task.type !== 'reward'
|
||||
&& !this.groupId
|
||||
&& this.user.preferences.automaticAllocation === true
|
||||
&& this.user.preferences.allocationMode === 'taskbased';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
task () {
|
||||
@@ -1305,9 +1438,16 @@ export default {
|
||||
}
|
||||
this.$root.$emit('bv::hide::modal', 'task-modal');
|
||||
},
|
||||
destroy () {
|
||||
async destroy () {
|
||||
const type = this.$t(this.task.type);
|
||||
if (!window.confirm(this.$t('sureDeleteType', { type }))) return; // eslint-disable-line no-alert
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:delete-task-confirm', {
|
||||
message: this.$t('sureDeleteType', { type }),
|
||||
taskType: type,
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) return;
|
||||
this.destroyTask(this.task);
|
||||
this.$emit('taskDestroyed', this.task);
|
||||
this.$root.$emit('bv::hide::modal', 'task-modal');
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
.badge-pin {
|
||||
background-color: $white;
|
||||
color: $gray-200;
|
||||
color: $gray-100;
|
||||
transition: none;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
@@ -32,8 +32,8 @@
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<template #button-content>
|
||||
<slot
|
||||
name="item"
|
||||
:item="selected || placeholder"
|
||||
:item="selectedItem || placeholder"
|
||||
:button="true"
|
||||
>
|
||||
<!-- Fallback content -->
|
||||
@@ -134,6 +134,14 @@ export default {
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
selectedItem () {
|
||||
if (this.activeKeyProp) {
|
||||
return this.items.find(item => item[this.activeKeyProp] === this.selected);
|
||||
}
|
||||
return this.items.find(item => item === this.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getKeyProp (item) {
|
||||
return this.keyProp ? item[this.keyProp] : item.key || item.identifier;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
type="checkbox"
|
||||
:checked="isChecked"
|
||||
:value="value"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
@change="handleChange"
|
||||
>
|
||||
<label
|
||||
class="toggle-switch-label"
|
||||
|
||||
@@ -1340,7 +1340,7 @@ export default {
|
||||
},
|
||||
|
||||
openAdminPanel () {
|
||||
this.$router.push(`/admin-panel/${this.hero._id}`);
|
||||
this.$router.push(`/admin/panel/${this.hero._id}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,15 @@ export default {
|
||||
};
|
||||
|
||||
const purchaseForKey = currencyToPurchaseForKey[currency];
|
||||
return window.confirm(this.$t(purchaseForKey, { cost })); // eslint-disable-line no-alert
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.$root.$emit('habitica:purchase-confirm', {
|
||||
message: this.$t(purchaseForKey, { cost }),
|
||||
currency,
|
||||
cost,
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -679,7 +679,7 @@ import NotificationMixins from '@/mixins/notifications';
|
||||
|
||||
// extract to a shared path
|
||||
const CONVERSATIONS_PER_PAGE = 10;
|
||||
const PM_PER_PAGE = 10;
|
||||
const PM_PER_PAGE = 50;
|
||||
|
||||
const UI_STATES = Object.freeze({
|
||||
LOADING: 'LOADING',
|
||||
|
||||
@@ -217,8 +217,18 @@ export default {
|
||||
}
|
||||
},
|
||||
async changeClassAndClose () {
|
||||
if (!this.classDisabled && !window.confirm(this.$t('changeClassConfirmCost'))) {
|
||||
return;
|
||||
if (!this.classDisabled) {
|
||||
const confirmed = await new Promise(resolve => {
|
||||
this.$root.$emit('habitica:purchase-confirm', {
|
||||
message: this.$t('changeClassConfirmCost'),
|
||||
currency: 'gems',
|
||||
cost: 3,
|
||||
resolve,
|
||||
});
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.$root.$once('bv::hide::modal', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<tr>
|
||||
<td colspan="3"
|
||||
<td
|
||||
v-if="!mixinData.inlineSettingMixin.modalVisible"
|
||||
colspan="3"
|
||||
>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h3
|
||||
@@ -18,8 +19,9 @@
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="3"
|
||||
<td
|
||||
v-if="mixinData.inlineSettingMixin.modalVisible"
|
||||
colspan="3"
|
||||
>
|
||||
<h3
|
||||
v-once
|
||||
@@ -59,8 +61,8 @@
|
||||
{{ $t('performanceAnalytics') }}
|
||||
</label>
|
||||
<toggle-switch
|
||||
class="mb-auto"
|
||||
v-model="user.preferences.analyticsConsent"
|
||||
class="mb-auto"
|
||||
@change="prefToggled()"
|
||||
/>
|
||||
</div>
|
||||
@@ -151,14 +153,14 @@ import { mapState } from '@/libs/store';
|
||||
import alert from '@/assets/svg/for-css/alert.svg?raw';
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
GenericUserPreferencesMixin,
|
||||
InlineSettingMixin,
|
||||
],
|
||||
components: {
|
||||
SaveCancelButtons,
|
||||
ToggleSwitch,
|
||||
},
|
||||
mixins: [
|
||||
GenericUserPreferencesMixin,
|
||||
InlineSettingMixin,
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
<bug-report-success-modal v-if="isUserLoaded" />
|
||||
<external-link-modal />
|
||||
<birthday-modal />
|
||||
<purchase-confirm-modal v-if="isUserLoaded" />
|
||||
<delete-task-confirm-modal v-if="isUserLoaded" />
|
||||
<template v-if="isUserLoaded">
|
||||
<privacy-banner />
|
||||
<chat-banner />
|
||||
@@ -138,6 +140,8 @@ import paymentsSuccessModal from '@/components/payments/successModal';
|
||||
import subCancelModalConfirm from '@/components/payments/cancelModalConfirm';
|
||||
import subCanceledModal from '@/components/payments/canceledModal';
|
||||
import externalLinkModal from '@/components/externalLinkModal.vue';
|
||||
import purchaseConfirmModal from '@/components/shops/purchaseConfirmModal.vue';
|
||||
import deleteTaskConfirmModal from '@/components/tasks/deleteTaskConfirmModal.vue';
|
||||
|
||||
import spellsMixin from '@/mixins/spells';
|
||||
import {
|
||||
@@ -172,6 +176,8 @@ export default {
|
||||
bugReportModal,
|
||||
bugReportSuccessModal,
|
||||
externalLinkModal,
|
||||
purchaseConfirmModal,
|
||||
deleteTaskConfirmModal,
|
||||
},
|
||||
mixins: [notifications, spellsMixin],
|
||||
data () {
|
||||
@@ -262,7 +268,6 @@ export default {
|
||||
this.$store.dispatch('user:fetch'),
|
||||
this.$store.dispatch('tasks:fetchUserTasks'),
|
||||
]).then(() => {
|
||||
this.$store.state.isUserLoaded = true;
|
||||
let analyticsConsent = localStorage.getItem('analyticsConsent');
|
||||
if (analyticsConsent !== null) {
|
||||
analyticsConsent = analyticsConsent === 'true';
|
||||
@@ -270,31 +275,11 @@ export default {
|
||||
this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent });
|
||||
}
|
||||
}
|
||||
if (window && window['habitica-i18n']) {
|
||||
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (window && window['habitica-i18n']) {
|
||||
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Analytics.updateUser();
|
||||
return axios.get(
|
||||
'/api/v4/i18n/browser-script',
|
||||
{
|
||||
language: this.user.preferences.language,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
Expires: '0',
|
||||
},
|
||||
},
|
||||
);
|
||||
return this.loadAllTranslations();
|
||||
}).then(() => {
|
||||
const i18nData = window && window['habitica-i18n'];
|
||||
this.$loadLocale(i18nData);
|
||||
this.$store.state.isUserLoaded = true;
|
||||
this.hideLoadingScreen();
|
||||
|
||||
// Adjust the timezone offset
|
||||
@@ -374,6 +359,36 @@ export default {
|
||||
hideLoadingScreen () {
|
||||
this.loading = false;
|
||||
},
|
||||
async loadContentTranslations () {
|
||||
const contentTranslations = await axios.get(
|
||||
'/api/v4/i18n/content',
|
||||
{
|
||||
language: this.user.preferences.language,
|
||||
},
|
||||
);
|
||||
const i18nData = window && window['habitica-i18n'];
|
||||
i18nData.strings = { ...i18nData.strings, ...contentTranslations.data };
|
||||
this.$loadLocale(i18nData);
|
||||
},
|
||||
async loadAllTranslations () {
|
||||
if (window && window['habitica-i18n']) {
|
||||
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
|
||||
return this.loadContentTranslations();
|
||||
}
|
||||
}
|
||||
await axios.get(
|
||||
'/api/v4/i18n/core',
|
||||
{
|
||||
language: this.user.preferences.language,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
Expires: '0',
|
||||
},
|
||||
},
|
||||
);
|
||||
return this.loadContentTranslations();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -11,7 +11,6 @@ import { DEPRECATED_ROUTES } from '@/router/deprecated-routes';
|
||||
|
||||
// NOTE: when adding a page make sure to implement the `common:setTitle` action
|
||||
|
||||
const RegisterLoginReset = () => import(/* webpackChunkName: "auth" */'@/components/auth/registerLoginReset');
|
||||
const Logout = () => import(/* webpackChunkName: "auth" */'@/components/auth/logout');
|
||||
|
||||
// Hall
|
||||
@@ -79,11 +78,6 @@ const router = new VueRouter({
|
||||
// in the route component to set a specific subtitle for the page.
|
||||
routes: [
|
||||
{ name: 'logout', path: '/logout', component: Logout },
|
||||
{
|
||||
name: 'resetPassword', path: '/reset-password', component: RegisterLoginReset, meta: { requiresLogin: false },
|
||||
}, {
|
||||
name: 'forgotPassword', path: '/forgot-password', component: RegisterLoginReset, meta: { requiresLogin: false },
|
||||
},
|
||||
{ name: 'tasks', path: '/', component: UserTasks },
|
||||
{
|
||||
name: 'userProfile',
|
||||
|
||||
@@ -57,6 +57,9 @@ export const STATIC_ROUTES = {
|
||||
{
|
||||
name: 'features', path: 'features', component: FeaturesPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'forgotPassword', path: '/forgot-password', component: RegisterLoginReset, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'front', path: 'front', component: HomePage, meta: { requiresLogin: false },
|
||||
},
|
||||
@@ -90,6 +93,9 @@ export const STATIC_ROUTES = {
|
||||
{
|
||||
name: 'register', path: '/register', component: RegisterLoginReset, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'resetPassword', path: '/reset-password', component: RegisterLoginReset, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'terms', path: 'terms', component: TermsPage, meta: { requiresLogin: false },
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import Vue from 'vue';
|
||||
import * as Analytics from '@/libs/analytics';
|
||||
|
||||
export async function getChat (store, payload) {
|
||||
const response = await axios.get(`/api/v4/groups/${payload.groupId}/chat`);
|
||||
const response = await axios.get(`/api/v4/groups/${payload.groupId}/chat?limit=400`);
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
"challenge": "Предизвикателство",
|
||||
"challengeDetails": "Предизвикателствата са обществени събития, в които играчите се състезават и печелят награди като изпълняват няколко свързани по някакъв начин задачи.",
|
||||
"brokenChaLink": "Повредена връзка на предизвикателство",
|
||||
"brokenTask": "Повредена връзка на предизвикателство: тази задача е била част от предизвикателство, но е била премахната от него. Какво бихте искали да направите?",
|
||||
"keepIt": "Запазване",
|
||||
"removeIt": "Премахване",
|
||||
"brokenChallenge": "Повредена връзка на предизвикателство: тази задача е била част от предизвикателство, но то (или групата) е било изтрито. Какво бихте искали да направите с останалите задачи?",
|
||||
"challengeCompleted": "Това предизвикателство е приключило и победителят е <span class=\"badge\"><%- user %></span>! Какво искате да направите с останалите задачи?",
|
||||
"challengeCompleted": "Това предизвикателство е приключило и победителят е <span class=\"badge\"><%= user %></span>! Какво искате да направите с останалите задачи?",
|
||||
"unsubChallenge": "Повредена връзка на предизвикателство: тази задача е била част от предизвикателство, но Вие сте се отписали от него. Какво искате да направите с останалите задачи?",
|
||||
"challenges": "Предизвикателства",
|
||||
"endDate": "Крайна дата",
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"questEggVelociraptorText": "Велоцираптор",
|
||||
"questEggVelociraptorMountText": "Велоцираптор",
|
||||
"questEggVelociraptorAdjective": "умен",
|
||||
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective %> <%= eggText %>.",
|
||||
"hatchingPotionBase": "Нормален цвят",
|
||||
"hatchingPotionWhite": "Бял цвят",
|
||||
"hatchingPotionDesert": "Пустинен цвят",
|
||||
@@ -211,7 +211,7 @@
|
||||
"hatchingPotionGlow": "Светещо в тъмното",
|
||||
"hatchingPotionFrost": "Скреж",
|
||||
"hatchingPotionIcySnow": "Леден сняг",
|
||||
"hatchingPotionNotes": "Излейте това върху яйце и от него ще се излюпи любимец с(ъс) <%= potText(locale) %>.",
|
||||
"hatchingPotionNotes": "Излейте това върху яйце и от него ще се излюпи любимец с(ъс) <%= potText %>.",
|
||||
"foodMeat": "Месо",
|
||||
"foodMeatThe": "Месото",
|
||||
"foodMeatA": "Месо",
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
"messages": "Съобщения",
|
||||
"emptyMessagesLine1": "Нямате съобщения",
|
||||
"emptyMessagesLine2": "Можете да изпратите ново съобщение на потребител, като посетите профила им и докоснете бутона \"Съобщение\".",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> Ви изпрати съобщение",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%= user %></span> Ви изпрати съобщение",
|
||||
"letsgo": "Хойде!",
|
||||
"selected": "Избрано",
|
||||
"howManyToBuy": "Колко искате да купите?",
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"userId": "Потребителски идентификатор",
|
||||
"invite": "Покана",
|
||||
"leave": "Напускане",
|
||||
"invitedToParty": "Получихте покана за присъединяване към групата <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPrivateGuild": "Получихте покана за присъединяване към частната гилдия <span class=\"notification-bold\"><%- guild %></span>",
|
||||
"invitedToPublicGuild": "Получихте покана за присъединяване към гилдията <span class=\"notification-bold-blue\"><%- guild %></span>",
|
||||
"invitedToParty": "Получихте покана за присъединяване към групата <span class=\"notification-bold\"><%= party %></span>",
|
||||
"invitedToPrivateGuild": "Получихте покана за присъединяване към частната гилдия <span class=\"notification-bold\"><%= guild %></span>",
|
||||
"invitedToPublicGuild": "Получихте покана за присъединяване към гилдията <span class=\"notification-bold-blue\"><%= guild %></span>",
|
||||
"invitationAcceptedHeader": "Поканата Ви беше приета",
|
||||
"invitationAcceptedBody": "<%= username %> прие поканата Ви да се присъедини към <%= groupName %>!",
|
||||
"systemMessage": "Системно съобщение",
|
||||
"newMsgGuild": "Има нови публикации в <span class=\"notification-bold-blue\"><%- name %></span>",
|
||||
"newMsgParty": "Има нови публикации в групата Ви — <span class=\"notification-bold-blue\"><%- name %></span>",
|
||||
"newMsgGuild": "Има нови публикации в <span class=\"notification-bold-blue\"><%= name %></span>",
|
||||
"newMsgParty": "Има нови публикации в групата Ви — <span class=\"notification-bold-blue\"><%= name %></span>",
|
||||
"chat": "Съобщения",
|
||||
"sendChat": "Изпращане на съобщението",
|
||||
"group": "Група",
|
||||
@@ -151,14 +151,14 @@
|
||||
"onlyGroupLeaderCanEditTasks": "Нямате право да управлявате задачите!",
|
||||
"onlyGroupTasksCanBeAssigned": "Само групови задачи могат да бъдат зададени",
|
||||
"assignedTo": "Назначена на",
|
||||
"assignedToUser": "Назначена на <strong><%- userName %></strong>",
|
||||
"assignedToUser": "Назначена на <strong><%= userName %></strong>",
|
||||
"assignedToMembers": "Назначена на <strong><%= userCount %> членове </strong>",
|
||||
"assignedToYouAndMembers": "Назначена на Вас и още <strong><%= userCount %> членове</strong>",
|
||||
"youAreAssigned": "Тази задача е назначена на Вас",
|
||||
"taskIsUnassigned": "Тази задача не е зададена на никого",
|
||||
"confirmUnClaim": "Наистина ли искате да оставите тази задача?",
|
||||
"confirmNeedsWork": "Наистина ли искате да отбележите, че тази задача се нуждае от още работа?",
|
||||
"userRequestsApproval": "<strong><%- userName %></strong> иска одобрение",
|
||||
"userRequestsApproval": "<strong><%= userName %></strong> иска одобрение",
|
||||
"userCountRequestsApproval": "<strong><%= userCount %> членове</strong> искат одобрение",
|
||||
"youAreRequestingApproval": "Вие искате одобрение",
|
||||
"chatPrivilegesRevoked": "Не можете да направите това, защото привилегиите Ви в чата са Ви били отнети. За детайли или запитване за връшане на привилегии, моля пратете email на нашия Обществен Оправител на admin@habitica.com или попитайте вашия родител или настойник да им прати email. Моля, напишете и потребителското си име в писмото. Ако модератор вече ви е казал че блокирането ви към чата е временно, няма нужда да пращате email.",
|
||||
@@ -168,9 +168,9 @@
|
||||
"claim": "Вземане на Задача",
|
||||
"removeClaim": "Отказване от задачата",
|
||||
"onlyGroupLeaderCanManageSubscription": "Само водачът на групата може да управлява абонамента ѝ",
|
||||
"yourTaskHasBeenApproved": "Задачата Ви <span class=\"notification-green notification-bold\"><%- taskText %></span>, беше одобрена.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%- managerName %></span> отбеляза, че задачата <span class=\"notification-bold\"><%- taskText %></span> се нуждае от още работа.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%- user %></span> помоли следната задача да бъде одобрена: <span class=\"notification-bold\"><%- taskName %></span>",
|
||||
"yourTaskHasBeenApproved": "Задачата Ви <span class=\"notification-green notification-bold\"><%= taskText %></span>, беше одобрена.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> отбеляза, че задачата <span class=\"notification-bold\"><%= taskText %></span> се нуждае от още работа.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%= user %></span> помоли следната задача да бъде одобрена: <span class=\"notification-bold\"><%= taskName %></span>",
|
||||
"approve": "Одобряване",
|
||||
"approveTask": "Одобряване на задачата",
|
||||
"needsWork": "Нуждае се от още работа",
|
||||
@@ -183,8 +183,8 @@
|
||||
"userIsClamingTask": "`<%= username %> пое:` <%= task %>",
|
||||
"approvalRequested": "Заявено е одобрение",
|
||||
"cantDeleteAssignedGroupTasks": "Не можете да изтриете груповите задачи, които са Ви разпределени.",
|
||||
"groupPlanUpgraded": "<strong><%- groupName %></strong> премина към групов план!",
|
||||
"groupPlanCreated": "Групата <strong><%- groupName %></strong> беше създадена!",
|
||||
"groupPlanUpgraded": "<strong><%= groupName %></strong> премина към групов план!",
|
||||
"groupPlanCreated": "Групата <strong><%= groupName %></strong> беше създадена!",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Само водачът на групата може да кани хора в група с абонамент.",
|
||||
"paymentDetails": "Подробности за разплащането",
|
||||
"aboutToJoinCancelledGroupPlan": "На път сте да се присъедините към група, чийто план е прекратен. НЯМА да получите безплатен абонамент.",
|
||||
@@ -325,8 +325,8 @@
|
||||
"PMDisabled": "Деактивиране на лични съобщения",
|
||||
"groupActivityNotificationTitle": "<%= user %> публикува в <%= group %>",
|
||||
"suggestedGroup": "Предложено, защото сте нови в Habitica.",
|
||||
"taskClaimed": "<%- userName %> взеха задачата <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"youHaveBeenAssignedTask": "<%- managerName %> ви присвои задачата <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"taskClaimed": "<%= userName %> взеха задачата <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"youHaveBeenAssignedTask": "<%= managerName %> ви присвои задачата <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"userWithUsernameOrUserIdNotFound": "Потребителското име или Потребителският Идентификатор не бяха намерени.",
|
||||
"usernameOrUserId": "Потребителско име или Потребителски Идентификатор",
|
||||
"sendGiftToWhom": "На кой бихте искали да пратите подарък?",
|
||||
|
||||
@@ -82,13 +82,12 @@
|
||||
"paymentMethods": "Купуване чрез",
|
||||
"paymentSuccessful": "Плащането Ви беше успешно!",
|
||||
"paymentYouReceived": "Получихте:",
|
||||
"paymentYouSentGems": "Изпратихте на <strong><%- name %></strong>:",
|
||||
"paymentYouSentSubscription": "Изпратихте на <strong><%- name %></strong> <%= months %>-месечен абонамент за Хабитика.",
|
||||
"paymentYouSentGems": "Изпратихте на <strong><%= name %></strong>:",
|
||||
"paymentYouSentSubscription": "Изпратихте на <strong><%= name %></strong> <%= months %>-месечен абонамент за Хабитика.",
|
||||
"paymentSubBilling": "Абонаментът Ви ще бъде таксуван с <strong>$<%= amount %></strong> всеки <strong><%= months %> месеца</strong>.",
|
||||
"success": "Готово!",
|
||||
"classGear": "Снаряжение за класа",
|
||||
"classGearText": "Поздравления за избора на клас! Добавих новата Ви основна екипировка в инвентара Ви. Погледнете по-долу, за да я екипирате!",
|
||||
"autoAllocate": "Автоматично разпределяне",
|
||||
"spells": "Умения",
|
||||
"skillsTitle": "Умения",
|
||||
"toDo": "Задача",
|
||||
|
||||
@@ -66,8 +66,8 @@
|
||||
"mountNotOwned": "Не притежавате този прево.",
|
||||
"feedPet": "Искате ли да дадете <%= text %> на <%= name %>?",
|
||||
"raisedPet": "Вие отгледахте <%= pet %>!",
|
||||
"petName": "<%= egg(locale) %> с(ъс) <%= potion(locale) %>",
|
||||
"mountName": "<%= mount(locale) %> с(ъс) <%= potion(locale) %>",
|
||||
"petName": "<%= egg %> с(ъс) <%= potion %>",
|
||||
"mountName": "<%= mount %> с(ъс) <%= potion %>",
|
||||
"keyToPets": "Ключ от зверилника за любимци",
|
||||
"keyToPetsDesc": "Освобождаване на всички стандартни любимци, за да можете да ги съберете отново. (Това не засяга любимците от мисии и редките любимци.)",
|
||||
"keyToMounts": "Ключ от зверилника за превози",
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
"challenge": "Výzva",
|
||||
"challengeDetails": "Výzvy jsou komunitní události, ve kterých hráči soutěží a získávají odměny za plnění úkolů.",
|
||||
"brokenChaLink": "Nefunkční odkaz na výzvu",
|
||||
"brokenTask": "Nefunkční odkaz na výzvu: tento úkol byl součástí výzvy, ale byl z ní odstraněn. Co chceš dělat?",
|
||||
"keepIt": "Ponechat",
|
||||
"removeIt": "Odstranit",
|
||||
"brokenChallenge": "Nefunkční odkaz na výzvu: tento úkol byl součástí výzvy, ale ta (nebo skupina, která ji vytvořila) byla odstraněna. Co chceš dělat s osiřelými úkoly?",
|
||||
"challengeCompleted": "Výzva byla ukončena a vítězem se stal <span class=\"badge\"><%- user %></span>! Co chceš dělat s osiřelými úkoly?",
|
||||
"challengeCompleted": "Výzva byla ukončena a vítězem se stal <span class=\"badge\"><%= user %></span>! Co chceš dělat s osiřelými úkoly?",
|
||||
"unsubChallenge": "Nefunkční odkaz na výzvu: tento úkol byl součástí výzvy, ze které jsi se odhlásil/a. Co chceš dělat s osiřelými úkoly?",
|
||||
"challenges": "Výzvy",
|
||||
"endDate": "Končí",
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"questEggVelociraptorText": "Velociraptor",
|
||||
"questEggVelociraptorMountText": "Velociraptor",
|
||||
"questEggVelociraptorAdjective": "chytrý",
|
||||
"eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a to se vylíhne v <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a to se vylíhne v <%= eggAdjective %> <%= eggText %>.",
|
||||
"hatchingPotionBase": "Základní",
|
||||
"hatchingPotionWhite": "Bílý",
|
||||
"hatchingPotionDesert": "Pouštní",
|
||||
@@ -211,7 +211,7 @@
|
||||
"hatchingPotionGlow": "Ve tmě svítící",
|
||||
"hatchingPotionFrost": "Zmrzlý",
|
||||
"hatchingPotionIcySnow": "Ledově Sněhový",
|
||||
"hatchingPotionNotes": "Nalij ho na vejce a vylíhne se ti <%= potText(locale) %> mazlíček.",
|
||||
"hatchingPotionNotes": "Nalij ho na vejce a vylíhne se ti <%= potText %> mazlíček.",
|
||||
"foodMeat": "Maso",
|
||||
"foodMeatThe": "Maso",
|
||||
"foodMeatA": "Maso",
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
"messages": "Zprávy",
|
||||
"emptyMessagesLine1": "Nemáš žádné zprávy",
|
||||
"emptyMessagesLine2": "Novou zprávu uživateli/Česku můžeš poslat tak, že navštívíš jeho/její profil a klikneš na tlačítko “Zprávy”.",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> ti poslal/a zprávu",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%= user %></span> ti poslal/a zprávu",
|
||||
"letsgo": "Pojďmě!",
|
||||
"selected": "Vybrané",
|
||||
"howManyToBuy": "Kolik by jsi chtěl koupit?",
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"userId": "Uživatelské ID",
|
||||
"invite": "Pozvat",
|
||||
"leave": "Odejít",
|
||||
"invitedToParty": "Byl jsi pozván do družiny <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPrivateGuild": "Byl jsi pozván do soukromého cechu <span class=\"notification-bold\"><%- guild %></span>",
|
||||
"invitedToPublicGuild": "Byl jsi pozván do cechu <span class=\"notification-bold-blue\"><%- guild %></span>",
|
||||
"invitedToParty": "Byl jsi pozván do družiny <span class=\"notification-bold\"><%= party %></span>",
|
||||
"invitedToPrivateGuild": "Byl jsi pozván do soukromého cechu <span class=\"notification-bold\"><%= guild %></span>",
|
||||
"invitedToPublicGuild": "Byl jsi pozván do cechu <span class=\"notification-bold-blue\"><%= guild %></span>",
|
||||
"invitationAcceptedHeader": "Tvá pozvánka byla přijata",
|
||||
"invitationAcceptedBody": "<%= username %> přijal tvoji pozvánku do <%= groupName %>!",
|
||||
"systemMessage": "Systémová zpráva",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%- name %></span> má nový příspěvek",
|
||||
"newMsgParty": "Tvá družina, <span class=\"notification-bold-blue\"><%- name %></span>, má nový příspěvek",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%= name %></span> má nový příspěvek",
|
||||
"newMsgParty": "Tvá družina, <span class=\"notification-bold-blue\"><%= name %></span>, má nový příspěvek",
|
||||
"chat": "Chat",
|
||||
"sendChat": "Poslat zprávu",
|
||||
"group": "Skupina",
|
||||
@@ -151,14 +151,14 @@
|
||||
"onlyGroupLeaderCanEditTasks": "Not authorized to manage tasks!",
|
||||
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
||||
"assignedTo": "Přiřadit k",
|
||||
"assignedToUser": "Přiřazeno <strong><%- userName %></strong>",
|
||||
"assignedToUser": "Přiřazeno <strong><%= userName %></strong>",
|
||||
"assignedToMembers": "Přiřazeno <strong><%= userCount %> members</strong>",
|
||||
"assignedToYouAndMembers": "Přiřazeno vám a <strong><%= userCount %> members</strong>",
|
||||
"youAreAssigned": "Jsi přiřazen/a k tomuto úkolu",
|
||||
"taskIsUnassigned": "This task is unassigned",
|
||||
"confirmUnClaim": "Are you sure you want to unclaim this task?",
|
||||
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
|
||||
"userRequestsApproval": "<strong><%- userName %></strong> požaduje schválení",
|
||||
"userRequestsApproval": "<strong><%= userName %></strong> požaduje schválení",
|
||||
"userCountRequestsApproval": "<strong><%= userCount %> members</strong> požadují schválení",
|
||||
"youAreRequestingApproval": "You are requesting approval",
|
||||
"chatPrivilegesRevoked": "Toto nelze provést, protože vaše oprávnění k chatu byla odstraněna. Chcete-li získat další informace nebo se zeptat, zda lze vaše oprávnění vrátit, pošlete e-mail našemu komunitnímu manažerovi na adrese admin@habitica.com nebo požádejte svého rodiče nebo zákonného zástupce o zaslání e-mailu. Do e-mailu uveďte prosím své @uživatelskéjméno. Pokud vám moderátor již řekl, že váš zákaz chatu je dočasný, nemusíte posílat e-maily.",
|
||||
@@ -168,9 +168,9 @@
|
||||
"claim": "Nárokovat úkol",
|
||||
"removeClaim": "Remove Claim",
|
||||
"onlyGroupLeaderCanManageSubscription": "Only the group leader can manage the group's subscription",
|
||||
"yourTaskHasBeenApproved": "Váš úkol <span class=\"notification-green notification-bold\"><%- taskText %></span> byl schválený.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%- managerName %></span> marked <span class=\"notification-bold\"><%- taskText %></span> as needing additional work.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%- user %></span> requests approval for <span class=\"notification-bold\"><%- taskName %></span>",
|
||||
"yourTaskHasBeenApproved": "Váš úkol <span class=\"notification-green notification-bold\"><%= taskText %></span> byl schválený.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> marked <span class=\"notification-bold\"><%= taskText %></span> as needing additional work.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%= user %></span> requests approval for <span class=\"notification-bold\"><%= taskName %></span>",
|
||||
"approve": "Approve",
|
||||
"approveTask": "Approve Task",
|
||||
"needsWork": "Needs Work",
|
||||
@@ -183,8 +183,8 @@
|
||||
"userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
|
||||
"approvalRequested": "Approval Requested",
|
||||
"cantDeleteAssignedGroupTasks": "Can't delete group tasks that are assigned to you.",
|
||||
"groupPlanUpgraded": "<strong><%- groupName %></strong> was upgraded to a Group Plan!",
|
||||
"groupPlanCreated": "<strong><%- groupName %></strong> was created!",
|
||||
"groupPlanUpgraded": "<strong><%= groupName %></strong> was upgraded to a Group Plan!",
|
||||
"groupPlanCreated": "<strong><%= groupName %></strong> was created!",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.",
|
||||
"paymentDetails": "Payment Details",
|
||||
"aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.",
|
||||
@@ -321,8 +321,8 @@
|
||||
"allAssignedCompletion": "All - Completes when all assigned users finish",
|
||||
"groupActivityNotificationTitle": "<%= user %> publikoval v <%= group %>",
|
||||
"suggestedGroup": "Navrženo, protože jste v Habitica nový/á.",
|
||||
"taskClaimed": "<%- userName %> nárokoval úkol <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"youHaveBeenAssignedTask": "<%- managerName %> vám přidělil úkol <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"taskClaimed": "<%= userName %> nárokoval úkol <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"youHaveBeenAssignedTask": "<%= managerName %> vám přidělil úkol <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"pmReported": "Děkujeme za nahlášení této zprávy.",
|
||||
"newPartyPlaceholder": "Zadej jméno tvé družiny.",
|
||||
"userWithUsernameOrUserIdNotFound": "Uživatelské jméno nebo uživatelské ID nebylo nalezeno.",
|
||||
@@ -336,7 +336,7 @@
|
||||
"PMDisabled": "Zakaž soukromé zprávy",
|
||||
"unassigned": "Nepřiřazeno",
|
||||
"claimRewards": "Vyzvedni si odměnu",
|
||||
"assignedDateAndUser": "Přiřazeno uživatelem/kou <strong>@<%- username %></strong> dne <strong><%= date %></strong>",
|
||||
"assignedDateAndUser": "Přiřazeno uživatelem/kou <strong>@<%= username %></strong> dne <strong><%= date %></strong>",
|
||||
"assignedDateOnly": "Přiřazeno k <strong><%= date %></strong>",
|
||||
"managerNotes": "Poznámky manažera",
|
||||
"thisTaskApproved": "Tento úkol byl schválen",
|
||||
|
||||
@@ -82,13 +82,12 @@
|
||||
"paymentMethods": "Platební metody",
|
||||
"paymentSuccessful": "Tvá platba proběhla úspěšně!",
|
||||
"paymentYouReceived": "Obdržel jsi:",
|
||||
"paymentYouSentGems": "Poslal/a jsi <strong><%- name %></strong>:",
|
||||
"paymentYouSentSubscription": "Poslal/a jsi <strong><%- name %></strong> předplatné na <%= months %>-měsíce/ů v Habitica.",
|
||||
"paymentYouSentGems": "Poslal/a jsi <strong><%= name %></strong>:",
|
||||
"paymentYouSentSubscription": "Poslal/a jsi <strong><%= name %></strong> předplatné na <%= months %>-měsíce/ů v Habitica.",
|
||||
"paymentSubBilling": "Tvoje předplatné ve výši <strong>$<%= amount %></strong> bude účtovano každé/ých <strong><%= months %> měsíce/ů </strong>.",
|
||||
"success": "Úspěch!",
|
||||
"classGear": "Vybavení pro tvé povolání",
|
||||
"classGearText": "Gratuluji k vybrání povolání! Přidal jsem ti základní zbraň do tvého inventáře. Podívej se dolů a vybav se!",
|
||||
"autoAllocate": "Připisovat automaticky",
|
||||
"spells": "Dovednosti",
|
||||
"skillsTitle": "<%= classStr %> Dovednosti",
|
||||
"toDo": "úkol",
|
||||
|
||||
@@ -66,8 +66,8 @@
|
||||
"mountNotOwned": "Nevlastníš toto jezdecké zvíře.",
|
||||
"feedPet": "Dát <%= text %> svému <%= name %>?",
|
||||
"raisedPet": "Vychoval jsi svého <%= pet %>!",
|
||||
"petName": "<%= potion(locale) %> <%= egg(locale) %>",
|
||||
"mountName": "<%= potion(locale) %> <%= mount(locale) %>",
|
||||
"petName": "<%= potion %> <%= egg %>",
|
||||
"mountName": "<%= potion %> <%= mount %>",
|
||||
"keyToPets": "Klíč ke Kotcům Mazlíčků",
|
||||
"keyToPetsDesc": "Propusť všechny své běžné mazlíčky abys je mohl sbírat znovu. (Ti vzácní a z výprav tím nebudou ovlivněni.)",
|
||||
"keyToMounts": "Klíč ke Kotcům Zvířat",
|
||||
|
||||
@@ -121,7 +121,6 @@
|
||||
"yesterDailiesCallToAction": "Začít můj nový den!",
|
||||
"sessionOutdated": "Tvá relace je zastaralá. Prosím, zkus ji obnovit nebo synchronizovat.",
|
||||
"errorTemporaryItem": "Tento předmět je dočasný a nemůže být připnut.",
|
||||
"sureDeleteType": "Chceš tento <%= type %> opravdu smazat?",
|
||||
"deleteTaskType": "Tento <%= type %> smazat",
|
||||
"addNotes": "Přidej poznámky",
|
||||
"addATitle": "Přidej název",
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
"challenge": "Udfordring",
|
||||
"challengeDetails": "Udfordringer er fællesskabsevents, i hvilke spillere konkurrerer og vinder belønninger ved at fuldføre en gruppe relaterede opgaver.",
|
||||
"brokenChaLink": "Defekt udfordringslink",
|
||||
"brokenTask": "Defekt udfordringslink: denne opgave var en del af en udfordring, men er blevet fjernet fra den. Hvad vil du gøre?",
|
||||
"keepIt": "Behold den",
|
||||
"removeIt": "Fjern den",
|
||||
"brokenChallenge": "Defekt udfordringslink: denne opgave var en del af en udfordring, men udfordringen (eller gruppen) er blevet fjernet. Hvad vil du gøre med de gruppeløse opgaver?",
|
||||
"challengeCompleted": "Denne udfordring er afsluttet, og vinderen blev <span class=\"badge\"><%- user %></span>! Hvad vil du gøre med de gruppeløse opgaver?",
|
||||
"challengeCompleted": "Denne udfordring er afsluttet, og vinderen blev <span class=\"badge\"><%= user %></span>! Hvad vil du gøre med de gruppeløse opgaver?",
|
||||
"unsubChallenge": "Defekt Udfordringslink: denne opgave var en del af en udfordring, som du ikke længere abonnerer på. Hvad vil du gøre med de gruppeløse opgaver?",
|
||||
"challenges": "Udfordringer",
|
||||
"endDate": "Afsluttes",
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"allocatePerPop": "Tilføj et point til Opfattelse",
|
||||
"allocateInt": "Point tilføjet til Intelligens:",
|
||||
"allocateIntPop": "Tilføj et point til Intelligens",
|
||||
"noMoreAllocate": "Nu hvor du har nået niveau 100, vil du ikke optjene flere Egenskabspoint. Du kan fortsætte, eller starte et nyt eventyr fra niveau 1 ved at bruge <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Genfødselskuglen</a>!",
|
||||
"noMoreAllocate": "Nu hvor du har nået niveau 100, vil du ikke optjene flere Egenskabspoint. Du kan fortsætte, eller starte et nyt eventyr fra niveau 1 ved at bruge<a href='/shops/market'>Genfødselskugle</a>.",
|
||||
"stats": "Egenskaber",
|
||||
"strength": "Styrke",
|
||||
"strText": "Styrke forøger chancen for tilfældige \"fuldtræffere\" og giver et boost til Guld, Erfaring, og chancen for at finde genstande fra dem. Det hjælper også med at påføre bossmonstre skade.",
|
||||
@@ -183,5 +183,10 @@
|
||||
"chatCastSpellParty": "<%= username %> kaster <%= spell %> for holdet.",
|
||||
"notEnoughGold": "Ikke nok guld.",
|
||||
"purchasePetItemConfirm": "Dette køb vil overskride det antal genstande du skal bruge for at klække alle mulige <%= itemText %> Kæledyr. Er du sikker?",
|
||||
"purchaseForGold": "Køb for <%= cost %> Guld?"
|
||||
"purchaseForGold": "Køb for <%= cost %> Guld?",
|
||||
"skins": "Hudfarve",
|
||||
"titleFacialHair": "Ansigts hår",
|
||||
"titleHaircolor": "Hårfarve",
|
||||
"titleHairbase": "Hår stil",
|
||||
"strTaskText": "Øg chancen for fuldtræffer slag og skade ved at færdiggøre opgaver. Dette øger også skade mod missions monstrene."
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"questEggVelociraptorText": "Velociraptor",
|
||||
"questEggVelociraptorMountText": "Velociraptor",
|
||||
"questEggVelociraptorAdjective": "en vaks",
|
||||
"eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective %> <%= eggText %>.",
|
||||
"hatchingPotionBase": "Almindelig",
|
||||
"hatchingPotionWhite": "Hvid",
|
||||
"hatchingPotionDesert": "Ørken",
|
||||
@@ -211,7 +211,7 @@
|
||||
"hatchingPotionGlow": "Selvlysende",
|
||||
"hatchingPotionFrost": "Frost",
|
||||
"hatchingPotionIcySnow": "Isnende sne",
|
||||
"hatchingPotionNotes": "Hæld denne over et æg, og det vil udklækkes til et <%= potText(locale) %> kæledyr.",
|
||||
"hatchingPotionNotes": "Hæld denne over et æg, og det vil udklækkes til et <%= potText %> kæledyr.",
|
||||
"foodMeat": "Kød",
|
||||
"foodMeatThe": "Kødet",
|
||||
"foodMeatA": "Kød",
|
||||
|
||||
@@ -13,5 +13,16 @@
|
||||
"faqQuestion28": "Kan jeg sætte mine Daglige på pause, hvis jeg har brug for en pause?",
|
||||
"webFaqAnswer28": "Ja! Knappen \"Pause Damage\" kan findes i Indstillinger. Det vil forhindre dig i at miste HP for mistede Daglige. Dette er nyttigt, hvis du er på ferie, har brug for et hvil, eller du af en eller anden grund måske har brug for en pause. Hvis du deltager i en Quest, vil dine egne afventende fremskridt blive sat på pause, men du vil stadig tage skade fra dit partimedlems missede Daglige.\n\nFor at sætte specifikke Daglige på pause, kan du redigere tidsplanen, så den forfalder hver 0. dag, indtil du er klar til at genstarte den.",
|
||||
"faqQuestion29": "Hvordan gendanner jeg HP?",
|
||||
"webFaqAnswer29": "Du kan genvinde 15 HP ved at købe en Health Potion fra din belønningskolonne for 25 guld. Derudover vil du altid genvinde fuld HP, når du stiger i niveau!"
|
||||
"webFaqAnswer29": "Du kan genvinde 15 HP ved at købe en Health Potion fra din belønningskolonne for 25 guld. Derudover vil du altid genvinde fuld HP, når du stiger i niveau!",
|
||||
"webFaqAnswer34": "Dyr kan lide mad som matcher deres farve, med undtagelse af basis dyr som alle kan lide det samme mad, uanset farve. Du kan se hvilken specifik mad de forskellige dyr kan lide, herunder: \n\n * Basis dyr kan lide kød\n * Hvide dyr kan lide mælk\n * Ørken dyr kan lide kartofler\n * Røde dyr kan lide jordbær\n * Skygge dyr kan lide chokolade\n * Skelet dyr kan lide fisk\n * Zombie dyr kan lide kød\n * Lyserøde candyfloss dyr kan lide lyserød candyfloss\n * Blå candyfloss dyr kan lide blå candyfloss\n * Gyldne dyr kan lide honning",
|
||||
"faqQuestion30": "Hvad sker der når jeg løber tør for SP?",
|
||||
"webFaqAnswer30": "Hvis din SP når ned på nul, mister du et level - det levels egenskabspoint, alt dit guld, og et stykke udstyr som kan købes igen. Du kan genvinde SP ved at færdiggøre opgaver, og ved at gå op i level igen.",
|
||||
"faqQuestion31": "Hvorfor mistede jeg SP ved at gennemføre en ikke-negativ opgave?",
|
||||
"webFaqAnswer31": "Hvis du gennemfører en opgave og mister SP du ikke burde have mistet, er der opstået en forsinkelse imens serveren synkroniserede ændringer mellem dine enheder. Fx. Hvis du bruger Guld, Magisk energi, eller mister SP på din telefon og efterfølgende gennemfører en opgave på hjemmesiden, mangler serveren bare at synkronisere dine enheder.",
|
||||
"faqQuestion32": "Hvordan vælger jeg klassering?",
|
||||
"webFaqAnswer32": "Alle spillere starter i kriger-klassen indtil de når level 10. Når du når level 10 får du valget mellem at skifte klassering eller fortsætte som kriger.\n\nHver klasse har forskelligt udstyr og færdigheder. Hvis du ikke har lyst til at skifte klassering, kan du trykke på “fravælg”. Hvis du vælger ikke at vælge klassering, kan du altid aktivere klasseringssystemet i indstillingerne senere.\n\nHvis du gerne vil skifte klasse efter level 10, kan du gøre dette ved at bruge en genfødselskugle. Genfødselskuglen vil være mulig at købe på markedet for 6 ædelsten når du når level 50, eller få den gratis ved at nå level 100.\n\nAlternativt, kan du på ethvert tidspunkt ændre klassering i indstillinger for 3 ædelsen. Dette nulstiller ikke dit level, som ellers sker ved brug af genfødselskuglen. Det vil derimod give dig mulighed for at omrokere de egenskabspoint du har samlet sammen ved at gå op i level, til at matche din nye klasse.",
|
||||
"faqQuestion33": "Hvad er den blå bjælke som kommer efter level 10?",
|
||||
"webFaqAnswer33": "Efter du låser op for klasseringssystemet kan du også låse op for færdigheder, som kræver at Magisk energi benyttes. Magisk energi bestemmes ud fra din intelligensstatus, og kan justeres med færdigheder og visse udstyr.",
|
||||
"faqQuestion34": "Hvilken slags mad kan mit dyr lide?",
|
||||
"faqQuestion35": "Mit dyr forsvandt da jeg fodrede det! Hvad skete der?"
|
||||
}
|
||||
|
||||
@@ -24,34 +24,34 @@
|
||||
"invalidEmail": "Det kræver en valid emailadresse for at få nulstillet dit kodeord.",
|
||||
"login": "Log ind",
|
||||
"logout": "Log Ud",
|
||||
"marketing1Header": "Forbedr dine vaner ved at spille et spil",
|
||||
"marketing1Lead1Title": "Dit liv, rollespillet",
|
||||
"marketing1Lead1": "Habitica er et computerspil, der hjælper med at forbedre dine vaner i virkeligheden. Det gør dit liv til et spil ved at lave alle dine opgaver (Vaner, Daglige og To-Do's) indtil små monstre, du skal besejre. Jo bedre du er til dette, desto større fremskridt vil du gøre i spillet. Hvis du begår fejl i livet, vil din karakter miste fremskridt i spillet.",
|
||||
"marketing1Lead2Title": "Få Lækkert Udstyr",
|
||||
"marketing1Lead2": "Forbedr dine vaner for at ændre din avatar. Vis det fede udstyr du har tjent!",
|
||||
"marketing1Lead3Title": "Find Tilfældige Præmier",
|
||||
"marketing1Header": "Forbedr dine vaner med spil, et level ad gangen!",
|
||||
"marketing1Lead1Title": "Gør dit liv til et spil",
|
||||
"marketing1Lead1": "Habitica er den perfekte app for alle der har svært ved at færdiggøre sin to-do liste. Vi bruger genkendelige spillemekanismer, såsom at belønne dig med Guld, Erfarring og genstande, for at hjælpe dig med at føle mere produktiv og samtidig øge følelsen af præstation, når du færdiggøre en opgave. Jo bedre du er til at færdiggøre dine opgaver, jo længere kommer du i spillet.",
|
||||
"marketing1Lead2Title": "Udstyr dig med stil",
|
||||
"marketing1Lead2": "Saml svær, udrustning og meget andet med Guld du tjener ved at gennemføre opgaver. Med mulighed for at indsamle, og vælge, mellem hundredevis af forskellige genstande, løber du aldrig tør for sammensætninger. Optimer for niveau, stil, eller begge! ",
|
||||
"marketing1Lead3Title": "Bliv belønnet for din indsats",
|
||||
"marketing1Lead3": "For nogle er det chancen, der motiverer dem: et system der hedder \"stokastiske belønninger.\" Habitica har plads til alle slags måder at forbedre eller straffe sig selv på: positive, negative, forudsigelige og tilfældige.",
|
||||
"marketing2Header": "Kæmp med venner, deltag i interessegrupper",
|
||||
"marketing2Header": "Slå dig sammen med dine venner",
|
||||
"marketing2Lead1Title": "Social produktivitet",
|
||||
"marketing2Lead1": "Selvom du selvfølgelig kan spille Habitica selv, bliver det først virkelig godt når I begynder at samarbejde, konkurrere og holde hinanden ansvarlige. Den mest effektive del af ethvert selvforbedringsprogram er social ansvarlighed, og hvad er et bedre miljø for ansvarlighed og konkurrence end et computerspil?",
|
||||
"marketing2Lead2Title": "Bekæmp monstre",
|
||||
"marketing2Lead2Title": "Bekæmp monstre i opgaver",
|
||||
"marketing2Lead2": "Hvad er et rollespil uden slåskampe? Bekæmp monstre med dit hold. Monstre er \"super-ansvarligheds-mode\" - en dag, du ikke træner, er en dag, hvor monstret skader *alle!*",
|
||||
"marketing2Lead3Title": "Udfordr Hinanden",
|
||||
"marketing2Lead3Title": "Udfordr hinanden",
|
||||
"marketing2Lead3": "Udfordringer lader dig konkurrere med venner og fremmede. Den, der er bedst i slutningen af en udfordring vinder særlige præmier.",
|
||||
"marketing3Header": "Apps og Udvidelser",
|
||||
"marketing3Header": "Forskellige måder at bruge Habitica på",
|
||||
"marketing3Lead1": "**iPhone & Android** apps lader dig klare dine ting på farten. Vi ved, at det nogen gange er for meget at skulle logge ind på websiden for at klikke på knapper.",
|
||||
"marketing3Lead2Title": "Integrationer",
|
||||
"marketing3Lead2Title": "Udviklet af fællesskabet",
|
||||
"marketing3Lead2": "Andre **tredjepartsværktøjer** kan binde Habitica sammen med andre dele af dit liv. Vores API muliggør integrationer som [Chrome Extension](https://chrome.google.com/webstore/detail/habitica/pidkmpibnnnhneohdgjclfdjpijggmjj?hl=en-US), med hvilken du mister point ved at bruge unyttige hjemmesider, og optjener point når du browser de nyttige i stedet. [Se mere her](https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations).",
|
||||
"marketing4Header": "Organisatorisk brug",
|
||||
"marketing4Header": "Udover hverdagens pligter",
|
||||
"marketing4Lead1": "Uddannelse er en af de bedste områder at bruge spilelementer. Vi ved alle, hvordan studerende nærmest er limet til deres telefon disse dage, så brug dette! Sæt dine elever til at kæmpe mod hinanden som hyggelig konkurrence. Beløn god opførsel med sjældne præmier. Se deres karakterer og opførsel blive forbedret.",
|
||||
"marketing4Lead1Title": "Brug af Spilelementer i Undervisning",
|
||||
"marketing4Lead1Title": "Spilelementer i undervisning",
|
||||
"marketing4Lead2": "Prisen for sundhedssektoren stiger, og der må ske noget. Hundredevis af programmer er bygget til at reducere udgifter og forbedre velvære. Vi tror på, at Habitica kan bane vejen for en sundere livsstil.",
|
||||
"marketing4Lead2Title": "Brug af Spilelementer i Sundhed og Velvære",
|
||||
"marketing4Lead3-1": "Vil du gøre dit liv til et spil?",
|
||||
"marketing4Lead2Title": "Spilelementer i sundhed og velvære",
|
||||
"marketing4Lead3-1": "Klar til at udrette noget imens du har det sjovt?",
|
||||
"marketing4Lead3-2": "Interesseret i at lede en gruppe for uddannelse, velvære og mere?",
|
||||
"marketing4Lead3Title": "Spilificér Alt",
|
||||
"mobileAndroid": "Android",
|
||||
"mobileIOS": "iOS",
|
||||
"marketing4Lead3Title": "Start din rejse!",
|
||||
"mobileAndroid": "Android App",
|
||||
"mobileIOS": "iOS App",
|
||||
"oldNews": "Nyheder",
|
||||
"setNewPass": "Sæt nyt kodeord",
|
||||
"password": "Kodeord",
|
||||
@@ -110,7 +110,7 @@
|
||||
"missingPassword": "Manglende kodeord.",
|
||||
"missingNewPassword": "Manglende nyt kodeord.",
|
||||
"invalidEmailDomain": "Du kan ikke registrere med emails med følgende domæner: <%= domains %>",
|
||||
"wrongPassword": "Forkert kodeord.",
|
||||
"wrongPassword": "Forkert kodeord. Hvis du har glemt dit kodeord, tryk på “Glemt kodeord”.",
|
||||
"incorrectDeletePhrase": "Skriv venligst <%= magicWord %> med store bogstaver for at slette din konto.",
|
||||
"notAnEmail": "Ugyldig e-mailadresse.",
|
||||
"emailTaken": "E-mailadressen er allerede brugt til en konto.",
|
||||
@@ -121,8 +121,8 @@
|
||||
"usernameTaken": "Brugernavn allerede taget.",
|
||||
"passwordConfirmationMatch": "Kodeord og godkendelse er ikke ens.",
|
||||
"passwordResetPage": "Nulstil kodeord",
|
||||
"passwordReset": "Hvis vi har din email på lager, vil instruktioner til opsætning af nyt kodeord være sendt til din email.",
|
||||
"invalidLoginCredentialsLong": "Åh-åh - din emailaddresse/brugernavn eller kodeord er forkert.\n- Vær sikker på du har indtastet korrekt. Der gøres forskel på store og små bogstaver.\n- Du kan have brugt Facebook eller Google til at oprette din konto, ikke email, så dobbeltcheck ved at prøve dem.\n- Hvis du har glemt dit kodeord, så klik på \"Glemt kodeord\".",
|
||||
"passwordReset": "Hvis din E-mail eller brugernavn allerede findes i vores system, vil instruktioner til opsætning af nyt kodeord være sendt til din email.",
|
||||
"invalidLoginCredentialsLong": "Åh-åh - din e-mailadresse, brugernavn eller kodeord er forkert.\nPrøv igen, eller klik på \"Glemt kodeord\".",
|
||||
"invalidCredentials": "Der er ingen konto med disse legitimationsoplysninger.",
|
||||
"accountSuspended": "Denne konto, bruger-ID \"<%= userId %>\", er blevet blokeret for at bryde Retningslinjerne for fællesskabet (https://habitica.com/static/community-guidelines) eller vores Vilkår og betingelser (https://habitica.com/static/terms). For at få detaljer eller bede om at få blokaden ophævet, så send venligst en email til vores Community Manager på <%= communityManagerEmail %>, eller bed din forælder eller værge om at gøre det. Inkluder venligst dit @Brugernavn i emailen.",
|
||||
"accountSuspendedTitle": "Kontoen er blevet suspenderet",
|
||||
@@ -132,14 +132,14 @@
|
||||
"invalidReqParams": "Ugyldige anmodningsparametre.",
|
||||
"memberIdRequired": "\"member\" skal være et gyldigt Unikt Bruger-ID.",
|
||||
"heroIdRequired": "\"heroID\" skal være et gyldigt Unikt Bruger-ID.",
|
||||
"cannotFulfillReq": "Din anmodning kan ikke udføres. Kontakt admin@habitica.com hvis fejlen fortsætter.",
|
||||
"cannotFulfillReq": "Denne e-mail er allerede taget i brug. Prøv at logge ind eller brug en anden e-mail til registrering. Hvis du har brug for hjælp, kontakt os på admin@habitica.com",
|
||||
"modelNotFound": "Denne model findes ikke.",
|
||||
"signUpWithSocial": "Tilmeld med <%= social %>",
|
||||
"signUpWithSocial": "Fortsæt med <%= social %>",
|
||||
"loginWithSocial": "Log in med<%= social %>",
|
||||
"confirmPassword": "Bekræft kodeord",
|
||||
"usernameLimitations": "Brugernavn skal være 1 til 20 tegn, kun bruge bogstaver fra a til z, tal fra 0 til 9, bindestreg eller bundstreg (_), og kan ikke inkludere nogle upassende ord.",
|
||||
"usernameLimitations": "Brugernavn kan ændres på alle tidspunkter. Det skal være 1 til 20 tegn, kun indeholde bogstaver fra a til z, tal fra 0 til 9, bindestreg eller understreg (_)",
|
||||
"usernamePlaceholder": "fx HabitRabbit",
|
||||
"emailPlaceholder": "e.g., rabbit@example.com",
|
||||
"emailPlaceholder": "Fx., kanin@eksempel.com",
|
||||
"passwordPlaceholder": "e.g., ******************",
|
||||
"confirmPasswordPlaceholder": "Sikr dig at det er det samme kodeord!",
|
||||
"joinHabitica": "Opret bruger",
|
||||
@@ -169,10 +169,22 @@
|
||||
"joinMany": "Tilslut dig over <%= userCountInMillions %> millioner andre, der har det sjovt imens de opnår deres mål!",
|
||||
"joinToday": "Tilmeld dig Habitica i dag",
|
||||
"signup": "Tilmeld dig",
|
||||
"getStarted": "Kom i gang!",
|
||||
"getStarted": "Kom i gang",
|
||||
"mobileApps": "Mobile apps",
|
||||
"learnMore": "Lær mere",
|
||||
"communityInstagram": "Instagram",
|
||||
"minPasswordLength": "Kodeord skal bestå af 8 eller flere tegn.",
|
||||
"enterHabitica": "Spil Habitica"
|
||||
"enterHabitica": "Spil Habitica",
|
||||
"footerProduct": "Produkt",
|
||||
"marketing4Lead3Button": "Start i dag",
|
||||
"incorrectResetPhrase": "Skriv <%= magicWord %> i store bogstaver for at nulstille din konto.",
|
||||
"minPasswordLengthLogin": "Dit kodeord er minimum 8 karakterer langt.",
|
||||
"enterValidEmail": "Indtast venligst en gyldig e-mailadresse.",
|
||||
"translateHabitica": "Oversæt Habitica",
|
||||
"whatToCallYou": "Hvad skal vi kalde dig?",
|
||||
"acceptPrivacyTOS": "Bekræfter du at du er over 18 år gammel, og har læst og accepteret vores <a href='/static/terms' target='_blank'>Terms of Services</a> og <a href='/static/privacy' target='_blank'>Privatlivspolitik</a>",
|
||||
"emailBlockedRegistration": "Denne e-mail er blokeret, og kan ikke benyttes til registrering. Hvis der er sket en fejl, kontakt os på admin@habitica.com",
|
||||
"emailUsernamePlaceholder": "Fx., vanedyr eller kanin@eksempel.com",
|
||||
"marketing3Lead1Title": "Android & iOS apps",
|
||||
"socialAlreadyExists": "Dette login benyttes allerede af en eksisterende Habitica konto."
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
"messages": "Beskeder",
|
||||
"emptyMessagesLine1": "Du har ingen beskeder",
|
||||
"emptyMessagesLine2": "Du kan sende en ny besked til en bruger ved at besøge deres profil og klikke på \"Besked\"-knappen.",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> sendte en besked",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%= user %></span> sendte en besked",
|
||||
"letsgo": "Lad os komme i gang!",
|
||||
"selected": "Valgt",
|
||||
"howManyToBuy": "Hvor mange vil du købe?",
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"userId": "Bruger-ID",
|
||||
"invite": "Invitér",
|
||||
"leave": "Forlad",
|
||||
"invitedToParty": "Du blev inviteret til at være med på Holdet <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPrivateGuild": "Du blev inviteret til den private Klan <span class=\"notification-bold\"><%- guild %></span>",
|
||||
"invitedToPublicGuild": "Du blev inviteret til Klanen <span class=\"notification-bold-blue\"><%- guild %></span>",
|
||||
"invitedToParty": "Du blev inviteret til at være med på Holdet <span class=\"notification-bold\"><%= party %></span>",
|
||||
"invitedToPrivateGuild": "Du blev inviteret til den private Klan <span class=\"notification-bold\"><%= guild %></span>",
|
||||
"invitedToPublicGuild": "Du blev inviteret til Klanen <span class=\"notification-bold-blue\"><%= guild %></span>",
|
||||
"invitationAcceptedHeader": "Din invitation blev accepteret",
|
||||
"invitationAcceptedBody": "<%= username %> har accepteret din invitation til <%= groupName %>!",
|
||||
"systemMessage": "Systembesked",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%- name %></span> har nye indlæg",
|
||||
"newMsgParty": "Dit Hold, <span class=\"notification-bold-blue\"><%- name %></span>, har nye indlæg",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%= name %></span> har nye indlæg",
|
||||
"newMsgParty": "Dit Hold, <span class=\"notification-bold-blue\"><%= name %></span>, har nye indlæg",
|
||||
"chat": "Chat",
|
||||
"sendChat": "Send besked",
|
||||
"group": "Gruppe",
|
||||
@@ -151,14 +151,14 @@
|
||||
"onlyGroupLeaderCanEditTasks": "Du har ikke rettigheder til at administrere opgaver!",
|
||||
"onlyGroupTasksCanBeAssigned": "Kun gruppeopgaver kan blive tildelt",
|
||||
"assignedTo": "Tildelt",
|
||||
"assignedToUser": "Tildelt <%- userName %>",
|
||||
"assignedToUser": "Tildelt <%= userName %>",
|
||||
"assignedToMembers": "Tildelt <%= userCount %> medlemmer",
|
||||
"assignedToYouAndMembers": "Tildelt dig og <%= userCount %> medlemmer",
|
||||
"youAreAssigned": "Du er blevet bedt om at udføre denne opgave",
|
||||
"taskIsUnassigned": "Denne opgave er ikke tildelt nogen",
|
||||
"confirmUnClaim": "Er du sikker på, du vil give afkald på denne opgave?",
|
||||
"confirmNeedsWork": "Er du sikker på, du vil markere denne opgave som ufuldstændig?",
|
||||
"userRequestsApproval": "<%- userName %> anmoder om godkendelse",
|
||||
"userRequestsApproval": "<%= userName %> anmoder om godkendelse",
|
||||
"userCountRequestsApproval": "<%= userCount %> medlemmer anmoder om godkendelse",
|
||||
"youAreRequestingApproval": "Du har anmodet om godkendelse",
|
||||
"chatPrivilegesRevoked": "Dine chatprivilegier er blevet inddraget, så du kan ikke udføre denne handling.",
|
||||
@@ -168,9 +168,9 @@
|
||||
"claim": "Gør krav på",
|
||||
"removeClaim": "Giv afkald på",
|
||||
"onlyGroupLeaderCanManageSubscription": "Kun gruppelederen kan styre gruppens abonnement",
|
||||
"yourTaskHasBeenApproved": "Din opgave, <span class=\"notification-green\"><%- taskText %></span>, er blevet godkendt.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%- managerName %></span> markerede <span class=\"notification-bold\"><%- taskText %></span> som ufuldstændig.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%- user %></span> anmoder om godkendelse for <span class=\"notification-bold\"><%- taskName %></span>",
|
||||
"yourTaskHasBeenApproved": "Din opgave, <span class=\"notification-green\"><%= taskText %></span>, er blevet godkendt.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> markerede <span class=\"notification-bold\"><%= taskText %></span> som ufuldstændig.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%= user %></span> anmoder om godkendelse for <span class=\"notification-bold\"><%= taskName %></span>",
|
||||
"approve": "Godkend",
|
||||
"approveTask": "Godkend opgave",
|
||||
"needsWork": "Ufuldstændig",
|
||||
@@ -183,8 +183,8 @@
|
||||
"userIsClamingTask": "`<%= username %> har gjort krav på:` <%= task %>",
|
||||
"approvalRequested": "Godkendelse efterspurgt",
|
||||
"cantDeleteAssignedGroupTasks": "Du kan ikke slette gruppeopgaver, der er blevet tildelt dig.",
|
||||
"groupPlanUpgraded": "<strong><%- groupName %></strong> blev opgraderet til en Gruppeplan!",
|
||||
"groupPlanCreated": "<strong><%- groupName %></strong> blev oprettet!",
|
||||
"groupPlanUpgraded": "<strong><%= groupName %></strong> blev opgraderet til en Gruppeplan!",
|
||||
"groupPlanCreated": "<strong><%= groupName %></strong> blev oprettet!",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Kun gruppelederen kan invitere brugere til en gruppe med et abonnement.",
|
||||
"paymentDetails": "Betalingsdetaljer",
|
||||
"aboutToJoinCancelledGroupPlan": "Du er ved at slutte dig til en gruppe med en opsagt gruppeplan. Du vil IKKE få et gratis abonnement.",
|
||||
@@ -321,7 +321,7 @@
|
||||
"allAssignedCompletion": "All - Completes when all assigned users finish",
|
||||
"pmReported": "Tak, fordi du rapporterede denne besked.",
|
||||
"features": "Funktioner",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%- userId %>\" target=\"_blank\">@<%- userName %></a> har inviteret dig til holdet <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%= userId %>\" target=\"_blank\">@<%= userName %></a> har inviteret dig til holdet <span class=\"notification-bold\"><%= party %></span>",
|
||||
"PMUserDoesNotReceiveMessages": "Denne bruger modtager ikke længere private beskeder",
|
||||
"blockedToSendToThisUser": "Du kan ikke sende til denne spiller da du har blokeret denne spiller.",
|
||||
"blockYourself": "Du kan ikke blokere dig selv",
|
||||
|
||||
@@ -82,13 +82,12 @@
|
||||
"paymentMethods": "Køb med",
|
||||
"paymentSuccessful": "Din betaling gik igennem!",
|
||||
"paymentYouReceived": "Du modtog:",
|
||||
"paymentYouSentGems": "Du sendte <strong><%- name %></strong>:",
|
||||
"paymentYouSentSubscription": "Du sendte <strong><%- name %></strong> et <%= months %>-måneders Habitica-abonnement.",
|
||||
"paymentYouSentGems": "Du sendte <strong><%= name %></strong>:",
|
||||
"paymentYouSentSubscription": "Du sendte <strong><%= name %></strong> et <%= months %>-måneders Habitica-abonnement.",
|
||||
"paymentSubBilling": "Betalingen for dit abonnement vil blive trukket <strong>$<%= amount %></strong> hver <strong><%= months %> måneder</strong>.",
|
||||
"success": "Succes!",
|
||||
"classGear": "Klasseudstyr",
|
||||
"classGearText": "Tillykke med at vælge klasse! Jeg har tilføjet dit nye basisudstyr til dit inventar. Tag et kig forneden og tag det på!",
|
||||
"autoAllocate": "Tildel automatisk",
|
||||
"spells": "Evner",
|
||||
"skillsTitle": "<%= classStr %> Evner",
|
||||
"toDo": "To Do",
|
||||
|
||||
@@ -66,8 +66,8 @@
|
||||
"mountNotOwned": "Du ejer ikke dette ridedyr.",
|
||||
"feedPet": "Giv <%= text %> til din <%= name %>?",
|
||||
"raisedPet": "Du har opdrættet din/dit <%= pet %>!",
|
||||
"petName": "<%= potion(locale) %> <%= egg(locale) %>",
|
||||
"mountName": "<%= potion(locale) %>-<%= mount(locale) %>",
|
||||
"petName": "<%= potion %> <%= egg %>",
|
||||
"mountName": "<%= potion %>-<%= mount %>",
|
||||
"keyToPets": "Nøgle til Kæledyrskennelen",
|
||||
"keyToPetsDesc": "Sæt alle standardkæledyrene fri, så du kan samle dem igen. (Kæledyr fra quests og sjældne kæledyr påvirkes ikke.)",
|
||||
"keyToMounts": "Nøgle til Ridedyrskennelen",
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
"userData": "Brugerdata",
|
||||
"exportUserData": "Eksportér brugerdata:",
|
||||
"export": "Eksportér",
|
||||
"xml": "(XML)",
|
||||
"json": "(JSON)",
|
||||
"xml": "XML",
|
||||
"json": "JSON",
|
||||
"customDayStart": "Brugerdefineret starttidspunkt",
|
||||
"sureChangeCustomDayStartTime": "Er du sikker på, at du vil ændre dit brugerdefinerede starttidspunkt? Dine Daglige vil blive opdateret næste gang du bruger Habitica efter <%= time %>. Vær sikker på, at du har udført dine Daglige før da!",
|
||||
"customDayStartHasChanged": "Dit brugerdefinerede starttidspunkt er ændret.",
|
||||
@@ -46,7 +46,7 @@
|
||||
"newUsername": "Nyt brugernavn",
|
||||
"dangerZone": "Farezone",
|
||||
"resetText1": "ADVARSEL! Dette nulstiller mange dele af din konto. Vi fraråder på det kraftigste dette, men nogen finder det brugbart i begyndelsen efter at have eksperimenteret med Habitica i et kort stykke tid.",
|
||||
"resetText2": "Du vil miste alle niveauer, Guld, og Erfaringspoint. Alle dine Opgaver (bortset fra dem fra Udfordringer) vil blive slettet permanent, og du vil miste al deres historik. Du vil miste alt dit udstyr, undtagen gratis gave-udstyr eller Mystiske abonnentsgenstande. Du vil være i stand til at købe alle de mistede genstand igen, inklusiv tidsbegrænset udstyr (du skal være den korrekte klasse for at købe klasse-begrænset udstyr). Du vil beholde din nuværende klasse, præstationer og dine kæle- og ridedyr. Du ville måske foretrække at bruge en Genfødselskugle i stedet. Det er en meget sikrere mulighed, og du vil beholde dine opgaver og udstyr.",
|
||||
"resetText2": "En anden mulighed er at bruge en <b>Genfødselskugle</b>, hvilket vil nulstille alt, men du vil beholde dine opgaver og dit udstyr.",
|
||||
"deleteLocalAccountText": "Er du sikker? Dette vil slette din konto for evigt, og den kan aldrig gendannes! Du skal registrere en ny konto for at kunne bruge Habitica igen. Ædelsten du har brugt eller har på lager vil ikke blive refunderet. Hvis du er fuldstændig sikker, så skriv dit kodeord i boksen herunder.",
|
||||
"deleteSocialAccountText": "Er du sikker? Dette vil slette din brugerkonto for evigt, og den kan aldrig gendannes! Du vil være nødt til at oprette en ny konto for at bruge Habitica igen. Ædelsten i en Klanbank eller som er blevet brugt vil ikke blive refunderet. Hvis du virkelig er helt sikker, så indtast \"<%= magicWord %>\" i tekstboksen nedenunder.",
|
||||
"API": "API",
|
||||
@@ -176,5 +176,24 @@
|
||||
"account": "Konto",
|
||||
"loginMethods": "Login metoder",
|
||||
"character": "Karakter",
|
||||
"siteLanguage": "Webstedets sprog"
|
||||
"siteLanguage": "Webstedets sprog",
|
||||
"showLevelUpModal": "Når man går et level op",
|
||||
"showHatchPetModal": "Når man udruger et dyr",
|
||||
"showRaisePetModal": "Når man opgradere et dyr til ridedyr",
|
||||
"showStreakModal": "Når man modtager en streak præstation",
|
||||
"baileyAnnouncement": "Seneste Bailey meddelelse",
|
||||
"view": "Vis",
|
||||
"feedbackPlaceholder": "Tilføj til feedback",
|
||||
"downloadCSV": "Download CSV",
|
||||
"downloadAs": "Download As",
|
||||
"yourUserData": "Dine brugerdata",
|
||||
"taskHistory": "Opgave historie",
|
||||
"resetTextLocal": "Hvis du er helt sikker, indsæt dit kodeord i tekstfeltet nedenfor.",
|
||||
"yourUserDataDisclaimer": "Her kan du downloade en kopi af din opgavehistorie og dine bruger data.",
|
||||
"useridCopied": "BrugerID er kopieret til udklipsholderen.",
|
||||
"developerMode": "Udviklingsmode",
|
||||
"api": "API",
|
||||
"currentPass": "Nuværende kodeord",
|
||||
"resetDetail1": "Du vil miste alle dine levels, dit Guld, og Erfaringspoint.",
|
||||
"resetDetail2": "Du vil forblive i din valgte klasse, og beholde dine præstationer, dyr og ridedyr."
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
"challenge": "Herausforderung",
|
||||
"challengeDetails": "Herausforderungen sind Gemeinschaftsereignisse, an denen Spieler teilnehmen und Preise gewinnen können, indem sie die dazugehörigen Aufgaben erledigen.",
|
||||
"brokenChaLink": "Toter Herausforderungs-Link",
|
||||
"brokenTask": "Toter Herausforderungs-Link: Diese Aufgabe war Teil einer Herausforderung, aber ist mittlerweile entfernt worden. Was möchtest Du tun?",
|
||||
"keepIt": "Behalten",
|
||||
"removeIt": "Entfernen",
|
||||
"brokenChallenge": "Toter Herausforderungs-Link: Diese Aufgabe war Teil einer Herausforderung, aber die Herausforderung (oder Gruppe) wurde gelöscht. Was möchtest Du mit den verwaisten Aufgaben tun?",
|
||||
"challengeCompleted": "Diese Herausforderung ist beendet, und gewonnen hat <span class=\"badge\"><%- user %></span>! Was soll mit den verwaisten Aufgaben geschehen?",
|
||||
"brokenChallenge": "Defekter Herausforderungslink",
|
||||
"challengeCompleted": "Herausforderung abgeschlossen!",
|
||||
"unsubChallenge": "Toter Herausforderungs-Link: Diese Aufgabe war Teil einer Herausforderung, aber Du hast aufgehört an dieser Herausforderungs teilzunehmen. Was soll mit den verwaisten Aufgaben geschehen?",
|
||||
"challenges": "Herausforderungen",
|
||||
"endDate": "Endet",
|
||||
@@ -109,5 +108,9 @@
|
||||
"cannotClone": "Diese Herausforderung kann nicht dupliziert werden, weil einer oder mehrere Spieler sie als unangemessen gemeldet haben. Einer der Mitarbeiter wird dich in Kürze mit Anweisungen kontaktieren. Wenn mehr als 48 Stunden vergangen sind, und du nichts von ihnen gehört hast, schicke bitte eine Email an admin@habitica.com, um Unterstützung zu erhalten.",
|
||||
"resetFlags": "Markierungen zurücksetzen",
|
||||
"messageChallengeFlagOfficial": "Offizielle Herausforderungen können nicht gemeldet werden.",
|
||||
"deleteChallengeRefundDescription": "Wenn du diese Herausforderung löschst, bekommst du den Preis in Edelsteinen erstattet und die Aufgaben der Herausforderung verbleiben auf der Aufgabentafel der Teilnehmer."
|
||||
"deleteChallengeRefundDescription": "Wenn du diese Herausforderung löschst, bekommst du den Preis in Edelsteinen erstattet und die Aufgaben der Herausforderung verbleiben auf der Aufgabentafel der Teilnehmer.",
|
||||
"brokenTaskDescription": "Diese Aufgabe war Teil einer Herausforderung, wurde jedoch daraus entfernt. Was möchtest Du tun?",
|
||||
"brokenChallengeDescription": "Diese Aufgabe war Teil einer Herausforderung, aber die Herausforderung (oder Gruppe) wurde gelöscht. Was soll mit den verwaisten Aufgaben geschehen?",
|
||||
"challengeCompletedDescription": "Gewonnen hat <%= user %>! Was soll mit den verwaisten Aufgaben geschehen?",
|
||||
"brokenTask": "Defekter Link zur Herausforderung"
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"allocatePerPop": "Erhöhe Wahrnehmung um einen Punkt",
|
||||
"allocateInt": "Zugewiesene Intelligenzpunkte:",
|
||||
"allocateIntPop": "Erhöhe Intelligenz um einen Punkt",
|
||||
"noMoreAllocate": "Jetzt, nach dem Erreichen von Level 100, wirst Du keine weiteren Attributpunkte erhalten. Du kannst weiter aufsteigen oder ein neues Abenteuer auf Level 1 anfangen, indem Du die <a href='/shops/market'>Sphäre der Wiedergeburt</a> benutzt!",
|
||||
"noMoreAllocate": "Nachdem du nun Level 100 erreicht hast, erhältst du keine weiteren Attributpunkte mehr. Du kannst weiter aufsteigen oder mit der <a href=‚/shops/market‘>Sphäre der Wiedergeburt</a> ein neues Abenteuer auf Level 1 beginnen.",
|
||||
"stats": "Attributwerte",
|
||||
"strength": "Stärke",
|
||||
"strText": "Stärke erhöht die Wahrscheinlichkeit zufälliger \"kritischer Treffer\" und die Rate mit der durch sie Gold, Beute und Erfahrung gewonnen wird. Und hilft auch dabei, Boss-Monstern Schaden zuzufügen.",
|
||||
@@ -114,12 +114,12 @@
|
||||
"unallocated": "Freie Attributspunkte",
|
||||
"autoAllocation": "Verteilungsmuster",
|
||||
"autoAllocationPop": "Verteilt gemäß Deiner Einstellungen Punkte auf Deine Attribute, wenn Du ein Level aufsteigst.",
|
||||
"evenAllocation": "Attributspunkte gleichmäßig verteilen",
|
||||
"evenAllocationPop": "Weist jedem Statuswert die gleiche Anzahl an Punkten zu.",
|
||||
"evenAllocation": "Gleichmäßig verteilen",
|
||||
"evenAllocationPop": "Weist jedem Attribut die gleiche Anzahl von Punkten zu.",
|
||||
"classAllocation": "Punkte anhand der Klasse verteilen",
|
||||
"classAllocationPop": "Weist den Statuswerten die wichtig für Deine Klasse sind, mehr Punkte zu.",
|
||||
"taskAllocation": "Verteile Punkte abhängig von Aufgaben-Aktivität",
|
||||
"taskAllocationPop": "Verteilt Punkte abhängig davon, welche Kategorien die Aufgaben haben, die Du überwiegend erledigst: Stärke, Intelligenz, Ausdauer oder Wahrnehmung.",
|
||||
"classAllocationPop": "Weist den Attributen die wichtig für Deine Klasse sind, mehr Punkte zu.",
|
||||
"taskAllocation": "Verteile Punkte abhängig von Aufgabenaktivität",
|
||||
"taskAllocationPop": "Verteilt Punkte basierend auf den Kategorien Stärke, Intelligenz, Konstitution und Wahrnehmung, die mit den von Dir erledigten Aufgaben verbunden sind.",
|
||||
"distributePoints": "Verteile freie Punkte automatisch",
|
||||
"distributePointsPop": "Verteilt alle freien Attributpunkte gemäß Deinem gewählten Verteilungsmuster.",
|
||||
"warriorText": "Krieger verursachen mehr und stärkere \"kritische Treffer\", die zufällige Boni auf Gold, Erfahrung und Beute beim Erfüllen einer Aufgabe geben. Sie sind auch sehr stark gegen Bossmonster. Spiele einen Krieger, wenn Dich die Chance auf Belohnungen im Lottogewinn-Stil besonders reizt und Du besonders effektiv gegen Bossmonster sein willst!",
|
||||
@@ -191,5 +191,14 @@
|
||||
"titleHaircolor": "Haarfarben",
|
||||
"titleFacialHair": "Bärte",
|
||||
"titleHairbase": "Frisuren",
|
||||
"customizations": "Individualisierungen"
|
||||
"customizations": "Individualisierungen",
|
||||
"strTaskText": "Erhöht die kritische Trefferchance und den Schaden beim Erfüllen von Aufgaben. Erhöht außerdem den Schaden, der Quest-Bossen zugefügt wird.",
|
||||
"conTaskText": "Reduziert den Schaden, der durch verpasste tägliche Aufgaben und negative Gewohnheiten verursacht wird. Reduziert nicht den Schaden durch Quest-Bosse.",
|
||||
"autoAllocate": "Automatische Zuweisung",
|
||||
"pointsAvailable": "Verfügbare Punkte",
|
||||
"allocationMethod": "Zuteilungsmethode",
|
||||
"assignedStat": "Zugewiesener Wert",
|
||||
"intTaskText": "Erhöht die durch Aufgaben gesammelte Erfahrung. Erhöht außerdem deine Manakapazität und Manaregenerationsrate.",
|
||||
"perTaskText": "Erhöht die Drop-Chance für Gegenstände, die tägliche Drop-Obergrenze für Gegenstände, die Serienboni für Aufgaben und das beim Abschließen von Aufgaben verdiente Gold.",
|
||||
"statAllocationInfo": "Mit jedem Level erhältst Du einen Punkt, den Du einem Attribut Deiner Wahl zuweisen kannst. Du kannst die Zuweisung manuell vornehmen oder es dem Spiel überlassen, indem Du eine der Optionen zur automatischen Zuweisung wählst."
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"questEggVelociraptorText": "Velociraptor-Haustier",
|
||||
"questEggVelociraptorMountText": "Velociraptor-Reittier",
|
||||
"questEggVelociraptorAdjective": "ein cleveres",
|
||||
"eggNotes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein <%= eggAdjective(locale) %> <%= eggText(locale) %> schlüpfen kann.",
|
||||
"eggNotes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein <%= eggAdjective %> <%= eggText %> schlüpfen kann.",
|
||||
"hatchingPotionBase": "Normales",
|
||||
"hatchingPotionWhite": "Weißes",
|
||||
"hatchingPotionDesert": "Wüstenfarbenes",
|
||||
@@ -211,7 +211,7 @@
|
||||
"hatchingPotionGlow": "Fluoreszierendes",
|
||||
"hatchingPotionFrost": "Frostiges",
|
||||
"hatchingPotionIcySnow": "Eisschnee",
|
||||
"hatchingPotionNotes": "Gieße dies über ein Ei und es wird ein <%= potText(locale) %> Haustier daraus schlüpfen.",
|
||||
"hatchingPotionNotes": "Gieße dies über ein Ei und es wird ein <%= potText %> Haustier daraus schlüpfen.",
|
||||
"foodMeat": "Fleisch",
|
||||
"foodMeatThe": "das Fleisch",
|
||||
"foodMeatA": "Fleisch",
|
||||
@@ -406,7 +406,7 @@
|
||||
"hatchingPotionBalloon": "Ballon",
|
||||
"wackyPotionAddlNotes": "Kann nicht zum Reittier großgezogen oder für Quest-Haustier Eier benutzt werden.",
|
||||
"hatchingPotionCryptid": "Kryptisch",
|
||||
"wackyPotionNotes": "Schütte dies über ein Ei und es wird als Durchgeknalltes <%= potText(locale) %> Haustier schlüpfen.",
|
||||
"wackyPotionNotes": "Schütte dies über ein Ei und es wird als Durchgeknalltes <%= potText %> Haustier schlüpfen.",
|
||||
"questEggPlatypusText": "Schnabeltier",
|
||||
"questEggPlatypusMountText": "Schnabeltier",
|
||||
"questEggPlatypusAdjective": "ein Perfektionist",
|
||||
|
||||
@@ -2800,7 +2800,7 @@
|
||||
"armorMystery202406Text": "Phantom-Seeräuber Kleidung",
|
||||
"headMystery202406Text": "Phantom-Seeräuber Hut",
|
||||
"eyewearMystery202406Text": "Phantom-Seeräuber Maske",
|
||||
"weaponArmoirePaintbrushNotes": "Ein Ruck purer Inspiration durchdringt dich, wenn du diesen Frabpinsel aufhebst, und ermöglicht dir, alles zu malen, was du dir vorstellen kannst. Erhöht Intelligenz um <%= int %>.Verzauberter Schrank: Malerset (Gegenstand 3 von 4).",
|
||||
"weaponArmoirePaintbrushNotes": "Ein Ruck purer Inspiration durchdringt Dich, wenn Du diesen Frabpinsel aufhebst, und ermöglicht Dir, alles zu malen, was Du Dir vorstellen kannst. Erhöht Intelligenz um <%= int %>.Verzauberter Schrank: Malerset (Gegenstand 3 von 4).",
|
||||
"weaponArmoirePaintbrushText": "Farbpinsel",
|
||||
"weaponArmoireMopText": "Mopp",
|
||||
"weaponArmoireCleaningClothText": "Putzlappen",
|
||||
@@ -3444,5 +3444,31 @@
|
||||
"weaponSpecialWinter2026WarriorNotes": "Sensen helfen beim Schneiden, Ernten und beim Abdecken großer Bereiche - alles Dinge, die du beim Verfeinern von Aufgabenlisten brauchst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winterausrüstung 2025-2026.",
|
||||
"weaponSpecialWinter2026RogueText": "Skistock",
|
||||
"weaponSpecialWinter2026RogueNotes": "Stistöcke helfen dir dabei, Balance, Stabilität und Timing zu wahren - alles Dinge, die du brauchst, um wirklich produktiv zu sein. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winterausrüstung 2025-2026.",
|
||||
"weaponSpecialWinter2026HealerText": "Polarstab"
|
||||
"weaponSpecialWinter2026HealerText": "Polarstab",
|
||||
"weaponSpecialWinter2026HealerNotes": "Stäbe dienen als Stütze, Stabilitätshilfe und zur Richtungsfindung - alles Dinge, die dir beim Bezwingen einer Aufgabenliste wirklich helfen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winterausrüstung 2025-2026.",
|
||||
"weaponSpecialWinter2026MageNotes": "Kandelaber helfen, indem sie mehrere Kerzen gleichzeitig halten - folge diesem Beispiel, wenn du das nächste Mal multitasken musst. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2025-2026.",
|
||||
"weaponSpecialWinter2026MageText": "Kandelaber Stab",
|
||||
"weaponMystery202512Text": "Klinge des Keks-Champions",
|
||||
"weaponMystery202512Notes": "Ein glänzendes Schwert, gegossen aus Zucker, Minze und arkanen Zaubern. Gewährt keinen Attributbonus. Dezember 2025 Abonnentengegenstand.",
|
||||
"weaponArmoireBambooFluteNotes": "Hwhoooo! Hu-whooooo! Versammle Deine Gruppe zu einer Meditationssitzung oder einem Selbstfürsorge-Nickerchen, während ihr euch zu den Klängen dieser Bambusflöte entspannt. Erhöht Konstitution und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Musikinstrumentenset 2 (Artikel 2 von 3)",
|
||||
"armorSpecialWinter2026WarriorNotes": "Eiszapfen brechen und gleiten bei jedem Schritt auf dem Weg zum Abschluss Deiner täglichen Aufgaben. Erhöht die Konstitution um <%= con %>. Limitierte Auflage Winter 2025-2026 Ausrüstung.",
|
||||
"armorMystery202512Notes": "Bereit für den Kampf mit diesem Schild, das sowohl süß als auch stark ist. Verleiht keinen Vorteil. Dezember 2025 Abonnenten-Gegenstand.",
|
||||
"armorSpecialWinter2026HealerNotes": "Wie eine natürliche Lichtshow wirst Du auf Deinem Weg zum Abschluss Deiner täglichen Aufgaben umwerfend aussehen. Erhöht die Konstitution um <%= con %>. Limitierte Auflage Winter 2025-2026 Ausrüstung.",
|
||||
"armorArmoireLoneCowpokeOutfitText": "Outfit eines einsamen Cowboys",
|
||||
"armorArmoireLoneCowpokeOutfitNotes": "Halt, halt! Möchtest Du ein Zeichen setzen, wenn Du als geheimnisvoller Fremder in die Stadt reitest, bereit, produktiv zu sein? Hier ist das perfekte Outfit, komplett mit Gamaschen und einer glänzenden, silbernen Gürtelschnalle. Erhöht die Konstitution um <%= con %>. Verzauberter Kleiderschrank: Set „Einsamer Cowboy“ (Artikel 2 von 2)",
|
||||
"headSpecialWinter2026WarriorNotes": "Behalte Deinen Fokus und Deine Konzentration bei, während Du dich in dieser Saison größere Ziele setzen. Erhöht die Kraft um <%= str %>. Limitierte Auflage 2025-2026 Winterausrüstung.",
|
||||
"weaponMystery202601Text": "Aegis des Winters",
|
||||
"weaponMystery202601Notes": "Ein eisiger Blasenschild, der magischen Schutz vor gegnerischen Elementen gewährt. Verleiht keinen Vorteil. Januar 2026 Abonnenten-Gegenstand.",
|
||||
"weaponArmoireBambooFluteText": "Bambusflöte",
|
||||
"weaponArmoirePrettyPinkParasolText": "Hübscher rosa Sonnenschirm",
|
||||
"weaponArmoirePrettyPinkParasolNotes": "Hübsch und praktisch ist die beste Kombination. Und für eine besonders beeindruckende Präsentation dreh diesen Sonnenschirm einfach einmal um! Erhöht alle Werte um jeweils <%= attrs %>. Verzauberter Schrank: Pretty in Pink-Set (Artikel 1 von 2)",
|
||||
"armorSpecialWinter2026WarriorText": "Raureif-Sensenmann-Anzug",
|
||||
"armorSpecialWinter2026RogueText": "Skianzug und Skier",
|
||||
"armorSpecialWinter2026RogueNotes": "Rase schnell die Pisten hinunter, um Deine täglichen Aufgaben zu erledigen. Erhöht die Wahrnehmung um <%= pro %>. Limitierte Auflage Winter 2025-2026 Ausrüstung.",
|
||||
"armorSpecialWinter2026HealerText": "Polar-Mantel",
|
||||
"armorSpecialWinter2026MageText": "Mitternachtskerzen-Gewand",
|
||||
"armorSpecialWinter2026MageNotes": "Gleite geschmeidig wie Wachs über Deinen Weg, um Deine täglichen Aufgaben zu erledigen. Erhöht die Intelligenz um <%= int %>. Limitierte Auflage Winter 2025-2026 Ausrüstung.",
|
||||
"armorMystery202512Text": "Keks-Champion-Rüstung",
|
||||
"headSpecialWinter2026WarriorText": "Frostsichel-Helm",
|
||||
"headSpecialWinter2026RogueText": "Skimaske und Schutzbrille"
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
"messages": "Nachrichten",
|
||||
"emptyMessagesLine1": "Du hast im Moment keine Nachrichten",
|
||||
"emptyMessagesLine2": "Sende eine Nachricht, um eine Konversation mit Mitgliedern deiner Gruppe oder anderen Habitica Spielern zu beginnen",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> hat Dir eine Nachricht gesendet",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%= user %></span> hat Dir eine Nachricht gesendet",
|
||||
"letsgo": "Auf geht's!",
|
||||
"selected": "Ausgewählt",
|
||||
"howManyToBuy": "Wie viele möchtest Du kaufen?",
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"userId": "Benutzer-ID",
|
||||
"invite": "Einladen",
|
||||
"leave": "Verlassen",
|
||||
"invitedToParty": "Du wurdest in die Party <span class=\"notification-bold\"><%- party %></span> eingeladen",
|
||||
"invitedToPrivateGuild": "Du wurdest eingeladen, der privaten Gruppe<span class=\"notification-bold\"><%- guild %></span> beizutreten",
|
||||
"invitedToPublicGuild": "Du wurdest eingeladen, der Gruppe<span class=\"notification-bold-blue\"><%- guild %></span> beizutreten",
|
||||
"invitedToParty": "Du wurdest in die Party <span class=\"notification-bold\"><%= party %></span> eingeladen",
|
||||
"invitedToPrivateGuild": "Du wurdest eingeladen, der privaten Gruppe<span class=\"notification-bold\"><%= guild %></span> beizutreten",
|
||||
"invitedToPublicGuild": "Du wurdest eingeladen, der Gruppe<span class=\"notification-bold-blue\"><%= guild %></span> beizutreten",
|
||||
"invitationAcceptedHeader": "Deine Einladung wurde angenommen",
|
||||
"invitationAcceptedBody": "<%= username %> hat Deine Einladung zu <%= groupName %> angenommen!",
|
||||
"systemMessage": "Systemmeldung",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%- name %></span> hat neue Beiträge",
|
||||
"newMsgParty": "Deine Party, <span class=\"notification-bold-blue\"><%- name %></span>, hat neue Beiträge",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%= name %></span> hat neue Beiträge",
|
||||
"newMsgParty": "Deine Party, <span class=\"notification-bold-blue\"><%= name %></span>, hat neue Beiträge",
|
||||
"chat": "Chat",
|
||||
"sendChat": "Nachricht senden",
|
||||
"group": "Gruppe",
|
||||
@@ -151,14 +151,14 @@
|
||||
"onlyGroupLeaderCanEditTasks": "Nicht berechtigt, Aufgaben zu bearbeiten!",
|
||||
"onlyGroupTasksCanBeAssigned": "Nur Team-Aufgaben können verteilt werden",
|
||||
"assignedTo": "Zugewiesen an",
|
||||
"assignedToUser": "Zugewiesen: <strong>@<%- userName %></strong>",
|
||||
"assignedToUser": "Zugewiesen: <strong>@<%= userName %></strong>",
|
||||
"assignedToMembers": "<%= userCount %> Mitgliedern",
|
||||
"assignedToYouAndMembers": "<strong>Dir</strong>, <%= userCount %> Mitgliedern",
|
||||
"youAreAssigned": "Zugewiesen: <strong>Dir</strong>",
|
||||
"taskIsUnassigned": "Diese Aufgabe ist niemandem zugewiesen",
|
||||
"confirmUnClaim": "Bist Du sicher, dass Du diese Aufgabe abgeben möchtest?",
|
||||
"confirmNeedsWork": "Bist Du sicher, dass Du diese Aufgabe auf \"Benötigt Arbeit\" setzen möchtest?",
|
||||
"userRequestsApproval": "<strong><%- userName %></strong> beantragt eine Bestätigung",
|
||||
"userRequestsApproval": "<strong><%= userName %></strong> beantragt eine Bestätigung",
|
||||
"userCountRequestsApproval": "<strong><%= userCount %> Mitglieder</strong> beantragen eine Bestätigung",
|
||||
"youAreRequestingApproval": "Du beantragst eine Bestätigung",
|
||||
"chatPrivilegesRevoked": "Du kannst dies nicht tun, da Dir Deine Chat-Privilegien entzogen wurden. Für genauere Angaben oder um zu fragen, ob Dir Deine Chat-Privilegien zurückgegeben werden können, schreibe bitte eine E-Mail an den Community-Manager unter admin@habitica.com oder bitte Deine Eltern diese E-Mail zu schreiben. Bitte gib Deinen @Usernamen in der E-Mail an. Falls ein Moderator Dir bereits mitgeteilt hat, dass diese Sperre zeitlich begrenzt ist, brauchst Du keine E-Mail zu schreiben.",
|
||||
@@ -168,9 +168,9 @@
|
||||
"claim": "Aufgabe übernehmen",
|
||||
"removeClaim": "Aufgabe abtreten",
|
||||
"onlyGroupLeaderCanManageSubscription": "Nur der Gruppenleiter kann Gruppen-Registrierungen verwalten",
|
||||
"yourTaskHasBeenApproved": "Deiner Aufgabe <span class=\"notification-green notification-bold\"><%- taskText %></span> wurde Zustimmung erteilt.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%- managerName %></span> hat <span class=\"notification-bold\"><%- taskText %></span> als unfertig markiert.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%- user %></span> bittet um Zustimmung für <span class=\"notification-bold\"><%- taskName %></span>",
|
||||
"yourTaskHasBeenApproved": "Deiner Aufgabe <span class=\"notification-green notification-bold\"><%= taskText %></span> wurde Zustimmung erteilt.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> hat <span class=\"notification-bold\"><%= taskText %></span> als unfertig markiert.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%= user %></span> bittet um Zustimmung für <span class=\"notification-bold\"><%= taskName %></span>",
|
||||
"approve": "Zustimmen",
|
||||
"approveTask": "Aufgabe zustimmen",
|
||||
"needsWork": "Benötigt Arbeit",
|
||||
@@ -183,8 +183,8 @@
|
||||
"userIsClamingTask": "`<%= username %> beansprucht:` <%= task %>",
|
||||
"approvalRequested": "Zustimmung erbeten",
|
||||
"cantDeleteAssignedGroupTasks": "Du kannst Gruppen-Aufgaben, die Dir zugewiesen wurden, nicht löschen.",
|
||||
"groupPlanUpgraded": "<strong><%- groupName %></strong> wurde erfolgreich auf einen Gruppenplan hochgestuft!",
|
||||
"groupPlanCreated": "<strong><%- groupName %></strong> wurde erstellt!",
|
||||
"groupPlanUpgraded": "<strong><%= groupName %></strong> wurde erfolgreich auf einen Gruppenplan hochgestuft!",
|
||||
"groupPlanCreated": "<strong><%= groupName %></strong> wurde erstellt!",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Nur der Gruppenleiter kann Nutzer zu einer Gruppe mit einem Abonnement hinzufügen.",
|
||||
"paymentDetails": "Zahlungsinformationen",
|
||||
"aboutToJoinCancelledGroupPlan": "Du bist dabei einer Gruppe mit gekündigtem Plan beizutreten. Du erhältst KEIN freies Abonnement.",
|
||||
@@ -321,8 +321,8 @@
|
||||
"allAssignedCompletion": "Alle – Ist erledigt, sobald alle zugeteilten Benutzer abschliessen",
|
||||
"pmReported": "Danke dass Du diese Nachricht gemeldet hast.",
|
||||
"suggestedGroup": "Vorgeschlagen weil Du bei Habitica neu bist.",
|
||||
"taskClaimed": "<%- userName %> hat die Aufgabe <span class=\"notification-bold\"><%- taskText %></span> übernommen.",
|
||||
"youHaveBeenAssignedTask": "<%- managerName %> hat Dir die Aufgabe <span class=\"notification-bold\"><%- taskText %></span> zugeteilt.",
|
||||
"taskClaimed": "<%= userName %> hat die Aufgabe <span class=\"notification-bold\"><%= taskText %></span> übernommen.",
|
||||
"youHaveBeenAssignedTask": "<%= managerName %> hat Dir die Aufgabe <span class=\"notification-bold\"><%= taskText %></span> zugeteilt.",
|
||||
"groupActivityNotificationTitle": "<%= user %> hat in <%= group %> gepostet",
|
||||
"blockedToSendToThisUser": "Du kannst dieser Person nicht schreiben, weil Du diese Person blockiert hast.",
|
||||
"PMDisabled": "Private Nachrichten deaktivieren",
|
||||
@@ -337,7 +337,7 @@
|
||||
"chooseTeamMember": "Wähle ein Teammitglied",
|
||||
"unassigned": "Nicht zugewiesen",
|
||||
"claimRewards": "Belohnung einfordern",
|
||||
"assignedDateAndUser": "Zugewiesen am <strong><%= date %></strong> von <strong>@<%- username %></strong>",
|
||||
"assignedDateAndUser": "Zugewiesen am <strong><%= date %></strong> von <strong>@<%= username %></strong>",
|
||||
"assignedDateOnly": "Zugewiesen am <strong><%= date %></strong>",
|
||||
"managerNotes": "Manager-Notizen",
|
||||
"thisTaskApproved": "Dieser Aufgabe wurde zugestimmt",
|
||||
@@ -399,7 +399,7 @@
|
||||
"bannedUser": "<strong>Dieser Spieler wurde gebannt.</strong>",
|
||||
"questWithOthers": "Übernimm Missionen mit anderen",
|
||||
"sendTotal": "Gesamt:",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%- userId %>\" target=\"_blank\">@<%- userName %></a> hat dich eingeladen, der Party beizutreten <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%= userId %>\" target=\"_blank\">@<%= userName %></a> hat dich eingeladen, der Party beizutreten <span class=\"notification-bold\"><%= party %></span>",
|
||||
"partyExceedsInvitesLimit": "Eine Party kann nur bis zu <%= maxInvites %> ausstehende Einladungen haben.",
|
||||
"lookForParty": "Suche eine Party",
|
||||
"currentlyLookingForParty": "Du suchst nach einer Party!",
|
||||
|
||||
@@ -82,13 +82,12 @@
|
||||
"paymentMethods": "Kauf mit",
|
||||
"paymentSuccessful": "Die Zahlung war erfolgreich!",
|
||||
"paymentYouReceived": "Du hast erhalten:",
|
||||
"paymentYouSentGems": "Du hast <strong><%- name %></strong> geschickt:",
|
||||
"paymentYouSentSubscription": "Du hast <strong><%- name %></strong><br> ein <%= months %>-Monate-Abo für Habitica geschickt.",
|
||||
"paymentYouSentGems": "Du hast <strong><%= name %></strong> geschickt:",
|
||||
"paymentYouSentSubscription": "Du hast <strong><%= name %></strong><br> ein <%= months %>-Monate-Abo für Habitica geschickt.",
|
||||
"paymentSubBilling": "Dein Abonnement wird mit <strong>$<%= amount %></strong> alle <strong><%= months %> Monate</strong> verrechnet.",
|
||||
"success": "Erfolg!",
|
||||
"classGear": "Klassenausrüstung",
|
||||
"classGearText": "Glückwunsch zur Wahl Deiner Klasse! Ich habe Deine neue Basiswaffe dem Inventar hinzugefügt. Schaue sie Dir unten an, um sie auszurüsten!",
|
||||
"autoAllocate": "Automatische Verteilung",
|
||||
"spells": "Fertigkeiten",
|
||||
"skillsTitle": "<%= classStr %> Fertigkeiten",
|
||||
"toDo": "To-Do",
|
||||
@@ -130,5 +129,5 @@
|
||||
"sellItems": "Items verkaufen",
|
||||
"customizationsShopText": "Willst du deinen Style ändern? Hier bist du richtig! Wir haben die frischesten Looks, passend zur Saison, auf Lager.",
|
||||
"notAvailable": "Dieser Gegenstand ist nicht verfügbar.",
|
||||
"paymentYouSentSubscriptionG1G1": "Du hast <strong><%- name %></strong><br> ein <%= months %>-Monat(e)-Abo für Habitica geschickt und dasselbe Abo wurde deinem Account im Zuge der \"Schenk' Eins, Bekomm' Eins\"-Aktion gutgeschrieben!"
|
||||
"paymentYouSentSubscriptionG1G1": "Du hast <strong><%= name %></strong><br> ein <%= months %>-Monat(e)-Abo für Habitica geschickt und dasselbe Abo wurde deinem Account im Zuge der \"Schenk' Eins, Bekomm' Eins\"-Aktion gutgeschrieben!"
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@
|
||||
"mountNotOwned": "Du besitzt dieses Reittier nicht.",
|
||||
"feedPet": "<%= text %> an <%= name %> verfüttern?",
|
||||
"raisedPet": "Du hast ein <%= pet %> aufgezogen!",
|
||||
"petName": "<%= potion(locale) %> <%= egg(locale) %>",
|
||||
"mountName": "<%= potion(locale) %> <%= mount(locale) %>",
|
||||
"petName": "<%= potion %> <%= egg %>",
|
||||
"mountName": "<%= potion %> <%= mount %>",
|
||||
"keyToPets": "Schlüssel zu den Haustier-Zwingern",
|
||||
"keyToPetsDesc": "Lässt alle Standard-Haustiere frei, so dass Du sie erneut sammeln kannst. (Quest- und seltene Haustiere sind nicht betroffen.)",
|
||||
"keyToMounts": "Schlüssel zu den Reittier-Zwingern",
|
||||
|
||||
@@ -123,7 +123,6 @@
|
||||
"errorTemporaryItem": "Dieser Gegenstand ist nur temporär verfügbar und kann nicht gepinnt werden.",
|
||||
"addNotes": "Notizen hinzufügen",
|
||||
"addATitle": "Überschrift hinzufügen",
|
||||
"sureDeleteType": "Möchtest Du diese <%= type %> wirklich löschen?",
|
||||
"deleteTaskType": "Diese <%= type %> löschen",
|
||||
"pressEnterToAddTag": "Drücke Enter um das Tag '<%= tagName %>' hinzuzufügen",
|
||||
"enterTag": "Gib ein Tag ein",
|
||||
|
||||
@@ -1063,6 +1063,18 @@
|
||||
"backgroundElegantPalaceText": "Elegant Palace",
|
||||
"backgroundElegantPalaceNotes": "Admire the colorful halls of an Elegant Palace.",
|
||||
|
||||
"backgrounds032026": "SET 142: Released March 2026",
|
||||
"backgroundWaterfallWithRainbowText": "Waterfall with Rainbow",
|
||||
"backgroundWaterfallWithRainbowNotes": "Admire the breathtaking beauty of a Waterfall with a Rainbow.",
|
||||
|
||||
"backgrounds042026": "SET 143: Released April 2026",
|
||||
"backgroundRidingACometText": "Riding a Comet",
|
||||
"backgroundRidingACometNotes": "Travel through space while Riding a Comet!",
|
||||
|
||||
"backgrounds052026": "SET 144: Released May 2026",
|
||||
"backgroundElvenCitadelText": "Elven Citadel",
|
||||
"backgroundElvenCitadelNotes": "Take the scenic journey to an Elven Citadel.",
|
||||
|
||||
"timeTravelBackgrounds": "Steampunk Backgrounds",
|
||||
"backgroundAirshipText": "Airship",
|
||||
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
"challenge": "Challenge",
|
||||
"challengeDetails": "Challenges are community events in which players compete and earn prizes by completing a group of related tasks.",
|
||||
"brokenChaLink": "Broken Challenge Link",
|
||||
"brokenTask": "Broken Challenge Link: this task was part of a challenge, but has been removed from it. What would you like to do?",
|
||||
"brokenTask": "Broken Challenge Link",
|
||||
"brokenTaskDescription": "This task was part of a challenge, but has been removed from it. What would you like to do?",
|
||||
"keepIt": "Keep It",
|
||||
"removeIt": "Remove It",
|
||||
"removeTasks": "Remove Tasks",
|
||||
"brokenChallenge": "Broken Challenge Link: this task was part of a challenge, but the challenge (or group) has been deleted. What to do with the orphan tasks?",
|
||||
"challengeCompleted": "This challenge has been completed, and the winner was <span class=\"badge\"><%- user %></span>! What to do with the orphan tasks?",
|
||||
"brokenChallenge": "Broken Challenge Link",
|
||||
"brokenChallengeDescription": "This task was part of a challenge, but the challenge (or group) has been deleted. What to do with the orphan tasks?",
|
||||
"challengeCompleted": "Challenge Completed!",
|
||||
"challengeCompletedDescription": "The winner was <%= user %>! What to do with the orphan tasks?",
|
||||
"unsubChallenge": "Broken Challenge Link: this task was part of a challenge, but you have unsubscribed from the challenge. What to do with the orphan tasks?",
|
||||
"challenges": "Challenges",
|
||||
"endDate": "Ends",
|
||||
|
||||
@@ -87,16 +87,20 @@
|
||||
"allocatePerPop": "Add a Point to Perception",
|
||||
"allocateInt": "Points allocated to Intelligence:",
|
||||
"allocateIntPop": "Add a Point to Intelligence",
|
||||
"noMoreAllocate": "Now that you've hit level 100, you won't gain any more Stat Points. You can continue leveling up, or start a new adventure at level 1 by using the <a href='/shops/market'>Orb of Rebirth</a>!",
|
||||
"noMoreAllocate": "Now that you've hit level 100, you won't gain any more Stat Points. You can continue leveling up, or start a new adventure at level 1 by using the <a href='/shops/market'>Orb of Rebirth</a>.",
|
||||
"stats": "Stats",
|
||||
"strength": "Strength",
|
||||
"strText": "Strength increases the chance of random \"critical hits\" and the Gold, Experience, and drop chance boost from them. It also helps deal damage to boss monsters.",
|
||||
"strTaskText": "Increases critical hit chance and damage when scoring tasks. Also increases damage dealt to Quest bosses.",
|
||||
"constitution": "Constitution",
|
||||
"conText": "Constitution reduces the damage you take from negative Habits and missed Dailies.",
|
||||
"conTaskText": "Reduces damage taken from missed Dailies and negative Habits. Does not reduce damage from Quest bosses.",
|
||||
"perception": "Perception",
|
||||
"perText": "Perception increases how much Gold you earn, and once you've unlocked the Market, increases the chance of finding items when scoring tasks.",
|
||||
"perTaskText": "Increases item drop chance, daily item drop cap, task streak bonuses, and Gold earned when completing tasks.",
|
||||
"intelligence": "Intelligence",
|
||||
"intText": "Intelligence increases how much Experience you earn, and once you've unlocked Classes, determines your maximum Mana available for class abilities.",
|
||||
"intTaskText": "Increases Experience earned from tasks. Also increases your Mana cap and Mana regeneration rate.",
|
||||
"levelBonus": "Level Bonus",
|
||||
"allocatedPoints": "Allocated Points",
|
||||
"allocated": "Allocated",
|
||||
@@ -117,13 +121,14 @@
|
||||
"levelPopover": "Each level earns you one Point to assign to a Stat of your choice. You can do so manually, or let the game decide for you using one of the Automatic Allocation options.",
|
||||
"unallocated": "Unallocated Stat Points",
|
||||
"autoAllocation": "Automatic Allocation",
|
||||
"autoAllocate": "Auto Allocate",
|
||||
"autoAllocationPop": "Places Points into Stats according to your preferences, when you level up.",
|
||||
"evenAllocation": "Distribute Stat Points evenly",
|
||||
"evenAllocationPop": "Assigns the same number of Points to each Stat.",
|
||||
"classAllocation": "Distribute Points based on Class",
|
||||
"classAllocationPop": "Assigns more Points to the Stats important to your Class.",
|
||||
"taskAllocation": "Distribute Points based on task activity",
|
||||
"taskAllocationPop": "Assigns Points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete.",
|
||||
"evenAllocation": "Distribute evenly",
|
||||
"evenAllocationPop": "Assigns the same number of points to each attribute",
|
||||
"classAllocation": "Distribute based on class",
|
||||
"classAllocationPop": "Assigns more points to the attributes important to your class",
|
||||
"taskAllocation": "Distribute based on task activity",
|
||||
"taskAllocationPop": "Assigns points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete",
|
||||
"distributePoints": "Distribute Unallocated Points",
|
||||
"distributePointsPop": "Assigns all unallocated Stat Points according to the selected allocation scheme.",
|
||||
"warriorText": "Warriors score more and better \"critical hits\", which randomly give bonus Gold, Experience, and drop chance for scoring a task. They also deal heavy damage to boss monsters. Play a Warrior if you find motivation from unpredictable jackpot-style rewards, or want to dish out the hurt in boss Quests!",
|
||||
@@ -190,6 +195,10 @@
|
||||
"mainHand": "Main-Hand",
|
||||
"offHand": "Off-Hand",
|
||||
"statPoints": "Stat Points",
|
||||
"pts": "pts",
|
||||
"customizations": "Customizations"
|
||||
"pointsAvailable": "Points Available",
|
||||
"allocationMethod": "Allocation Method",
|
||||
"statAllocationInfo": "Each level earns you one point to assign to a Stat of your choice. You can do so manually, or let the game decide for you using one of the Automatic Allocation options.",
|
||||
"pts": "PTS",
|
||||
"customizations": "Customizations",
|
||||
"assignedStat": "Assigned Stat"
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
"questEggPlatypusMountText": "Platypus",
|
||||
"questEggPlatypusAdjective": "a perfectionist",
|
||||
|
||||
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective %> <%= eggText %>.",
|
||||
|
||||
"hatchingPotionBase": "Base",
|
||||
"hatchingPotionWhite": "White",
|
||||
@@ -357,9 +357,9 @@
|
||||
"hatchingPotionCryptid": "Cryptid",
|
||||
"hatchingPotionOpal": "Opal",
|
||||
|
||||
"hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> Pet.",
|
||||
"hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText %> Pet.",
|
||||
"premiumPotionUnlimitedNotes": "Not usable on Quest Pet eggs.",
|
||||
"wackyPotionNotes": "Pour this on an egg, and it will hatch as a Wacky <%= potText(locale) %> Pet.",
|
||||
"wackyPotionNotes": "Pour this on an egg, and it will hatch as a Wacky <%= potText %> Pet.",
|
||||
"wackyPotionAddlNotes": "Cannot be raised to Mounts or used on Quest Pet eggs.",
|
||||
|
||||
"foodMeat": "Meat",
|
||||
|
||||
@@ -138,6 +138,15 @@
|
||||
"faqQuestion68": "How do I prevent losing HP?",
|
||||
"webFaqAnswer68": "If you find yourself losing HP often, try some of these tips:\n\n- Pause your Dailies. The \"Pause Damage\" button in Settings will prevent you from losing HP for missed Dailies.\n- Adjust the schedule of your Dailies. By setting them to never be due, you can still complete them for rewards without risking HP loss.\n- Try using class skills:\n\t- Rogues can cast Stealth to prevent damage from missed Dailies\n\t- Warriors can cast Brutal Smash to reduce a Daily's redness, lowering damage taken if missed\n\t- Healers can cast Searing Brightness to reduce Dailies' redness, lowering damage taken if missed",
|
||||
|
||||
"faqQuestion69": "What are character stats?",
|
||||
"webFaqAnswer69": "All players have four character stats that provide different benefits:\n\n* Strength - Increases critical hit chance and damage when scoring tasks. Also increases damage dealt to Quest bosses.\n* Intelligence - Increases Experience earned from tasks. Also increases your Mana cap and Mana regeneration rate.\n* Constitution - Reduces damage taken from missed Dailies and negative Habits. Does not reduce damage from Quest bosses.\n* Perception - Increases item drop chance, daily item drop cap, task streak bonuses, and Gold earned when completing tasks.\n\nStats can be increased through stat point allocation, Equipment, class skills, and leveling up. You also gain one bonus point to all stats every two levels, up to level 100.",
|
||||
|
||||
"faqQuestion70": "What are stat points?",
|
||||
"webFaqAnswer70": "Stat points let you increase your character's core stats. You earn one stat point each time you level up (up to level 100), which you can assign manually or automatically using the Automatic Allocation feature. Stat allocation unlocks with the Class System at level 10.",
|
||||
|
||||
"faqQuestion71": "How does Automatic Allocation work?",
|
||||
"webFaqAnswer71": "The Automatic Allocation feature automatically assigns stat points according to one of the following distribution methods:\n\n* Distribute evenly - Assigns the same number of points to each attribute\n* Distribute based on class - Assigns more points to the attributes important to your class\n* Distribute based on task activity - Assigns points based on Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete\n\nIf you choose not to use Automatic Allocation, you can manually assign your stat points from the Stats section.",
|
||||
|
||||
"iosFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
"androidFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
"webFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
|
||||
@@ -578,6 +578,15 @@
|
||||
"weaponSpecialWinter2026MageText": "Candelabra Staff",
|
||||
"weaponSpecialWinter2026MageNotes": "Candelabras help by holding multiple candles at a time—follow its lead the next time you need to multitask. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"weaponSpecialSpring2026WarriorText": "Mighty Froggy Foil",
|
||||
"weaponSpecialSpring2026WarriorNotes": "An opportunity to duel might present itself at any moment, and with this formidable foil, you will be ready! Increases Strength by <%= str %>. Limited Edition Spring 2026 Gear.",
|
||||
"weaponSpecialSpring2026RogueText": "Spring Branch",
|
||||
"weaponSpecialSpring2026RogueNotes": "An opportunity to grow is nearly upon you, and with these budding branches, you will be ready! Increases Strength by <%= str %>. Limited Edition Spring 2026 Gear.",
|
||||
"weaponSpecialSpring2026HealerText": "Snowdrop Staff",
|
||||
"weaponSpecialSpring2026HealerNotes": "An opportunity to begin anew with a fresh start is right up ahead, and with this splendid staff, you will be ready! Increases Intelligence by <%= int %>. Limited Edition Spring 2026 Gear.",
|
||||
"weaponSpecialSpring2026MageText": "Maypole Parasol",
|
||||
"weaponSpecialSpring2026MageNotes": "An opportunity to celebrate approaches, and with this pretty parasol pole, you will be ready! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Spring 2026 Gear.",
|
||||
|
||||
"weaponMystery201411Text": "Pitchfork of Feasting",
|
||||
"weaponMystery201411Notes": "Stab your enemies or dig in to your favorite foods - this versatile pitchfork does it all! Confers no benefit. November 2014 Subscriber Item.",
|
||||
"weaponMystery201502Text": "Shimmery Winged Staff of Love and Also Truth",
|
||||
@@ -626,6 +635,8 @@
|
||||
"weaponMystery202512Notes": "A shining sword cast from sugar, mint, and arcane enchantments. Confers no benefit. December 2025 Subscriber Item.",
|
||||
"weaponMystery202601Text": "Winter's Aegis",
|
||||
"weaponMystery202601Notes": "An icy bubble shield that grants magical protection from opposing elements. Confers no benefit. January 2026 Subscriber Item.",
|
||||
"weaponMystery202603Text": "Wisteria Wizard Staff",
|
||||
"weaponMystery202603Notes": "Cast spells to warm the spring air and encourage the blossoms to bud! Confers no benefit. March 2026 Subscriber Item.",
|
||||
|
||||
"weaponMystery301404Text": "Steampunk Cane",
|
||||
"weaponMystery301404Notes": "Excellent for taking a turn about town. March 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -1412,6 +1423,15 @@
|
||||
"armorSpecialWinter2026MageText": "Midwinter Candle Robe",
|
||||
"armorSpecialWinter2026MageNotes": "Glide smoothly along your path like wax on your way to completing your Dailies. Increases Intelligence by <%= int %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"armorSpecialSpring2026WarriorText": "Frog Armor",
|
||||
"armorSpecialSpring2026WarriorNotes": "Spring into action just as soon as the snow begins to thaw. Increases Constitution by <%= con %>. Limited Edition Spring 2026 Gear.",
|
||||
"armorSpecialSpring2026RogueText": "Birch Bark Armor",
|
||||
"armorSpecialSpring2026RogueNotes": "Withstand inevitable spring rains as well as light breezes. Increases Perception by <%= per %>. Limited Edition Spring 2026 Gear.",
|
||||
"armorSpecialSpring2026HealerText": "Snowdrop Gown",
|
||||
"armorSpecialSpring2026HealerNotes": "Glide gracefully from a cold, dark winter into glorious spring. Increases Constitution by <%= con %>. Limited Edition Spring 2026 Gear.",
|
||||
"armorSpecialSpring2026MageText": "Maypole Dancer Outfit",
|
||||
"armorSpecialSpring2026MageNotes": "Arrive ready to dance, picnic, and enjoy the warm weather spring brings. Increases Intelligence by <%= int %>. Limited Edition Spring 2026 Gear.",
|
||||
|
||||
"armorMystery201402Text": "Messenger Robes",
|
||||
"armorMystery201402Notes": "Shimmering and strong, these robes have many pockets to carry letters. Confers no benefit. February 2014 Subscriber Item.",
|
||||
"armorMystery201403Text": "Forest Walker Armor",
|
||||
@@ -1550,6 +1570,8 @@
|
||||
"armorMystery202509Notes": "Bright silks protect you from the weather, hot or cold. Confers no benefit. September 2025 Subscriber Item.",
|
||||
"armorMystery202512Text": "Cookie Champion Armor",
|
||||
"armorMystery202512Notes": "Ready for battle in this plate that is both sweet and strong. Confers no benefit. December 2025 Subscriber Item.",
|
||||
"armorMystery202604Text": "Audacious Astronaut Spacesuit",
|
||||
"armorMystery202604Notes": "One small step for your To Do list, one giant leap for your sense of accomplishment! Confers no benefit. April 2026 Subscriber Item.",
|
||||
|
||||
"armorMystery301404Text": "Steampunk Suit",
|
||||
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
||||
@@ -1800,6 +1822,10 @@
|
||||
"armorArmoireBlackPartyDressNotes": "You’re strong, smart, hearty, and so fashionable! Increases Strength, Intelligence, and Constitution by <%= attrs %> each. Enchanted Armoire: Black Hairbow Set (Item 2 of 2).",
|
||||
"armorArmoireLoneCowpokeOutfitText": "Lone Cowpoke Outfit",
|
||||
"armorArmoireLoneCowpokeOutfitNotes": "Whoa, there! Want to make a statement when you ride into town as a mysterious stranger ready to be productive? Here’s the perfect outfit, complete with chaps and a shining, silver belt buckle. Increases Constitution by <%= con %>. Enchanted Armoire: Lone Cowpoke Set (Item 2 of 2)",
|
||||
"armorArmoireSoftYellowSuitText": "Soft Yellow Suit",
|
||||
"armorArmoireSoftYellowSuitNotes": "Yellow is an energetic color. Wear this to bed, and you will wake up with the sun the next morning ready to tackle a day full of tasks. Increases Constitution and Strength by <%= attrs %> each. Enchanted Armoire: Yellow Loungewear Set (Item 2 of 3).",
|
||||
"armorArmoireHandstandOutfitText": "Handstand",
|
||||
"armorArmoireHandstandOutfitNotes": "Things sure do look different when you’re upside-down, don’t they? If you’re feeling stuck, it’s time for a fresh perspective! Increases Perception by <%= per %>. Enchanted Armoire: Handstand Set (Item 1 of 1).",
|
||||
|
||||
"headgear": "helm",
|
||||
"headgearCapitalized": "Headgear",
|
||||
@@ -2352,6 +2378,15 @@
|
||||
"headSpecialWinter2026MageText": "Midwinter Candle Hat",
|
||||
"headSpecialWinter2026MageNotes": "Maintain focus and illumination as you set your sights on greater goals this season. Increases Perception by <%= per %>. Limited Edition 2025-2026 Winter Gear.",
|
||||
|
||||
"headSpecialSpring2026WarriorText": "Frog Warrior Helm",
|
||||
"headSpecialSpring2026WarriorNotes": "Frogs are well-known for their resistance to corruption. This helm will grant you their noble qualities! Increases Strength by <%= str %>. Limited Edition Spring 2026 Gear.",
|
||||
"headSpecialSpring2026RogueText": "Spring Branch Helm",
|
||||
"headSpecialSpring2026RogueNotes": "Make a striking statement with twigs and buds growing wild in all directions. Increases Perception by <%= per %>. Limited Edition Spring 2026 Gear.",
|
||||
"headSpecialSpring2026HealerText": "Snowdrop Helm",
|
||||
"headSpecialSpring2026HealerNotes": "Make a hopeful statement with these beautiful, resilient petals. Increases Intelligence by <%= int %>. Limited Edition Spring 2026 Gear.",
|
||||
"headSpecialSpring2026MageText": "Mayflower Crown",
|
||||
"headSpecialSpring2026MageNotes": "Make a joyous statement with bright blooms encircling your head. Increases Perception by <%= per %>. Limited Edition Spring 2026 Gear.",
|
||||
|
||||
"headSpecialGaymerxText": "Rainbow Warrior Helm",
|
||||
"headSpecialGaymerxNotes": "In celebration of the GaymerX Conference, this special helmet is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGTBQ and gaming and is open to everyone.",
|
||||
|
||||
@@ -2538,7 +2573,11 @@
|
||||
"headMystery202512Text": "Cookie Champion Helm",
|
||||
"headMystery202512Notes": "Gingerbread forged with ancient magic will protect you as long as you can hold off your urge to try a bite! Confers no benefit. December 2025 Subscriber Item.",
|
||||
"headMystery202602Text": "Sakura Fox Ears",
|
||||
"headMystery202602Notes": " Your hearing will be sharpened by these ears such that you can hear the buds of blossoms growing on tree branches as spring approaches. Confers no benefit. February 2026 Subscriber Item.",
|
||||
"headMystery202602Notes": "Your hearing will be sharpened by these ears such that you can hear the buds of blossoms growing on tree branches as spring approaches. Confers no benefit. February 2026 Subscriber Item.",
|
||||
"headMystery202603Text": "Wisteria Wizard Hat",
|
||||
"headMystery202603Notes": "This jaunty hat not only enhances your magical ability, it also has a lovely spring scent! Confers no benefit. March 2026 Subscriber Item.",
|
||||
"headMystery202604Text": "Audacious Astronaut Helmet",
|
||||
"headMystery202604Notes": "In space, no one can hear you check off your To Do’s. But the real reward is your sense of personal accomplishment! Confers no benefit. April 2026 Subscriber Item.",
|
||||
|
||||
"headMystery301404Text": "Fancy Top Hat",
|
||||
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -2769,6 +2808,10 @@
|
||||
"headArmoireBlacksmithsGogglesNotes": "Shatter and heat-resistant ocular protection is yours when you’re working in a forge. Increases Perception by <%= per %>. Enchanted Armoire: Blacksmith Set (Item 1 of 3).",
|
||||
"headArmoireLoneCowpokeHatText": "Lone Cowpoke Hat",
|
||||
"headArmoireLoneCowpokeHatNotes": "Howdy there, pardner! D’you hate when you’re out on the range, workin’ on tasks, and sun gets in your eyes? Well, good thing you’ve got a hat for that now. Increases Perception by <%= per %>. Enchanted Armoire: Lone Cowpoke Set (Item 1 of 2)",
|
||||
"headArmoireFloppyYellowHatText": "Yellow Floppy Hat",
|
||||
"headArmoireFloppyYellowHatNotes": "Many spells have been sewn into this simple hat, giving it a youthful yellow color. Increases all stats by <%= attrs %> each. Enchanted Armoire: Yellow Loungewear Set (Item 1 of 3).",
|
||||
"headArmoireVerdantArmingCapText": "Verdant Page Arming Cap",
|
||||
"headArmoireVerdantArmingCapNotes": "This comfy, cushioned coif makes you battle-ready and helps you withstand anything heavy that could come your way. Increases Perception and Constitution by <%= attrs %> each. Enchanted Armoire: Verdant Page Set (Item 1 of 2).",
|
||||
|
||||
"offhand": "off-hand item",
|
||||
"offHandCapitalized": "Off-Hand Item",
|
||||
@@ -3086,6 +3129,13 @@
|
||||
"shieldSpecialWinter2026HealerText": "Starburst",
|
||||
"shieldSpecialWinter2026HealerNotes": "Stars help with wayfinding, energy, and illumination—all things that help you better conquer a task list. Increases Constitution by <%= con %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"shieldSpecialSpring2026WarriorText": "Frog Warrior Candelabra",
|
||||
"shieldSpecialSpring2026WarriorNotes": "Not only can this candelabra light your way, you can use it to melt any lingering snow and ice. Increases Constitution by <%= con %>. Limited Edition Spring 2026 Gear.",
|
||||
"shieldSpecialSpring2026RogueText": "Spring Branch",
|
||||
"shieldSpecialSpring2026RogueNotes": "Reach out and reach high with these branches. They double as a back scratcher in a pinch. Increases Strength by <%= str %>. Limited Edition Spring 2026 Gear.",
|
||||
"shieldSpecialSpring2026HealerText": "Snowdrop Leaf",
|
||||
"shieldSpecialSpring2026HealerNotes": "Create a light breeze with this fan as the days grow warmer. It doubles as a writing utensil in a pinch. Increases Constitution by <%= con %>. Limited Edition Spring 2026 Gear.",
|
||||
|
||||
"shieldMystery201601Text": "Resolution Slayer",
|
||||
"shieldMystery201601Notes": "This blade can be used to parry away all distractions. Confers no benefit. January 2016 Subscriber Item.",
|
||||
"shieldMystery201701Text": "Time-Freezer Shield",
|
||||
@@ -3116,6 +3166,8 @@
|
||||
"shieldMystery202508Notes": "If you thought one spinning blade was cool looking, try two! Confers no benefit. August 2025 Subscriber Item.",
|
||||
"shieldMystery202511Text": "Frost Shield",
|
||||
"shieldMystery202511Notes": "This rugged shield of icy rock protects you from bad Habits but won't freeze your hands. Confers no benefit. November 2025 Subscriber Item.",
|
||||
"shieldMystery202605Text": "Nightfall Shield",
|
||||
"shieldMystery202605Notes": "Let the moon’s shining light protect you from dangers in the dark. Confers no benefit. May 2026 Subscriber Item.",
|
||||
|
||||
"shieldMystery301405Text": "Clock Shield",
|
||||
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
|
||||
@@ -3298,6 +3350,10 @@
|
||||
"shieldArmoireDoubleBassNotes": "Bom doo bom brrrr brr brr brrrr! Gather your party for some grounding or dancing as you listen to music on this deep double bass. Increases Constitution and Strength by <%= attrs %> each. Enchanted Armoire: Musical Instrument Set 2 (Item 3 of 3)",
|
||||
"shieldArmoirePrettyPinkGiftBoxText": "Pretty Pink Present",
|
||||
"shieldArmoirePrettyPinkGiftBoxNotes": "Is this gift from a dear friend? A caring relative? A true love? A secret admirer? Whoever sent it knows you’ll be pleased with what’s inside. Increases all stats by <%= attrs %> each. Enchanted Armoire: Pretty in Pink Set (Item 2 of 2)",
|
||||
"shieldArmoireSoftYellowPillowText": "Soft Yellow Pillow",
|
||||
"shieldArmoireSoftYellowPillowNotes": "The experienced warrior packs a pillow for any expedition. Grow and shine as you consolidate all you’ve learned during past adventures… even while you nap. Increases Intelligence and Perception by <%= attrs %> each. Enchanted Armoire: Yellow Loungewear Set (Item 3 of 3).",
|
||||
"shieldArmoireVerdantBannerText": "Verdant Page Banner",
|
||||
"shieldArmoireVerdantBannerNotes": "Wave your banner high to signal friends it’s time to rally together! Intelligence by <%= int %>. Enchanted Armoire: Verdant Page Set (Item 2 of 2).",
|
||||
|
||||
"back": "Back Accessory",
|
||||
"backBase0Text": "No Back Accessory",
|
||||
@@ -3392,6 +3448,8 @@
|
||||
"backMystery202601Notes": "This mark grants the user control over the elements of the season of cold and frost. Confers no benefit. January 2026 Subscriber Item.",
|
||||
"backMystery202602Text": "Five Tails of Sakura",
|
||||
"backMystery202602Notes": "These fluffy tails are the color of cherry blossoms, a reminder that spring is on the way! Confers no benefit. February 2026 Subscriber Item.",
|
||||
"backMystery202605Text": "Nightfall Nimbus",
|
||||
"backMystery202605Notes": "A glowing aureole of moonlight and starlight to illuminate the darkest night. Confers no benefit. May 2026 Subscriber Item.",
|
||||
|
||||
"backArmoireHarpsichordText": "Harpsichord",
|
||||
"backArmoireHarpsichordNotes": "Pting! Ptiiing! Gather your party for a dinner or picnic and listen to a tinny melody on this harpsichord. Increases Perception and Intelligence by <%= attrs %> each. Enchanted Armoire: Musical Instrument Set 2 (Item 1 of 3)",
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
"emptyMessagesLine1": "You don't have any messages",
|
||||
"emptyMessagesLine2": "Send a message to start a conversation with your Party members or another Habitica player",
|
||||
"newMessage": "New Message",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> sent you a message",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%= user %></span> sent you a message",
|
||||
"letsgo": "Let's Go!",
|
||||
"selected": "Selected",
|
||||
"howManyToBuy": "How many would you like to purchase?",
|
||||
@@ -242,5 +242,6 @@
|
||||
"whyReportingPlayerPlaceholder": "Reason for report",
|
||||
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habitica’s Community Guidelines.",
|
||||
"targetUserNotExist": "Target User: '<%= userName %>' does not exist.",
|
||||
"rememberToBeKind": "Please remember to be kind, respectful, and follow the <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>."
|
||||
"rememberToBeKind": "Please remember to be kind, respectful, and follow the <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>.",
|
||||
"confirmPurchase": "Confirm Purchase"
|
||||
}
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
"userId": "User ID",
|
||||
"invite": "Invite",
|
||||
"leave": "Leave",
|
||||
"invitedToParty": "You were invited to join the Party <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%- userId %>\" target=\"_blank\">@<%- userName %></a> has invited you to join the Party <span class=\"notification-bold\"><%- party %></span>",
|
||||
"invitedToPrivateGuild": "You were invited to join the private Group <span class=\"notification-bold\"><%- guild %></span>",
|
||||
"invitedToPublicGuild": "You were invited to join the Group <span class=\"notification-bold-blue\"><%- guild %></span>",
|
||||
"invitedToParty": "You were invited to join the Party <span class=\"notification-bold\"><%= party %></span>",
|
||||
"invitedToPartyBy": "<a href=\"/profile/<%= userId %>\" target=\"_blank\">@<%= userName %></a> has invited you to join the Party <span class=\"notification-bold\"><%= party %></span>",
|
||||
"invitedToPrivateGuild": "You were invited to join the private Group <span class=\"notification-bold\"><%= guild %></span>",
|
||||
"invitedToPublicGuild": "You were invited to join the Group <span class=\"notification-bold-blue\"><%= guild %></span>",
|
||||
"invitationAcceptedHeader": "Your Invitation has been Accepted",
|
||||
"invitationAcceptedBody": "<%= username %> accepted your invitation to <%= groupName %>!",
|
||||
"systemMessage": "System Message",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%- name %></span> has new posts",
|
||||
"newMsgParty": "Your Party, <span class=\"notification-bold-blue\"><%- name %></span>, has new posts",
|
||||
"newMsgGuild": "<span class=\"notification-bold-blue\"><%= name %></span> has new posts",
|
||||
"newMsgParty": "Your Party, <span class=\"notification-bold-blue\"><%= name %></span>, has new posts",
|
||||
"chat": "Chat",
|
||||
"sendChat": "Send Chat",
|
||||
"group": "Group",
|
||||
@@ -184,7 +184,7 @@
|
||||
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
||||
"assignTo": "Assign To",
|
||||
"assignedTo": "Assigned to",
|
||||
"assignedToUser": "Assigned: <strong>@<%- userName %></strong>",
|
||||
"assignedToUser": "Assigned: <strong>@<%= userName %></strong>",
|
||||
"assignedToMembers": "<%= userCount %> users",
|
||||
"assignedToYouAndMembers": "<strong>You</strong>, <%= userCount %> users",
|
||||
"youAreAssigned": "Assigned: <strong>you</strong>",
|
||||
@@ -193,7 +193,7 @@
|
||||
"chooseTeamMember": "Search for a team member",
|
||||
"confirmUnClaim": "Are you sure you want to unclaim this task?",
|
||||
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?",
|
||||
"userRequestsApproval": "<strong><%- userName %></strong> requests approval",
|
||||
"userRequestsApproval": "<strong><%= userName %></strong> requests approval",
|
||||
"userCountRequestsApproval": "<strong><%= userCount %> members</strong> request approval",
|
||||
"youAreRequestingApproval": "You are requesting approval",
|
||||
"chatPrivilegesRevoked": "You cannot do this because your chat privileges have been removed. For details or to ask if your privileges can be returned, please email our Community Manager at admin@habitica.com or ask your parent or guardian to email them. Please include your @Username in the email. If a moderator has already told you that your chat ban is temporary, you do not need to send an email.",
|
||||
@@ -204,12 +204,12 @@
|
||||
"removeClaim": "Remove Claim",
|
||||
"onlyGroupLeaderCanManageSubscription": "Only the group leader can manage the group's subscription",
|
||||
"onlyPrivateGuildsCanUpgrade": "Only private guilds can be upgraded to a group plan.",
|
||||
"youHaveBeenAssignedTask": "<%- managerName %> has assigned you the task <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"yourTaskHasBeenApproved": "Your task <span class=\"notification-green notification-bold\"><%- taskText %></span> has been approved.",
|
||||
"youHaveBeenAssignedTask": "<%= managerName %> has assigned you the task <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"yourTaskHasBeenApproved": "Your task <span class=\"notification-green notification-bold\"><%= taskText %></span> has been approved.",
|
||||
"thisTaskApproved": "This task was approved",
|
||||
"taskClaimed": "<%- userName %> has claimed the task <span class=\"notification-bold\"><%- taskText %></span>.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%- taskText %></span> was unchecked by <span class=\"notification-bold\">@<%- managerName %></span>. Your rewards for completing the task were reverted.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%- user %></span> requests approval for <span class=\"notification-bold\"><%- taskName %></span>",
|
||||
"taskClaimed": "<%= userName %> has claimed the task <span class=\"notification-bold\"><%= taskText %></span>.",
|
||||
"taskNeedsWork": "<span class=\"notification-bold\"><%= taskText %></span> was unchecked by <span class=\"notification-bold\">@<%= managerName %></span>. Your rewards for completing the task were reverted.",
|
||||
"userHasRequestedTaskApproval": "<span class=\"notification-bold\"><%= user %></span> requests approval for <span class=\"notification-bold\"><%= taskName %></span>",
|
||||
"approve": "Approve",
|
||||
"approveTask": "Approve Task",
|
||||
"needsWork": "Needs Work",
|
||||
@@ -222,8 +222,8 @@
|
||||
"userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
|
||||
"approvalRequested": "Approval Requested",
|
||||
"cantDeleteAssignedGroupTasks": "Can't delete group tasks that are assigned to you.",
|
||||
"groupPlanUpgraded": "<strong><%- groupName %></strong> was successfully upgraded to a Group Plan!",
|
||||
"groupPlanCreated": "<strong><%- groupName %></strong> was created!",
|
||||
"groupPlanUpgraded": "<strong><%= groupName %></strong> was successfully upgraded to a Group Plan!",
|
||||
"groupPlanCreated": "<strong><%= groupName %></strong> was created!",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.",
|
||||
"paymentDetails": "Payment Details",
|
||||
"aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.",
|
||||
@@ -389,7 +389,7 @@
|
||||
"groupActivityNotificationTitle": "<%= user %> posted in <%= group %>",
|
||||
"managerNotes": "Manager's Notes",
|
||||
"assignedDateOnly": "Assigned on <strong><%= date %></strong>",
|
||||
"assignedDateAndUser": "Assigned by @<%- username %> on <%= date %>",
|
||||
"assignedDateAndUser": "Assigned by @<%= username %> on <%= date %>",
|
||||
"claimRewards": "Claim Rewards",
|
||||
"dayStart": "<strong>Day start</strong>: <%= startTime %>",
|
||||
"viewStatus": "Status",
|
||||
|
||||
@@ -223,26 +223,30 @@
|
||||
"fall2024UnderworldSorcerorMageSet": "Underworld Sorceror Set (Mage)",
|
||||
"fall2024SpaceInvaderHealerSet": "Space Invader Set (Healer)",
|
||||
"fall2024BlackCatRogueSet": "Black Cat Set (Rogue)",
|
||||
"winter2025MooseWarriorSet": "Moose Warrior Set",
|
||||
"winter2025AuroraMageSet": "Aurora Mage Set",
|
||||
"winter2025StringLightsHealerSet": "String Lights Healer Set",
|
||||
"winter2025SnowRogueSet": "Snow Rogue Set",
|
||||
"spring2025SunshineWarriorSet": "Sunshine Warrior Set",
|
||||
"spring2025CrystalPointRogueSet": "Crystal Point Rogue Set",
|
||||
"spring2025PlumeriaHealerSet": "Plumeria Healer Set",
|
||||
"spring2025MantisMageSet": "Mantis Mage Set",
|
||||
"summer2025ScallopWarriorSet": "Scallop Warrior Set",
|
||||
"summer2025SquidRogueSet": "Squid Rogue Set",
|
||||
"summer2025SeaAngelHealerSet": "Sea Angel Healer Set",
|
||||
"summer2025FairyWrasseMageSet": "Fairy Wrasse Mage Set",
|
||||
"fall2025SasquatchWarriorSet": "Sasquatch Warrior Set",
|
||||
"fall2025SkeletonRogueSet": "Skeleton Rogue Set",
|
||||
"fall2025KoboldHealerSet": "Kobold Healer Set",
|
||||
"fall2025MaskedGhostMageSet": "Masked Ghost Mage Set",
|
||||
"winter2026RimeReaperWarriorSet": "Rime Reaper Warrior Set",
|
||||
"winter2026SkiRogueSet": "Ski Rogue Set",
|
||||
"winter2026PolarBearHealerSet": "Polar Bear Healer Set",
|
||||
"winter2026MidwinterCandleMageSet": "Midwinter Candle Mage Set",
|
||||
"winter2025MooseWarriorSet": "Moose Set (Warrior)",
|
||||
"winter2025AuroraMageSet": "Aurora Set (Mage)",
|
||||
"winter2025StringLightsHealerSet": "String Lights Set (Healer)",
|
||||
"winter2025SnowRogueSet": "Snow Set (Rogue)",
|
||||
"spring2025SunshineWarriorSet": "Sunshine Set (Warrior)",
|
||||
"spring2025CrystalPointRogueSet": "Crystal Point Set (Rogue)",
|
||||
"spring2025PlumeriaHealerSet": "Plumeria Set (Healer)",
|
||||
"spring2025MantisMageSet": "Mantis Set (Mage)",
|
||||
"summer2025ScallopWarriorSet": "Scallop Set (Warrior)",
|
||||
"summer2025SquidRogueSet": "Squid Set (Rogue)",
|
||||
"summer2025SeaAngelHealerSet": "Sea Angel Set (Healer)",
|
||||
"summer2025FairyWrasseMageSet": "Fairy Wrasse Set (Mage)",
|
||||
"fall2025SasquatchWarriorSet": "Sasquatch Set (Warrior)",
|
||||
"fall2025SkeletonRogueSet": "Skeleton Set (Rogue)",
|
||||
"fall2025KoboldHealerSet": "Kobold Set (Healer)",
|
||||
"fall2025MaskedGhostMageSet": "Masked Ghost Set (Mage)",
|
||||
"winter2026RimeReaperWarriorSet": "Rime Reaper Set (Warrior)",
|
||||
"winter2026SkiRogueSet": "Ski Set (Rogue)",
|
||||
"winter2026PolarBearHealerSet": "Polar Bear Set (Healer)",
|
||||
"winter2026MidwinterCandleMageSet": "Midwinter Candle Set (Mage)",
|
||||
"spring2026FrogWarriorSet": "Frog Set (Warrior)",
|
||||
"spring2026BranchRogueSet": "Spring Branch Set (Rogue)",
|
||||
"spring2026SnowdropHealerSet": "Snowdrop Set (Healer)",
|
||||
"spring2026MaypoleMageSet": "Maypole Set (Mage)",
|
||||
"winterPromoGiftHeader": "GIFT A SUBSCRIPTION, GET ONE FREE!",
|
||||
"winterPromoGiftDetails1": "Until January 6th only, when you gift somebody a subscription, you get the same subscription for yourself for free!",
|
||||
"winterPromoGiftDetails2": "Please note that if you or your gift recipient already have a recurring subscription, the gifted subscription will only start after that subscription is cancelled or has expired. Thanks so much for your support! <3",
|
||||
|
||||
@@ -92,9 +92,9 @@
|
||||
"paymentMethods": "Purchase using",
|
||||
"paymentSuccessful": "Your payment was successful!",
|
||||
"paymentYouReceived": "You received:",
|
||||
"paymentYouSentGems": "You sent <strong><%- name %></strong>:",
|
||||
"paymentYouSentSubscription": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription.",
|
||||
"paymentYouSentSubscriptionG1G1": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription, and the same subscription was applied to your account for our Gift One Get One promotion!",
|
||||
"paymentYouSentGems": "You sent <strong><%= name %></strong>:",
|
||||
"paymentYouSentSubscription": "You sent <strong><%= name %></strong><br> a <%= months %> month(s) Habitica subscription.",
|
||||
"paymentYouSentSubscriptionG1G1": "You sent <strong><%= name %></strong><br> a <%= months %> month(s) Habitica subscription, and the same subscription was applied to your account for our Gift One Get One promotion!",
|
||||
"paymentSubBilling": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong>.",
|
||||
"groupsPaymentSubBilling": "Your next billing date is <strong><%= renewalDate %></strong>.",
|
||||
"paymentSubBillingWithMethod": "Your subscription will be billed<br><strong>$<%= amount %>.00 USD</strong> every <strong><%= months %> months</strong> via <strong><%= paymentMethod %></strong>",
|
||||
@@ -104,7 +104,6 @@
|
||||
"success": "Success!",
|
||||
"classGear": "Class Gear",
|
||||
"classGearText": "Congratulations on choosing a class! I've added your new basic weapon to your inventory. Take a look below to equip it!",
|
||||
"autoAllocate": "Auto Allocate",
|
||||
"spells": "Skills",
|
||||
"skillsTitle": "<%= classStr %> Skills",
|
||||
"toDo": "To Do",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user