diff --git a/.drone.yml b/.drone.yml
index 38ff2044..3f7c8926 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -528,3 +528,34 @@ steps:
status:
- success
- failure
+---
+kind: pipeline
+name: ping-weblate
+
+depends_on:
+ - build
+
+trigger:
+ branch:
+ - main
+ event:
+ - push
+
+steps:
+ - name: update-translation-base
+ image: appleboy/drone-git-push
+ settings:
+ branch: translations
+ remote: ssh://git@kolaente.dev:9022/vikunja/frontend.git
+ ssh_key:
+ from_secret: translations_branch_update_ssh_key
+ - name: notify-weblate
+ image: curlimages/curl
+ depends_on:
+ - update-translation-base
+ environment:
+ WEBLATE_TOKEN:
+ from_secret: weblate_token
+ commands:
+ - 'curl -d operation=pull -H "Authorization: Token ${WEBLATE_TOKEN}" https://hosted.weblate.org/api/projects/vikunja/repository/'
+ - 'curl -d operation=push -H "Authorization: Token ${WEBLATE_TOKEN}" https://hosted.weblate.org/api/projects/vikunja/repository/'
diff --git a/README.md b/README.md
index 40fcb1c6..852c4b4d 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
[![Build Status](https://drone.kolaente.de/api/badges/vikunja/frontend/status.svg)](https://drone.kolaente.de/vikunja/frontend)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE)
[![Download](https://img.shields.io/badge/download-v0.17.0-brightgreen.svg)](https://dl.vikunja.io)
+[![Translation](https://hosted.weblate.org/widgets/vikunja/-/frontend/svg-badge.svg)](https://hosted.weblate.org/engage/vikunja/)
This is the web frontend for Vikunja, written in Vue.js.
diff --git a/cypress/integration/list/list.spec.js b/cypress/integration/list/list.spec.js
index 3c8c0d6f..843d8291 100644
--- a/cypress/integration/list/list.spec.js
+++ b/cypress/integration/list/list.spec.js
@@ -388,7 +388,7 @@ describe('Lists', () => {
.first()
.click()
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item')
- .contains('Limit: Not set')
+ .contains('Limit: Not Set')
.click()
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input')
.first()
diff --git a/cypress/integration/list/namespaces.spec.js b/cypress/integration/list/namespaces.spec.js
index 9d3125b5..e8c15443 100644
--- a/cypress/integration/list/namespaces.spec.js
+++ b/cypress/integration/list/namespaces.spec.js
@@ -24,7 +24,7 @@ describe('Namepaces', () => {
cy.visit('/namespaces')
cy.get('a.button')
- .contains('Create namespace')
+ .contains('Create a new namespace')
.click()
cy.url()
diff --git a/cypress/integration/sharing/team.spec.js b/cypress/integration/sharing/team.spec.js
index 09455635..7c48a59a 100644
--- a/cypress/integration/sharing/team.spec.js
+++ b/cypress/integration/sharing/team.spec.js
@@ -11,7 +11,7 @@ describe('Team', () => {
const newTeamName = 'New Team'
cy.get('a.button')
- .contains('New Team')
+ .contains('Create a new team')
.click()
cy.url()
.should('contain', '/teams/new')
@@ -113,7 +113,7 @@ describe('Team', () => {
cy.get('.card')
.contains('Team Members')
.get('.card-content .button')
- .contains('Add To Team')
+ .contains('Add to team')
.click()
cy.get('table.table td')
diff --git a/cypress/integration/task/task.spec.js b/cypress/integration/task/task.spec.js
index e0793637..ac948115 100644
--- a/cypress/integration/task/task.spec.js
+++ b/cypress/integration/task/task.spec.js
@@ -27,7 +27,7 @@ describe('Task', () => {
it('Should be created new', () => {
cy.visit('/lists/1/list')
- cy.get('input.input[placeholder="Add a new task..."')
+ cy.get('input.input[placeholder="Add a new task…"')
.type('New Task')
cy.get('.button')
.contains('Add')
@@ -43,7 +43,7 @@ describe('Task', () => {
cy.visit('/lists/1/list')
cy.get('.list-is-empty-notice')
.should('not.exist')
- cy.get('input.input[placeholder="Add a new task..."')
+ cy.get('input.input[placeholder="Add a new task…"')
.type('New Task')
cy.get('.button')
.contains('Add')
diff --git a/package.json b/package.json
index 4de17161..4917fc5d 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"vue-advanced-cropper": "1.7.0",
"vue-drag-resize": "1.5.4",
"vue-easymde": "1.4.0",
+ "vue-i18n": "^8.24.4",
"vue-shortkey": "3.1.7",
"vue-smooth-dnd": "0.8.1",
"vuex": "3.6.2"
diff --git a/src/App.vue b/src/App.vue
index cb017b6b..774d8161 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -34,6 +34,7 @@ import TopNavigation from '@/components/home/topNavigation'
import ContentAuth from '@/components/home/contentAuth'
import ContentLinkShare from '@/components/home/contentLinkShare'
import ContentNoAuth from '@/components/home/contentNoAuth'
+import {setLanguage} from '@/i18n/setup'
export default {
name: 'app',
@@ -53,6 +54,8 @@ export default {
beforeCreate() {
this.$store.dispatch('config/update')
this.$store.dispatch('auth/checkAuth')
+
+ setLanguage()
},
created() {
// Make sure to always load the home route when running with electron
diff --git a/src/components/home/contentLinkShare.vue b/src/components/home/contentLinkShare.vue
index 0cf68556..e3602c56 100644
--- a/src/components/home/contentLinkShare.vue
+++ b/src/components/home/contentLinkShare.vue
@@ -10,12 +10,12 @@
- {{ currentList.title === '' ? 'Loading...' : currentList.title }}
+ {{ currentList.title === '' ? $t('misc.loading') : currentList.title }}
- Logout
+ {{ $t('user.auth.logout') }}
@@ -23,7 +23,7 @@
diff --git a/src/components/home/contentNoAuth.vue b/src/components/home/contentNoAuth.vue
index ad8dc789..f8349fbd 100644
--- a/src/components/home/contentNoAuth.vue
+++ b/src/components/home/contentNoAuth.vue
@@ -4,7 +4,7 @@
{{ motd }}
diff --git a/src/components/home/navigation.vue b/src/components/home/navigation.vue
index 05b8cd2a..65b04508 100644
--- a/src/components/home/navigation.vue
+++ b/src/components/home/navigation.vue
@@ -10,7 +10,7 @@
- Overview
+ {{ $t('navigation.overview') }}
@@ -18,7 +18,7 @@
- Upcoming
+ {{ $t('navigation.upcoming') }}
@@ -26,7 +26,7 @@
- Namespaces & Lists
+ {{ $t('namespace.title') }}
@@ -34,7 +34,7 @@
- Labels
+ {{ $t('label.title') }}
@@ -42,7 +42,7 @@
- Teams
+ {{ $t('team.title') }}
@@ -109,7 +109,9 @@
-
+
diff --git a/src/components/home/topNavigation.vue b/src/components/home/topNavigation.vue
index dba162ef..385f971a 100644
--- a/src/components/home/topNavigation.vue
+++ b/src/components/home/topNavigation.vue
@@ -25,14 +25,16 @@
>
-
-
- {{ currentList.title === '' ? 'Loading...' : currentList.title }}
-
+
+
+
+ {{ currentList.title === '' ? $t('misc.loading') : currentList.title }}
+
-
+
+
@@ -117,8 +119,14 @@ export default {
canWriteCurrentList: state => state.currentList.maxRight > Rights.READ,
}),
mounted() {
- const usernameWidth = this.$refs.usernameDropdown.$el.clientWidth
- this.$refs.listTitle.style.setProperty('--nav-username-width', `${usernameWidth}px`)
+ this.$nextTick(() => {
+ if (typeof this.$refs.usernameDropdown === 'undefined' || typeof this.$refs.listTitle === 'undefined') {
+ return
+ }
+
+ const usernameWidth = this.$refs.usernameDropdown.$el.clientWidth
+ this.$refs.listTitle.style.setProperty('--nav-username-width', `${usernameWidth}px`)
+ })
},
methods: {
logout() {
diff --git a/src/components/home/update.vue b/src/components/home/update.vue
index 63559e3c..2569c9c3 100644
--- a/src/components/home/update.vue
+++ b/src/components/home/update.vue
@@ -1,8 +1,8 @@
-
There is an update for Vikunja available!
+
{{ $t('update.available') }}
- Update Now
+ {{ $t('update.do') }}
diff --git a/src/components/input/colorPicker.vue b/src/components/input/colorPicker.vue
index 5b2395fd..868ad58e 100644
--- a/src/components/input/colorPicker.vue
+++ b/src/components/input/colorPicker.vue
@@ -19,7 +19,7 @@
:class="{'is-empty': empty}"
/>
- Reset Color
+ {{ $t('input.resetColor') }}
diff --git a/src/components/input/datepicker.vue b/src/components/input/datepicker.vue
index 2260d67d..029ccac1 100644
--- a/src/components/input/datepicker.vue
+++ b/src/components/input/datepicker.vue
@@ -18,7 +18,7 @@
- Today
+ {{ $t('input.datepicker.today') }}
{{ getWeekdayFromStringInterval('today') }}
@@ -31,7 +31,7 @@
- Tomorrow
+ {{ $t('input.datepicker.tomorrow') }}
{{ getWeekdayFromStringInterval('tomorrow') }}
@@ -44,7 +44,7 @@
- Next Monday
+ {{ $t('input.datepicker.nextMonday') }}
{{ getWeekdayFromStringInterval('nextMonday') }}
@@ -57,7 +57,7 @@
- This Weekend
+ {{ $t('input.datepicker.thisWeekend') }}
{{ getWeekdayFromStringInterval('thisWeekend') }}
@@ -70,7 +70,7 @@
- Later This Week
+ {{ $t('input.datepicker.laterThisWeek') }}
{{ getWeekdayFromStringInterval('laterThisWeek') }}
@@ -83,7 +83,7 @@
- Next Week
+ {{ $t('input.datepicker.nextWeek') }}
{{ getWeekdayFromStringInterval('nextWeek') }}
@@ -102,7 +102,7 @@
:shadow="false"
@click="close"
>
- Confirm
+ {{ $t('misc.confirm') }}
@@ -118,7 +118,6 @@ import {calculateDayInterval} from '@/helpers/time/calculateDayInterval'
import {calculateNearestHours} from '@/helpers/time/calculateNearestHours'
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
import {createDateFromString} from '@/helpers/time/createDateFromString'
-import {mapState} from 'vuex'
export default {
name: 'datepicker',
@@ -142,7 +141,9 @@ export default {
},
chooseDateLabel: {
type: String,
- default: 'Choose a date'
+ default() {
+ return this.$t('input.datepicker.chooseDate')
+ }
},
disabled: {
type: Boolean,
@@ -165,19 +166,21 @@ export default {
this.updateData()
},
},
- computed: mapState({
- flatPickerConfig: state => ({
- altFormat: 'j M Y H:i',
- altInput: true,
- dateFormat: 'Y-m-d H:i',
- enableTime: true,
- time_24hr: true,
- inline: true,
- locale: {
- firstDayOfWeek: state.auth.settings.weekStart,
- },
- })
- }),
+ computed: {
+ flatPickerConfig() {
+ return {
+ altFormat: this.$t('date.altFormatLong'),
+ altInput: true,
+ dateFormat: 'Y-m-d H:i',
+ enableTime: true,
+ time_24hr: true,
+ inline: true,
+ locale: {
+ firstDayOfWeek: this.$store.state.auth.settings.weekStart,
+ },
+ }
+ },
+ },
methods: {
setDateValue(newVal) {
if(newVal === null) {
diff --git a/src/components/input/editor.vue b/src/components/input/editor.vue
index 0334bac6..06879990 100644
--- a/src/components/input/editor.vue
+++ b/src/components/input/editor.vue
@@ -15,7 +15,7 @@
:shadow="false"
type="secondary"
>
- Done
+ {{ $t('input.editor.done') }}
@@ -129,112 +129,112 @@ export default {
{
name: 'heading-1',
action: EasyMDE.toggleHeading1,
- title: 'Heading 1',
+ title: this.$t('input.editor.heading1'),
icon: ' ',
},
{
name: 'heading-2',
action: EasyMDE.toggleHeading2,
- title: 'Heading 2',
+ title: this.$t('input.editor.heading2'),
icon: ' ',
},
{
name: 'heading-3',
action: EasyMDE.toggleHeading3,
- title: 'Heading 3',
+ title: this.$t('input.editor.heading3'),
icon: ' ',
},
{
name: 'heading-smaller',
action: EasyMDE.toggleHeadingSmaller,
- title: 'Heading Smaller',
+ title: this.$t('input.editor.headingSmaller'),
icon: ' ',
},
{
name: 'heading-bigger',
action: EasyMDE.toggleHeadingBigger,
- title: 'Heading Bigger',
+ title: this.$t('input.editor.headingBigger'),
icon: ' ',
},
'|',
{
name: 'bold',
action: EasyMDE.toggleBold,
- title: 'Bold',
+ title: this.$t('input.editor.bold'),
icon: ' ',
},
{
name: 'italic',
action: EasyMDE.toggleItalic,
- title: 'Italic',
+ title: this.$t('input.editor.italic'),
icon: ' ',
},
{
name: 'strikethrough',
action: EasyMDE.toggleStrikethrough,
- title: 'Strikethrough',
+ title: this.$t('input.editor.strikethrough'),
icon: ' ',
},
{
name: 'code',
action: EasyMDE.toggleCodeBlock,
- title: 'Code',
+ title: this.$t('input.editor.code'),
icon: ' ',
},
{
name: 'quote',
action: EasyMDE.toggleBlockquote,
- title: 'Quote',
+ title: this.$t('input.editor.quote'),
icon: ' ',
},
{
name: 'unordered-list',
action: EasyMDE.toggleUnorderedList,
- title: 'Unordered List',
+ title: this.$t('input.editor.unorderedList'),
icon: ' ',
},
{
name: 'ordered-list',
action: EasyMDE.toggleOrderedList,
- title: 'Ordered List',
+ title: this.$t('input.editor.orderedList'),
icon: ' ',
},
'|',
{
name: 'clean-block',
action: EasyMDE.cleanBlock,
- title: 'Clean Block',
+ title: this.$t('input.editor.cleanBlock'),
icon: ' ',
},
{
name: 'link',
action: EasyMDE.drawLink,
- title: 'Link',
+ title: this.$t('input.editor.link'),
icon: ' ',
},
{
name: 'image',
action: EasyMDE.drawImage,
- title: 'Image',
+ title: this.$t('input.editor.image'),
icon: ' ',
},
{
name: 'table',
action: EasyMDE.drawTable,
- title: 'Table',
+ title: this.$t('input.editor.table'),
icon: ' ',
},
{
name: 'horizontal-rule',
action: EasyMDE.drawHorizontalRule,
- title: 'Horizontal Rule',
+ title: this.$t('input.editor.horizontalRule'),
icon: ' ',
},
'|',
{
name: 'side-by-side',
action: EasyMDE.toggleSideBySide,
- title: 'Side By Side',
+ title: this.$t('input.editor.sideBySide'),
icon: ' ',
},
{
@@ -242,7 +242,7 @@ export default {
action: () => {
window.open('https://www.markdownguide.org/basic-syntax/', '_blank')
},
- title: 'Guide',
+ title: this.$t('input.editor.guide'),
icon: ' ',
},
],
diff --git a/src/components/input/multiselect.vue b/src/components/input/multiselect.vue
index f0db907c..34a81fad 100644
--- a/src/components/input/multiselect.vue
+++ b/src/components/input/multiselect.vue
@@ -149,15 +149,15 @@ export default {
createPlaceholder: {
type: String,
default() {
- return 'Create new'
- },
+ return this.$t('input.multiselect.createPlaceholder')
+ }
},
// The text shown next to an option.
selectPlaceholder: {
type: String,
default() {
- return 'Click or press enter to select'
- },
+ return this.$t('input.multiselect.selectPlaceholder')
+ }
},
// If true, allows for selecting multiple items. v-model will be an array with all selected values in that case.
multiple: {
diff --git a/src/components/list/list-settings-dropdown.vue b/src/components/list/list-settings-dropdown.vue
index 090defb1..e44bec3a 100644
--- a/src/components/list/list-settings-dropdown.vue
+++ b/src/components/list/list-settings-dropdown.vue
@@ -5,13 +5,13 @@
:to="{ name: `${listRoutePrefix}.settings.edit`, params: { listId: list.id } }"
icon="pen"
>
- Edit
+ {{ $t('menu.edit') }}
- Delete
+ {{ $t('misc.delete') }}
@@ -19,7 +19,7 @@
:to="{ name: `${listRoutePrefix}.settings.archive`, params: { listId: list.id } }"
icon="archive"
>
- Un-Archive
+ {{ $t('menu.unarchive') }}
@@ -27,32 +27,32 @@
:to="{ name: `${listRoutePrefix}.settings.edit`, params: { listId: list.id } }"
icon="pen"
>
- Edit
+ {{ $t('menu.edit') }}
- Set background
+ {{ $t('menu.setBackground') }}
- Share
+ {{ $t('menu.share') }}
- Duplicate
+ {{ $t('menu.duplicate') }}
- Archive
+ {{ $t('menu.archive') }}
- Delete
+ {{ $t('menu.delete') }}
diff --git a/src/components/list/partials/filters.vue b/src/components/list/partials/filters.vue
index 448222d0..1bb58659 100644
--- a/src/components/list/partials/filters.vue
+++ b/src/components/list/partials/filters.vue
@@ -1,28 +1,30 @@
- Include Tasks which don't have a value set
+ {{ $t('filters.attributes.includeNulls') }}
- Require all filters to be true for a task to show up
+ {{ $t('filters.attributes.requireAll') }}
-
Show Done Tasks
+
+ {{ $t('filters.attributes.showDoneTasks') }}
+
- Show Done Tasks
+ {{ $t('filters.attributes.showDoneTasks') }}
-
Search
+
{{ $t('misc.search') }}
-
Priority
+
{{ $t('task.attributes.priority') }}
- Enable Filter By Priority
+ {{ $t('filters.attributes.enablePriority') }}
-
Percent Done
+
{{ $t('task.attributes.percentDone') }}
- Enable Filter By Percent Done
+ {{ $t('filters.attributes.enablePercentDone') }}
-
Due Date
+
{{ $t('task.attributes.dueDate') }}
-
Start Date
+
{{ $t('task.attributes.startDate') }}
-
End Date
+
{{ $t('task.attributes.endDate') }}
-
Reminders
+
{{ $t('task.attributes.reminders') }}
-
Assignees
+
{{ $t('task.attributes.assignees') }}
find('users', query)"
:search-results="foundusers"
@select="() => add('users', 'assignees')"
@@ -128,10 +130,10 @@
-
Labels
+
{{ $t('task.attributes.label') }}
addLabel(label)"
@@ -153,11 +155,11 @@
-
Lists
+
{{ $t('list.lists') }}
find('lists', query)"
:search-results="foundlists"
@select="() => add('lists', 'list_id')"
@@ -169,11 +171,11 @@
-
Namespaces
+
{{ $t('namespace.namespaces') }}
find('namespace', query)"
:search-results="foundnamespace"
@select="() => add('namespace', 'namespace')"
@@ -203,7 +205,6 @@ import Multiselect from '@/components/input/multiselect'
import UserService from '@/services/user'
import ListService from '@/services/list'
import NamespaceService from '@/services/namespace'
-import {mapState} from 'vuex'
export default {
name: 'filters',
@@ -290,19 +291,19 @@ export default {
return first.id === second.id
})
},
- ...mapState({
- flatPickerConfig: state => ({
- altFormat: 'j M Y H:i',
+ flatPickerConfig() {
+ return {
+ altFormat: this.$t('date.altFormatLong'),
altInput: true,
dateFormat: 'Y-m-d H:i',
enableTime: true,
time_24hr: true,
mode: 'range',
locale: {
- firstDayOfWeek: state.auth.settings.weekStart,
+ firstDayOfWeek: this.$store.state.auth.settings.weekStart,
},
- }),
- }),
+ }
+ },
},
methods: {
change() {
diff --git a/src/components/migrator/migration.vue b/src/components/migrator/migration.vue
index c6de5f2b..d24c08bd 100644
--- a/src/components/migrator/migration.vue
+++ b/src/components/migrator/migration.vue
@@ -1,15 +1,15 @@
-
Import your data from {{ name }} to Vikunja
-
Vikunja will import all lists, tasks, notes, reminders and files you have access to.
+
{{ $t('migrate.titleService', { name: name }) }}
+
{{ $t('migrate.descriptionDo') }}
- To authorize Vikunja to access your {{ name }} Account, click the button below.
+ {{ $t('migrate.authorize', {name: name}) }}
- Get Started
+ {{ $t('migrate.getStarted') }}
-
Importing in progress, hang tight...
+
{{ $t('migrate.inProgress') }}
- It looks like you've already imported your stuff from {{ name }} at {{ formatDate(lastMigrationDate) }}.
- Importing again is possible, but might create duplicates.
- Are you sure?
+ {{ $t('migrate.alreadyMigrated1', { name: name, date: formatDate(lastMigrationDate) }) }}
+ {{ $t('migrate.alreadyMigrated2') }}
- I am sure, please start migrating now!
- Cancel
+ {{ $t('migrate.confirm') }}
+ {{ $t('misc.cancel') }}
@@ -48,7 +47,7 @@
{{ message }}
-
Refresh
+
{{ $t('misc.refresh') }}
diff --git a/src/components/misc/api-config.vue b/src/components/misc/api-config.vue
index d055ed2d..8673e691 100644
--- a/src/components/misc/api-config.vue
+++ b/src/components/misc/api-config.vue
@@ -1,13 +1,13 @@
-
Vikunja URL
+
{{ $t('apiConfig.url') }}
{
// Still not found, url is still invalid
this.successMsg = ''
- this.errorMsg = `Could not find or use Vikunja installation at "${this.apiDomain()}".`
+ this.errorMsg = this.$t('apiConfig.error', {domain: this.apiDomain()})
window.API_URL = oldUrl
})
.then((r) => {
if (typeof r !== 'undefined') {
// Set it + save it to local storage to save us the hoops
this.errorMsg = ''
- this.successMsg = `Using Vikunja installation at "${this.apiDomain()}".`
+ this.successMsg = this.$t('apiConfig.success', {domain: this.apiDomain()})
localStorage.setItem('API_URL', window.API_URL)
this.configureApi = false
this.apiUrl = window.API_URL
diff --git a/src/components/misc/create-edit.vue b/src/components/misc/create-edit.vue
index 01aba2d3..c98378d8 100644
--- a/src/components/misc/create-edit.vue
+++ b/src/components/misc/create-edit.vue
@@ -26,7 +26,7 @@
type="secondary"
@click.prevent.stop="$router.back()"
>
- Cancel
+ {{ $t('misc.cancel') }}
diff --git a/src/components/misc/keyboard-shortcuts.vue b/src/components/misc/keyboard-shortcuts.vue
index d95aa265..d0fb9d44 100644
--- a/src/components/misc/keyboard-shortcuts.vue
+++ b/src/components/misc/keyboard-shortcuts.vue
@@ -2,56 +2,56 @@
-
+
- These shortcuts work on all pages.
+ {{ $t('keyboardShortcuts.allPages') }}
- Toggle The Menu
+ {{ $t('keyboardShortcuts.toggleMenu') }}
- Open the search/quick action bar
+ {{ $t('keyboardShortcuts.quickSearch') }}
- Kanban
+ {{ $t('list.kanban.title') }}
- These shortcuts work only on the current page.
+ {{ $t('keyboardShortcuts.currentPageOnly') }}
- Mark a task as done
+ {{ $t('keyboardShortcuts.task.done') }}
- Task Page
+ {{ $t('keyboardShortcuts.task.title') }}
- These shortcuts work only on the current page.
+ {{ $t('keyboardShortcuts.currentPageOnly') }}
- Assign this task to a user
+ {{ $t('keyboardShortcuts.task.assign') }}
- Add labels to this task
+ {{ $t('keyboardShortcuts.task.labels') }}
- Change the due date of this task
+ {{ $t('keyboardShortcuts.task.dueDate') }}
- Add an attachment to this task
+ {{ $t('keyboardShortcuts.task.attachment') }}
- Modify related tasks of this task
+ {{ $t('keyboardShortcuts.task.related') }}
diff --git a/src/components/misc/legal.vue b/src/components/misc/legal.vue
index 2afcb472..cc55ea1a 100644
--- a/src/components/misc/legal.vue
+++ b/src/components/misc/legal.vue
@@ -1,8 +1,8 @@
diff --git a/src/components/misc/subscription.vue b/src/components/misc/subscription.vue
index 82ad2f62..3ffc4de3 100644
--- a/src/components/misc/subscription.vue
+++ b/src/components/misc/subscription.vue
@@ -54,16 +54,19 @@ export default {
},
computed: {
tooltipText() {
- if(this.disabled) {
- return `You can't unsubscribe here because you are subscribed to this ${this.entity} through its ${this.subscription.entity}.`
+ if (this.disabled) {
+ return this.$t('task.subscription.subscribedThroughParent', {
+ entity: this.entity,
+ parent: this.subscription.entity
+ })
}
return this.subscription !== null ?
- `You are currently subscribed to this ${this.entity} and will receive notifications for changes.` :
- `You are not subscribed to this ${this.entity} and won't receive notifications for changes.`
+ this.$t('task.subscription.subscribed', {entity: this.entity}) :
+ this.$t('task.subscription.notSubscribed', {entity: this.entity})
},
buttonText() {
- return this.subscription !== null ? 'Unsubscribe' : 'Subscribe'
+ return this.subscription !== null ? this.$t('task.subscription.unsubscribe') : this.$t('task.subscription.subscribe')
},
icon() {
return this.subscription !== null ? ['far', 'bell-slash'] : 'bell'
@@ -78,7 +81,7 @@ export default {
},
methods: {
changeSubscription() {
- if(this.disabled) {
+ if (this.disabled) {
return
}
@@ -96,7 +99,7 @@ export default {
this.subscriptionService.create(subscription)
.then(() => {
this.$emit('change', subscription)
- this.success({message: `You are now subscribed to this ${this.entity}`})
+ this.success({message: this.$t('task.subscription.subscribeSuccess', {entity: this.entity})})
})
.catch(e => {
this.error(e)
@@ -110,7 +113,7 @@ export default {
this.subscriptionService.delete(subscription)
.then(() => {
this.$emit('change', null)
- this.success({message: `You are now unsubscribed to this ${this.entity}`})
+ this.success({message: this.$t('task.subscription.unsubscribeSuccess', {entity: this.entity})})
})
.catch(e => {
this.error(e)
diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue
index 4f58cf3e..4f0057cc 100644
--- a/src/components/modal/modal.vue
+++ b/src/components/modal/modal.vue
@@ -16,14 +16,14 @@
type="tertary"
class="has-text-danger"
>
- Cancel
+ {{ $t('misc.cancel') }}
- Do it!
+ {{ $t('misc.doit') }}
diff --git a/src/components/namespace/namespace-search.vue b/src/components/namespace/namespace-search.vue
index 8444d616..daf46817 100644
--- a/src/components/namespace/namespace-search.vue
+++ b/src/components/namespace/namespace-search.vue
@@ -1,7 +1,7 @@
- Un-Archive
+ {{ $t('menu.unarchive') }}
@@ -13,25 +13,25 @@
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id } }"
icon="pen"
>
- Edit
+ {{ $t('menu.edit') }}
- Share
+ {{ $t('menu.share') }}
- New list
+ {{ $t('menu.newList') }}
- Archive
+ {{ $t('menu.archive') }}
- Delete
+ {{ $t('menu.delete') }}
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index ff990623..21049a3f 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -37,9 +37,9 @@
- You don't have any notifications. Have a nice day!
+ {{ $t('notification.none') }}
- Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen.
+ {{ $t('notification.explainer') }}
diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue
index c55b887f..b99c6fca 100644
--- a/src/components/quick-actions/quick-actions.vue
+++ b/src/components/quick-actions/quick-actions.vue
@@ -123,22 +123,22 @@ export default {
return [
{
type: TYPE_CMD,
- title: 'Commands',
+ title: this.$t('quickActions.commands'),
items: cmds,
},
{
type: TYPE_TASK,
- title: 'Tasks',
+ title: this.$t('quickActions.tasks'),
items: this.foundTasks,
},
{
type: TYPE_LIST,
- title: 'Lists',
+ title: this.$t('quickActions.lists'),
items: lists,
},
{
type: TYPE_TEAM,
- title: 'Teams',
+ title: this.$t('quickActions.teams'),
items: this.foundTeams,
},
].filter(i => i.items.length > 0)
@@ -156,17 +156,17 @@ export default {
if (this.selectedCmd !== null) {
switch (this.selectedCmd.action) {
case CMD_NEW_TASK:
- return 'Enter the title of the new task...'
+ return this.$t('quickActions.newTask')
case CMD_NEW_LIST:
- return 'Enter the title of the new list...'
+ return this.$t('quickActions.newList')
case CMD_NEW_NAMESPACE:
- return 'Enter the title of the new namespace...'
+ return this.$t('quickActions.newNamespace')
case CMD_NEW_TEAM:
- return 'Enter the name of the new team...'
+ return this.$t('quickActions.newTeam')
}
}
- return 'Type a command or search...'
+ return this.$t('quickActions.placeholder')
},
hintText() {
let namespace
@@ -174,14 +174,14 @@ export default {
if (this.selectedCmd !== null && this.currentList !== null) {
switch (this.selectedCmd.action) {
case CMD_NEW_TASK:
- return `Create a task in the current list (${this.currentList.title})`
+ return this.$t('quickActions.createTask', {title: this.currentList.title})
case CMD_NEW_LIST:
namespace = this.$store.getters['namespaces/getNamespaceById'](this.currentList.namespaceId)
- return `Create a list in the current namespace (${namespace.title})`
+ return this.$t('quickActions.createList', {title: namespace.title})
}
}
- return 'You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.'
+ return this.$t('quickActions.hint')
},
currentList() {
return Object.keys(this.$store.state[CURRENT_LIST]).length === 0 ? null : this.$store.state[CURRENT_LIST]
@@ -191,20 +191,20 @@ export default {
if (this.currentList !== null) {
cmds.push({
- title: 'New task',
+ title: this.$t('quickActions.cmds.newTask'),
action: CMD_NEW_TASK,
})
cmds.push({
- title: 'New list',
+ title: this.$t('quickActions.cmds.newList'),
action: CMD_NEW_LIST,
})
}
cmds.push({
- title: 'New namespace',
+ title: this.$t('quickActions.cmds.newNamespace'),
action: CMD_NEW_NAMESPACE,
})
cmds.push({
- title: 'New Team',
+ title: this.$t('quickActions.cmds.newTeam'),
action: CMD_NEW_TEAM,
})
@@ -361,7 +361,7 @@ export default {
})
this.taskService.create(newTask)
.then(r => {
- this.success({message: 'The task was successfully created.'})
+ this.success({message: this.$t('task.createSuccess')})
this.$router.push({name: 'task.detail', params: {id: r.id}})
this.closeQuickActions()
})
@@ -380,7 +380,7 @@ export default {
})
this.listService.create(newList)
.then(r => {
- this.success({message: 'The list was successfully created.'})
+ this.success({message: this.$t('list.create.createdSuccess')})
this.$router.push({name: 'list.index', params: {listId: r.id}})
this.closeQuickActions()
})
@@ -393,7 +393,7 @@ export default {
this.namespaceService.create(newNamespace)
.then(r => {
this.$store.commit('namespaces/addNamespace', r)
- this.success({message: 'The namespace was successfully created.'})
+ this.success({message: this.$t('namespace.create.success')})
this.closeQuickActions()
})
.catch((e) => {
@@ -408,7 +408,7 @@ export default {
name: 'teams.edit',
params: {id: r.id},
})
- this.success({message: 'The team was successfully created.'})
+ this.success({message: this.$t('team.create.success')})
this.closeQuickActions()
})
.catch((e) => {
diff --git a/src/components/sharing/linkSharing.vue b/src/components/sharing/linkSharing.vue
index 80201577..d7fb695c 100644
--- a/src/components/sharing/linkSharing.vue
+++ b/src/components/sharing/linkSharing.vue
@@ -1,72 +1,76 @@
- Share Links
+ {{ $t('list.share.links.title') }}
- What is a share link?
+ v-tooltip="$t('list.share.links.explanation')">
+ {{ $t('list.share.links.what') }}
-
- Create a new link share
+ {{ $t('list.share.links.create') }}
- Right
+ {{ $t('list.share.right.title') }}
- Read only
-
- Read & write
+
+ {{ $t('list.share.right.read') }}
+
+
+ {{ $t('list.share.right.readWrite') }}
+
+
+ {{ $t('list.share.right.admin') }}
- Admin
-
Share
+
+ {{ $t('list.share.share') }}
+
- Link
- Name
- Shared by
- Right
- Delete
+ {{ $t('list.share.attributes.link') }}
+ {{ $t('list.share.attributes.name') }}
+ {{ $t('list.share.attributes.sharedBy') }}
+ {{ $t('list.share.attributes.right') }}
+ {{ $t('list.share.attributes.delete') }}
@@ -98,7 +102,7 @@
@@ -111,7 +115,7 @@
{{ s.name }}
- No name set
+ {{ $t('list.share.links.noName') }}
{{ s.sharedBy.getDisplayName() }}
@@ -121,19 +125,19 @@
- Admin
+ {{ $t('list.share.right.admin') }}
- Write
+ {{ $t('list.share.right.readWrite') }}
- Read-only
+ {{ $t('list.share.right.read') }}
@@ -159,12 +163,9 @@
@submit="remove()"
v-if="showDeleteModal"
>
- Remove a link share
+ {{ $t('list.share.links.remove') }}
- 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!
+ {{ $t('list.share.links.removeText') }}
@@ -248,7 +249,7 @@ export default {
this.name = ''
this.password = ''
this.showNewForm = false
- this.success({message: 'The link share was successfully created'})
+ this.success({message: this.$t('list.share.links.createSuccess')})
this.load()
})
.catch((e) => {
@@ -263,7 +264,7 @@ export default {
this.linkShareService
.delete(linkshare)
.then(() => {
- this.success({message: 'The link share was successfully deleted'})
+ this.success({message: this.$t('list.share.links.deleteSuccess')})
this.load()
})
.catch((e) => {
diff --git a/src/components/sharing/userTeam.vue b/src/components/sharing/userTeam.vue
index 3a72d7e3..6f4612b6 100644
--- a/src/components/sharing/userTeam.vue
+++ b/src/components/sharing/userTeam.vue
@@ -1,6 +1,8 @@
-
Shared with these {{ shareType }}s
+
+ {{ $t('list.share.userTeam.shared', {type: shareTypeNames}) }}
+
- Share
+ {{ $t('list.share.share') }}
@@ -29,7 +31,7 @@
{{ s.getDisplayName() }}
- You
+ {{ $t('list.share.userTeam.you') }}
@@ -50,19 +52,19 @@
- Admin
+ {{ $t('list.share.right.admin') }}
- Write
+ {{ $t('list.share.right.readWrite') }}
- Read-only
+ {{ $t('list.share.right.read') }}
@@ -76,19 +78,19 @@
:selected="s.right === rights.READ"
:value="rights.READ"
>
- Read only
+ {{ $t('list.share.right.read') }}
- Read & write
+ {{ $t('list.share.right.readWrite') }}
- Admin
+ {{ $t('list.share.right.admin') }}
@@ -108,7 +110,7 @@
- Not shared with any {{ shareType }} yet.
+ {{ $t('list.share.userTeam.notShared', {type: shareTypeNames}) }}
@@ -117,13 +119,11 @@
@submit="deleteSharable()"
v-if="showDeleteModal"
>
- Remove a {{ shareType }} from the {{ typeString }}
+
+ {{ $t('list.share.userTeam.removeHeader', {type: shareTypeName, sharable: sharableName}) }}
+
- Are you sure you want to remove this {{ shareType }} from the
- {{ typeString }}?
- This CANNOT BE UNDONE!
+ {{ $t('list.share.userTeam.removeText', {type: shareTypeName, sharable: sharableName}) }}
@@ -131,8 +131,6 @@