diff --git a/.drone.yml b/.drone.yml
index 72f4874ce..27e99bade 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -99,7 +99,7 @@ steps:
- dependencies
- name: test-frontend
- image: cypress/browsers:node14.17.0-chrome91-ff89
+ image: cypress/browsers:node16.5.0-chrome94-ff93
pull: true
environment:
CYPRESS_API_URL: http://api:3456/api/v1
diff --git a/cypress/integration/user/login.spec.js b/cypress/integration/user/login.spec.js
index ce6086ce0..238ec77f4 100644
--- a/cypress/integration/user/login.spec.js
+++ b/cypress/integration/user/login.spec.js
@@ -8,7 +8,7 @@ const testAndAssertFailed = fixture => {
cy.wait(5000) // It can take waaaayy too long to log the user in
cy.url().should('include', '/')
- cy.get('div.notification.is-danger').contains('Wrong username or password.')
+ cy.get('div.message.danger').contains('Wrong username or password.')
}
context('Login', () => {
diff --git a/cypress/integration/user/registration.spec.js b/cypress/integration/user/registration.spec.js
index fc1b0fbde..fd940aa7e 100644
--- a/cypress/integration/user/registration.spec.js
+++ b/cypress/integration/user/registration.spec.js
@@ -32,7 +32,7 @@ context('Registration', () => {
cy.get('h2').should('contain', `Hi ${fixture.username}!`)
})
- it('Should fail', () => {
+ it.only('Should fail', () => {
const fixture = {
username: 'test',
password: '123456',
@@ -45,6 +45,6 @@ context('Registration', () => {
cy.get('#password').type(fixture.password)
cy.get('#passwordValidation').type(fixture.password)
cy.get('#register-submit').click()
- cy.get('div.notification.is-danger').contains('A user with this username already exists.')
+ cy.get('div.message.danger').contains('A user with this username already exists.')
})
})
\ No newline at end of file
diff --git a/package.json b/package.json
index 3439849aa..b73d36fa9 100644
--- a/package.json
+++ b/package.json
@@ -17,17 +17,17 @@
"browserslist:update": "npx browserslist@latest --update-db"
},
"dependencies": {
- "@bulvar/bulma": "^0.9.3",
+ "@bulvar/bulma": "^0.9.4",
"@github/hotkey": "1.6.0",
"@kyvg/vue3-notification": "2.3.4",
"@sentry/tracing": "6.15.0",
"@sentry/vue": "6.15.0",
- "@vue/compat": "3.2.22",
- "@vueuse/core": "7.0.1",
+ "@vue/compat": "3.2.23",
+ "@vueuse/core": "7.1.2",
"camel-case": "4.1.2",
"codemirror": "5.64.0",
"copy-to-clipboard": "3.3.1",
- "date-fns": "2.26.0",
+ "date-fns": "2.27.0",
"dompurify": "2.3.3",
"easymde": "2.15.0",
"flatpickr": "4.6.9",
@@ -36,57 +36,58 @@
"is-touch-device": "1.0.1",
"lodash.clonedeep": "4.5.0",
"lodash.debounce": "4.0.8",
- "marked": "4.0.4",
+ "marked": "4.0.5",
"register-service-worker": "1.7.2",
"snake-case": "3.0.4",
"ufo": "0.7.9",
"v-tooltip": "4.0.0-beta.2",
- "vue": "3.2.22",
+ "vue": "3.2.23",
"vue-advanced-cropper": "2.7.0",
"vue-drag-resize": "2.0.3",
"vue-flatpickr-component": "9.0.5",
- "vue-i18n": "9.2.0-beta.20",
+ "vue-i18n": "9.2.0-beta.22",
"vue-router": "4.0.12",
"vuedraggable": "4.1.0",
"vuex": "4.0.2",
"workbox-precaching": "6.4.1"
},
"devDependencies": {
- "@4tw/cypress-drag-drop": "2.0.0",
+ "@4tw/cypress-drag-drop": "2.1.0",
"@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/vue-fontawesome": "3.0.0-5",
"@types/flexsearch": "0.7.2",
"@types/jest": "27.0.3",
- "@typescript-eslint/eslint-plugin": "5.4.0",
- "@typescript-eslint/parser": "5.4.0",
+ "@typescript-eslint/eslint-plugin": "5.5.0",
+ "@typescript-eslint/parser": "5.5.0",
"@vitejs/plugin-legacy": "1.6.3",
- "@vitejs/plugin-vue": "1.10.0",
+ "@vitejs/plugin-vue": "1.10.1",
"@vue/eslint-config-typescript": "9.1.0",
+ "autoprefixer": "10.4.0",
"axios": "0.24.0",
"browserslist": "4.18.1",
"cypress": "8.7.0",
"cypress-file-upload": "5.0.8",
- "esbuild": "0.13.15",
+ "esbuild": "0.14.1",
"eslint": "8.3.0",
"eslint-plugin-vue": "8.1.1",
"express": "4.17.1",
"faker": "5.5.3",
- "jest": "27.3.1",
- "netlify-cli": "7.1.0",
- "postcss": "8.3.11",
+ "jest": "27.4.2",
+ "netlify-cli": "8.0.6",
+ "postcss": "8.4.4",
"postcss-preset-env": "7.0.1",
- "rollup": "2.60.1",
+ "rollup": "2.60.2",
"rollup-plugin-visualizer": "5.5.2",
- "sass": "1.43.4",
+ "sass": "1.44.0",
"slugify": "1.6.3",
"ts-jest": "27.0.7",
"typescript": "4.5.2",
"vite": "2.6.14",
- "vite-plugin-pwa": "0.11.7",
+ "vite-plugin-pwa": "0.11.9",
"vite-svg-loader": "3.1.0",
- "vue-tsc": "0.29.6",
+ "vue-tsc": "0.29.8",
"wait-on": "6.0.0",
"workbox-cli": "6.4.1"
},
@@ -95,7 +96,8 @@
"env": {
"browser": true,
"es2021": true,
- "node": true
+ "node": true,
+ "vue/setup-compiler-macros": true
},
"extends": [
"eslint:recommended",
@@ -119,6 +121,7 @@
"error",
"never"
],
+ "vue/script-setup-uses-vars": "error",
"vue/multi-word-component-names": 0
},
"parser": "vue-eslint-parser",
@@ -129,7 +132,10 @@
"ignorePatterns": [
"*.test.*",
"cypress/*"
- ]
+ ],
+ "globals": {
+ "defineProps": "readonly"
+ }
},
"postcss": {
"plugins": {
@@ -154,5 +160,6 @@
"json"
]
},
- "license": "AGPL-3.0-or-later"
-}
+ "license": "AGPL-3.0-or-later",
+ "packageManager": "yarn@1.22.17"
+}
\ No newline at end of file
diff --git a/src/components/home/contentAuth.vue b/src/components/home/contentAuth.vue
index 7a2bd2427..016ba078b 100644
--- a/src/components/home/contentAuth.vue
+++ b/src/components/home/contentAuth.vue
@@ -82,7 +82,7 @@ export default {
this.$route.name === 'labels.index' ||
this.$route.name === 'migrate.start' ||
this.$route.name === 'migrate.wunderlist' ||
- this.$route.name === 'user.settings' ||
+ this.$route.name.startsWith('user.settings') ||
this.$route.name === 'namespaces.index'
) {
return this.$store.dispatch(CURRENT_LIST, null)
diff --git a/src/components/misc/api-config.vue b/src/components/misc/api-config.vue
index 07ca857b8..c0e542f3a 100644
--- a/src/components/misc/api-config.vue
+++ b/src/components/misc/api-config.vue
@@ -30,27 +30,25 @@
(configureApi = true)">{{ $t('apiConfig.change') }}
-
+
{{ successMsg }}
-
-
+
+
{{ errorMsg }}
-
+
+
+
diff --git a/src/components/misc/no-auth-wrapper.vue b/src/components/misc/no-auth-wrapper.vue
index 22832fe94..3dfc7f5e8 100644
--- a/src/components/misc/no-auth-wrapper.vue
+++ b/src/components/misc/no-auth-wrapper.vue
@@ -2,14 +2,9 @@
@@ -17,6 +12,7 @@
diff --git a/src/components/tasks/gantt-component.vue b/src/components/tasks/gantt-component.vue
index ca88ce15b..cfdc4eca7 100644
--- a/src/components/tasks/gantt-component.vue
+++ b/src/components/tasks/gantt-component.vue
@@ -2,13 +2,6 @@
-
- {{ $t('filters.title') }}
-
{
- const store = useStorage(STORAGE_KEY, DEFAULT_COLOR_SCHEME_SETTING)
+ const store = useStorage(STORAGE_KEY, DEFAULT_COLOR_SCHEME_SETTING)
const preferredColorScheme = usePreferredColorScheme()
diff --git a/src/i18n/lang/cs-CZ.json b/src/i18n/lang/cs-CZ.json
index 248ee2caf..8ebcc352d 100644
--- a/src/i18n/lang/cs-CZ.json
+++ b/src/i18n/lang/cs-CZ.json
@@ -901,7 +901,7 @@
"5010": "Tento tým nemá k tomuto prostoru přístup.",
"5011": "Tento uživatel již má přístup k tomuto prostoru.",
"5012": "Prostor je archivován, a proto je přístupný pouze pro čtení.",
- "6001": "Název týmu nemůže být prázdný.",
+ "6001": "The team name cannot be empty.",
"6002": "Tým neexistuje.",
"6004": "Tým již má přístup k tomuto prostoru nebo seznamu.",
"6005": "Uživatel je již členem tohoto týmu.",
diff --git a/src/i18n/lang/de-DE.json b/src/i18n/lang/de-DE.json
index 509d8acb7..f2d57a937 100644
--- a/src/i18n/lang/de-DE.json
+++ b/src/i18n/lang/de-DE.json
@@ -114,12 +114,12 @@
"vikunja": "Vikunja"
},
"appearance": {
- "title": "Color Scheme",
- "setSuccess": "Saved change of color scheme to {colorScheme}",
+ "title": "Farbschema",
+ "setSuccess": "Änderung des Farbschemas auf {colorScheme} gespeichert",
"colorScheme": {
- "light": "Light",
+ "light": "Hell",
"system": "System",
- "dark": "Dark"
+ "dark": "Dunkel"
}
}
},
@@ -556,7 +556,7 @@
"text2": "Dies wird auch alle Anhänge, Erinnerungen und Verknüpfungen, die zu dieser Aufgabe gehören löschen und kann nicht rückgängig gemacht werden!"
},
"actions": {
- "assign": "Assign to a user",
+ "assign": "Benutzer:in zuweisen",
"label": "Label hinzufügen",
"priority": "Priorität setzen",
"dueDate": "Fälligkeitsdatum setzen",
@@ -775,7 +775,7 @@
"task": {
"title": "Aufgabenseite",
"done": "Eine Aufgabe als erledigt markieren",
- "assign": "Assign to a user",
+ "assign": "Benutzer:in zuweisen",
"labels": "Dieser Aufgabe ein Label hinzufügen",
"dueDate": "Ändere das Fälligkeitsdatum dieser Aufgabe",
"attachment": "Einen Anhang dieser Aufgabe hinzufügen",
diff --git a/src/i18n/lang/de-swiss.json b/src/i18n/lang/de-swiss.json
index 21b697624..d35125e5b 100644
--- a/src/i18n/lang/de-swiss.json
+++ b/src/i18n/lang/de-swiss.json
@@ -114,12 +114,12 @@
"vikunja": "Vikunja"
},
"appearance": {
- "title": "Color Scheme",
- "setSuccess": "Saved change of color scheme to {colorScheme}",
+ "title": "Farbschema",
+ "setSuccess": "Änderung des Farbschemas auf {colorScheme} gespeichert",
"colorScheme": {
- "light": "Light",
+ "light": "Hell",
"system": "System",
- "dark": "Dark"
+ "dark": "Dunkel"
}
}
},
@@ -556,7 +556,7 @@
"text2": "Das wird au alli Ahhäng, Errinnerige und Beziehige wo mit dere Uufgab verchnüpft sind chüble und cha nid rückgängig gmacht werde!"
},
"actions": {
- "assign": "Assign to a user",
+ "assign": "Benutzer:in zuweisen",
"label": "Label hinzuefüege",
"priority": "Priorität setzä",
"dueDate": "Fälligkeitsdatum setze",
@@ -775,7 +775,7 @@
"task": {
"title": "Uufgabesiite",
"done": "Uufgab als erledigt markiere",
- "assign": "Assign to a user",
+ "assign": "Benutzer:in zuweisen",
"labels": "Labels ennere Uufgab hinzuefüege",
"dueDate": "S'Fälligkeitsdatum für die Uufgab ändere",
"attachment": "En Aahang dere Uufgab hinzuefüege",
@@ -901,7 +901,7 @@
"5010": "Da Team hett kei zuegriff uf de Namensruum.",
"5011": "De Benutzer hett bereits zuegriff uf de Namensruum.",
"5012": "De Namensruum isch momentan schriibgschützt weil er archiviert isch.",
- "6001": "Der TeamName kann nicht leer sein.",
+ "6001": "Der Teamname kann nicht leer sein.",
"6002": "Da Team giz nid.",
"6004": "Da Team het scho Zuegang zu dem Namensruum oder Liste.",
"6005": "De Benutzer isch scho bi dem Team.",
diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/en.json
+++ b/src/i18n/lang/en.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/es-ES.json b/src/i18n/lang/es-ES.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/es-ES.json
+++ b/src/i18n/lang/es-ES.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/fr-FR.json b/src/i18n/lang/fr-FR.json
index 342bab076..88a30c07f 100644
--- a/src/i18n/lang/fr-FR.json
+++ b/src/i18n/lang/fr-FR.json
@@ -901,7 +901,7 @@
"5010": "Cette équipe n’a pas accès à cet espace de noms.",
"5011": "Cet·e utilisateur·rice a déjà accès à cet espace de noms.",
"5012": "L’espace de noms est archivé et ne peut donc être consulté qu’en lecture seule.",
- "6001": "Le nom de l’équipe ne peut pas être vide.",
+ "6001": "The team name cannot be empty.",
"6002": "L’équipe n’existe pas.",
"6004": "L’équipe a déjà accès à cet espace de noms ou à cette liste.",
"6005": "L’utilisateur·rice est déjà membre de cette équipe.",
diff --git a/src/i18n/lang/it-IT.json b/src/i18n/lang/it-IT.json
index 438a436d5..8190677d6 100644
--- a/src/i18n/lang/it-IT.json
+++ b/src/i18n/lang/it-IT.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/nl-NL.json b/src/i18n/lang/nl-NL.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/nl-NL.json
+++ b/src/i18n/lang/nl-NL.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/pt-BR.json b/src/i18n/lang/pt-BR.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/pt-BR.json
+++ b/src/i18n/lang/pt-BR.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/pt-PT.json b/src/i18n/lang/pt-PT.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/pt-PT.json
+++ b/src/i18n/lang/pt-PT.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/ro-RO.json b/src/i18n/lang/ro-RO.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/ro-RO.json
+++ b/src/i18n/lang/ro-RO.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/ru-RU.json b/src/i18n/lang/ru-RU.json
index fb92d727a..0abea93ad 100644
--- a/src/i18n/lang/ru-RU.json
+++ b/src/i18n/lang/ru-RU.json
@@ -901,7 +901,7 @@
"5010": "У этой команды нет доступа к этому пространству имён.",
"5011": "Этот пользователь уже имеет доступ к этому пространству имён.",
"5012": "Это пространство имён архивировано и поэтому доступно только для чтения.",
- "6001": "Имя команды не может быть пустым.",
+ "6001": "The team name cannot be empty.",
"6002": "Команда не существует.",
"6004": "Эта команда уже имеет доступ к этому пространству имён или списку.",
"6005": "Пользователь уже является участником этой команды.",
diff --git a/src/i18n/lang/sv-SE.json b/src/i18n/lang/sv-SE.json
new file mode 100644
index 000000000..4a939660c
--- /dev/null
+++ b/src/i18n/lang/sv-SE.json
@@ -0,0 +1,933 @@
+{
+ "home": {
+ "welcomeNight": "Good Night {username}",
+ "welcomeMorning": "Good Morning {username}",
+ "welcomeDay": "Hi {username}",
+ "welcomeEvening": "Good Evening {username}",
+ "lastViewed": "Last viewed",
+ "list": {
+ "newText": "You can create a new list for your new tasks:",
+ "new": "Create a new list",
+ "importText": "Or import your lists and tasks from other services into Vikunja:",
+ "import": "Import your data into Vikunja"
+ }
+ },
+ "404": {
+ "title": "Not found",
+ "text": "The page you requested does not exist."
+ },
+ "ready": {
+ "loading": "Vikunja is loading…",
+ "errorOccured": "An error occured:",
+ "checkApiUrl": "Please check if the api url is correct.",
+ "noApiUrlConfigured": "No API url was configured. Please set one below:"
+ },
+ "offline": {
+ "title": "You are offline.",
+ "text": "Please check your network connection and try again."
+ },
+ "user": {
+ "auth": {
+ "username": "Username",
+ "usernameEmail": "Username Or Email Address",
+ "usernamePlaceholder": "e.g. frederick",
+ "email": "E-mail address",
+ "emailPlaceholder": "e.g. frederic{'@'}vikunja.io",
+ "password": "Password",
+ "passwordRepeat": "Retype your password",
+ "passwordPlaceholder": "e.g. •••••••••••",
+ "resetPassword": "Reset your password",
+ "resetPasswordAction": "Send me a password reset link",
+ "resetPasswordSuccess": "Check your inbox! You should have an e-mail with instructions on how to reset your password.",
+ "passwordsDontMatch": "Passwords don't match",
+ "confirmEmailSuccess": "You successfully confirmed your email! You can log in now.",
+ "totpTitle": "Two Factor Authentication Code",
+ "totpPlaceholder": "e.g. 123456",
+ "login": "Login",
+ "register": "Register",
+ "loginWith": "Log in with {provider}",
+ "authenticating": "Authenticating…",
+ "openIdStateError": "State does not match, refusing to continue!",
+ "openIdGeneralError": "An error occured while authenticating against the third party.",
+ "logout": "Logout"
+ },
+ "settings": {
+ "title": "Settings",
+ "newPasswordTitle": "Update Your Password",
+ "newPassword": "New Password",
+ "newPasswordConfirm": "New Password Confirmation",
+ "currentPassword": "Current Password",
+ "currentPasswordPlaceholder": "Your current password",
+ "passwordsDontMatch": "The new password and its confirmation don't match.",
+ "passwordUpdateSuccess": "The password was successfully updated.",
+ "updateEmailTitle": "Update Your E-Mail Address",
+ "updateEmailNew": "New Email Address",
+ "updateEmailSuccess": "Your email address was successfully updated. We've sent you a link to confirm it.",
+ "general": {
+ "title": "General Settings",
+ "name": "Name",
+ "newName": "The new Name",
+ "savedSuccess": "The settings were successfully updated.",
+ "emailReminders": "Send me reminders for tasks via Email",
+ "overdueReminders": "Send me reminders for overdue undone tasks via email each morning",
+ "discoverableByName": "Let other users find me when they search for my name",
+ "discoverableByEmail": "Let other users find me when they search for my full email",
+ "playSoundWhenDone": "Play a sound when marking tasks as done",
+ "weekStart": "Week starts on",
+ "weekStartSunday": "Sunday",
+ "weekStartMonday": "Monday",
+ "language": "Language",
+ "defaultList": "Default List"
+ },
+ "totp": {
+ "title": "Two Factor Authentication",
+ "enroll": "Enroll",
+ "finishSetupPart1": "To finish your setup, use this secret in your totp app (Google Authenticator or similar):",
+ "finishSetupPart2": "After that, enter a code from your app below.",
+ "scanQR": "Alternatively you can scan this QR code:",
+ "passcode": "Passcode",
+ "passcodePlaceholder": "A code generated by your totp application",
+ "setupSuccess": "You've sucessfully set up two factor authentication!",
+ "enterPassword": "Please Enter Your Password",
+ "disable": "Disable two factor authentication",
+ "confirmSuccess": "You've successfully confirmed your totp setup and can use it from now on!",
+ "disableSuccess": "Two factor authentication was sucessfully disabled."
+ },
+ "caldav": {
+ "title": "Caldav",
+ "howTo": "You can connect Vikunja to caldav clients to view and manage all tasks from different clients. Enter this url into your client:",
+ "more": "More information about caldav in Vikunja"
+ },
+ "avatar": {
+ "title": "Avatar",
+ "initials": "Initials",
+ "gravatar": "Gravatar",
+ "upload": "Upload",
+ "uploadAvatar": "Upload Avatar",
+ "statusUpdateSuccess": "Avatar status was updated successfully!",
+ "setSuccess": "The avatar has been set successfully!"
+ },
+ "quickAddMagic": {
+ "title": "Quick Add Magic Mode",
+ "disabled": "Disabled",
+ "todoist": "Todoist",
+ "vikunja": "Vikunja"
+ },
+ "appearance": {
+ "title": "Color Scheme",
+ "setSuccess": "Saved change of color scheme to {colorScheme}",
+ "colorScheme": {
+ "light": "Light",
+ "system": "System",
+ "dark": "Dark"
+ }
+ }
+ },
+ "deletion": {
+ "title": "Delete your Vikunja Account",
+ "text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, lists, tasks and everything associated with it.",
+ "text2": "To proceed, please enter your password. You will receive an email with further instructions.",
+ "confirm": "Delete my account",
+ "requestSuccess": "The request was successful. You'll receive an email with further instructions.",
+ "passwordRequired": "Please enter your password.",
+ "confirmSuccess": "You've successfully confirmed the deletion of your account. We will delete your account in three days.",
+ "scheduled": "We will delete your Vikunja account at {date} ({dateSince}).",
+ "scheduledCancel": "To cancel the deletion of your account, click here.",
+ "scheduledCancelText": "To cancel the deletion of your account, please enter your password below:",
+ "scheduledCancelConfirm": "Cancel the deletion of my account",
+ "scheduledCancelSuccess": "We will not delete your account."
+ },
+ "export": {
+ "title": "Export your Vikunja data",
+ "description": "You can request a copy of all your Vikunja data. This include Namespaces, Lists, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
+ "descriptionPasswordRequired": "Please enter your password to proceed:",
+ "request": "Request a copy of my Vikunja Data",
+ "success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
+ "downloadTitle": "Download your exported Vikunja data"
+ }
+ },
+ "list": {
+ "archived": "This list is archived. It is not possible to create new or edit tasks for it.",
+ "title": "List Title",
+ "color": "Color",
+ "lists": "Lists",
+ "search": "Type to search for a list…",
+ "searchSelect": "Click or press enter to select this list",
+ "shared": "Shared Lists",
+ "create": {
+ "header": "Create a new list",
+ "titlePlaceholder": "The list's title goes here…",
+ "addTitleRequired": "Please specify a title.",
+ "createdSuccess": "The list was successfully created.",
+ "addListRequired": "Please specify a list or set a default list in the settings."
+ },
+ "archive": {
+ "title": "Archive \"{list}\"",
+ "archive": "Archive this list",
+ "unarchive": "Un-Archive this list",
+ "unarchiveText": "You will be able to create new tasks or edit it.",
+ "archiveText": "You won't be able to edit this list or create new tasks until you un-archive it.",
+ "success": "The list was successfully archived."
+ },
+ "background": {
+ "title": "Set list background",
+ "remove": "Remove Background",
+ "upload": "Choose a background from your pc",
+ "searchPlaceholder": "Search for a background…",
+ "poweredByUnsplash": "Powered by Unsplash",
+ "loadMore": "Load more photos",
+ "success": "The background has been set successfully!",
+ "removeSuccess": "The background has been removed successfully!"
+ },
+ "delete": {
+ "title": "Delete \"{list}\"",
+ "header": "Delete this list",
+ "text1": "Are you sure you want to delete this list and all of its contents?",
+ "text2": "This includes all tasks and CANNOT BE UNDONE!",
+ "success": "The list was successfully deleted."
+ },
+ "duplicate": {
+ "title": "Duplicate this list",
+ "label": "Duplicate",
+ "text": "Select a namespace which should hold the duplicated list:",
+ "success": "The list was successfully duplicated."
+ },
+ "edit": {
+ "header": "Edit This List",
+ "title": "Edit \"{list}\"",
+ "titlePlaceholder": "The list title goes here…",
+ "identifierTooltip": "The list identifier can be used to uniquely identify a task across lists. You can set it to empty to disable it.",
+ "identifier": "List Identifier",
+ "identifierPlaceholder": "The list identifier goes here…",
+ "description": "Description",
+ "descriptionPlaceholder": "The lists description goes here…",
+ "color": "Color",
+ "success": "The list was successfully updated."
+ },
+ "share": {
+ "header": "Share this list",
+ "title": "Share \"{list}\"",
+ "share": "Share",
+ "links": {
+ "title": "Share Links",
+ "what": "What is a share link?",
+ "explanation": "Share Links allow you to easily share a list with other users who don't have an account on Vikunja.",
+ "create": "Create a new link share",
+ "name": "Name (optional)",
+ "namePlaceholder": "e.g. Lorem Ipsum",
+ "nameExplanation": "All actions done by this link share will show up with the name.",
+ "password": "Password (optional)",
+ "passwordExplanation": "When authenticating, the user will be required to enter this password.",
+ "noName": "No name set",
+ "remove": "Remove a link share",
+ "removeText": "Are you sure you want to remove this link share? It will no longer be possible to access this list with this link share. This cannot be undone!",
+ "createSuccess": "The link share was successfully created.",
+ "deleteSuccess": "The link share was successfully deleted"
+ },
+ "userTeam": {
+ "typeUser": "user | users",
+ "typeTeam": "team | teams",
+ "shared": "Shared with these {type}",
+ "you": "You",
+ "notShared": "Not shared with any {type} yet.",
+ "removeHeader": "Remove a {type} from the {sharable}",
+ "removeText": "Are you sure you want to remove this {sharable} from the {type}? This cannot be undone!",
+ "removeSuccess": "The {sharable} was successfully removed from the {type}.",
+ "addedSuccess": "The {type} was successfully added.",
+ "updatedSuccess": "The {type} was successfully added."
+ },
+ "right": {
+ "title": "Right",
+ "read": "Read only",
+ "readWrite": "Read & write",
+ "admin": "Admin"
+ },
+ "attributes": {
+ "link": "Link",
+ "name": "Name",
+ "sharedBy": "Shared by",
+ "right": "Right",
+ "delete": "Delete"
+ }
+ },
+ "list": {
+ "title": "List",
+ "add": "Add",
+ "addPlaceholder": "Add a new task…",
+ "empty": "This list is currently empty.",
+ "newTaskCta": "Create a new task.",
+ "editTask": "Edit Task"
+ },
+ "gantt": {
+ "title": "Gantt",
+ "showTasksWithoutDates": "Show tasks which don't have dates set",
+ "size": "Size",
+ "default": "Default",
+ "month": "Month",
+ "day": "Day",
+ "from": "From",
+ "to": "To",
+ "noDates": "This task has no dates set."
+ },
+ "table": {
+ "title": "Table",
+ "columns": "Columns"
+ },
+ "kanban": {
+ "title": "Kanban",
+ "limit": "Limit: {limit}",
+ "noLimit": "Not Set",
+ "doneBucket": "Done bucket",
+ "doneBucketHint": "All tasks moved into this bucket will automatically marked as done.",
+ "doneBucketHintExtended": "All tasks moved into the done bucket will be marked as done automatically. All tasks marked as done from elsewhere will be moved as well.",
+ "doneBucketSavedSuccess": "The done bucket has been saved successfully.",
+ "deleteLast": "You cannot remove the last bucket.",
+ "addTaskPlaceholder": "Enter the new task title…",
+ "addTask": "Add a task",
+ "addAnotherTask": "Add another task",
+ "addBucket": "Create a new bucket",
+ "addBucketPlaceholder": "Enter the new bucket title…",
+ "deleteHeaderBucket": "Delete the bucket",
+ "deleteBucketText1": "Are you sure you want to delete this bucket?",
+ "deleteBucketText2": "This will not delete any tasks but move them into the default bucket.",
+ "deleteBucketSuccess": "The bucket has been deleted successfully.",
+ "bucketTitleSavedSuccess": "The bucket title has been saved successfully.",
+ "bucketLimitSavedSuccess": "The bucket limit been saved successfully.",
+ "collapse": "Collapse this bucket"
+ },
+ "pseudo": {
+ "favorites": {
+ "title": "Favorites"
+ }
+ }
+ },
+ "namespace": {
+ "title": "Namespaces & Lists",
+ "namespace": "Namespace",
+ "showArchived": "Show Archived",
+ "noneAvailable": "You don't have any namespaces right now.",
+ "unarchive": "Un-Archive",
+ "archived": "Archived",
+ "noLists": "This namespace does not contain any lists.",
+ "createList": "Create a new list in this namespace.",
+ "namespaces": "Namespaces",
+ "search": "Type to search for a namespace…",
+ "create": {
+ "title": "Create a new namespace",
+ "titleRequired": "Please specify a title.",
+ "explanation": "A namespace is a collection of lists you can share and use to organize your lists with. In fact, every list belongs to a namepace.",
+ "tooltip": "What's a namespace?",
+ "success": "The namespace was successfully created."
+ },
+ "archive": {
+ "titleArchive": "Archive \"{namespace}\"",
+ "titleUnarchive": "Un-Archive \"{namespace}\"",
+ "archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
+ "unarchiveText": "You will be able to create new lists or edit it.",
+ "success": "The namespace was successfully archived.",
+ "description": "If a namespace is archived, you cannot create new lists or edit it."
+ },
+ "delete": {
+ "title": "Delete \"{namespace}\"",
+ "text1": "Are you sure you want to delete this namespace and all of its contents?",
+ "text2": "This includes all lists and tasks and CANNOT BE UNDONE!",
+ "success": "The namespace was successfully deleted."
+ },
+ "edit": {
+ "title": "Edit \"{namespace}\"",
+ "success": "The namespace was successfully updated."
+ },
+ "share": {
+ "title": "Share \"{namespace}\""
+ },
+ "attributes": {
+ "title": "Namespace Title",
+ "titlePlaceholder": "The namespace title goes here…",
+ "description": "Description",
+ "descriptionPlaceholder": "The namespaces description goes here…",
+ "color": "Color",
+ "archived": "Is Archived",
+ "isArchived": "This namespace is archived"
+ },
+ "pseudo": {
+ "sharedLists": {
+ "title": "Shared Lists"
+ },
+ "favorites": {
+ "title": "Favorites"
+ },
+ "savedFilters": {
+ "title": "Filters"
+ }
+ }
+ },
+ "filters": {
+ "title": "Filters",
+ "clear": "Clear Filters",
+ "attributes": {
+ "title": "Title",
+ "titlePlaceholder": "The saved filter title goes here…",
+ "description": "Description",
+ "descriptionPlaceholder": "The description goes here…",
+ "includeNulls": "Include Tasks which don't have a value set",
+ "requireAll": "Require all filters to be true for a task to show up",
+ "showDoneTasks": "Show Done Tasks",
+ "enablePriority": "Enable Filter By Priority",
+ "enablePercentDone": "Enable Filter By Percent Done",
+ "dueDateRange": "Due Date Range",
+ "startDateRange": "Start Date Range",
+ "endDateRange": "End Date Range",
+ "reminderRange": "Reminder Date Range"
+ },
+ "create": {
+ "title": "Create A Saved Filter",
+ "description": "A saved filter is a virtual list which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
+ "action": "Create new saved filter"
+ },
+ "delete": {
+ "header": "Delete this saved filter",
+ "text": "Are you sure you want to delete this saved filter?",
+ "success": "The filter was deleted successfully."
+ },
+ "edit": {
+ "title": "Edit This Saved Filter",
+ "success": "The filter was saved successfully."
+ }
+ },
+ "migrate": {
+ "title": "Migrate from other services to Vikunja",
+ "titleService": "Import your data from {name} into Vikunja",
+ "import": "Import your data into Vikunja",
+ "description": "Click on the logo of one of the third-party services below to get started.",
+ "descriptionDo": "Vikunja will import all lists, tasks, notes, reminders and files you have access to.",
+ "authorize": "To authorize Vikunja to access your {name} Account, click the button below.",
+ "getStarted": "Get Started",
+ "inProgress": "Importing in progress…",
+ "alreadyMigrated1": "It looks like you've already imported your stuff from {name} at {date}.",
+ "alreadyMigrated2": "Importing again is possible, but might create duplicates. Are you sure?",
+ "confirm": "I am sure, please start migrating now!",
+ "importUpload": "To import data from {name} into Vikunja, click the button below to select a file.",
+ "upload": "Upload file"
+ },
+ "label": {
+ "title": "Labels",
+ "manage": "Manage labels",
+ "description": "Click on a label to edit it. You can edit all labels you created, you can use all labels which are associated with a task to whose list you have access.",
+ "newCTA": "You currently do not have any labels.",
+ "search": "Type to search for a label…",
+ "create": {
+ "header": "New label",
+ "title": "Create a new label",
+ "titleRequired": "Please specify a title.",
+ "success": "The label was successfully created."
+ },
+ "edit": {
+ "header": "Edit Label",
+ "forbidden": "You are not allowed to edit this label because you dont own it.",
+ "success": "The label was successfully updated."
+ },
+ "deleteSuccess": "The label was successfully deleted.",
+ "attributes": {
+ "title": "Title",
+ "titlePlaceholder": "The label title goes here…",
+ "description": "Description",
+ "descriptionPlaceholder": "Label description",
+ "color": "Color"
+ }
+ },
+ "sharing": {
+ "authenticating": "Authenticating…",
+ "passwordRequired": "This shared list requires a password. Please enter it below:",
+ "error": "An error occured.",
+ "invalidPassword": "The password is invalid."
+ },
+ "navigation": {
+ "overview": "Overview",
+ "upcoming": "Upcoming",
+ "settings": "Settings",
+ "imprint": "Imprint",
+ "privacy": "Privacy Policy"
+ },
+ "misc": {
+ "loading": "Loading…",
+ "save": "Save",
+ "delete": "Delete",
+ "confirm": "Confirm",
+ "cancel": "Cancel",
+ "refresh": "Refresh",
+ "disable": "Disable",
+ "copy": "Copy to clipboard",
+ "search": "Search",
+ "searchPlaceholder": "Type to search…",
+ "previous": "Previous",
+ "next": "Next",
+ "poweredBy": "Powered by Vikunja",
+ "info": "Info",
+ "create": "Create",
+ "doit": "Do it!",
+ "saving": "Saving…",
+ "saved": "Saved!",
+ "default": "Default",
+ "close": "Close",
+ "download": "Download",
+ "showMenu": "Show the menu",
+ "hideMenu": "Hide the menu"
+ },
+ "input": {
+ "resetColor": "Reset Color",
+ "datepicker": {
+ "today": "Today",
+ "tomorrow": "Tomorrow",
+ "nextMonday": "Next Monday",
+ "thisWeekend": "This Weekend",
+ "laterThisWeek": "Later This Week",
+ "nextWeek": "Next Week",
+ "chooseDate": "Choose a date"
+ },
+ "editor": {
+ "edit": "Edit",
+ "done": "Done",
+ "heading1": "Heading 1",
+ "heading2": "Heading 2",
+ "heading3": "Heading 3",
+ "headingSmaller": "Heading Smaller",
+ "headingBigger": "Heading Bigger",
+ "bold": "Bold",
+ "italic": "Italic",
+ "strikethrough": "Strikethrough",
+ "code": "Code",
+ "quote": "Quote",
+ "unorderedList": "Unordered List",
+ "orderedList": "Ordered List",
+ "cleanBlock": "Clean Block",
+ "link": "Link",
+ "image": "Image",
+ "table": "Table",
+ "horizontalRule": "Horizontal Rule",
+ "sideBySide": "Side By Side",
+ "guide": "Guide"
+ },
+ "multiselect": {
+ "createPlaceholder": "Create new",
+ "selectPlaceholder": "Click or press enter to select"
+ }
+ },
+ "task": {
+ "task": "Task",
+ "new": "Create a new task",
+ "delete": "Delete this task",
+ "createSuccess": "The task was successfully created.",
+ "addReminder": "Add a new reminder…",
+ "doneSuccess": "The task was successfully marked as done.",
+ "undoneSuccess": "The task was successfully un-marked as done.",
+ "openDetail": "Open task detail view",
+ "checklistTotal": "{checked} of {total} tasks",
+ "checklistAllDone": "{total} tasks",
+ "show": {
+ "titleCurrent": "Current Tasks",
+ "titleDates": "Tasks from {from} until {to}",
+ "noDates": "Show tasks without dates",
+ "current": "Current tasks",
+ "from": "Tasks from",
+ "until": "until",
+ "today": "Today",
+ "nextWeek": "Next Week",
+ "nextMonth": "Next Month",
+ "noTasks": "Nothing to do — Have a nice day!"
+ },
+ "detail": {
+ "chooseDueDate": "Click here to set a due date",
+ "chooseStartDate": "Click here to set a start date",
+ "chooseEndDate": "Click here to set an end date",
+ "move": "Move task to a different list",
+ "done": "Done!",
+ "undone": "Mark as undone",
+ "created": "Created {0} by {1}",
+ "updated": "Updated {0}",
+ "doneAt": "Done {0}",
+ "updateSuccess": "The task was saved successfully.",
+ "deleteSuccess": "The task has been deleted successfully.",
+ "belongsToList": "This task belongs to list '{list}'",
+ "due": "Due {at}",
+ "closePopup": "Close popup",
+ "delete": {
+ "header": "Delete this task",
+ "text1": "Are you sure you want to remove this task?",
+ "text2": "This will also remove all attachments, reminders and relations associated with this task and cannot be undone!"
+ },
+ "actions": {
+ "assign": "Assign to a user",
+ "label": "Add labels",
+ "priority": "Set Priority",
+ "dueDate": "Set Due Date",
+ "startDate": "Set a Start Date",
+ "endDate": "Set an End Date",
+ "reminders": "Set Reminders",
+ "repeatAfter": "Set a repeating interval",
+ "percentDone": "Set Percent Done",
+ "attachments": "Add attachments",
+ "relatedTasks": "Add task relations",
+ "moveList": "Move task",
+ "color": "Set task color",
+ "delete": "Delete task",
+ "favorite": "Save as favorite",
+ "unfavorite": "Remove from favorites"
+ }
+ },
+ "attributes": {
+ "assignees": "Assignees",
+ "color": "Color",
+ "created": "Created",
+ "createdBy": "Created By",
+ "description": "Description",
+ "done": "Done",
+ "dueDate": "Due Date",
+ "endDate": "End Date",
+ "labels": "Labels",
+ "percentDone": "% Done",
+ "priority": "Priority",
+ "relatedTasks": "Related Tasks",
+ "reminders": "Reminders",
+ "repeat": "Repeat",
+ "startDate": "Start Date",
+ "title": "Title",
+ "updated": "Updated"
+ },
+ "subscription": {
+ "subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
+ "subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
+ "notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
+ "subscribe": "Subscribe",
+ "unsubscribe": "Unsubscribe",
+ "subscribeSuccess": "You are now subscribed to this {entity}",
+ "unsubscribeSuccess": "You are now unsubscribed to this {entity}"
+ },
+ "attachment": {
+ "title": "Attachments",
+ "createdBy": "created {0} by {1}",
+ "downloadTooltip": "Download this attachment",
+ "upload": "Upload attachment",
+ "drop": "Drop files here to upload",
+ "delete": "Delete attachment",
+ "deleteTooltip": "Delete this attachment",
+ "deleteText1": "Are you sure you want to delete the attachment {filename}?",
+ "deleteText2": "This cannot be undone!",
+ "copyUrl": "Copy URL",
+ "copyUrlTooltip": "Copy the url of this attachment for usage in text"
+ },
+ "comment": {
+ "title": "Comments",
+ "loading": "Loading comments…",
+ "edited": "edited {date}",
+ "creating": "Creating comment…",
+ "placeholder": "Add your comment…",
+ "comment": "Comment",
+ "delete": "Delete this comment",
+ "deleteText1": "Are you sure you want to delete this comment?",
+ "deleteText2": "This cannot be undone!",
+ "addedSuccess": "The comment was added successfully."
+ },
+ "deferDueDate": {
+ "title": "Defer due date",
+ "1day": "1 day",
+ "3days": "3 days",
+ "1week": "1 week"
+ },
+ "description": {
+ "placeholder": "Click here to enter a description…",
+ "empty": "No description available yet."
+ },
+ "assignee": {
+ "placeholder": "Type to assign a user…",
+ "selectPlaceholder": "Assign this user",
+ "assignSuccess": "The user has been assigned successfully.",
+ "unassignSuccess": "The user has been unassigned successfully."
+ },
+ "label": {
+ "placeholder": "Type to add a new label…",
+ "createPlaceholder": "Add this as new label",
+ "addSuccess": "The label has been added successfully.",
+ "createSuccess": "The label has been created successfully.",
+ "removeSuccess": "The label has been removed successfully.",
+ "addCreateSuccess": "The label has been created and added successfully."
+ },
+ "priority": {
+ "unset": "Unset",
+ "low": "Low",
+ "medium": "Medium",
+ "high": "high",
+ "urgent": "Urgent",
+ "doNow": "DO NOW"
+ },
+ "relation": {
+ "add": "Add a New Task Relation",
+ "new": "New Task Relation",
+ "searchPlaceholder": "Type search for a new task to add as related…",
+ "createPlaceholder": "Add this as new related task",
+ "differentList": "This task belongs to a different list.",
+ "differentNamespace": "This task belongs to a different namespace.",
+ "noneYet": "No task relations yet.",
+ "delete": "Delete Task Relation",
+ "deleteText1": "Are you sure you want to delete this task relation?",
+ "deleteText2": "This cannot be undone!",
+ "select": "Select a relation kind",
+ "kinds": {
+ "subtask": "Subtask | Subtasks",
+ "parenttask": "Parent Task | Parent Tasks",
+ "related": "Related Task | Related Tasks",
+ "duplicateof": "Duplicate Of | Duplicates Of",
+ "duplicates": "Duplicates | Duplicates",
+ "blocking": "Blocking | Blocking",
+ "blocked": "Blocked By | Blocked By",
+ "precedes": "Precedes | Precedes",
+ "follows": "Follows | Follows",
+ "copiedfrom": "Copied From | Copied From",
+ "copiedto": "Copied To | Copied To"
+ }
+ },
+ "repeat": {
+ "everyDay": "Every Day",
+ "everyWeek": "Every Week",
+ "everyMonth": "Every Month",
+ "mode": "Repeat mode",
+ "monthly": "Monthly",
+ "fromCurrentDate": "From Current Date",
+ "each": "Each",
+ "specifyAmount": "Specify an amount…",
+ "hours": "Hours",
+ "days": "Days",
+ "weeks": "Weeks",
+ "months": "Months",
+ "years": "Years"
+ },
+ "quickAddMagic": {
+ "hint": "You can use Quick Add Magic",
+ "what": "What?",
+ "title": "Quick Add Magic",
+ "intro": "When creating a task, you can use special keywords to directly add attributes to the newly created task. This allows to add commonly used attributes to tasks much faster.",
+ "multiple": "You can use this multiple times.",
+ "label1": "To add a label, simply prefix the name of the label with {prefix}.",
+ "label2": "Vikunja will first check if the label already exist and create it if not.",
+ "label3": "To use spaces, simply add a \" around the label name.",
+ "label4": "For example: {prefix}\"Label with spaces\".",
+ "priority1": "To set a task's priority, add a number 1-5, prefixed with a {prefix}.",
+ "priority2": "The higher the number, the higher the priority.",
+ "assignees": "To directly assign the task to a user, add their username prefixed with {prefix} to the task.",
+ "list1": "To set a list for the task to appear in, enter its name prefixed with {prefix}.",
+ "list2": "This will return an error if the list does not exist.",
+ "dateAndTime": "Date and time",
+ "date": "Any date will be used as the due date of the new task. You can use dates in any of these formats:",
+ "dateWeekday": "any weekday, will use the next date with that date",
+ "dateCurrentYear": "will use the current year",
+ "dateNth": "will use the {day}th of the current month",
+ "dateTime": "Combine any of the date formats with \"{time}\" (or {timePM}) to set a time."
+ }
+ },
+ "team": {
+ "title": "Teams",
+ "noTeams": "You are currently not part of any teams.",
+ "create": {
+ "title": "Create a new team",
+ "success": "The team was successfully created."
+ },
+ "edit": {
+ "title": "Edit Team \"{team}\"",
+ "members": "Team Members",
+ "search": "Type to search a user…",
+ "addUser": "Add to team",
+ "makeMember": "Make Member",
+ "makeAdmin": "Make Admin",
+ "success": "The team was successfully updated.",
+ "userAddedSuccess": "The team member was successfully added.",
+ "madeMember": "The team member was successfully made member.",
+ "madeAdmin": "The team member was successfully made admin.",
+ "delete": {
+ "header": "Delete the team",
+ "text1": "Are you sure you want to delete this team and all of its members?",
+ "text2": "All team members will lose access to lists and namespaces shared with this team. This CANNOT BE UNDONE!",
+ "success": "The team was successfully deleted."
+ },
+ "deleteUser": {
+ "header": "Remove a user from the team",
+ "text1": "Are you sure you want to remove this user from the team?",
+ "text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
+ "success": "The user was successfully deleted from the team."
+ }
+ },
+ "attributes": {
+ "name": "Team Name",
+ "namePlaceholder": "The team's name goes here…",
+ "nameRequired": "Please specify a name.",
+ "description": "Description",
+ "descriptionPlaceholder": "The teams description goes here…",
+ "admin": "Admin",
+ "member": "Member"
+ }
+ },
+ "keyboardShortcuts": {
+ "title": "Keyboard Shortcuts",
+ "general": "General",
+ "allPages": "These shortcuts work on all pages.",
+ "currentPageOnly": "These shortcuts work only on the current page.",
+ "toggleMenu": "Toggle The Menu",
+ "quickSearch": "Open the search/quick action bar",
+ "then": "then",
+ "task": {
+ "title": "Task Page",
+ "done": "Mark a task as done",
+ "assign": "Assign to a user",
+ "labels": "Add labels to this task",
+ "dueDate": "Change the due date of this task",
+ "attachment": "Add an attachment to this task",
+ "related": "Modify related tasks of this task"
+ },
+ "list": {
+ "title": "List Views",
+ "switchToListView": "Switch to list view",
+ "switchToGanttView": "Switch to gantt view",
+ "switchToKanbanView": "Switch to kanban view",
+ "switchToTableView": "Switch to table view"
+ }
+ },
+ "update": {
+ "available": "There is an update for Vikunja available!",
+ "do": "Update Now"
+ },
+ "menu": {
+ "edit": "Edit",
+ "archive": "Archive",
+ "duplicate": "Duplicate",
+ "delete": "Delete",
+ "unarchive": "Un-Archive",
+ "setBackground": "Set background",
+ "share": "Share",
+ "newList": "New list"
+ },
+ "apiConfig": {
+ "url": "Vikunja URL",
+ "urlPlaceholder": "eg. https://localhost:3456",
+ "change": "change",
+ "signInOn": "Sign in to your Vikunja account on {0}",
+ "error": "Could not find or use Vikunja installation at \"{domain}\". Please try a different url.",
+ "success": "Using Vikunja installation at \"{domain}\".",
+ "urlRequired": "A url is required."
+ },
+ "loadingError": {
+ "failed": "Loading failed, please {0}. If the error persists, please {1}.",
+ "tryAgain": "try again",
+ "contact": "contact us"
+ },
+ "notification": {
+ "title": "Notifications",
+ "none": "You don't have any notifications. Have a nice day!",
+ "explainer": "Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen."
+ },
+ "quickActions": {
+ "commands": "Commands",
+ "placeholder": "Type a command or search…",
+ "hint": "You can use {list} to limit the search to a list. Combine {list} or {label} (labels) with a search query to search for a task with these labels or on that list. Use {assignee} to only search for teams.",
+ "tasks": "Tasks",
+ "lists": "Lists",
+ "teams": "Teams",
+ "newList": "Enter the title of the new list…",
+ "newTask": "Enter the title of the new task…",
+ "newNamespace": "Enter the title of the new namespace…",
+ "newTeam": "Enter the name of the new team…",
+ "createTask": "Create a task in the current list ({title})",
+ "createList": "Create a list in the current namespace ({title})",
+ "cmds": {
+ "newTask": "New task",
+ "newList": "New list",
+ "newNamespace": "New namespace",
+ "newTeam": "New team"
+ }
+ },
+ "date": {
+ "locale": "en",
+ "altFormatLong": "j M Y H:i",
+ "altFormatShort": "j M Y"
+ },
+ "error": {
+ "error": "Error",
+ "success": "Success",
+ "0001": "You're not allowed to do that.",
+ "1001": "A user with this username already exists.",
+ "1002": "A user with this email address already exists.",
+ "1004": "No username and password specified.",
+ "1005": "The user does not exist.",
+ "1006": "Could not get the user id.",
+ "1008": "No password reset token provided.",
+ "1009": "Invalid password reset token.",
+ "1010": "Invalid email confirm token.",
+ "1011": "Wrong username or password.",
+ "1012": "Email address of the user not confirmed.",
+ "1013": "New password is empty.",
+ "1014": "Old password is empty.",
+ "1015": "Totp is already enabled for this user.",
+ "1016": "Totp is not enabled for this user.",
+ "1017": "The totp passcode is invalid.",
+ "1018": "The user avatar type setting is invalid.",
+ "2001": "ID cannot be empty or 0.",
+ "2002": "Some of the request data was invalid.",
+ "3001": "The list does not exist.",
+ "3004": "You need to have read permissions on that list to perform that action.",
+ "3005": "The list title cannot be empty.",
+ "3006": "The list share does not exist.",
+ "3007": "A list with this identifier already exists.",
+ "3008": "The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list.",
+ "4001": "The list task text cannot be empty.",
+ "4002": "The list task does not exist.",
+ "4003": "All bulk editing tasks must belong to the same list.",
+ "4004": "Need at least one task when bulk editing tasks.",
+ "4005": "You do not have the right to see the task.",
+ "4006": "You can't set a parent task as the task itself.",
+ "4007": "You can't create a task relation with an invalid kind of relation.",
+ "4008": "You can't create a task relation which already exists.",
+ "4009": "The task relation does not exist.",
+ "4010": "Cannot relate a task with itself.",
+ "4011": "The task attachment does not exist.",
+ "4012": "The task attachment is too large.",
+ "4013": "The task sort param is invalid.",
+ "4014": "The task sort order is invalid.",
+ "4015": "The task comment does not exist.",
+ "4016": "Invalid task field.",
+ "4017": "Invalid task filter comparator.",
+ "4018": "Invalid task filter concatinator.",
+ "4019": "Invalid task filter value.",
+ "5001": "The namespace does not exist.",
+ "5003": "You do not have access to the specified namespace.",
+ "5006": "The namespace name cannot be empty.",
+ "5009": "You need to have namespace read access to perform that action.",
+ "5010": "This team does not have access to that namespace.",
+ "5011": "This user has already access to that namespace.",
+ "5012": "The namespace is archived and can therefore only be accessed read only.",
+ "6001": "The team name cannot be empty.",
+ "6002": "The team does not exist.",
+ "6004": "The team already has access to that namespace or list.",
+ "6005": "The user is already a member of that team.",
+ "6006": "Cannot delete the last team member.",
+ "6007": "The team does not have access to the list to perform that action.",
+ "7002": "The user already has access to that list.",
+ "7003": "You do not have access to that list.",
+ "8001": "This label already exists on that task.",
+ "8002": "The label does not exist.",
+ "8003": "You do not have access to this label.",
+ "9001": "The right is invalid.",
+ "10001": "The bucket does not exist.",
+ "10002": "The bucket does not belong to that list.",
+ "10003": "You cannot remove the last bucket on a list.",
+ "10004": "You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold.",
+ "10005": "There can be only one done bucket per list.",
+ "11001": "The saved filter does not exist.",
+ "11002": "Saved filters are not available for link shares.",
+ "12001": "The subscription entity type is invalid.",
+ "12002": "You are already subscribed to the entity itself or a parent entity.",
+ "13001": "This link share requires a password for authentication, but none was provided.",
+ "13002": "The provided link share password was invalid."
+ },
+ "about": {
+ "title": "About",
+ "frontendVersion": "Frontend Version: {version}",
+ "apiVersion": "API Version: {version}"
+ }
+}
diff --git a/src/i18n/lang/tr-TR.json b/src/i18n/lang/tr-TR.json
index a0366b2ce..4a939660c 100644
--- a/src/i18n/lang/tr-TR.json
+++ b/src/i18n/lang/tr-TR.json
@@ -901,7 +901,7 @@
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
- "6001": "The team name cannot be emtpy.",
+ "6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
diff --git a/src/i18n/lang/vi-VN.json b/src/i18n/lang/vi-VN.json
index 7bba63001..67ff213e2 100644
--- a/src/i18n/lang/vi-VN.json
+++ b/src/i18n/lang/vi-VN.json
@@ -114,12 +114,12 @@
"vikunja": "Vikunja"
},
"appearance": {
- "title": "Color Scheme",
- "setSuccess": "Saved change of color scheme to {colorScheme}",
+ "title": "Phối màu",
+ "setSuccess": "Đã lưu phối màu vào {colorScheme}",
"colorScheme": {
- "light": "Light",
- "system": "System",
- "dark": "Dark"
+ "light": "Sáng",
+ "system": "Hệ thống",
+ "dark": "Tối"
}
}
},
@@ -556,7 +556,7 @@
"text2": "Thao tác này cũng sẽ xóa tất cả tệp đính kèm, lời nhắc và liên kết đến công việc này. Nó không thể hoàn tác!"
},
"actions": {
- "assign": "Assign to a user",
+ "assign": "Chỉ định một người",
"label": "Thêm nhãn",
"priority": "Mức độ ưu tiên",
"dueDate": "Đặt ngày đến hạn",
@@ -775,7 +775,7 @@
"task": {
"title": "Trang công việc",
"done": "Đánh dấu hoàn thành",
- "assign": "Assign to a user",
+ "assign": "Chỉ định một người",
"labels": "Thêm nhãn cho công việc này",
"dueDate": "Thay đổi ngày hết hạn của công việc này",
"attachment": "Thêm tệp đính kèm cho công việc này",
@@ -901,7 +901,7 @@
"5010": "Team này không có quyền bước vào góc làm việc đó.",
"5011": "Người này đã có quyền bước vào góc làm việc đó.",
"5012": "Góc làm việc đã được lưu trữ nên chỉ có thể vào đó để đọc.",
- "6001": "Team cũng cần có tên gọi mà.",
+ "6001": "The team name cannot be empty.",
"6002": "Team không tồn tại.",
"6004": "Team đã có quyền bước vào góc làm việc và xem danh sách.",
"6005": "Người này đã là thành viên của Team đó rồi.",
diff --git a/src/styles/common-imports.scss b/src/styles/common-imports.scss
index bfcbfe6b6..b4e6032ed 100644
--- a/src/styles/common-imports.scss
+++ b/src/styles/common-imports.scss
@@ -19,14 +19,12 @@ $mobile: math.div($tablet, 2);
$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif;
$vikunja-font: 'Quicksand', sans-serif;
-$thickness: 1px;
$pagination-current-border: var(--primary);
$navbar-item-active-color: var(--primary);
$dropdown-content-shadow: none;
$dropdown-item-hover-background-color: var(--grey-100);
-$bulmaswatch-import-font: false !default;
$site-background: var(--grey-100);
$transition-duration: 150ms;
diff --git a/src/styles/custom-properties/colors.scss b/src/styles/custom-properties/colors.scss
index 3b23f3eed..2fc3ba0d0 100644
--- a/src/styles/custom-properties/colors.scss
+++ b/src/styles/custom-properties/colors.scss
@@ -79,6 +79,8 @@
--link: var(--primary);
--link-hover: hsla(var(--primary-h), var(--primary-s), var(--primary-l), .75);
--border: var(--grey-200);
+ --input-disabled-background-color: var(--grey-100);
+ --input-disabled-border-color: var(--grey-300);
&.dark {
// Light mode colours reversed for dark mode
diff --git a/src/styles/global.scss b/src/styles/global.scss
index f4bea3171..6e357958b 100644
--- a/src/styles/global.scss
+++ b/src/styles/global.scss
@@ -23,7 +23,7 @@
@import "@bulvar/bulma/sass/elements/content";
@import "@bulvar/bulma/sass/elements/icon";
@import "@bulvar/bulma/sass/elements/image";
-@import "@bulvar/bulma/sass/elements/notification";
+// @import "@bulvar/bulma/sass/elements/notification"; // not used
@import "@bulvar/bulma/sass/elements/progress";
@import "@bulvar/bulma/sass/elements/table";
@import "@bulvar/bulma/sass/elements/tag";
@@ -48,7 +48,7 @@
// @import "@bulvar/bulma/sass/components/level"; // not used
@import "@bulvar/bulma/sass/components/media";
@import "@bulvar/bulma/sass/components/menu";
-@import "@bulvar/bulma/sass/components/message";
+// @import "@bulvar/bulma/sass/components/message"; //not used
@import "@bulvar/bulma/sass/components/modal";
@import "@bulvar/bulma/sass/components/navbar";
@import "@bulvar/bulma/sass/components/pagination";
diff --git a/src/styles/theme/_index.scss b/src/styles/theme/_index.scss
index 2c1a5b44b..b3eb47e0a 100644
--- a/src/styles/theme/_index.scss
+++ b/src/styles/theme/_index.scss
@@ -7,4 +7,4 @@
@import "form";
@import "link-share";
@import "loading";
-@import "notification";
\ No newline at end of file
+@import "flatpickr";
\ No newline at end of file
diff --git a/src/styles/theme/flatpickr.scss b/src/styles/theme/flatpickr.scss
new file mode 100644
index 000000000..1a21ca1f9
--- /dev/null
+++ b/src/styles/theme/flatpickr.scss
@@ -0,0 +1,221 @@
+// Flatpickr overrides to use css custom properties and enable styling it
+
+.flatpickr-calendar {
+ background: var(--white);
+ box-shadow: 1px 0 0 var(--grey-200), -1px 0 0 var(--grey-200), 0 1px 0 var(--grey-200), 0 -1px 0 var(--grey-200), 0 3px 13px rgba(0, 0, 0, 0.08);
+}
+
+.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1) {
+ box-shadow: -2px 0 0 var(--grey-200), 5px 0 0 var(--grey-200);
+}
+
+.flatpickr-calendar.hasTime .flatpickr-time {
+ border-top: 1px solid var(--grey-200);
+}
+
+.flatpickr-calendar.arrowTop:before {
+ border-bottom-color: var(--grey-200);
+}
+
+.flatpickr-calendar.arrowTop:after {
+ border-bottom-color: var(--white);
+}
+
+.flatpickr-calendar.arrowBottom:before {
+ border-top-color: var(--grey-200);
+}
+
+.flatpickr-calendar.arrowBottom:after {
+ border-top-color: var(--white);
+}
+
+.flatpickr-months .flatpickr-month,
+.flatpickr-months .flatpickr-prev-month,
+.flatpickr-months .flatpickr-next-month {
+ color: var(--text);
+ fill: var(--grey-900);
+}
+
+.flatpickr-months .flatpickr-prev-month:hover,
+.flatpickr-months .flatpickr-next-month:hover {
+ color: var(--grey-400);
+}
+
+.flatpickr-months .flatpickr-prev-month:hover svg,
+.flatpickr-months .flatpickr-next-month:hover svg {
+ fill: var(--primary);
+}
+
+.numInputWrapper span {
+ border: 1px solid var(--grey-200);
+}
+
+.numInputWrapper span:hover {
+ background: var(--grey-800);
+}
+
+.numInputWrapper span:active {
+ background: var(--grey-800);
+}
+
+.numInputWrapper span.arrowUp:after {
+ border-bottom: 4px solid var(--grey-200);
+}
+
+.numInputWrapper span.arrowDown:after {
+ border-top: 4px solid var(--grey-200);
+ top: 40%;
+}
+
+.numInputWrapper span svg path {
+ fill: var(--grey-800);
+}
+
+.numInputWrapper:hover {
+ background: var(--grey-100);
+}
+
+.flatpickr-current-month span.cur-month:hover {
+ background: var(--grey-100);
+}
+
+.flatpickr-current-month .numInputWrapper span.arrowUp:after {
+ border-bottom-color: var(--grey-900);
+}
+
+.flatpickr-current-month .numInputWrapper span.arrowDown:after {
+ border-top-color: var(--grey-900);
+}
+
+.flatpickr-current-month input.cur-year[disabled],
+.flatpickr-current-month input.cur-year[disabled]:hover {
+ color: var(--grey-800);
+}
+
+.flatpickr-current-month .flatpickr-monthDropdown-months:hover {
+ background: var(--grey-100);
+}
+
+span.flatpickr-weekday {
+ color: var(--grey-600);
+}
+
+.dayContainer + .dayContainer {
+ box-shadow: -1px 0 0 var(--grey-200);
+}
+
+.flatpickr-day {
+ color: var(--grey-500);
+}
+
+.flatpickr-day.inRange,
+.flatpickr-day.prevMonthDay.inRange,
+.flatpickr-day.nextMonthDay.inRange,
+.flatpickr-day.today.inRange,
+.flatpickr-day.prevMonthDay.today.inRange,
+.flatpickr-day.nextMonthDay.today.inRange,
+.flatpickr-day:hover,
+.flatpickr-day.prevMonthDay:hover,
+.flatpickr-day.nextMonthDay:hover,
+.flatpickr-day:focus,
+.flatpickr-day.prevMonthDay:focus,
+.flatpickr-day.nextMonthDay:focus {
+ background: var(--grey-200);
+ border-color: var(--grey-200);
+}
+
+.flatpickr-day.today {
+ border-color: var(--grey-400);
+}
+
+.flatpickr-day.today:hover,
+.flatpickr-day.today:focus {
+ border-color: var(--grey-400);
+ background: var(--grey-400);
+ color: var(--white);
+}
+
+.flatpickr-day.selected,
+.flatpickr-day.startRange,
+.flatpickr-day.endRange,
+.flatpickr-day.selected.inRange,
+.flatpickr-day.startRange.inRange,
+.flatpickr-day.endRange.inRange,
+.flatpickr-day.selected:focus,
+.flatpickr-day.startRange:focus,
+.flatpickr-day.endRange:focus,
+.flatpickr-day.selected:hover,
+.flatpickr-day.startRange:hover,
+.flatpickr-day.endRange:hover,
+.flatpickr-day.selected.prevMonthDay,
+.flatpickr-day.startRange.prevMonthDay,
+.flatpickr-day.endRange.prevMonthDay,
+.flatpickr-day.selected.nextMonthDay,
+.flatpickr-day.startRange.nextMonthDay,
+.flatpickr-day.endRange.nextMonthDay {
+ background: var(--primary);
+ color: var(--white);
+ border-color: var(--primary);
+}
+
+.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
+.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
+.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) {
+ box-shadow: -10px 0 0 var(--primary);
+}
+
+.flatpickr-day.inRange {
+ box-shadow: -5px 0 0 var(--grey-200), 5px 0 0 var(--grey-200);
+}
+
+.flatpickr-day.flatpickr-disabled,
+.flatpickr-day.flatpickr-disabled:hover,
+.flatpickr-day.prevMonthDay,
+.flatpickr-day.nextMonthDay,
+.flatpickr-day.notAllowed,
+.flatpickr-day.notAllowed.prevMonthDay,
+.flatpickr-day.notAllowed.nextMonthDay {
+ color: var(--grey-300);
+}
+
+.flatpickr-day.flatpickr-disabled,
+.flatpickr-day.flatpickr-disabled:hover {
+ color: var(--grey-800);
+}
+
+.flatpickr-day.week.selected {
+ box-shadow: -5px 0 0 var(--primary), 5px 0 0 var(--primary);
+}
+
+.flatpickr-weekwrapper .flatpickr-weeks {
+ box-shadow: 1px 0 0 var(--grey-200);
+}
+
+.flatpickr-weekwrapper span.flatpickr-day,
+.flatpickr-weekwrapper span.flatpickr-day:hover {
+ color: var(--grey-300);
+}
+
+.flatpickr-time .numInputWrapper span.arrowUp:after {
+ border-bottom-color: var(--grey-500);
+}
+
+.flatpickr-time .numInputWrapper span.arrowDown:after {
+ border-top-color: var(--grey-500);
+}
+
+.flatpickr-time input {
+ color: var(--grey-500);
+}
+
+.flatpickr-time .flatpickr-time-separator,
+.flatpickr-time .flatpickr-am-pm {
+ color: var(--grey-500);
+}
+
+.flatpickr-time input:hover,
+.flatpickr-time .flatpickr-am-pm:hover,
+.flatpickr-time input:focus,
+.flatpickr-time .flatpickr-am-pm:focus {
+ background: var(--grey-100);
+}
diff --git a/src/styles/theme/form.scss b/src/styles/theme/form.scss
index b5bbf0c5c..86c78f2fd 100644
--- a/src/styles/theme/form.scss
+++ b/src/styles/theme/form.scss
@@ -40,6 +40,7 @@
}
.select select {
+ $thickness: 1px;
border-width: $thickness;
&:not([multiple]) {
diff --git a/src/styles/theme/notification.scss b/src/styles/theme/notification.scss
deleted file mode 100644
index 9950b9606..000000000
--- a/src/styles/theme/notification.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.notification {
- border: $thickness solid $border;
-}
-
-.notifications {
- left: 0.5rem !important;
- bottom: 1rem !important;
-}
-
-.message .message-body {
- border: $thickness solid;
-}
diff --git a/src/views/Home.vue b/src/views/Home.vue
index ea16c717a..b0c6c25d1 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -3,7 +3,7 @@
{{ $t(`home.welcome${welcome}`, {username: userInfo.name !== '' ? userInfo.name : userInfo.username}) }}!
-
+
{{
$t('user.deletion.scheduled', {
date: formatDateShort(deletionScheduledAt),
@@ -13,7 +13,7 @@
{{ $t('user.deletion.scheduledCancel') }}
-
+
-
@@ -147,7 +127,7 @@ export default {
flex-wrap: wrap;
max-height: calc(#{$list-height * 2} + #{$list-spacing * 2} - 4px);
overflow: hidden;
-
+
@media screen and (max-width: $mobile) {
max-height: calc(#{$list-height * 4} + #{$list-spacing * 4} - 4px);
}
diff --git a/src/views/list/ShowList.vue b/src/views/list/ShowList.vue
index 5ed589096..d0c1d20fe 100644
--- a/src/views/list/ShowList.vue
+++ b/src/views/list/ShowList.vue
@@ -36,9 +36,9 @@
-
+
{{ $t('list.archived') }}
-
+
@@ -46,6 +46,7 @@