Compare commits

...

102 Commits

Author SHA1 Message Date
Frederick [Bot]
165d046307 chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-08 00:29:28 +00:00
01b7ae8091
fix(datepicker): make the date format in the picker consistent with the input field
All checks were successful
continuous-integration/drone/push Build is passing
Resolves #2340
2024-06-06 22:31:07 +02:00
6f4895b8cf
chore(auth): show registration disabled message when registration is disabled
All checks were successful
continuous-integration/drone/push Build is passing
The route still exists when the registration is disabled, even though all links to the page are removed.
2024-06-06 22:09:19 +02:00
b5a88d8657
fix(favorites): allow marking favorite tasks as done from favorites pseudo project
Resolves https://www.reddit.com/r/Vikunja/comments/1bkrek7/tasks_listed_under_favourite_list_view_mode/
2024-06-06 21:58:30 +02:00
acf4e3aa18
fix(tasks): ambiguous column name error when fetching favorite tasks
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-06 21:50:30 +02:00
92cdf5fe9c
fix(quick add magic): assume today when no date was specified with time
Some checks failed
continuous-integration/drone/push Build is failing
2024-06-06 21:44:29 +02:00
5af8b54618
fix(logo): add width and height to pride logo svg
Some checks failed
continuous-integration/drone/push Build is failing
2024-06-06 16:26:56 +02:00
0c411fd1e9
fix(kanban): remove leftovers of kanban_position property
Some checks failed
continuous-integration/drone/push Build is failing
This might fix a bug where the kanban position would not be saved correctly.
2024-06-06 16:22:51 +02:00
e7041f02d0
fix(caldav): do not crash for wrong parameters
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-06 11:05:32 +02:00
dd58d37db3
feat(typesense): move partial reindex to a flag instead of a separate command
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-05 10:49:37 +02:00
f131289d32
fix(typesense): correctly index assignee changes on tasks
Some checks failed
continuous-integration/drone/push Build is failing
This change fixes a bug where adding or removing an assignee to a task would not update the index in Typesense, causing filter queries for that assignee to return incorrect data. This was caused by the events being dispatched by the task update process not containing all the data.

Resolves https://github.com/go-vikunja/vikunja/issues/255
2024-06-05 10:36:25 +02:00
e56b2232bb
fix(typesense): do not try to sort by position when searching in a saved filter
This change fixes a bug where Typesense would try to sort by the project view of a saved filter. The view position is not indexed in Typesense, hence filtering fails. Because sorting by position is not a feature in saved filters, I've removed the logic for sorting saved filters with Typesense.
2024-06-05 10:24:28 +02:00
506ce66434
fix(typesense): correctly join task position table when sorting by it
All checks were successful
continuous-integration/drone/push Build is passing
This change fixes a bug where the project view to use for joining was empty, since Typesense only supports 3 sorting parameters. When using more than that, the logic to fetch the view ID parameter would not return the correct parameter, but the logic building the order by statement would. That led to inconsistencies where the task position was included in the order by statement, but the table would not be joined, failing the query.
2024-06-05 09:54:55 +02:00
Frederick [Bot]
d32a2526ba chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-05 00:28:50 +00:00
b386dfae87
fix(typesense): only return distinct tasks once
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-04 18:22:05 +02:00
5fc4ec48b7
fix(typesense): correctly incorporate existing filter when it is empty 2024-06-04 18:22:05 +02:00
Frederick [Bot]
37c89ea826 [skip ci] Updated swagger docs 2024-06-04 16:17:19 +00:00
1843f1d0d8
fix(docs): correctly document filter query usage
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-04 18:02:31 +02:00
0bb4a5a2b2
chore(desktop): only build zip in ci to speed up smoke test builds
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-04 15:02:21 +02:00
Frederick [Bot]
b4b17ed966 [skip ci] Updated swagger docs 2024-06-04 10:40:08 +00:00
48676050d7 feat(tasks): expand subtasks (#2345)
All checks were successful
continuous-integration/drone/push Build is passing
This change adds a parameter to expand subtasks - if provided, Vikunja will ensure all subtasks are present in the results list.

Resolves https://community.vikunja.io/t/subtasks-show-on-different-pages/2292
Reviewed-on: #2345
Co-authored-by: kolaente <k@knt.li>
Co-committed-by: kolaente <k@knt.li>
2024-06-04 10:27:23 +00:00
a38e768895
fix(db migration): do not try to create a unique index
All checks were successful
continuous-integration/drone/push Build is passing
Related to #2243
2024-06-04 08:45:39 +02:00
c17e4564e7
fix(migration): ensure tasks are put into the correct bucket when migrating from todoist
Some checks failed
continuous-integration/drone/push Build is failing
Resolves https://github.com/go-vikunja/vikunja/issues/254
2024-06-04 08:33:11 +02:00
Frederick [Bot]
dbf5e61fc9 chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-04 00:28:55 +00:00
68d233684f
fix(views): edit views with filters
All checks were successful
continuous-integration/drone/push Build is passing
This change fixes a bug where filter values of views would be transformed in the wrong order, not transformed at all or at the wrong time. Transforming the filters now happens transparently in the background without anything funky happening visible to the user.
2024-06-03 22:21:09 +02:00
Frederick [Bot]
244ca262df [skip ci] Updated swagger docs 2024-06-03 19:51:44 +00:00
99a67e09b1
feat(api): all usable routes behind authentication now have permissions
All checks were successful
continuous-integration/drone/push Build is passing
Previously, only routes which were coming from crudable entities could be used with an api token because there was no way to assign permissions to them. This change implements a more flexible structure for api permissions under the hood, allowing to add permissions for these routes and making them usable with an api token.

Resolves https://github.com/go-vikunja/vikunja/issues/266
2024-06-03 21:35:09 +02:00
5ef140fba2
fix(tasklist): migrate old tasklist format
All checks were successful
continuous-integration/drone/push Build is passing
Resolves https://community.vikunja.io/t/task-list-from-0-21-0-0-23-0/2340
Resolves https://community.vikunja.io/t/general-feedback-after-trying-out-vikunja/1943/6
2024-06-03 17:39:35 +02:00
755e53af70
fix(views): transform bucket configurations
All checks were successful
continuous-integration/drone/push Build is passing
This fixes a bug where filter buckets would not be editable because the bucket configuration was a read-only entry from the watcher.
2024-06-03 17:04:09 +02:00
c47d8c6dbe
fix(task): do not try to set bucket for filtered bucket configuration 2024-06-03 17:02:50 +02:00
43244156b4
fix(filter): do not add enter in input field
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-03 16:30:17 +02:00
4ce761eba7
fix(filter): trim search term before searching
Some checks failed
continuous-integration/drone/push Build is failing
2024-06-03 16:28:04 +02:00
6c8299772a
fix(task): do not require admin permission to move tasks between buckets
Some checks failed
continuous-integration/drone/push Build is failing
Resolves https://community.vikunja.io/t/moving-between-buckets-requires-admin-permissions-now/2390
2024-06-03 16:26:07 +02:00
a6fccfb908
fix(webhook): log errors in webhook response
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-03 13:11:44 +02:00
73780e4b50 feat: add pluralization rules for Russian (#2344)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2344
Reviewed-by: konrad <k@knt.li>
Co-authored-by: andreymal <andriyano-31@mail.ru>
Co-committed-by: andreymal <andriyano-31@mail.ru>
2024-06-03 08:51:11 +00:00
81bdad4beb fix: ignore casing to check if file extensions can be previewed (#2341)
All checks were successful
continuous-integration/drone/push Build is passing
Now .PNG is supported as well as .PnG and so on

Co-authored-by: Elscrux <nickposer2102@gmail.com>
Reviewed-on: #2341
Co-authored-by: Elscrux <elscrux@gmail.com>
Co-committed-by: Elscrux <elscrux@gmail.com>
2024-06-02 19:23:52 +00:00
8bc23b3a54 docs: remove superfluous yaml code block (#2342)
Some checks reported errors
continuous-integration/drone/push Build was killed
Fixes the ```yaml shown in the documentation.

Reviewed-on: #2342
Reviewed-by: konrad <k@knt.li>
Co-authored-by: David Baakman <kolaente@davidbaakman.nl>
Co-committed-by: David Baakman <kolaente@davidbaakman.nl>
2024-06-02 19:20:09 +00:00
aac01c7a35 feat: default view setting (#2306)
All checks were successful
continuous-integration/drone/push Build is passing
This PR adds configuration of default project view in settings, which is used when the user has not visited the project and thus last view hasn't yet been saved in projects. Updates old settings and adds "First View" option with fallback.

Resolves #2153

Co-authored-by: Elscrux <nickposer2102@gmail.com>
Reviewed-on: #2306
Reviewed-by: konrad <k@knt.li>
Co-authored-by: Elscrux <elscrux@gmail.com>
Co-committed-by: Elscrux <elscrux@gmail.com>
2024-06-02 08:15:53 +00:00
Frederick [Bot]
a175214aa0 chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-02 00:28:49 +00:00
8b2c3075c3
fix(logo): use correct month for pride logo change
Some checks failed
continuous-integration/drone/push Build is failing
2024-06-01 23:20:02 +02:00
Frederick [Bot]
a53ee4143f chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-28 00:27:42 +00:00
Frederick [Bot]
aeadce8631 chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-27 00:27:50 +00:00
Frederick [Bot]
e618becdf4 chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-26 00:28:14 +00:00
34d69fa588 feat(task): show attachment preview for image attachments (#2266)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2266
Reviewed-by: konrad <k@knt.li>
2024-05-25 12:11:03 +00:00
Elscrux
aba045ff24 Set attachment width to 100%
All checks were successful
continuous-integration/drone/pr Build is passing
2024-05-25 13:45:26 +02:00
Elscrux
4eb0df256c Improve preview spacing
All checks were successful
continuous-integration/drone/pr Build is passing
2024-05-25 12:06:23 +02:00
Elscrux
8b066bf0e9 Add cover tooltips 2024-05-25 12:05:37 +02:00
Elscrux
c2fc444bc0 Use file fallback icon 2024-05-25 12:05:37 +02:00
Elscrux
680cb72f29 Make fallback icon grey 2024-05-25 12:05:37 +02:00
fd66e6875c feat(editor): add hotkeys to quickly edit and discard (#2265)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2265
Reviewed-by: konrad <k@knt.li>
2024-05-25 08:13:10 +00:00
fb1f461e51
feat(i18n): add Croatian to selectable languages
Some checks failed
continuous-integration/drone/push Build is failing
2024-05-25 10:03:08 +02:00
Frederick [Bot]
3925536a7c chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-25 00:27:52 +00:00
Elscrux
00bfa2c552 Rename discardShortcutEnabled to enableDiscardShortcut
All checks were successful
continuous-integration/drone/pr Build is passing
2024-05-24 15:23:15 +02:00
Elscrux
ebb093797c Rename discardShortcutEnabled to enableDiscardShortcut 2024-05-24 15:23:15 +02:00
Elscrux
c13a991c16 Merge import 2024-05-24 15:23:15 +02:00
Elscrux
ecd44059e4 Use if to conditionally add escape hotkey 2024-05-24 15:23:15 +02:00
Elscrux
308a98c876 Add discardShortcutEnabled setting to opt into this feature
Only editing the task description and comments have this feature enabled
2024-05-24 15:23:15 +02:00
Elscrux
6ad8ce8f44 Cancel current edits and exit edit mode with escape 2024-05-24 15:23:15 +02:00
Elscrux
9de48aa6b2 Enter edit mode when double clicking 2024-05-24 15:23:15 +02:00
2e298ffc11
fix(i18n): adjust tests from 34780daab0
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-24 15:05:09 +02:00
536047c4c4
fix(i18n): typo
Some checks failed
continuous-integration/drone/push Build is failing
2024-05-24 13:17:53 +02:00
Elscrux
6543795755 Only allow cover if a preview is available
Some checks failed
continuous-integration/drone/pr Build is failing
2024-05-24 12:47:15 +02:00
Elscrux
56d9223fc4 Replace cover text links with icons 2024-05-24 12:46:46 +02:00
Elscrux
ef8bb5aca9 Add file image as fallback preview 2024-05-24 12:45:30 +02:00
Elscrux
658936a070 File name and cover label styling improvement 2024-05-24 12:45:06 +02:00
34780daab0
chore(i18n): remove "new" from creation strings
Some checks failed
continuous-integration/drone/push Build is failing
You can't create an "old" thing, therefore the "new" is redundant in that context. This change clarifies usage of this in all places.
2024-05-24 09:11:27 +02:00
Elscrux
c80d77ca69 Add width: 100%
All checks were successful
continuous-integration/drone/pr Build is passing
2024-05-23 10:26:42 +02:00
Elscrux
eafd4da038 Fix test again 2024-05-23 10:26:15 +02:00
76b3ac39b6
fix(filter): clarify in filter syntax
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-22 22:17:50 +02:00
Elscrux
7664534618 Change attachment div to button
Some checks failed
continuous-integration/drone/pr Build is failing
2024-05-16 19:29:40 +02:00
Elscrux
230fef3559 Attempt to fix attachment verification
All checks were successful
continuous-integration/drone/pr Build is passing
2024-05-16 14:36:41 +02:00
Elscrux
4b4c7840e2 Rename grid-item class to attachment
Some checks failed
continuous-integration/drone/pr Build is failing
2024-05-16 14:32:29 +02:00
Elscrux
2d3bf4c210 Move object-fit to styles 2024-05-16 14:32:15 +02:00
Elscrux
6fa15d30ad Replace px with rem
Some checks failed
continuous-integration/drone/pr Build is failing
2024-05-15 23:58:28 +02:00
Elscrux
9c7187b4aa Adjust file preview style 2024-05-15 23:58:28 +02:00
Elscrux
2ab6894542 Replace table with grid 2024-05-15 23:58:28 +02:00
Elscrux
e47d6d1605 Extract img to FilePreview component
Now images will also be displayed when they are uploaded initially
2024-05-15 23:58:28 +02:00
Elscrux
c2dfa9be83 Proof of concept for image preview 2024-05-15 23:58:28 +02:00
Frederick [Bot]
86b460d09c chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-11 00:06:24 +00:00
b93e237899 chore(deps): update dev-dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-09 06:06:20 +00:00
Frederick [Bot]
9706ebb2fc chore(i18n): update translations via Crowdin
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-09 00:06:59 +00:00
1d2ee77e8a fix(deps): update tiptap to v2.3.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-08 21:05:52 +00:00
5098363e56 fix(deps): update sentry-javascript monorepo to v7.114.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-08 09:05:57 +00:00
4c1dc6930d chore(deps): update dev-dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-08 05:05:55 +00:00
db6d88fff5 chore(deps): update dependency go to v1.22.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-07 17:06:20 +00:00
b021dd7237 chore(deps): update dependency node to v20.13.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-07 16:40:39 +00:00
e1dcf2e859
feat: do not save language on the server when in demo mode
Some checks failed
continuous-integration/drone/push Build is failing
When the demo mode is enabled, people set the language to their own language - which is understandable. However, this is really confusing for other people when they log in and the language is something unexpected.
This change overrides the configured language when saving it while Vikunja is in demo mode.
2024-05-07 18:39:50 +02:00
6e759b3bee
fix(i18n): clarify from current date string
Some checks failed
continuous-integration/drone/push Build is failing
Resolves https://community.vikunja.io/t/suggestion-rename-from-current-date-to-after-completed/2344
2024-05-07 18:28:22 +02:00
d3a7d79eb9
fix: use correct project title in project card
Some checks failed
continuous-integration/drone/push Build is failing
2024-05-07 18:18:19 +02:00
e0ce3e50bd
fix(attachment): correct spacing around creation date
Some checks failed
continuous-integration/drone/push Build is failing
2024-05-07 18:11:40 +02:00
272f643955
fix(project): show "remove background" button only when the project has a background set
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-07 17:17:06 +02:00
cf46c76811
fix(i18n): use correct title for background settings menu 2024-05-07 17:14:04 +02:00
31e502d711
fix(project): do not remove project from navigation after removing background image 2024-05-07 17:13:22 +02:00
fa628edc0c
fix(project): make sure gantt and kanban views shared with link share are full width
All checks were successful
continuous-integration/drone/push Build is passing
Resolves https://github.com/go-vikunja/vikunja/issues/258
2024-05-07 16:53:21 +02:00
053c4d5842
fix(project): bottom spacing in list view
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-07 16:27:13 +02:00
8d1fc08de6
docs: clarify where to file issues
Some checks failed
continuous-integration/drone/push Build is failing
Resolves https://github.com/go-vikunja/vikunja/issues/262
2024-05-07 16:13:25 +02:00
eee7b060b6
fix(docs): typos
Some checks failed
continuous-integration/drone/push Build is failing
Apply patch from https://github.com/go-vikunja/vikunja/issues/263
2024-05-07 16:06:17 +02:00
794fc4c1bb fix(deps): update dependency vue to v3.4.27
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2024-05-07 09:05:51 +00:00
e58d10bc72 chore(deps): update dev-dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-07 03:05:41 +00:00
7837bcfaae
fix(task): only count unique tasks in a bucket when checking bucket limit
All checks were successful
continuous-integration/drone/push Build is passing
This fixes a bug where the current number of tasks in a bucket was computed wrong when moving tasks into a bucket with a limit. Sometimes the bug would prevent adding a task to a bucket which seemed to have space left but ultimately failed when moving the task.
2024-05-06 20:07:06 +02:00
615d40f4cd fix(deps): update module golang.org/x/crypto to v0.23.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-06 15:05:56 +00:00
fbf7037974 chore(deps): update pnpm to v9.1.0
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
2024-05-06 11:05:37 +00:00
108 changed files with 5069 additions and 2570 deletions

View File

@ -1120,7 +1120,7 @@ steps:
- sed -i 's/\\/api\\/v1//g' frontend/index.html
- ./bumpp.sh
- yarn install
- yarn dist --linux --windows
- yarn dist --linux zip
# - name: rebuild-cache
# image: meltwater/drone-cache:dev
@ -1400,6 +1400,6 @@ steps:
- failure
---
kind: signature
hmac: f2753482faf9e2a3d34a9111587a75dfb4519cb77002cc64a51266540fd2478e
hmac: 16b8cd92b0c32f4821b45858464e645ba053f15e9eed85926589c4d9bc503864
...

View File

@ -156,7 +156,7 @@ mailer:
username: "user"
# SMTP password
password: ""
# Wether to skip verification of the tls certificate on the server
# Whether to skip verification of the tls certificate on the server
skiptlsverify: false
# The default from address when sending emails
fromemail: "mail@vikunja"
@ -306,7 +306,7 @@ auth:
# The provider needs to support the `openid`, `profile` and `email` scopes.<br/>
# **Note:** Some openid providers (like Gitlab) only make the email of the user available through OpenID if they have set it to be publicly visible.
# If the email is not public in those cases, authenticating will fail.
# **Note 2:** The frontend expects the third party to rediect the user <frontend-url>/auth/openid/<auth key> after authentication. Please make sure to configure the redirect url in your third party auth service accordingly if you're using the default vikunja frontend.
# +**Note 2:** The frontend expects the third party to redirect the user <frontend-url>/auth/openid/<auth key> after authentication. Please make sure to configure the redirect url in your third party auth service accordingly if you're using the default vikunja frontend.
# The frontend will automatically provide the API with the redirect url, composed from the current url where it's hosted.
# If you want to use the desktop client with OpenID, make sure to allow redirects to `127.0.0.1`.
# Take a look at the [default config file](https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample) for more information about how to configure openid authentication.
@ -368,8 +368,8 @@ defaultsettings:
webhooks:
# Whether to enable support for webhooks
enabled: true
# The timout in seconds until a webhook request fails when no response has been received.
timoutseconds: 30
# The timeout in seconds until a webhook request fails when no response has been received.
timeoutseconds: 30
# The URL of [a mole instance](https://github.com/frain-dev/mole) to use to proxy outgoing webhook requests. You should use this and configure appropriately if you're not the only one using your Vikunja instance. More info about why: https://webhooks.fyi/best-practices/webhook-providers#implement-security-on-egress-communication. Must be used in combination with `webhooks.password` (see below).
proxyurl:
# The proxy password to use when authenticating against the proxy.

View File

@ -51,7 +51,7 @@
}
},
"devDependencies": {
"electron": "29.3.2",
"electron": "29.3.3",
"electron-builder": "24.13.3"
},
"dependencies": {

View File

@ -14,8 +14,8 @@ dependencies:
devDependencies:
electron:
specifier: 29.3.2
version: 29.3.2
specifier: 29.3.3
version: 29.3.3
electron-builder:
specifier: 24.13.3
version: 24.13.3(electron-builder-squirrel-windows@24.13.3)
@ -917,8 +917,8 @@ packages:
- supports-color
dev: true
/electron@29.3.2:
resolution: {integrity: sha512-pRWsaFtbd78kEHR0lg5aMhZDY6b5JykIEhZRtyTCaJpGFObB2NFIJDzR7mTia0cZp3pPq60n/SS4gRxvSM5WFQ==}
/electron@29.3.3:
resolution: {integrity: sha512-I/USTe9UsQUKb/iuiYnmt074vHxNHCJZWYiU4Xg6lNPKVBsPadAhZcc+g2gYLqC1rA7KT4AvKTmNsY8n7oEUCw==}
engines: {node: '>= 12.20.55'}
hasBin: true
requiresBuild: true

View File

@ -24,7 +24,7 @@ In other packages, use the `db.NewSession()` method to get a new database sessio
To add a new table to the database, create the struct and [add a migration for it]({{< ref "db-migrations.md" >}}).
To learn more about how to configure your struct to create "good" tables, refer to [the xorm documentaion](https://xorm.io/docs/).
To learn more about how to configure your struct to create "good" tables, refer to [the xorm documentation](https://xorm.io/docs/).
In most cases you will also need to implement the `TableName() string` method on the new struct to make sure the table name matches the rest of the tables - plural.

View File

@ -26,6 +26,15 @@ If you plan to do a bigger change, it is better to open an issue for discussion
The main repo is [`vikunja/vikunja`](https://kolaente.dev/vikunja/vikunja), it contains all code for the api, frontend and desktop applications.
## Where to file issues
You can file issues on [the Gitea repo](https://kolaente.dev/vikunja/vikunja) or [on the GitHub mirror](https://github.com/go-vikunja/vikunja), when you don't want to create an account on the Gitea instance.
Please note that due to a spam problem, we need to manually enable accounts on Gitea after you've registered there.
To get that started, please reach out on another channel with your username.
Another option is [the community forum](https://community.vikunja.io), especially if you want to discuss a feature in more detail.
## API
You'll need at least Go 1.21 to build Vikunja's api.

View File

@ -101,7 +101,7 @@ You should also document the routes with [swagger annotations]({{< ref "swagger-
There is a method available in the `migration` package which takes a fully nested Vikunja structure and creates it with all relations.
This means you start by adding a project, then add projects inside that project, then tasks in the lists and so on.
In general, it is reccommended to have one root project with all projects of the other service as child projects.
In general, it is recommended to have one root project with all projects of the other service as child projects.
The root structure must be present as `[]*models.ProjectWithTasksAndBuckets`. It allows to represent all of Vikunja's hierarchy as a single data structure.

View File

@ -16,7 +16,7 @@ menu:
The following parts are about the kinds of tests in the API package and how to run them.
### Prerequesites
### Prerequisites
To run any kind of test, you need to specify Vikunja's [root path](https://vikunja.io/docs/config-options/#rootpath).
This is required to make sure all test fixtures are correctly loaded.
@ -39,7 +39,7 @@ This definition is a bit blurry, but we haven't found a better one yet.
All integration tests live in `pkg/integrations`.
You can run them by executing `mage test:integration`.
The integration tests use the same config and fixtures as the unit tests and therefor have the same options available,
The integration tests use the same config and fixtures as the unit tests and therefore have the same options available,
see at the beginning of this document.
To run integration tests, use `mage test:integration`.

View File

@ -22,7 +22,6 @@ export VIKUNJA_FIRST_CHILD=true
is the same as defining it in a `config.yml` like so:
```yaml
```yaml
first:
child: true
@ -348,6 +347,7 @@ Environment path: `VIKUNJA_SERVICE_CUSTOMLOGOURL`
### enablepublicteams
Enables the public team feature. If enabled, it is possible to configure teams to be public, which makes them
discoverable when sharing a project, therefore not only showing teams the user is member of.
Default: `false`
@ -779,7 +779,7 @@ Environment path: `VIKUNJA_MAILER_PASSWORD`
### skiptlsverify
Wether to skip verification of the tls certificate on the server
Whether to skip verification of the tls certificate on the server
Default: `false`
@ -1222,7 +1222,7 @@ OpenID configuration will allow users to authenticate through a third-party Open
The provider needs to support the `openid`, `profile` and `email` scopes.<br/>
**Note:** Some openid providers (like Gitlab) only make the email of the user available through OpenID if they have set it to be publicly visible.
If the email is not public in those cases, authenticating will fail.
**Note 2:** The frontend expects the third party to rediect the user <frontend-url>/auth/openid/<auth key> after authentication. Please make sure to configure the redirect url in your third party auth service accordingly if you're using the default vikunja frontend.
+**Note 2:** The frontend expects the third party to redirect the user <frontend-url>/auth/openid/<auth key> after authentication. Please make sure to configure the redirect url in your third party auth service accordingly if you're using the default vikunja frontend.
The frontend will automatically provide the API with the redirect url, composed from the current url where it's hosted.
If you want to use the desktop client with OpenID, make sure to allow redirects to `127.0.0.1`.
Take a look at the [default config file](https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample) for more information about how to configure openid authentication.
@ -1421,15 +1421,15 @@ Full path: `webhooks.enabled`
Environment path: `VIKUNJA_WEBHOOKS_ENABLED`
### timoutseconds
### timeoutseconds
The timout in seconds until a webhook request fails when no response has been received.
The timeout in seconds until a webhook request fails when no response has been received.
Default: `30`
Full path: `webhooks.timoutseconds`
Full path: `webhooks.timeoutseconds`
Environment path: `VIKUNJA_WEBHOOKS_TIMOUTSECONDS`
Environment path: `VIKUNJA_WEBHOOKS_TIMEOUTSECONDS`
### proxyurl

View File

@ -40,7 +40,7 @@ chown 1000 $PWD/files
You'll need to do this before running any of the examples on this page.
Vikunja will not try to aquire ownership of the files folder, as that would mean it had to run as root.
Vikunja will not try to acquire ownership of the files folder, as that would mean it had to run as root.
## PostgreSQL
@ -312,7 +312,7 @@ To do that, you can
* Either activate SSH and paste the adapted compose file in a terminal (using Putty or similar)
* Without activating SSH as a "custom script" (go to Control Panel / Task Scheduler / Create / Scheduled Task / User-defined script)
* Without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for exmple):
* Without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for example):
1. Go to **Dashboard / Stacks** click the button **"Add Stack"**
2. Give it the name Vikunja and paste the adapted docker compose file
3. Deploy the Stack with the "Deploy Stack" button:

View File

@ -37,7 +37,7 @@ This document provides an overview and instructions for the different methods:
* [FreeBSD](#freebsd--freenas)
* [Kubernetes]({{< ref "k8s.md" >}})
And after you installed Vikunja, you may want to check out these other ressources:
And after you installed Vikunja, you may want to check out these other resources:
* [Configuration]({{< ref "config.md">}})
* [UTF-8 Settings]({{< ref "utf-8.md">}})
@ -229,7 +229,7 @@ git clone https://code.vikunja.io/vikunja
cd vikunja
```
**Note:** Ceck out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use.
**Note:** Check out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use.
If you don't do this, you'll build the [latest unstable build]({{< ref "versions.md">}}), which might contain bugs.
### Compile binaries

View File

@ -17,7 +17,7 @@ Vikunja allows for authentication with an external identity source such as Authe
## OpenID Connect Overview
OpenID Connect is a standardized identity layer built on top of the more generic OAuth 2.0 specification, simplying interaction between the involved parties significantly.
OpenID Connect is a standardized identity layer built on top of the more generic OAuth 2.0 specification, simplifying interaction between the involved parties significantly.
While the [OpenID specification](https://openid.net/specs/openid-connect-core-1_0.html#Overview) is worth a read, we summarize the most important basics here.
The involved parties are:

View File

@ -17,7 +17,7 @@ However, you can still run it in a subdirectory but need to build the frontend y
First, make sure you're able to build the frontend from source.
Check [the guide about building from source]({{< ref "build-from-source.md">}}#frontend) about that.
### Dynamicly set with build command
### Dynamically set with build command
Run the build with the `VIKUNJA_FRONTEND_BASE` variable specified.

View File

@ -10,17 +10,9 @@ menu:
# Command line interface
You can interact with Vikunja using its `cli` interface.<br />
The following commands are available:
You can interact with Vikunja using its `cli` interface.
* [dump](#dump)
* [help](#help)
* [migrate](#migrate)
* [restore](#restore)
* [testmail](#testmail)
* [user](#user)
* [version](#version)
* [web](#web)
{{< table_of_contents >}}
If you don't specify a command, the [`web`](#web) command will be executed.
@ -43,7 +35,7 @@ alias vikunja-docker='docker exec <name of the vikunja container> /app/vikunja/v
Then use it as `vikunja-docker <subcommand>`.
### `dump`
## `dump`
Creates a zip file with all vikunja-related files.
This includes config, version, all files and the full database.
@ -53,7 +45,21 @@ Usage:
$ vikunja dump
```
### `help`
## `index`
Perform a full reindex of all tasks into Typesense. This will clear all tasks already present in the index unless the `--partial` flag is provided, see below.
The command will only work if Typesense is enabled.
Flags:
* `-p`, `--partial`: If provided, Vikunja will only index tasks which are not present in the index yet.
Usage:
```
$ vikunja index [flags]
```
## `help`
Shows more detailed help about any command.
@ -63,7 +69,7 @@ Usage:
$ vikunja help [command]
```
### `migrate`
## `migrate`
Run all database migrations which didn't already run.
@ -73,7 +79,7 @@ $ vikunja migrate [flags]
$ vikunja migrate [command]
```
#### `migrate list`
### `migrate list`
Shows a list with all database migrations.
@ -82,7 +88,7 @@ Usage:
$ vikunja migrate list
```
#### `migrate rollback`
### `migrate rollback`
Roll migrations back until a certain point.
@ -94,42 +100,42 @@ $ vikunja migrate rollback [flags]
Flags:
* `-n`, `--name` string: The id of the migration you want to roll back until.
### `restore`
## `restore`
Restores a previously created dump from a zip file, see `dump`.
Usage:
```
$ vikunja restore <path to dump zip file>
$ vikunja restore [path to dump zip file]
```
### `testmail`
## `testmail`
Sends a test mail using the configured smtp connection.
Usage:
```
$ vikunja testmail <email to send the test mail to>
$ vikunja testmail [email to send the test mail to]
```
### `user`
## `user`
Bundles a few commands to manage users.
#### `user change-status`
### `user change-status`
Enable or disable a user. Will toggle the current status if no flag (`--enable` or `--disable`) is provided.
Usage:
```
$ vikunja user change-status <user id> <flags>
$ vikunja user change-status [user id] [flags]
```
Flags:
* `-d`, `--disable`: Disable the user.
* `-e`, `--enable`: Enable the user.
#### `user create`
### `user create`
Create a new user.
@ -144,22 +150,22 @@ Flags:
* `-p`, `--password`: The password of the new user. You will be asked to enter it if not provided through the flag.
* `-u`, `--username`: The username of the new user.
#### `user delete`
### `user delete`
Start the user deletion process.
If called without the `--now` flag, this command will only trigger an email to the user in order for them to confirm and start the deletion process (this is the same behavoir as if the user requested their deletion via the web interface).
If called without the `--now` flag, this command will only trigger an email to the user in order for them to confirm and start the deletion process (this is the same behavior as if the user requested their deletion via the web interface).
With the flag the user is deleted **immediately**.
**USE WITH CAUTION.**
```
$ vikunja user delete <id> <flags>
$ vikunja user delete [id] [flags]
```
Flags:
* `-n`, `--now` If provided, deletes the user immediately instead of emailing them first.
#### `user list`
### `user list`
Shows a list of all users.
@ -168,26 +174,26 @@ Usage:
$ vikunja user list
```
#### `user reset-password`
### `user reset-password`
Reset a users password, either through mailing them a reset link or directly.
Usage:
```
$ vikunja user reset-password <flags>
$ vikunja user reset-password [flags]
```
Flags:
* `-d`, `--direct`: If provided, reset the password directly instead of sending the user a reset mail.
* `-p`, `--password`: The new password of the user. Only used in combination with --direct. You will be asked to enter it if not provided through the flag.
#### `user update`
### `user update`
Update an existing user.
Usage:
```
$ vikunja user update <user id>
$ vikunja user update [user id]
```
Flags:
@ -195,19 +201,19 @@ Flags:
* `-e`, `--email`: The new email address of the user.
* `-u`, `--username`: The new username of the user.
### `version`
## `version`
Prints the version of Vikunja.
This is either the semantic version (something like `0.7`) or version + git commit hash.
This is either the semantic version (something like `0.24.0`) or version + git commit hash.
Usage:
```
$ vikunja version
```
### `web`
## `web`
Starts Vikunja's REST api server.
Starts Vikunja's web server, serving the api and frontend.
Usage:
```

View File

@ -51,7 +51,7 @@ This document describes the different errors Vikunja can return.
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 2001 | 400 | ID cannot be empty or 0. |
| 2002 | 400 | Some of the request data was invalid. The response contains an aditional array with all invalid fields. |
| 2002 | 400 | Some of the request data was invalid. The response contains an additional array with all invalid fields. |
## Project

View File

@ -61,7 +61,7 @@ Here are some examples of filter queries:
* `priority = 4`: Matches tasks with priority level 4
* `dueDate < now`: Matches tasks with a due date in the past
* `done = false && priority >= 3`: Matches undone tasks with priority level 3 or higher
* `assignees in [user1, user2]`: Matches tasks assigned to either "user1" or "user2
* `assignees in user1, user2`: Matches tasks assigned to either "user1" or "user2
* `(priority = 1 || priority = 2) && dueDate <= now`: Matches tasks with priority level 1 or 2 and a due date in the past

View File

@ -18,7 +18,7 @@ Starting with version 0.22.0, Vikunja allows you to define webhooks to notify ot
To create a webhook, in the project options select "Webhooks". The form will allow you to create and modify webhooks.
Check out [the api docs](https://try.vikunja.io/api/v1/docs#tag/webhooks) for information about how to create webhooks programatically.
Check out [the api docs](https://try.vikunja.io/api/v1/docs#tag/webhooks) for information about how to create webhooks programmatically.
## Available events and their payload

View File

@ -1 +1 @@
20.12.2
20.13.0

View File

@ -68,7 +68,7 @@ describe('Project View List', () => {
cy.get('.project-title-wrapper .icon')
.should('not.exist')
cy.get('input.input[placeholder="Add a new task..."')
cy.get('input.input[placeholder="Add a task..."')
.should('not.exist')
})

View File

@ -27,7 +27,7 @@ describe('Link shares', () => {
cy.get('h1.title')
.should('contain', project.title)
cy.get('input.input[placeholder="Add a new task..."')
cy.get('input.input[placeholder="Add a task..."')
.should('not.exist')
cy.get('.tasks')
.should('contain', tasks[0].title)
@ -42,7 +42,7 @@ describe('Link shares', () => {
cy.get('h1.title')
.should('contain', project.title)
cy.get('input.input[placeholder="Add a new task..."')
cy.get('input.input[placeholder="Add a task..."')
.should('not.exist')
cy.get('.tasks')
.should('contain', tasks[0].title)

View File

@ -14,12 +14,12 @@ describe('Team', () => {
const newTeamName = 'New Team'
cy.get('a.button')
.contains('Create a new team')
.contains('Create a team')
.click()
cy.url()
.should('contain', '/teams/new')
cy.get('.card-header-title')
.contains('Create a new team')
.contains('Create a team')
cy.get('input.input')
.type(newTeamName)
cy.get('.button')

View File

@ -42,7 +42,7 @@ function uploadAttachmentAndVerify(taskId: number) {
.selectFile('cypress/fixtures/image.jpg', {force: true}) // The input is not visible, but on purpose
cy.wait('@uploadAttachment')
cy.get('.attachments .attachments .files a.attachment')
cy.get('.attachments .attachments .files button.attachment')
.should('exist')
}
@ -65,7 +65,7 @@ describe('Task', () => {
it('Should be created new', () => {
cy.visit('/projects/1/1')
cy.get('.input[placeholder="Add a new task…"')
cy.get('.input[placeholder="Add a task…"')
.type('New Task')
cy.get('.button')
.contains('Add')
@ -81,7 +81,7 @@ describe('Task', () => {
cy.visit('/projects/1/1')
cy.get('.project-is-empty-notice')
.should('not.exist')
cy.get('.input[placeholder="Add a new task…"')
cy.get('.input[placeholder="Add a task…"')
.type('New Task')
cy.get('.button')
.contains('Add')
@ -640,7 +640,7 @@ describe('Task', () => {
.contains('Set Reminders')
.click()
cy.get('.task-view .columns.details .column button')
.contains('Add a new reminder')
.contains('Add a reminder')
.click()
cy.get('.datepicker__quick-select-date')
.contains('Tomorrow')
@ -665,7 +665,7 @@ describe('Task', () => {
.contains('Set Reminders')
.click()
cy.get('.task-view .columns.details .column button')
.contains('Add a new reminder')
.contains('Add a reminder')
.click()
cy.get('.datepicker__quick-select-date')
.should('not.exist')
@ -694,7 +694,7 @@ describe('Task', () => {
.contains('Set Reminders')
.click()
cy.get('.task-view .columns.details .column button')
.contains('Add a new reminder')
.contains('Add a reminder')
.click()
cy.get('.datepicker__quick-select-date')
.should('not.exist')
@ -723,7 +723,7 @@ describe('Task', () => {
.contains('Set Reminders')
.click()
cy.get('.task-view .columns.details .column button')
.contains('Add a new reminder')
.contains('Add a reminder')
.click()
cy.get('.datepicker__quick-select-date')
.should('not.exist')
@ -759,7 +759,7 @@ describe('Task', () => {
.contains('Set Reminders')
.click()
cy.get('.task-view .columns.details .column button')
.contains('Add a new reminder')
.contains('Add a reminder')
.click()
cy.get('.datepicker__quick-select-date')
.should('not.exist')

View File

@ -13,7 +13,7 @@
},
"homepage": "https://vikunja.io/",
"funding": "https://opencollective.com/vikunja",
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.1.0",
"keywords": [
"todo",
"productivity",
@ -58,41 +58,41 @@
"@infectoone/vue-ganttastic": "2.3.2",
"@intlify/unplugin-vue-i18n": "4.0.0",
"@kyvg/vue3-notification": "3.2.1",
"@sentry/tracing": "7.113.0",
"@sentry/vue": "7.113.0",
"@tiptap/core": "2.3.1",
"@tiptap/extension-blockquote": "2.3.1",
"@tiptap/extension-bold": "2.3.1",
"@tiptap/extension-bullet-list": "2.3.1",
"@tiptap/extension-code": "2.3.1",
"@tiptap/extension-code-block-lowlight": "2.3.1",
"@tiptap/extension-document": "2.3.1",
"@tiptap/extension-dropcursor": "2.3.1",
"@tiptap/extension-gapcursor": "2.3.1",
"@tiptap/extension-hard-break": "2.3.1",
"@tiptap/extension-heading": "2.3.1",
"@tiptap/extension-history": "2.3.1",
"@tiptap/extension-horizontal-rule": "2.3.1",
"@tiptap/extension-image": "2.3.1",
"@tiptap/extension-italic": "2.3.1",
"@tiptap/extension-link": "2.3.1",
"@tiptap/extension-list-item": "2.3.1",
"@tiptap/extension-ordered-list": "2.3.1",
"@tiptap/extension-paragraph": "2.3.1",
"@tiptap/extension-placeholder": "2.3.1",
"@tiptap/extension-strike": "2.3.1",
"@tiptap/extension-table": "2.3.1",
"@tiptap/extension-table-cell": "2.3.1",
"@tiptap/extension-table-header": "2.3.1",
"@tiptap/extension-table-row": "2.3.1",
"@tiptap/extension-task-item": "2.3.1",
"@tiptap/extension-task-list": "2.3.1",
"@tiptap/extension-text": "2.3.1",
"@tiptap/extension-typography": "2.3.1",
"@tiptap/extension-underline": "2.3.1",
"@tiptap/pm": "2.3.1",
"@tiptap/suggestion": "2.3.1",
"@tiptap/vue-3": "2.3.1",
"@sentry/tracing": "7.114.0",
"@sentry/vue": "7.114.0",
"@tiptap/core": "2.3.2",
"@tiptap/extension-blockquote": "2.3.2",
"@tiptap/extension-bold": "2.3.2",
"@tiptap/extension-bullet-list": "2.3.2",
"@tiptap/extension-code": "2.3.2",
"@tiptap/extension-code-block-lowlight": "2.3.2",
"@tiptap/extension-document": "2.3.2",
"@tiptap/extension-dropcursor": "2.3.2",
"@tiptap/extension-gapcursor": "2.3.2",
"@tiptap/extension-hard-break": "2.3.2",
"@tiptap/extension-heading": "2.3.2",
"@tiptap/extension-history": "2.3.2",
"@tiptap/extension-horizontal-rule": "2.3.2",
"@tiptap/extension-image": "2.3.2",
"@tiptap/extension-italic": "2.3.2",
"@tiptap/extension-link": "2.3.2",
"@tiptap/extension-list-item": "2.3.2",
"@tiptap/extension-ordered-list": "2.3.2",
"@tiptap/extension-paragraph": "2.3.2",
"@tiptap/extension-placeholder": "2.3.2",
"@tiptap/extension-strike": "2.3.2",
"@tiptap/extension-table": "2.3.2",
"@tiptap/extension-table-cell": "2.3.2",
"@tiptap/extension-table-header": "2.3.2",
"@tiptap/extension-table-row": "2.3.2",
"@tiptap/extension-task-item": "2.3.2",
"@tiptap/extension-task-list": "2.3.2",
"@tiptap/extension-text": "2.3.2",
"@tiptap/extension-typography": "2.3.2",
"@tiptap/extension-underline": "2.3.2",
"@tiptap/pm": "2.3.2",
"@tiptap/suggestion": "2.3.2",
"@tiptap/vue-3": "2.3.2",
"@types/is-touch-device": "1.0.2",
"@types/lodash.clonedeep": "4.5.9",
"@vueuse/core": "10.9.0",
@ -118,7 +118,7 @@
"sortablejs": "1.15.2",
"tippy.js": "6.3.7",
"ufo": "1.5.3",
"vue": "3.4.26",
"vue": "3.4.27",
"vue-advanced-cropper": "2.8.8",
"vue-flatpickr-component": "11.0.5",
"vue-i18n": "9.13.1",
@ -142,26 +142,26 @@
"@types/is-touch-device": "1.0.2",
"@types/lodash.debounce": "4.0.9",
"@types/marked": "5.0.2",
"@types/node": "20.12.8",
"@types/node": "20.12.11",
"@types/postcss-preset-env": "7.7.0",
"@types/sortablejs": "1.15.8",
"@typescript-eslint/eslint-plugin": "7.8.0",
"@typescript-eslint/parser": "7.8.0",
"@vitejs/plugin-legacy": "5.3.2",
"@vitejs/plugin-legacy": "5.4.0",
"@vitejs/plugin-vue": "5.0.4",
"@vue/eslint-config-typescript": "13.0.0",
"@vue/test-utils": "2.4.5",
"@vue/test-utils": "2.4.6",
"@vue/tsconfig": "0.5.1",
"autoprefixer": "10.4.19",
"browserslist": "4.23.0",
"caniuse-lite": "1.0.30001616",
"caniuse-lite": "1.0.30001617",
"css-has-pseudo": "6.0.3",
"csstype": "3.1.3",
"cypress": "13.8.1",
"esbuild": "0.20.2",
"cypress": "13.9.0",
"esbuild": "0.21.1",
"eslint": "8.57.0",
"eslint-plugin-vue": "9.25.0",
"happy-dom": "14.7.1",
"eslint-plugin-vue": "9.26.0",
"happy-dom": "14.10.1",
"histoire": "0.17.17",
"postcss": "8.4.38",
"postcss-easing-gradients": "3.0.1",
@ -170,7 +170,7 @@
"postcss-preset-env": "9.5.11",
"rollup": "4.17.2",
"rollup-plugin-visualizer": "5.12.0",
"sass": "1.76.0",
"sass": "1.77.0",
"start-server-and-test": "2.0.3",
"typescript": "5.4.5",
"vite": "5.2.11",

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -9,7 +9,7 @@ import {MILLISECONDS_A_HOUR} from '@/constants/date'
const now = useNow({
interval: MILLISECONDS_A_HOUR,
})
const Logo = computed(() => window.ALLOW_ICON_CHANGES && now.value.getMonth() === 6 ? LogoFullPride : LogoFull)
const Logo = computed(() => window.ALLOW_ICON_CHANGES && now.value.getMonth() === 5 ? LogoFullPride : LogoFull)
const CustomLogo = computed(() => window.CUSTOM_LOGO_URL)
</script>

View File

@ -1,26 +1,27 @@
<template>
<div
:class="[background ? 'has-background' : '', $route.name as string +'-view']"
:class="{
'has-background': background,
'link-share-is-fullwidth': isFullWidth,
}"
:style="{'background-image': `url(${background})`}"
class="link-share-container"
>
<div class="container has-text-centered link-share-view">
<div class="column is-10 is-offset-1">
<Logo
v-if="logoVisible"
class="logo"
/>
<h1
:class="{'m-0': !logoVisible}"
:style="{ 'opacity': currentProject?.title === '' ? '0': '1' }"
class="title"
>
{{ currentProject?.title === '' ? $t('misc.loading') : currentProject?.title }}
</h1>
<div class="box has-text-left view">
<router-view />
<PoweredByLink />
</div>
<div class="has-text-centered link-share-view">
<Logo
v-if="logoVisible"
class="logo"
/>
<h1
:class="{'m-0': !logoVisible}"
:style="{ 'opacity': currentProject?.title === '' ? '0': '1' }"
class="title"
>
{{ currentProject?.title === '' ? $t('misc.loading') : currentProject?.title }}
</h1>
<div class="box has-text-left view">
<router-view />
<PoweredByLink />
</div>
</div>
</div>
@ -30,11 +31,13 @@
import {computed} from 'vue'
import {useBaseStore} from '@/stores/base'
import {useRoute} from 'vue-router'
import Logo from '@/components/home/Logo.vue'
import PoweredByLink from './PoweredByLink.vue'
import {useProjectStore} from '@/stores/projects'
import {useLabelStore} from '@/stores/labels'
import {PROJECT_VIEW_KINDS} from '@/modelTypes/IProjectView'
const baseStore = useBaseStore()
const currentProject = computed(() => baseStore.currentProject)
@ -46,6 +49,20 @@ projectStore.loadAllProjects()
const labelStore = useLabelStore()
labelStore.loadAllLabels()
const route = useRoute()
const isFullWidth = computed(() => {
const viewId = route.params?.viewId ?? null
const projectId = route.params?.projectId ?? null
if (!viewId || !projectId) {
return false
}
const view = projectStore.projects[Number(projectId)]?.views.find(v => v.id === Number(viewId))
return view?.viewKind === PROJECT_VIEW_KINDS.KANBAN ||
view?.viewKind === PROJECT_VIEW_KINDS.GANTT
})
</script>
<style lang="scss" scoped>
@ -57,20 +74,34 @@ labelStore.loadAllLabels()
.logo {
max-width: 300px;
width: 90%;
margin: 2rem 0 1.5rem;
margin: 1rem auto 2rem;
height: 100px;
}
.column {
max-width: 100%;
}
.title {
text-shadow: 0 0 1rem var(--white);
}
// FIXME: this should be defined somewhere deep
.link-share-view .card {
background-color: var(--white);
.link-share-view {
width: 100%;
max-width: $desktop;
margin: 0 auto;
}
.link-share-container.link-share-is-fullwidth {
.link-share-view {
max-width: 100vw;
}
}
.link-share-container:not(.has-background) {
:deep(.loader-container, .gantt-chart-container > .card) {
box-shadow: none !important;
border: none;
.task-add {
padding: 1rem 0 0;
}
}
}
</style>

View File

@ -67,6 +67,7 @@
class="tiptap__editor"
:class="{'tiptap__editor-is-edit-enabled': isEditing}"
:editor="editor"
@dblclick="setEditIfApplicable()"
@click="focusIfEditing()"
/>
@ -171,7 +172,7 @@ import {OrderedList} from '@tiptap/extension-ordered-list'
import {Paragraph} from '@tiptap/extension-paragraph'
import {Strike} from '@tiptap/extension-strike'
import {Text} from '@tiptap/extension-text'
import {BubbleMenu, EditorContent, useEditor} from '@tiptap/vue-3'
import {BubbleMenu, EditorContent, type Extensions, useEditor} from '@tiptap/vue-3'
import {Node} from '@tiptap/pm/model'
import Commands from './commands'
@ -189,7 +190,7 @@ import BaseButton from '@/components/base/BaseButton.vue'
import XButton from '@/components/input/button.vue'
import {Placeholder} from '@tiptap/extension-placeholder'
import {eventToHotkeyString} from '@github/hotkey'
import {mergeAttributes} from '@tiptap/core'
import {Extension, mergeAttributes} from '@tiptap/core'
import {isEditorContentEmpty} from '@/helpers/editorContentEmpty'
import inputPrompt from '@/helpers/inputPrompt'
import {setLinkInEditor} from '@/components/input/editor/setLinkInEditor'
@ -202,6 +203,7 @@ const {
showSave = false,
placeholder = '',
editShortcut = '',
enableDiscardShortcut = false,
} = defineProps<{
modelValue: string,
uploadCallback?: UploadCallback,
@ -210,6 +212,7 @@ const {
showSave?: boolean,
placeholder?: string,
editShortcut?: string,
enableDiscardShortcut?: boolean,
}>()
const emit = defineEmits(['update:modelValue', 'save'])
@ -311,6 +314,8 @@ const internalMode = ref<Mode>('preview')
const isEditing = computed(() => internalMode.value === 'edit' && isEditEnabled)
const contentHasChanged = ref<boolean>(false)
let lastSavedState = modelValue
watch(
() => internalMode.value,
mode => {
@ -320,109 +325,127 @@ watch(
},
)
const extensions : Extensions = [
// Starterkit:
Blockquote,
Bold,
BulletList,
Code,
CodeBlockLowlight.configure({
lowlight,
}),
Document,
Dropcursor,
Gapcursor,
HardBreak.extend({
addKeyboardShortcuts() {
return {
'Shift-Enter': () => this.editor.commands.setHardBreak(),
'Mod-Enter': () => {
if (contentHasChanged.value) {
bubbleSave()
}
return true
},
}
},
}),
Heading,
History,
HorizontalRule,
Italic,
ListItem,
OrderedList,
Paragraph,
Strike,
Text,
Placeholder.configure({
placeholder: ({editor}) => {
if (!isEditing.value) {
return ''
}
if (editor.getText() !== '' && !editor.isFocused) {
return ''
}
return placeholder !== ''
? placeholder
: t('input.editor.placeholder')
},
}),
Typography,
Underline,
Link.configure({
openOnClick: false,
validate: (href: string) => /^https?:\/\//.test(href),
}),
Table.configure({
resizable: true,
}),
TableRow,
TableHeader,
// Custom TableCell with backgroundColor attribute
CustomTableCell,
CustomImage,
TaskList,
TaskItem.configure({
nested: true,
onReadOnlyChecked: (node: Node, checked: boolean): boolean => {
if (!isEditEnabled) {
return false
}
// The following is a workaround for this bug:
// https://github.com/ueberdosis/tiptap/issues/4521
// https://github.com/ueberdosis/tiptap/issues/3676
editor.value!.state.doc.descendants((subnode, pos) => {
if (node.eq(subnode)) {
const {tr} = editor.value!.state
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
checked,
})
editor.value!.view.dispatch(tr)
bubbleSave()
}
})
return true
},
}),
Commands.configure({
suggestion: suggestionSetup(t),
}),
BubbleMenu,
]
// Add a custom extension for the Escape key
if (enableDiscardShortcut) {
extensions.push(Extension.create({
name: 'escapeKey',
addKeyboardShortcuts() {
return {
'Escape': () => {
exitEditMode()
return true
},
}
},
}))
}
const editor = useEditor({
// eslint-disable-next-line vue/no-ref-object-destructure
editable: isEditing.value,
extensions: [
// Starterkit:
Blockquote,
Bold,
BulletList,
Code,
CodeBlockLowlight.configure({
lowlight,
}),
Document,
Dropcursor,
Gapcursor,
HardBreak.extend({
addKeyboardShortcuts() {
return {
'Shift-Enter': () => this.editor.commands.setHardBreak(),
'Mod-Enter': () => {
if (contentHasChanged.value) {
bubbleSave()
}
return true
},
}
},
}),
Heading,
History,
HorizontalRule,
Italic,
ListItem,
OrderedList,
Paragraph,
Strike,
Text,
Placeholder.configure({
placeholder: ({editor}) => {
if (!isEditing.value) {
return ''
}
if (editor.getText() !== '' && !editor.isFocused) {
return ''
}
return placeholder !== ''
? placeholder
: t('input.editor.placeholder')
},
}),
Typography,
Underline,
Link.configure({
openOnClick: false,
validate: (href: string) => /^https?:\/\//.test(href),
}),
Table.configure({
resizable: true,
}),
TableRow,
TableHeader,
// Custom TableCell with backgroundColor attribute
CustomTableCell,
CustomImage,
TaskList,
TaskItem.configure({
nested: true,
onReadOnlyChecked: (node: Node, checked: boolean): boolean => {
if (!isEditEnabled) {
return false
}
// The following is a workaround for this bug:
// https://github.com/ueberdosis/tiptap/issues/4521
// https://github.com/ueberdosis/tiptap/issues/3676
editor.value!.state.doc.descendants((subnode, pos) => {
if (node.eq(subnode)) {
const {tr} = editor.value!.state
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
checked,
})
editor.value!.view.dispatch(tr)
bubbleSave()
}
})
return true
},
}),
Commands.configure({
suggestion: suggestionSetup(t),
}),
BubbleMenu,
],
extensions: extensions,
onUpdate: () => {
bubbleNow()
},
@ -461,12 +484,27 @@ function bubbleNow() {
function bubbleSave() {
bubbleNow()
emit('save', editor.value?.getHTML())
lastSavedState = editor.value?.getHTML() ?? ''
emit('save', lastSavedState)
if (isEditing.value) {
internalMode.value = 'preview'
}
}
function exitEditMode() {
editor.value?.commands.setContent(lastSavedState, false)
if (isEditing.value) {
internalMode.value = 'preview'
}
}
function setEditIfApplicable() {
if (!isEditEnabled) return
if (isEditing.value) return
setEdit()
}
function setEdit(focus: boolean = true) {
internalMode.value = 'edit'
if (focus) {

View File

@ -24,11 +24,15 @@ import {
faCocktail,
faCoffee,
faCog,
faCopy,
faDownload,
faEllipsisH,
faEllipsisV,
faExclamation,
faEye,
faEyeSlash,
faFile,
faFileImage,
faFillDrip,
faFilter,
faForward,
@ -81,7 +85,6 @@ import {
faCheckSquare,
faClock,
faComments,
faFileImage,
faSave,
faSquareCheck,
faStar,
@ -102,6 +105,7 @@ library.add(faUnlink)
library.add(faParagraph)
library.add(faSquareCheck)
library.add(faTable)
library.add(faFile)
library.add(faFileImage)
library.add(faCheckSquare)
library.add(faStrikethrough)
@ -130,6 +134,8 @@ library.add(faCocktail)
library.add(faCoffee)
library.add(faCog)
library.add(faComments)
library.add(faCopy)
library.add(faDownload)
library.add(faEllipsisH)
library.add(faEllipsisV)
library.add(faExclamation)

View File

@ -35,6 +35,11 @@ const {
const emit = defineEmits(['update:modelValue', 'blur'])
const userService = new UserService()
const projectUserService = new ProjectUserService()
const labelStore = useLabelStore()
const projectStore = useProjectStore()
const filterQuery = ref<string>('')
const {
textarea: filterInput,
@ -60,9 +65,6 @@ watch(
},
)
const userService = new UserService()
const projectUserService = new ProjectUserService()
function escapeHtml(unsafe: string): string {
return unsafe
.replace(/&/g, '&amp;')
@ -196,8 +198,6 @@ const autocompleteMatchText = ref('')
const autocompleteResultType = ref<'labels' | 'assignees' | 'projects' | null>(null)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const autocompleteResults = ref<any[]>([])
const labelStore = useLabelStore()
const projectStore = useProjectStore()
function handleFieldInput() {
const cursorPosition = filterInput.value.selectionStart
@ -288,6 +288,7 @@ const blurDebounced = useDebounceFn(() => emit('blur'), 500)
@input="handleFieldInput"
@focus="onFocusField"
@keydown="onKeydown"
@keydown.enter.prevent="blurDebounced"
@blur="blurDebounced"
/>
<div

View File

@ -57,7 +57,7 @@ const showDocs = ref(false)
<code>done = false &amp;&amp; priority &gt;= 3</code>:
{{ $t('filters.query.help.examples.undoneHighPriority') }}
</li>
<li><code>assignees in [user1, user2]</code>: {{ $t('filters.query.help.examples.assigneesIn') }}</li>
<li><code>assignees in user1, user2</code>: {{ $t('filters.query.help.examples.assigneesIn') }}</li>
<li>
<code>(priority = 1 || priority = 2) &amp;&amp; dueDate &lt;= now</code>:
{{ $t('filters.query.help.examples.priorityOneOrTwoPastDue') }}

View File

@ -30,7 +30,7 @@
>
<icon icon="filter" />
</span>
{{ project.title }}
{{ getProjectTitle(project) }}
</div>
<BaseButton
class="project-button"
@ -59,6 +59,7 @@ import BaseButton from '@/components/base/BaseButton.vue'
import {useProjectBackground} from './useProjectBackground'
import {useProjectStore} from '@/stores/projects'
import {getProjectTitle} from '@/helpers/getProjectTitle'
const {
project,

View File

@ -486,8 +486,8 @@ async function updateTaskPosition(e) {
const newTask = klona(task) // cloning the task to avoid pinia store manipulation
newTask.bucketId = newBucket.id
const position = calculateItemPosition(
taskBefore !== null ? taskBefore.kanbanPosition : null,
taskAfter !== null ? taskAfter.kanbanPosition : null,
taskBefore !== null ? taskBefore.position : null,
taskAfter !== null ? taskAfter.position : null,
)
if (
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
@ -525,13 +525,13 @@ async function updateTaskPosition(e) {
}
// Make sure the first and second task don't both get position 0 assigned
if (newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
if (newTaskIndex === 0 && taskAfter !== null && taskAfter.position === 0) {
const taskAfterAfter = newBucket.tasks[newTaskIndex + 2] ?? null
const newTaskAfter = klona(taskAfter) // cloning the task to avoid pinia store manipulation
newTaskAfter.bucketId = newBucket.id
newTaskAfter.kanbanPosition = calculateItemPosition(
newTaskAfter.position = calculateItemPosition(
0,
taskAfterAfter !== null ? taskAfterAfter.kanbanPosition : null,
taskAfterAfter !== null ? taskAfterAfter.position : null,
)
await taskStore.update(newTaskAfter)

View File

@ -66,7 +66,7 @@
<SingleTaskInProject
:show-list-color="false"
:disabled="!canWrite"
:can-mark-as-done="canWrite || isSavedFilter(project)"
:can-mark-as-done="canWrite || isPseudoProject"
:the-task="t"
:all-tasks="allTasks"
@taskUpdated="updateTasks"
@ -195,6 +195,8 @@ const canWrite = computed(() => {
return project.value.maxRight > Rights.READ && project.value.id > 0
})
const isPseudoProject = computed(() => (project.value && isSavedFilter(project.value)) || project.value?.id === -1)
onMounted(async () => {
await nextTick()
ctaVisible.value = true
@ -306,4 +308,12 @@ function prepareFiltersAndLoadTasks() {
}
}
}
.list-view {
padding-bottom: 1rem;
:deep(.card) {
margin-bottom: 0;
}
}
</style>

View File

@ -2,70 +2,86 @@
import type {IProjectView} from '@/modelTypes/IProjectView'
import XButton from '@/components/input/button.vue'
import FilterInput from '@/components/project/partials/FilterInput.vue'
import {ref, watch} from 'vue'
import {ref, onBeforeMount} from 'vue'
import {transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
import {useLabelStore} from '@/stores/labels'
import {useProjectStore} from '@/stores/projects'
const {
modelValue,
loading = false,
showSaveButtons = false,
} = defineProps<{
modelValue: IProjectView,
loading?: bool,
showSaveButtons?: bool,
}>()
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue', 'cancel'])
const view = ref<IProjectView>()
const labelStore = useLabelStore()
const projectStore = useProjectStore()
watch(
() => modelValue,
newValue => {
const transformed = {
...newValue,
filter: transformFilterStringFromApi(
newValue.filter,
labelId => labelStore.getLabelById(labelId)?.title,
projectId => projectStore.projects[projectId]?.title || null,
),
}
onBeforeMount(() => {
const transform = filterString => transformFilterStringFromApi(
filterString,
labelId => labelStore.getLabelById(labelId)?.title,
projectId => projectStore.projects[projectId]?.title || null,
)
if (JSON.stringify(view.value) !== JSON.stringify(transformed)) {
view.value = transformed
}
},
{immediate: true, deep: true},
)
const transformed = {
...modelValue,
filter: transform(modelValue.filter),
bucketConfiguration: modelValue.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transform(bc.filter),
})),
}
watch(
() => view.value,
newView => {
emit('update:modelValue', {
...newView,
filter: transformFilterStringForApi(
newView.filter,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle)
return found?.id || null
},
),
})
},
{deep: true},
)
if (JSON.stringify(view.value) !== JSON.stringify(transformed)) {
view.value = transformed
}
})
function save() {
const transformFilter = filterQuery => transformFilterStringForApi(
filterQuery,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle)
return found?.id || null
},
)
emit('update:modelValue', {
...view.value,
filter: transformFilter(view.value?.filter),
bucketConfiguration: view.value?.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transformFilter(bc.filter),
})),
})
}
const titleValid = ref(true)
function validateTitle() {
titleValid.value = view.value?.title !== ''
}
function handleBubbleSave() {
if (showSaveButtons) {
return
}
save()
}
</script>
<template>
<form>
<form @focusout="handleBubbleSave">
<div class="field">
<label
class="label"
@ -123,6 +139,7 @@ function validateTitle() {
<FilterInput
v-model="view.filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>
@ -192,6 +209,7 @@ function validateTitle() {
<FilterInput
v-model="view.bucketConfiguration[index].filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>
</div>
@ -207,6 +225,24 @@ function validateTitle() {
</div>
</div>
</div>
<div
v-if="showSaveButtons"
class="is-flex is-justify-content-end"
>
<XButton
variant="tertiary"
class="mr-2"
@click="emit('cancel')"
>
{{ $t('misc.cancel') }}
</XButton>
<XButton
:loading="loading"
@click="save"
>
{{ $t('misc.save') }}
</XButton>
</div>
</form>
</template>

View File

@ -27,83 +27,87 @@
v-if="attachments.length > 0"
class="files"
>
<!-- FIXME: don't use a for element that wraps other links / buttons
Instead: overlay element with button that is inside.
-->
<a
<button
v-for="a in attachments"
:key="a.id"
class="attachment"
@click="viewOrDownload(a)"
>
<div class="filename">
{{ a.file.name }}
<span
v-if="task.coverImageAttachmentId === a.id"
class="is-task-cover"
>
{{ $t('task.attachment.usedAsCover') }}
</span>
<div class="preview-column">
<FilePreview
class="attachment-preview"
:model-value="a"
/>
</div>
<div class="info">
<p class="attachment-info-meta">
<i18n-t
keypath="task.attachment.createdBy"
scope="global"
<div class="attachment-info-column">
<div class="filename">
{{ a.file.name }}
<span
v-if="task.coverImageAttachmentId === a.id"
class="is-task-cover"
>
<span v-tooltip="formatDateLong(a.created)">
{{ formatDateSince(a.created) }}
{{ $t('task.attachment.usedAsCover') }}
</span>
</div>
<div class="info">
<p class="attachment-info-meta">
<i18n-t
keypath="task.attachment.createdBy"
scope="global"
>
<span v-tooltip="formatDateLong(a.created)">
{{ formatDateSince(a.created) }}
</span>
<User
:avatar-size="24"
:user="a.createdBy"
:is-inline="true"
/>
</i18n-t>
<span>
{{ getHumanSize(a.file.size) }}
</span>
<User
:avatar-size="24"
:user="a.createdBy"
:is-inline="true"
/>
</i18n-t>
<span>
{{ getHumanSize(a.file.size) }}
</span>
<span v-if="a.file.mime">
{{ a.file.mime }}
</span>
</p>
<p>
<BaseButton
v-tooltip="$t('task.attachment.downloadTooltip')"
class="attachment-info-meta-button"
@click.prevent.stop="downloadAttachment(a)"
>
{{ $t('misc.download') }}
</BaseButton>
<BaseButton
v-tooltip="$t('task.attachment.copyUrlTooltip')"
class="attachment-info-meta-button"
@click.stop="copyUrl(a)"
>
{{ $t('task.attachment.copyUrl') }}
</BaseButton>
<BaseButton
v-if="editEnabled"
v-tooltip="$t('task.attachment.deleteTooltip')"
class="attachment-info-meta-button"
@click.prevent.stop="setAttachmentToDelete(a)"
>
{{ $t('misc.delete') }}
</BaseButton>
<BaseButton
v-if="editEnabled"
class="attachment-info-meta-button"
@click.prevent.stop="setCoverImage(task.coverImageAttachmentId === a.id ? null : a)"
>
{{
task.coverImageAttachmentId === a.id
<span v-if="a.file.mime">
{{ a.file.mime }}
</span>
</p>
<p>
<BaseButton
v-tooltip="$t('task.attachment.downloadTooltip')"
class="attachment-info-meta-button"
@click.prevent.stop="downloadAttachment(a)"
>
<icon icon="download" />
</BaseButton>
<BaseButton
v-tooltip="$t('task.attachment.copyUrlTooltip')"
class="attachment-info-meta-button"
@click.stop="copyUrl(a)"
>
<icon icon="copy" />
</BaseButton>
<BaseButton
v-if="editEnabled"
v-tooltip="$t('task.attachment.deleteTooltip')"
class="attachment-info-meta-button"
@click.prevent.stop="setAttachmentToDelete(a)"
>
<icon icon="trash-alt" />
</BaseButton>
<BaseButton
v-if="editEnabled && canPreview(a)"
v-tooltip="task.coverImageAttachmentId === a.id
? $t('task.attachment.unsetAsCover')
: $t('task.attachment.setAsCover')
}}
</BaseButton>
</p>
: $t('task.attachment.setAsCover')"
class="attachment-info-meta-button"
@click.prevent.stop="setCoverImage(task.coverImageAttachmentId === a.id ? null : a)"
>
<icon :icon="task.coverImageAttachmentId === a.id ? 'eye-slash' : 'eye'" />
</BaseButton>
</p>
</div>
</div>
</a>
</button>
</div>
<x-button
@ -188,6 +192,7 @@ import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
import {error, success} from '@/message'
import {useTaskStore} from '@/stores/tasks'
import {useI18n} from 'vue-i18n'
import FilePreview from '@/components/tasks/partials/file-preview.vue'
const {
task,
@ -260,13 +265,17 @@ async function deleteAttachment() {
const attachmentImageBlobUrl = ref<string | null>(null)
async function viewOrDownload(attachment: IAttachment) {
if (SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) {
if (canPreview(attachment)) {
attachmentImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
} else {
downloadAttachment(attachment)
}
}
function canPreview(attachment: IAttachment): boolean {
return SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.toLowerCase().endsWith(suffix))
}
const copy = useCopyToClipboard()
function copyUrl(attachment: IAttachment) {
@ -298,11 +307,18 @@ async function setCoverImage(attachment: IAttachment | null) {
}
.attachment {
margin-bottom: .5rem;
display: block;
transition: background-color $transition;
border-radius: $radius;
display: grid;
grid-template-columns: 9rem 1fr;
align-items: center;
width: 100%;
padding: .5rem;
transition: background-color $transition;
background-color: transparent;
border: transparent;
border-radius: $radius;
&:hover {
background-color: var(--grey-200);
@ -310,22 +326,25 @@ async function setCoverImage(attachment: IAttachment | null) {
}
.filename {
display: flex;
align-items: center;
font-weight: bold;
margin-bottom: .25rem;
height: 2rem;
color: var(--text);
}
.info {
color: var(--grey-500);
font-size: .9rem;
display: flex;
flex-direction: column;
p {
margin-bottom: 0;
display: flex;
> span:not(:last-child):after,
> span,
> button:not(:last-child):after {
content: '·';
padding: 0 .25rem;
}
}
@ -376,6 +395,12 @@ async function setCoverImage(attachment: IAttachment | null) {
}
}
.attachment-info-column {
display: flex;
flex-flow: column wrap;
align-self: start;
}
.attachment-info-meta {
display: flex;
align-items: center;
@ -407,6 +432,7 @@ async function setCoverImage(attachment: IAttachment | null) {
.attachment-info-meta-button {
color: var(--link);
padding: 0 .25rem;
}
@keyframes bounce {
@ -435,9 +461,19 @@ async function setCoverImage(attachment: IAttachment | null) {
}
}
.preview-column {
max-width: 8rem;
height: 5.2rem;
}
.attachment-preview {
height: 100%;
}
.is-task-cover {
background: var(--primary);
color: var(--white);
margin-left: .25rem;
padding: .25rem .35rem;
border-radius: 4px;
font-size: .75rem;

View File

@ -85,6 +85,7 @@
:upload-enabled="true"
:bottom-actions="actions[c.id]"
:show-save="true"
:enable-discard-shortcut="true"
initial-mode="preview"
@update:modelValue="
() => {

View File

@ -30,6 +30,7 @@
:placeholder="$t('task.description.placeholder')"
:show-save="true"
edit-shortcut="e"
:enable-discard-shortcut="true"
@update:modelValue="saveWithDelay"
@save="save"
/>

View File

@ -0,0 +1,58 @@
<template>
<!-- Preview image -->
<img
v-if="blobUrl"
:src="blobUrl"
alt="Attachment preview"
>
<!-- Fallback -->
<div
v-else
class="icon-wrapper"
>
<icon
size="6x"
icon="file"
/>
</div>
</template>
<script setup lang="ts">
import {type PropType, ref, shallowReactive, watchEffect} from 'vue'
import AttachmentService from '@/services/attachment'
import type {IAttachment} from '@/modelTypes/IAttachment'
import {SUPPORTED_IMAGE_SUFFIX} from '@/models/attachment'
const props = defineProps({
modelValue: {
type: Object as PropType<IAttachment>,
default: undefined,
},
})
const attachmentService = shallowReactive(new AttachmentService())
const blobUrl = ref<string | undefined>(undefined)
watchEffect(async () => {
if (props.modelValue && canPreview(props.modelValue)) {
blobUrl.value = await attachmentService.getBlobUrl(props.modelValue)
}
})
function canPreview(attachment: IAttachment): boolean {
return SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.toLowerCase().endsWith(suffix))
}
</script>
<style scoped lang="scss">
img {
width: 100%;
border-radius: $radius;
object-fit: cover;
}
.icon-wrapper {
color: var(--grey-500);
}
</style>

View File

@ -162,7 +162,7 @@ async function maybeDownloadCoverImage() {
}
const attachment = task.attachments.find(a => a.id === task.coverImageAttachmentId)
if (!attachment || !SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) {
if (!attachment || !SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.toLowerCase().endsWith(suffix))) {
return
}

View File

@ -79,6 +79,12 @@ export const parseDate = (text: string, now: Date = new Date()): dateParseResult
parsed = getDateFromText(text, now)
if (parsed.date === null) {
const time = addTimeToDate(text, new Date(now), parsed.foundText)
if (time.date !== null && +now !== +time.date) {
return time
}
return {
newText: replaceAll(text, parsed.foundText, ''),
date: parsed.date,
@ -122,7 +128,7 @@ const addTimeToDate = (text: string, date: Date, previousMatch: string | null):
const replace = results !== null ? results[0] : previousMatch
return {
newText: replaceAll(text, replace, '').trim(),
date: date,
date,
}
}

View File

@ -1,4 +1,5 @@
import {createI18n} from 'vue-i18n'
import type {PluralizationRule} from 'vue-i18n'
import langEN from './lang/en.json'
export const SUPPORTED_LOCALES = {
@ -22,6 +23,7 @@ export const SUPPORTED_LOCALES = {
'ar-SA': 'اَلْعَرَبِيَّةُ',
'sl-SI': 'Slovenščina',
'pt-BR': 'Português Brasileiro',
'hr-HR': 'Hrvatski',
// IMPORTANT: Also add new languages to useDayjsLanguageSync
} as const
@ -35,6 +37,24 @@ export type ISOLanguage = string
export const i18n = createI18n({
fallbackLocale: DEFAULT_LANGUAGE,
legacy: false,
pluralRules: {
'ru-RU': (choice: number, choicesLength: number, orgRule?: PluralizationRule) => {
if (choicesLength !== 3) {
return orgRule ? orgRule(choice, choicesLength) : 0
}
const n = Math.abs(choice) % 100
if (n > 10 && n < 20) {
return 2
}
if (n % 10 === 1) {
return 0
}
if (n % 10 >= 2 && n % 10 <= 4) {
return 1
}
return 2
},
},
messages: {
[DEFAULT_LANGUAGE]: langEN,
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -53,7 +53,7 @@
"loginWith": "تسجيل الدخول باستخدام {provider}",
"authenticating": "جاري التحقق…",
"openIdStateError": "حالة التحقق غير متطابقة، لا يمكن المتابعة!",
"openIdGeneralError": "حدث خطأ أثناء التحقق مع الطرف الثالث.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "تسجيل الخروج",
"emailInvalid": "الرجاء إدخال عنوان بريد إلكتروني صحيح.",
"usernameRequired": "الرجاء إدخال اسم المستخدم.",
@ -66,7 +66,8 @@
"hidePassword": "إخفاء كلمة المرور",
"noAccountYet": "ليس لديك حساب بعد؟",
"alreadyHaveAnAccount": "لديك حساب مسبقا؟",
"remember": "البقاء متصلاً"
"remember": "البقاء متصلاً",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "الإعدادات",
@ -95,6 +96,7 @@
"weekStartMonday": "الإثنين",
"language": "اللّغة",
"defaultProject": "المشروع الافتراضي",
"defaultView": "Default View",
"timezone": "منطقة التوقيت",
"overdueTasksRemindersTime": "وقت تذكير للمهام المتأخرة بالبريد الإلكتروني",
"filterUsedOnOverview": "الفلتر المحفوظ والمستخدم في صفحة العرض العام"
@ -227,8 +229,8 @@
"title": "أرشفة \"{project}\"",
"archive": "أرشفة هذا المشروع",
"unarchive": "إلغاء أرشفة هذا المشروع",
"unarchiveText": "ستتمكن من إنشاء مهام جديدة أو تعديلها.",
"archiveText": "لن تتمكن من تعديل هذا المشروع أو إنشاء مهام جديدة حتى تقوم بإلغاء أرشفته.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "تم أرشفة المشروع بنجاح."
},
"background": {
@ -277,7 +279,7 @@
"title": "روابط المشاركة",
"what": "ما هو رابط المشاركة؟",
"explanation": "تتيح لك روابط المشاركة سهولة مشاركة مشروع مع المستخدمين الآخرين الذين ليس لديهم حساب في Vikunja.",
"create": "إنشاء رابط مشاركة جديد",
"create": "Create a link share",
"name": "الاسم (اختياري)",
"namePlaceholder": "مثال: Lorem Ipsum",
"nameExplanation": "ستظهر جميع الإجراءات التي يقوم بها رابط المشاركة مع الاسم.",
@ -314,12 +316,15 @@
"delete": "حذف"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "القائمة",
"add": "إضافة",
"addPlaceholder": "إضافة مهمة جديدة…",
"addPlaceholder": "Add a task…",
"empty": "هذا المشروع فارغ حاليا.",
"newTaskCta": "إنشاء مهمة جديدة.",
"newTaskCta": "Create a task.",
"editTask": "تعديل المهمة"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "أدخل عنوان المهمة الجديدة…",
"addTask": "إضافة مهمة",
"addAnotherTask": "إضافة مهمة أخرى",
"addBucket": "إنشاء حافظة جديدة",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "أدخل عنوان الحافظة الجديدة…",
"deleteHeaderBucket": "حذف الحافظة",
"deleteBucketText1": "هل أنت متأكد من رغبتك في حذف هذه الحافظة؟",
@ -423,7 +428,7 @@
"create": {
"title": "فلتر جديد محفوظ",
"description": "الفلتر المحفوظ هو مشروع افتراضي يتم حسابه من مجموعة من الفلاتر في كل مرة يتم الوصول إليها.",
"action": "إنشاء فلتر جديد محفوظ",
"action": "Create saved filter",
"titleRequired": "يرجى تحديد عنوان للفلتر."
},
"delete": {
@ -507,7 +512,7 @@
"search": "اكتب للبحث عن تسمية…",
"create": {
"header": "تسمية جديدة",
"title": "إنشاء تسمية جديدة",
"title": "Create a label",
"titleRequired": "الرجاء تحديد العنوان.",
"success": "تم إنشاء التسمية بنجاح."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "جاري التحقق…",
"passwordRequired": "هذا المشروع المشترك يتطلب كلمة مرور. الرجاء إدخالها أدناه:",
"error": "حدث خطأ.",
"error": "An error occurred.",
"invalidPassword": "كلمة المرور غير صحيحة."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "إنشاء جديد",
"createPlaceholder": "Create",
"selectPlaceholder": "انقر أو اضغط على إدخال للاختيار"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "مهمة",
"new": "إنشاء مهمة جديدة",
"new": "Create a task",
"delete": "حذف هذه المهمة",
"createSuccess": "تم إنشاء المهمة بنجاح.",
"addReminder": "إضافة تذكير جديد…",
"addReminder": "Add a reminder…",
"doneSuccess": "تم بنجاح وضع علامة مكتملة على المهمة.",
"undoneSuccess": "تم بنجاح إلغاء وضع علامة مكتملة على المهمة.",
"undo": "تراجع",
@ -860,7 +865,7 @@
"unassignSuccess": "تم إلغاء تعيين المستخدم بنجاح."
},
"label": {
"placeholder": "اكتب لإضافة تسمية جديدة…",
"placeholder": "Type to add a label…",
"createPlaceholder": "أضف هذا كتسمية جديدة",
"addSuccess": "تمت إضافة التسمية بنجاح.",
"createSuccess": "تم إنشاء التسمية بنجاح.",
@ -883,8 +888,8 @@
"relation": {
"add": "أضف علاقة لمهمة جديدة",
"new": "علاقة لمهمة جديدة",
"searchPlaceholder": "ابحث عن مهمة جديدة لإضافتها كـمهمة مرتبطة…",
"createPlaceholder": "إضافة هذه كمهمة ذات علاقة جديدة",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "هذه المهمة تنتمي إلى مشروع آخر.",
"noneYet": "لا توجد علاقات للمهام حتى الآن.",
"delete": "حذف علاقة المهمة",
@ -922,7 +927,7 @@
"every30d": "كل 30 يوماً",
"mode": "وضع التكرار",
"monthly": "شهرياً",
"fromCurrentDate": "من التاريخ الحالي",
"fromCurrentDate": "From completion date",
"each": "كل",
"specifyAmount": "حدد قيمة…",
"hours": "الساعات",
@ -962,7 +967,7 @@
"title": "الفِرق",
"noTeams": "أنت حاليا لست جزءا من أي فريق.",
"create": {
"title": "إنشاء فريق جديد",
"title": "Create a team",
"success": "تم إنشاء الفريق بنجاح."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "تكرار",
"delete": "حذف",
"unarchive": "إلغاء الأرشفة",
"setBackground": "تعيين خلفية",
"setBackground": "Background settings",
"share": "مشاركة",
"newProject": "مشروع جديد",
"createProject": "إنشاء مشروع",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -66,7 +66,8 @@
"hidePassword": "Skrýt heslo",
"noAccountYet": "Ještě nemáte účet?",
"alreadyHaveAnAccount": "Už máte svůj účet?",
"remember": "Zůstat trvale přihlášen"
"remember": "Zůstat trvale přihlášen",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Nastavení",
@ -95,6 +96,7 @@
"weekStartMonday": "Pondělí",
"language": "Jazyk",
"defaultProject": "Výchozí projekt",
"defaultView": "Default View",
"timezone": "Časové pásmo",
"overdueTasksRemindersTime": "Čas odeslání emailu o zpožděných úkolech",
"filterUsedOnOverview": "Uložený filtr použitý na stránce přehledu"
@ -227,8 +229,8 @@
"title": "Archivovat \"{project}\"",
"archive": "Archivovat tento projekt",
"unarchive": "Zrušit archivaci tohoto projektu",
"unarchiveText": "Budete moci vytvářet nové úkoly nebo je upravovat.",
"archiveText": "Tento projekt nebudete moci upravovat ani v něm vytvářet nové úkoly, dokud jej neodarchivujete.",
"unarchiveText": "Budete moci vytvářet úkoly nebo je upravovat.",
"archiveText": "Tento projekt nebudete moci upravovat ani v něm vytvářet nové úkoly, dokud jej neobnovíte z archivu.",
"success": "Projekt byl úspěšně archivován."
},
"background": {
@ -314,10 +316,13 @@
"delete": "Smazat"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Seznam",
"add": "Přidat",
"addPlaceholder": "Přidat nový úkol…",
"addPlaceholder": "Přidat úkol…",
"empty": "Tento projekt je zatím prázdný.",
"newTaskCta": "Vytvořit nový úkol.",
"editTask": "Upravit úkol"
@ -383,21 +388,21 @@
"secretDocs": "Další podrobnosti o používání tajných klíčů naleznete v dokumentaci."
},
"views": {
"header": "Edit views",
"title": "Title",
"actions": "Actions",
"kind": "Kind",
"bucketConfigMode": "Bucket configuration mode",
"bucketConfig": "Bucket configuration",
"bucketConfigManual": "Manual",
"filter": "Filter",
"create": "Create view",
"createSuccess": "The view was created successfully.",
"titleRequired": "Please provide a title.",
"delete": "Delete this view",
"deleteText": "Are you sure you want to remove this view? It will no longer be possible to use it to view tasks in this project. This action won't delete any tasks. This cannot be undone!",
"deleteSuccess": "The view was successfully deleted",
"onlyAdminsCanEdit": "Only project admins can edit views."
"header": "Upravit pohled",
"title": "Název",
"actions": "Akce",
"kind": "Druh",
"bucketConfigMode": "Režim nastavení sloupce",
"bucketConfig": "Nastavení sloupce",
"bucketConfigManual": "Manuál",
"filter": "Filtr",
"create": "Vytvořit pohled",
"createSuccess": "Pohled byl úspěšně vytvořen.",
"titleRequired": "Zadejte prosím název.",
"delete": "Odstranit tento pohled",
"deleteText": "Jste si jisti, že chcete odstranit tento pohled? Nebude již možné jej použít k zobrazení úkolů v tomto projektu. Tato akce neodstraní žádné úkoly. Toto nelze vrátit zpět!",
"deleteSuccess": "Pohled byl úspěšně odstraněn",
"onlyAdminsCanEdit": "Pohledy mohou upravovat pouze správci projektu."
}
},
"filters": {
@ -507,7 +512,7 @@
"search": "Zadejte hledaný štítek…",
"create": {
"header": "Nový štítek",
"title": "Vytvořit nový štítek",
"title": "Vytvořit štítek",
"titleRequired": "Zadejte název prosím.",
"success": "Štítek byl úspěšně vytvořen."
},
@ -642,7 +647,7 @@
"placeholder": "Zadejte nějaký text nebo stiskněte '/' pro zobrazení více možností…"
},
"multiselect": {
"createPlaceholder": "Vytvořit nový",
"createPlaceholder": "Vytvořit",
"selectPlaceholder": "Kliknutím nebo stisknutím klávesy Enter vyberte"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Úkol",
"new": "Vytvořit nový úkol",
"new": "Vytvořit úkol",
"delete": "Smazat tento úkol",
"createSuccess": "Úkol byl úspěšně vytvořen.",
"addReminder": "Přidat novou připomínku…",
"addReminder": "Přidat připomínku…",
"doneSuccess": "Úkol byl úspěšně označen jako dokončený.",
"undoneSuccess": "Úkol byl úspěšně znovu otevřen.",
"undo": "Vrátit zpět",
@ -860,7 +865,7 @@
"unassignSuccess": "Uživatel byl úspěšně vyloučen."
},
"label": {
"placeholder": "Zadejte pro přidání nového štítku…",
"placeholder": "Pište pro přidání nového štítku…",
"createPlaceholder": "Přidat toto jako nový štítek",
"addSuccess": "Štítek byl úspěšně přidán.",
"createSuccess": "Štítek byl úspěšně vytvořen.",
@ -883,8 +888,8 @@
"relation": {
"add": "Přidat nový vztah úkolu",
"new": "Nový vztah k úkolu",
"searchPlaceholder": "Hledejte nový úkol, který chcete přidat jako související…",
"createPlaceholder": "Přidat toto jako nový související úkol",
"searchPlaceholder": "Hledejte úkol, který chcete přidat jako související…",
"createPlaceholder": "Přidat jako související úkol",
"differentProject": "Tento úkol patří do jiného projektu.",
"noneYet": "Zatím žádné vztahy mezi úkoly.",
"delete": "Odstranit vztah k úloze",
@ -922,7 +927,7 @@
"every30d": "Každých 30 dní",
"mode": "Režim opakování",
"monthly": "Měsíčně",
"fromCurrentDate": "Od aktuálního data",
"fromCurrentDate": "Od data dokončení",
"each": "Každý",
"specifyAmount": "Zadejte množství…",
"hours": "Hodin",
@ -962,7 +967,7 @@
"title": "Týmy",
"noTeams": "Momentálně nejste v žádném týmu.",
"create": {
"title": "Vytvořit nový tým",
"title": "Vytvořit tým",
"success": "Tým byl úspěšně vytvořen."
},
"edit": {
@ -1060,13 +1065,13 @@
"duplicate": "Duplikovat",
"delete": "Smazat",
"unarchive": "Zrušit archivaci",
"setBackground": "Nastavit pozadí",
"setBackground": "Nastavení pozadí",
"share": "Sdílet",
"newProject": "Nový projekt",
"createProject": "Vytvořit projekt",
"cantArchiveIsDefault": "Nemůžete archivovat svůj výchozí projekt.",
"cantDeleteIsDefault": "Nemůžete smazat svůj výchozí projekt.",
"views": "Views"
"views": "Pohledy"
},
"apiConfig": {
"url": "Vikunja URL",
@ -1110,14 +1115,14 @@
},
"date": {
"locale": "cs",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {
"reactedWith": "{user} reacted with {value}",
"reactedWithAnd": "{users} and {lastUser} reacted with {value}",
"reactedWithAndMany": "{users} and {num} more reacted reacted with {value}",
"add": "Add your reaction"
"reactedWith": "{user} zareagoval s {value}",
"reactedWithAnd": "{users} a {lastUser} zareagovali s {value}",
"reactedWithAndMany": "{users} a {num} zareagovali s {value}",
"add": "Přidejte svou reakci"
},
"error": {
"error": "Chyba",

View File

@ -53,7 +53,7 @@
"loginWith": "Log ind med {provider}",
"authenticating": "Godkender…",
"openIdStateError": "Indholdet stemmer ikke overens, nægter at fortsætte!",
"openIdGeneralError": "Der opstod en fejl under godkendelse mod tredjeparten.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Log ud",
"emailInvalid": "Indtast venligst en gyldig e-mailadresse.",
"usernameRequired": "Angiv venligst et brugernavn.",
@ -66,7 +66,8 @@
"hidePassword": "Skjul adgangskoden",
"noAccountYet": "Har du ikke en konto endnu?",
"alreadyHaveAnAccount": "Har du allerede en konto?",
"remember": "Forbliv logget ind"
"remember": "Forbliv logget ind",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Indstillinger",
@ -95,6 +96,7 @@
"weekStartMonday": "Mandag",
"language": "Sprog",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Tidszone",
"overdueTasksRemindersTime": "Forfaldne opgaver påmindelse e-mail tidspunkt",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "Nyt Gemt Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Opret nyt gemt filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Skriv for at søge efter en etiket…",
"create": {
"header": "Ny etiket",
"title": "Opret ny etiket",
"title": "Create a label",
"titleRequired": "Angiv venligst en titel.",
"success": "Etiketten blev oprettet."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Godkender…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "Der opstod en fejl.",
"error": "An error occurred.",
"invalidPassword": "Adgangskoden er ugyldig."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Opret ny",
"createPlaceholder": "Create",
"selectPlaceholder": "Klik eller tryk på Enter for at vælge"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Opgave",
"new": "Opret en ny opgave",
"new": "Create a task",
"delete": "Slet denne opgave",
"createSuccess": "Opgaven blev oprettet.",
"addReminder": "Tilføj en ny påmindelse…",
"addReminder": "Add a reminder…",
"doneSuccess": "Opgaven blev markeret som udført.",
"undoneSuccess": "Opgaven fik fjernet sin udført-markering.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "Brugeren er blevet frakoblet."
},
"label": {
"placeholder": "Skriv for at tilføje en ny etiket…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Tilføj dette som ny etiket",
"addSuccess": "Etiketten er blevet tilføjet.",
"createSuccess": "Etiketten er blevet oprettet.",
@ -883,8 +888,8 @@
"relation": {
"add": "Tilføj en ny opgaverelation",
"new": "Ny Opgaverelation",
"searchPlaceholder": "Indtast søgning efter en ny opgave der tilføjes som relateret…",
"createPlaceholder": "Tilføj dette som en ny relateret opgave",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "Ingen opgaverelationer endnu.",
"delete": "Slet Opgaverelation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Gentagelsestilstand",
"monthly": "Månedligt",
"fromCurrentDate": "Fra Nuværende Dato",
"fromCurrentDate": "From completion date",
"each": "Hver",
"specifyAmount": "Angiv et beløb…",
"hours": "Timer",
@ -962,7 +967,7 @@
"title": "Hold",
"noTeams": "Du er i øjeblikket ikke en del af et hold.",
"create": {
"title": "Opret et nyt hold",
"title": "Create a team",
"success": "Holdet blev oprettet."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Dupliker",
"delete": "Slet",
"unarchive": "Tilbagekald",
"setBackground": "Indstil baggrund",
"setBackground": "Background settings",
"share": "Del",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "da",
"altFormatLong": "d m Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Mit {provider} anmelden",
"authenticating": "Authentifizierung…",
"openIdStateError": "Zustand stimmt nicht überein, fahre nicht fort!",
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentifizierung aufgetreten.",
"logout": "Abmelden",
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
"usernameRequired": "Bitte gib einen Anmeldenamen ein.",
@ -66,7 +66,8 @@
"hidePassword": "Passwort verbergen",
"noAccountYet": "Noch kein Account?",
"alreadyHaveAnAccount": "Hast du bereits einen Account?",
"remember": "Angemeldet bleiben"
"remember": "Angemeldet bleiben",
"registrationDisabled": "Registrierung ist deaktiviert."
},
"settings": {
"title": "Einstellungen",
@ -95,6 +96,7 @@
"weekStartMonday": "Montag",
"language": "Sprache",
"defaultProject": "Standard-Projekt",
"defaultView": "Standardansicht",
"timezone": "Zeitzone",
"overdueTasksRemindersTime": "Zeit der E-Mail-Zusammenfassung der überfälligen Aufgaben",
"filterUsedOnOverview": "Gespeicherter Filter, der für die Startseite verwendet wird"
@ -227,8 +229,8 @@
"title": "„{project}“ archivieren",
"archive": "Dieses Projekt archivieren",
"unarchive": "Archivierung dieses Projekts aufheben",
"unarchiveText": "Du wirst neue Aufgaben erstellen oder sie bearbeiten können.",
"archiveText": "Du kannst dieses Projekt nicht bearbeiten oder neue Aufgaben erstellen, bis du die Archivierung aufhebst.",
"unarchiveText": "Du kannst Aufgaben erstellen oder diese bearbeiten.",
"archiveText": "Du kannst dieses Projekt nicht bearbeiten oder Aufgaben erstellen, bis du die Archivierung aufhebst.",
"success": "Das Projekt wurde erfolgreich archiviert."
},
"background": {
@ -277,7 +279,7 @@
"title": "Linkfreigaben",
"what": "Was ist eine Linkfreigabe?",
"explanation": "Mit Linkfreigaben kannst Projekt du Listen mit Benutzer:innen ohne Vikunja-Account teilen.",
"create": "Erstelle ein neue Linkfreigabe",
"create": "Erstelle ein Linkfreigabe",
"name": "Name (optional)",
"namePlaceholder": "z.B. Lorem Ipsum",
"nameExplanation": "Alle Aktionen, die mit dieser Linkfreigabe durchgeführt werden, werden mit diesem Namen angezeigt.",
@ -314,12 +316,15 @@
"delete": "Löschen"
}
},
"first": {
"title": "Erste Ansicht"
},
"list": {
"title": "Liste",
"add": "Hinzufügen",
"addPlaceholder": "Neue Aufgabe hinzufügen…",
"addPlaceholder": "Aufgabe hinzufügen…",
"empty": "Dieses Project ist derzeit leer.",
"newTaskCta": "Eine neue Aufgabe erstellen.",
"newTaskCta": "Aufgabe erstellen.",
"editTask": "Aufgabe bearbeiten"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Gebe einen Aufgabentitel ein …",
"addTask": "Eine Aufgabe hinzufügen",
"addAnotherTask": "Weitere Aufgabe hinzufügen",
"addBucket": "Eine neue Spalte erstellen",
"addBucket": "Bucket erstellen",
"addBucketPlaceholder": "Gebe einen Spaltentitel ein…",
"deleteHeaderBucket": "Spalte löschen",
"deleteBucketText1": "Bist du sicher, dass du diese Spalte löschen möchtest?",
@ -423,7 +428,7 @@
"create": {
"title": "Neuer gespeicherter Filter",
"description": "Ein gespeicherter Filter ist ein virtuelles Projekt, das bei jedem Zugriff aus einem Satz von Filtern errechnet wird.",
"action": "Neuen gespeicherten Filter erstellen",
"action": "Gespeicherten Filter erstellen",
"titleRequired": "Bitte gib den Titel für den Filter an."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Beginne zu schreiben, um nach einem Label zu suchen…",
"create": {
"header": "Neues Label",
"title": "Erstelle ein neues Label",
"title": "Label erstellen",
"titleRequired": "Bitte gebe einen Titel an.",
"success": "Das Label wurde erfolgreich erstellt."
},
@ -642,7 +647,7 @@
"placeholder": "Gib Text ein, drücke '/' für mehr Optionen…"
},
"multiselect": {
"createPlaceholder": "Neu erstellen",
"createPlaceholder": "Erstellen",
"selectPlaceholder": "Klicken oder Enter drücken zum Auswählen"
},
"datepickerRange": {
@ -721,7 +726,7 @@
},
"task": {
"task": "Aufgabe",
"new": "Eine neue Aufgabe erstellen",
"new": "Aufgabe erstellen",
"delete": "Diese Aufgabe löschen",
"createSuccess": "Die Aufgabe wurde erfolgreich erstellt.",
"addReminder": "Eine Erinnerung hinzufügen…",
@ -860,7 +865,7 @@
"unassignSuccess": "Benutzer:innenzuweisung aufgehoben."
},
"label": {
"placeholder": "Tippen, um ein neues Label hinzuzufügen…",
"placeholder": "Beginne zu schreiben, um ein Label hinzuzufügen…",
"createPlaceholder": "Dies als neues Label hinzufügen",
"addSuccess": "Das Label wurde erfolgreich hinzugefügt.",
"createSuccess": "Das Label wurde erfolgreich erstellt.",
@ -883,8 +888,8 @@
"relation": {
"add": "Neue Aufgabenbeziehung hinzufügen",
"new": "Neue Aufgabenbeziehung",
"searchPlaceholder": "Beginne zu schreiben, um eine Aufgabe zu suchen, die als Beziehung hinzugefügt werden soll…",
"createPlaceholder": "Füge diese Aufgabe als neue Aufgabenbeziehung hinzu",
"searchPlaceholder": "Suche nach einer Aufgabe für diese Beziehung…",
"createPlaceholder": "Füge diese Aufgabe als Aufgabenbeziehung hinzu",
"differentProject": "Diese Aufgabe gehört zu einem anderen Projekt.",
"noneYet": "Keine Aufgabenbeziehung vorhanden.",
"delete": "Aufgabenbeziehung entfernen",
@ -922,7 +927,7 @@
"every30d": "Alle 30 Tage",
"mode": "Wiederholungsmodus",
"monthly": "Monatlich",
"fromCurrentDate": "Ab dem aktuellen Datum",
"fromCurrentDate": "Ab Fertigstellungsdatum",
"each": "Alle",
"specifyAmount": "Gib einen Anzahl an …",
"hours": "Stunden",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "Du bist derzeit in keinem Team.",
"create": {
"title": "Erstelle ein neues Team",
"title": "Team erstellen",
"success": "Das Team wurde erfolgreich erstellt."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplizieren",
"delete": "Löschen",
"unarchive": "Archivierung aufheben",
"setBackground": "Hintergrund einstellen",
"setBackground": "Hintergrundeinstellungen",
"share": "Teilen",
"newProject": "Neues Projekt",
"createProject": "Projekt erstellen",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "de",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Iihlogge mit {provider}",
"authenticating": "Authentifiziere…",
"openIdStateError": "Status stimmt nid überiih, ich verweigerä wiiter zmache!",
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentifizierung aufgetreten.",
"logout": "Uuslogge",
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
"usernameRequired": "Bitte gib einen Anmeldenamen ein.",
@ -66,7 +66,8 @@
"hidePassword": "Passwort verbergen",
"noAccountYet": "Noch kein Account?",
"alreadyHaveAnAccount": "Hast du bereits einen Account?",
"remember": "Angemeldet bleiben"
"remember": "Angemeldet bleiben",
"registrationDisabled": "Registrierung ist deaktiviert."
},
"settings": {
"title": "Iihstellige",
@ -95,6 +96,7 @@
"weekStartMonday": "Määntig",
"language": "Sproch",
"defaultProject": "Standard-Projekt",
"defaultView": "Standardansicht",
"timezone": "Zeitzone",
"overdueTasksRemindersTime": "Zeit der E-Mail-Zusammenfassung der überfälligen Aufgaben",
"filterUsedOnOverview": "Gespeicherter Filter, der für die Startseite verwendet wird"
@ -227,8 +229,8 @@
"title": "„{project}“ archivieren",
"archive": "Dieses Projekt archivieren",
"unarchive": "Archivierung dieses Projekts aufheben",
"unarchiveText": "Du wirst neue Aufgaben erstellen oder sie bearbeiten können.",
"archiveText": "Du kannst dieses Projekt nicht bearbeiten oder neue Aufgaben erstellen, bis du die Archivierung aufhebst.",
"unarchiveText": "Du kannst Aufgaben erstellen oder diese bearbeiten.",
"archiveText": "Du kannst dieses Projekt nicht bearbeiten oder Aufgaben erstellen, bis du die Archivierung aufhebst.",
"success": "Das Projekt wurde erfolgreich archiviert."
},
"background": {
@ -277,7 +279,7 @@
"title": "Linkfreigaben",
"what": "Was ist eine Linkfreigabe?",
"explanation": "Mit Linkfreigaben kannst Projekt du Listen mit Benutzer:innen ohne Vikunja-Account teilen.",
"create": "Erstelle ein neue Linkfreigabe",
"create": "Erstelle ein Linkfreigabe",
"name": "Name (optional)",
"namePlaceholder": "z.B. Lorem Ipsum",
"nameExplanation": "Alle Aktionen, die mit dieser Linkfreigabe durchgeführt werden, werden mit diesem Namen angezeigt.",
@ -314,12 +316,15 @@
"delete": "Löschen"
}
},
"first": {
"title": "Erste Ansicht"
},
"list": {
"title": "Liste",
"add": "Hinzufügen",
"addPlaceholder": "Neue Aufgabe hinzufügen…",
"addPlaceholder": "Aufgabe hinzufügen…",
"empty": "Dieses Project ist derzeit leer.",
"newTaskCta": "Eine neue Aufgabe erstellen.",
"newTaskCta": "Aufgabe erstellen.",
"editTask": "Aufgabe bearbeiten"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Gebe einen Aufgabentitel ein …",
"addTask": "Eine Aufgabe hinzufügen",
"addAnotherTask": "Weitere Aufgabe hinzufügen",
"addBucket": "Eine neue Spalte erstellen",
"addBucket": "Bucket erstellen",
"addBucketPlaceholder": "Gebe einen Spaltentitel ein…",
"deleteHeaderBucket": "Spalte löschen",
"deleteBucketText1": "Bist du sicher, dass du diese Spalte löschen möchtest?",
@ -423,7 +428,7 @@
"create": {
"title": "Neuer gespeicherter Filter",
"description": "Ein gespeicherter Filter ist ein virtuelles Projekt, das bei jedem Zugriff aus einem Satz von Filtern errechnet wird.",
"action": "Neue gspeicherete Filter erstelle",
"action": "Gespeicherten Filter erstellen",
"titleRequired": "Bitte gib den Titel für den Filter an."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Schriib, um nachemne Label z'sueche…",
"create": {
"header": "Neus Label",
"title": "Neus Label erstelle",
"title": "Label erstellen",
"titleRequired": "Bitte gib en Titl ah.",
"success": "Da Label isch erfolgriich erstellt wore."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authentifiziere…",
"passwordRequired": "Dieses geteilte Projekt benötigt ein Passwort. Bitte gebe es unten ein:",
"error": "Het en Fähler geh. :(",
"error": "Es ist ein Fehler aufgetreten.",
"invalidPassword": "Da Passwort isch ungültig."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Gib Text ein, drücke '/' für mehr Optionen…"
},
"multiselect": {
"createPlaceholder": "Neu erstelle",
"createPlaceholder": "Erstellen",
"selectPlaceholder": "Druck uf Enter zum uuswähle"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Uufgab",
"new": "Neui Uufgab erstelle",
"new": "Aufgabe erstellen",
"delete": "Die Uufgab chüble",
"createSuccess": "Die Uufgab isch erfolgriich erstellt wordä.",
"addReminder": "Neui Errinnerig erstelle…",
"addReminder": "Eine Erinnerung hinzufügen…",
"doneSuccess": "Die Uufgab isch erfolgriich als \"Fertig\" markiert wordä.",
"undoneSuccess": "Die Uufgaab isch nüme als fertig markiert.",
"undo": "Rückgängig",
@ -860,7 +865,7 @@
"unassignSuccess": "D'Zuewiisig vom Benutzer isch erfolgriich entfernt worde."
},
"label": {
"placeholder": "Schriib, um es neues Label hinzuezfüege…",
"placeholder": "Beginne zu schreiben, um ein Label hinzuzufügen…",
"createPlaceholder": "Das als neues Label hinzuefüege",
"addSuccess": "Das Label isch erfolgriich hinzuegfüegt worde.",
"createSuccess": "Das Label isch erfolgriich erstellt worde.",
@ -883,8 +888,8 @@
"relation": {
"add": "Neui Uufgabe Beziehig hinzuefüege",
"new": "Neui Uufgabe Beziehig",
"searchPlaceholder": "Schriib, um e neui Uufgab als Zueghörigkeit hinzuezfüege…",
"createPlaceholder": "Das als en neui Zueghörigkeit hinzuefüege",
"searchPlaceholder": "Suche nach einer Aufgabe für diese Beziehung…",
"createPlaceholder": "Füge diese Aufgabe als Aufgabenbeziehung hinzu",
"differentProject": "Diese Aufgabe gehört zu einem anderen Projekt.",
"noneYet": "S'git kei Uufgabe Beziehige.",
"delete": "Uufgabe Beziehig chüble",
@ -922,7 +927,7 @@
"every30d": "Alle 30 Tage",
"mode": "Widerholigs Modus",
"monthly": "Monatlich",
"fromCurrentDate": "Vom Hüttige Datum",
"fromCurrentDate": "Ab Fertigstellungsdatum",
"each": "Jedä",
"specifyAmount": "Gib e Ahzahl ah…",
"hours": "Stundä",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "Du hesch momentan kei Team Ahghörigkeit.",
"create": {
"title": "E neus Team erstelle",
"title": "Team erstellen",
"success": "Da Team isch erfolgriich erstellt wordä."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Dublizierä",
"delete": "Chüble",
"unarchive": "Ent-archiviere",
"setBackground": "Hintergrund iihstelle",
"setBackground": "Hintergrundeinstellungen",
"share": "Teilä",
"newProject": "Neues Projekt",
"createProject": "Projekt erstellen",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "ch",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -643,7 +648,7 @@
}
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -722,10 +727,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -861,7 +866,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -884,8 +889,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -923,7 +928,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -963,7 +968,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1061,7 +1066,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1111,7 +1116,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Inicie sesión con {provider}",
"authenticating": "Autenticando…",
"openIdStateError": "El estado no coincide, ¡negándose a continuar!",
"openIdGeneralError": "Se ha producido un error al autenticarse contra terceros.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Cerrar sesión",
"emailInvalid": "Por favor, introduce una dirección de correo electrónico válida.",
"usernameRequired": "Por favor, proporciona un nombre de usuario.",
@ -66,7 +66,8 @@
"hidePassword": "Ocultar la contraseña",
"noAccountYet": "¿Aún no tienes una cuenta?",
"alreadyHaveAnAccount": "¿Ya tienes una cuenta?",
"remember": "Mantener la sesión abierta"
"remember": "Mantener la sesión abierta",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Ajustes",
@ -95,6 +96,7 @@
"weekStartMonday": "Lunes",
"language": "Idioma",
"defaultProject": "Proyecto por defecto",
"defaultView": "Default View",
"timezone": "Zona Horaria",
"overdueTasksRemindersTime": "Hora de envío del correo electrónico de tareas pendientes",
"filterUsedOnOverview": "Filtro guardado utilizado en la página de resumen"
@ -227,8 +229,8 @@
"title": "Archivar \"{project}\"",
"archive": "Archiva este proyecto",
"unarchive": "Desarchivar este proyecto",
"unarchiveText": "Desde aquí podrás crear nuevas tareas o editarlas.",
"archiveText": "No será posible editar este proyecto o crear nuevas tareas hasta que deje de estar archivado.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "El proyecto ha sido archivado con éxito."
},
"background": {
@ -277,7 +279,7 @@
"title": "Compartir Enlaces",
"what": "¿Qué es un enlace compartido?",
"explanation": "Los Enlaces Compartidos te permiten compartir fácilmente un proyecto con otros usuarios que no tienen una cuenta en Vikunja.",
"create": "Crear un nuevo enlace compartido",
"create": "Create a link share",
"name": "Nombre (opcional)",
"namePlaceholder": "ej. Lorem Ipsum",
"nameExplanation": "Todas las acciones realizadas por este enlace compartido se mostrarán con el nombre.",
@ -314,12 +316,15 @@
"delete": "Eliminar"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Lista",
"add": "Añadir",
"addPlaceholder": "Añadir una nueva tarea…",
"addPlaceholder": "Add a task…",
"empty": "Este proyecto está actualmente vacío.",
"newTaskCta": "Crear una nueva tarea.",
"newTaskCta": "Create a task.",
"editTask": "Editar Tarea"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Introduce el nuevo título de la tarea…",
"addTask": "Añadir una tarea",
"addAnotherTask": "Añadir otra tarea",
"addBucket": "Crear un nuevo contenedor",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Introduzca el nuevo título del contenedor…",
"deleteHeaderBucket": "Eliminar el contenedor",
"deleteBucketText1": "¿Estás seguro de que quieres eliminar este contenedor?",
@ -423,7 +428,7 @@
"create": {
"title": "Nuevo Filtro Guardado",
"description": "Un filtro guardado es un proyecto virtual que se calcula a partir de un conjunto de filtros cada vez que se accede.",
"action": "Crear nuevo filtro guardado",
"action": "Create saved filter",
"titleRequired": "Por favor, introduce un título para el filtro."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Escribe para buscar una etiqueta…",
"create": {
"header": "Nueva etiqueta",
"title": "Crear una nueva etiqueta",
"title": "Create a label",
"titleRequired": "Por favor, especifica un título.",
"success": "La etiqueta se ha creado correctamente."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Autenticando…",
"passwordRequired": "Este proyecto compartido requiere una contraseña. Por favor introdúcelo debajo:",
"error": "Ha ocurrido un error.",
"error": "An error occurred.",
"invalidPassword": "La contraseña es inválida."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Crear nuevo",
"createPlaceholder": "Create",
"selectPlaceholder": "Clic o Enter para seleccionar"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Tarea",
"new": "Crear una nueva tarea",
"new": "Create a task",
"delete": "Eliminar esta tarea",
"createSuccess": "La tarea se ha creado con éxito.",
"addReminder": "Añadir un nuevo recordatorio…",
"addReminder": "Add a reminder…",
"doneSuccess": "La tarea fue marcada con éxito como realizada.",
"undoneSuccess": "La tarea fue marcada correctamente como incompleta.",
"undo": "Deshacer",
@ -860,7 +865,7 @@
"unassignSuccess": "El usuario ha sido desasignado con éxito."
},
"label": {
"placeholder": "Escriba para añadir una nueva etiqueta…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Añadir esto como nueva etiqueta",
"addSuccess": "La etiqueta ha sido añadida con éxito.",
"createSuccess": "La etiqueta ha sido creada con éxito.",
@ -883,8 +888,8 @@
"relation": {
"add": "Añadir una Nueva Tarea Relacionada",
"new": "Nueva Tarea Relacionada",
"searchPlaceholder": "Escriba para buscar una nueva tarea a añadir como relacionada…",
"createPlaceholder": "Añadir esto como nueva tarea relacionada",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Esta tarea pertenece a un proyecto diferente.",
"noneYet": "Aún no hay tareas relacionadas.",
"delete": "Eliminar Relación de Tarea",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Modo de repetición",
"monthly": "Mensualmente",
"fromCurrentDate": "Desde la Fecha Actual",
"fromCurrentDate": "From completion date",
"each": "Cada",
"specifyAmount": "Especifique una cantidad…",
"hours": "Horas",
@ -962,7 +967,7 @@
"title": "Equipos",
"noTeams": "Actualmente no formas parte de ningún equipo.",
"create": {
"title": "Crear un nuevo equipo",
"title": "Create a team",
"success": "El equipo fue creado con éxito."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicar",
"delete": "Eliminar",
"unarchive": "Desarchivar",
"setBackground": "Establecer fondo",
"setBackground": "Background settings",
"share": "Compartir",
"newProject": "Nuevo proyecto",
"createProject": "Crear proyecto",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "es",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Se connecter avec {provider}",
"authenticating": "Authentification…",
"openIdStateError": "Létat ne correspond pas, impossible de continuer !",
"openIdGeneralError": "Une erreur s'est produite lors de l'authentification contre un tiers.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Se déconnecter",
"emailInvalid": "Veuillez saisir une adresse courriel valide.",
"usernameRequired": "Veuillez saisir un nom d'utilisateur.",
@ -66,7 +66,8 @@
"hidePassword": "Masquer le mot de passe",
"noAccountYet": "Vous n'avez pas encore de compte?",
"alreadyHaveAnAccount": "Vous avez déjà un compte?",
"remember": "Rester connecté(e)"
"remember": "Rester connecté(e)",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Paramètres",
@ -95,6 +96,7 @@
"weekStartMonday": "lundi",
"language": "Langue",
"defaultProject": "Projet par défaut",
"defaultView": "Default View",
"timezone": "Fuseau horaire",
"overdueTasksRemindersTime": "Heure du courriel de rappel des tâches en retard",
"filterUsedOnOverview": "Filtre enregistré utilisé sur la vue densemble"
@ -227,8 +229,8 @@
"title": "Archiver « {project} »",
"archive": "Archiver ce projet",
"unarchive": "Désarchiver ce projet",
"unarchiveText": "Vous serez en mesure de créer de nouvelles tâches ou de les modifier.",
"archiveText": "Vous ne pourrez pas modifier ce projet ou créer de nouvelles tâches si vous ne le désarchivez pas.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "Le projet a bien été archivé."
},
"background": {
@ -277,7 +279,7 @@
"title": "Liens de partage",
"what": "Quest-ce quun lien de partage ?",
"explanation": "Les liens de partage permettent de partager facilement un projet avec dautres personnes qui nont pas de compte sur Vikunja.",
"create": "Créer un nouveau lien de partage",
"create": "Create a link share",
"name": "Nom (facultatif)",
"namePlaceholder": "par ex., Lorem Ipsum",
"nameExplanation": "Toutes les actions effectuées par ce partage de lien apparaîtront avec le nom.",
@ -314,12 +316,15 @@
"delete": "Supprimer"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Liste",
"add": "Ajouter",
"addPlaceholder": "Ajouter une nouvelle tâche…",
"addPlaceholder": "Add a task…",
"empty": "Ce projet est actuellement vide.",
"newTaskCta": "Créer une nouvelle tâche.",
"newTaskCta": "Create a task.",
"editTask": "Modifier la tâche"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Saisir le nouveau nom de la tâche…",
"addTask": "Ajouter une tâche",
"addAnotherTask": "Ajouter une autre tâche",
"addBucket": "Créer une nouvelle colonne",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Saisir le titre de la nouvelle colonne…",
"deleteHeaderBucket": "Supprimer la colonne",
"deleteBucketText1": "Voulez-vous supprimer cette colonne ?",
@ -423,7 +428,7 @@
"create": {
"title": "Nouveau filtre enregistré",
"description": "Un filtre sauvegardé est un projet virtuel qui est calculé à partir dun ensemble de filtres à chaque fois quil est consulté.",
"action": "Créer un nouveau filtre enregistré",
"action": "Create saved filter",
"titleRequired": "Veuillez donner un nom au filtre."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Taper pour rechercher une étiquette…",
"create": {
"header": "Nouvelle étiquette",
"title": "Créer une nouvelle étiquette",
"title": "Create a label",
"titleRequired": "Indiquer un nom.",
"success": "Étiquette créée."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authentification…",
"passwordRequired": "Ce projet partagé nécessite un mot de passe. Saisissez-le ci-dessous :",
"error": "Une erreur sest produite.",
"error": "An error occurred.",
"invalidPassword": "Le mot de passe est invalide."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Créer un nouveau",
"createPlaceholder": "Create",
"selectPlaceholder": "Cliquer ou appuyer sur la touche Entrée pour sélectionner"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Tâche",
"new": "Créer une nouvelle tâche",
"new": "Create a task",
"delete": "Supprimer cette tâche",
"createSuccess": "Tâche créée.",
"addReminder": "Ajouter un nouveau rappel…",
"addReminder": "Add a reminder…",
"doneSuccess": "Tâche marquée comme terminée.",
"undoneSuccess": "Tâche marquée comme non terminée.",
"undo": "Annuler",
@ -860,7 +865,7 @@
"unassignSuccess": "Désaffectation réussie."
},
"label": {
"placeholder": "Taper pour ajouter une nouvelle étiquette…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Ajouter ceci comme nouvelle étiquette",
"addSuccess": "Étiquette ajoutée.",
"createSuccess": "Étiquette créée.",
@ -883,8 +888,8 @@
"relation": {
"add": "Ajouter une nouvelle relation de tâche",
"new": "Nouvelle relation de tâche",
"searchPlaceholder": "Saisir une nouvelle tâche à ajouter comme connexe…",
"createPlaceholder": "Ajouter cette tâche comme nouvelle tâche connexe",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Cette tâche appartient à un autre projet.",
"noneYet": "Pas encore de relations de tâches.",
"delete": "Supprimer la relation de tâche",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Mode de répétition",
"monthly": "Mensuel",
"fromCurrentDate": "À partir de la date actuelle",
"fromCurrentDate": "From completion date",
"each": "Tous ou toutes les",
"specifyAmount": "Indiquer un nombre…",
"hours": "Heures",
@ -962,7 +967,7 @@
"title": "Équipes",
"noTeams": "Vous ne faites actuellement partie daucune équipe.",
"create": {
"title": "Créer une nouvelle équipe",
"title": "Create a team",
"success": "Équipe créée."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Dupliquer",
"delete": "Supprimer",
"unarchive": "Désarchiver",
"setBackground": "Définir larrière-plan",
"setBackground": "Background settings",
"share": "Partager",
"newProject": "Nouveau projet",
"createProject": "Créer un projet",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "fr",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@
"loginWith": "Bejelentkezés {provider}-profillal",
"authenticating": "Hitelesítés…",
"openIdStateError": "Állapot nem egyezik, nem lehet folytatni!",
"openIdGeneralError": "Hiba történt a harmadik féllel szembeni hitelesítés során.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Kijelentkezés",
"emailInvalid": "Kérjük, adjon meg egy valós email címet!",
"usernameRequired": "Kérjük adjon meg egy felhasználónevet.",
@ -66,7 +66,8 @@
"hidePassword": "A jelszó elrejtése",
"noAccountYet": "Még nincs fiókja?",
"alreadyHaveAnAccount": "Már rendelkezik fiókkal?",
"remember": "Maradjon bejelentkezve"
"remember": "Maradjon bejelentkezve",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Beállítások",
@ -95,6 +96,7 @@
"weekStartMonday": "Hétfő",
"language": "Nyelv",
"defaultProject": "Alapértelmezett projekt",
"defaultView": "Default View",
"timezone": "Időzóna",
"overdueTasksRemindersTime": "Esedékes feladatokra emlékeztető e-mail küldésének ideje",
"filterUsedOnOverview": "Az áttekintő oldalon használt mentett szűrő"
@ -227,8 +229,8 @@
"title": "\"{project}\" archiválása.",
"archive": "Archiválja ezt a projektet",
"unarchive": "Projekt archiválásának visszaállítása",
"unarchiveText": "Új feladatokat hozhat létre, vagy szerkeszthet.",
"archiveText": "Addig nem szerkesztheti ezt a projektet, és nem hozhat létre új feladatokat, amíg nem állítja vissza az archiválást.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "A projekt sikeresen archiválva."
},
"background": {
@ -277,7 +279,7 @@
"title": "Hivatkozások megosztása",
"what": "Mi az a megosztási link?",
"explanation": "A Linkek megosztása segítségével egyszerűen megoszthat egy projektet más felhasználókkal, akik nem rendelkeznek fiókkal a Vikunján.",
"create": "Hozzon létre egy új linkmegosztást",
"create": "Create a link share",
"name": "Név (nem kötelező)",
"namePlaceholder": "Például: Kis Géza",
"nameExplanation": "A link megosztása által végzett összes művelet a névvel együtt fog megjelenni.",
@ -314,12 +316,15 @@
"delete": "Törlés"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Lista",
"add": "Új hozzáadása",
"addPlaceholder": "Új feladat hozzáadása...",
"addPlaceholder": "Add a task…",
"empty": "Ez a projekt jelenleg üres.",
"newTaskCta": "Új feladat létrehozása.",
"newTaskCta": "Create a task.",
"editTask": "Feladat szerkesztése."
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Adja meg az új feladatcímet…",
"addTask": "Feladat hozzáadása",
"addAnotherTask": "Adjon hozzá egy másik feladatot",
"addBucket": "Új vödör létrehozása",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Adja meg az új vödör címét…",
"deleteHeaderBucket": "Vödör törlése",
"deleteBucketText1": "Biztosan törli ezt az vödröt?",
@ -423,7 +428,7 @@
"create": {
"title": "Új mentett szűrő",
"description": "A mentett szűrő egy virtuális projekt, amely szűrőkészletből kerül kiszámításra minden alkalommal, amikor hozzáfér.",
"action": "Új mentett szűrő létrehozása",
"action": "Create saved filter",
"titleRequired": "Adja meg a szűrő címét."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Címke kereséséhez írja be…",
"create": {
"header": "Új címke",
"title": "Új címke létrehozása",
"title": "Create a label",
"titleRequired": "Kérjük, adjon meg egy címet.",
"success": "A címke sikeresen létrehozva."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Hitelesítés…",
"passwordRequired": "Ehhez a megosztott projekthez jelszó szükséges. Kérjük, írja be alább:",
"error": "Hiba lépett fel.",
"error": "An error occurred.",
"invalidPassword": "A jelszó érvénytelen."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Írjon be egy szöveget, vagy nyomja meg a „/” gombot a további lehetőségek megtekintéséhez…"
},
"multiselect": {
"createPlaceholder": "Új létrehozása",
"createPlaceholder": "Create",
"selectPlaceholder": "Kattintson, vagy nyomja meg az Enter billentyűt a kiválasztáshoz"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Feladat",
"new": "Új feladat létrehozása",
"new": "Create a task",
"delete": "Feladat törlése",
"createSuccess": "A feladat sikeresen létrehozva.",
"addReminder": "Új emlékeztető hozzáadása...",
"addReminder": "Add a reminder…",
"doneSuccess": "A feladat sikeresen meg lett jelölve elkészültként.",
"undoneSuccess": "A feladat sikeresen meg lett jelölve nem elkészültként.",
"undo": "Visszavonás",
@ -860,7 +865,7 @@
"unassignSuccess": "A felhasználó sikeresen leiratkozott!"
},
"label": {
"placeholder": "Új címke hozzáadásához írjon be…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Adja hozzá ezt új címkeként",
"addSuccess": "A címke sikeresen hozzáadva.",
"createSuccess": "A címke sikeresen létrehozva.",
@ -883,8 +888,8 @@
"relation": {
"add": "Új feladatkapcsolat hozzáadása",
"new": "Új feladatkapcsolat",
"searchPlaceholder": "A kapcsolódóként hozzáadandó új feladathoz írja be a keresést…",
"createPlaceholder": "Adja hozzá ezt új kapcsolódó feladatként",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Ez a feladat egy másik projekthez tartozik.",
"noneYet": "Még nincsenek feladatkapcsolatok.",
"delete": "Feladatkapcsolat törlése",
@ -922,7 +927,7 @@
"every30d": "30 naponta",
"mode": "Ismétlés típusa",
"monthly": "Havi",
"fromCurrentDate": "Aktuális dátumtól",
"fromCurrentDate": "From completion date",
"each": "Minden egyes",
"specifyAmount": "Adja meg a mennyiséget…",
"hours": "Órák",
@ -962,7 +967,7 @@
"title": "Csapatok",
"noTeams": "Jelenleg nem tagja egyetlen csapatnak sem.",
"create": {
"title": "Új csapat létrehozása",
"title": "Create a team",
"success": "A csapat sikeresen létrehozva."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplikálás",
"delete": "Törlés",
"unarchive": "Archiválás visszavonása",
"setBackground": "Háttérkép beállítása",
"setBackground": "Background settings",
"share": "Megosztás",
"newProject": "Új projekt",
"createProject": "Projekt létrehozása",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Accedi con {provider}",
"authenticating": "Autenticazione…",
"openIdStateError": "Stato non corrispondente, impossibile continuare!",
"openIdGeneralError": "Si è verificato un errore durante l'autenticazione con terze parti.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Esci",
"emailInvalid": "Inserisci un indirizzo e-mail valido.",
"usernameRequired": "Inserisci un nome utente.",
@ -66,7 +66,8 @@
"hidePassword": "Nascondi la password",
"noAccountYet": "Non hai un account?",
"alreadyHaveAnAccount": "Hai già un account?",
"remember": "Resta connesso"
"remember": "Resta connesso",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Impostazioni",
@ -95,6 +96,7 @@
"weekStartMonday": "Lunedì",
"language": "Lingua",
"defaultProject": "Progetto Predefinito",
"defaultView": "Default View",
"timezone": "Fuso Orario",
"overdueTasksRemindersTime": "Orario email attività in scadute",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archivia \"{project}\"",
"archive": "Archivia questo progetto",
"unarchive": "Estrai questo progetto dall'archivio",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "Progetto archiviato."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "Nuovo Filtro Salvato",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Crea nuovo filtro salvato",
"action": "Create saved filter",
"titleRequired": "È necessario un titolo per il filtro."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Digita per cercare un'etichetta…",
"create": {
"header": "Nuova etichetta",
"title": "Crea una nuova etichetta",
"title": "Create a label",
"titleRequired": "Specifica un titolo.",
"success": "L'etichetta è stata creata correttamente."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Autenticazione…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "Si è verificato un errore.",
"error": "An error occurred.",
"invalidPassword": "La password non è valida."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Crea nuovo",
"createPlaceholder": "Create",
"selectPlaceholder": "Clicca o premere invio per selezionare"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Attività",
"new": "Crea una nuova attività",
"new": "Create a task",
"delete": "Elimina questa attività",
"createSuccess": "Attività creata.",
"addReminder": "Aggiungi un nuovo promemoria…",
"addReminder": "Add a reminder…",
"doneSuccess": "Attività segnata come completata.",
"undoneSuccess": "Attività segnata come non completata.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "Utente disassegnato."
},
"label": {
"placeholder": "Digita per aggiungere una nuova etichetta…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Aggiungila come nuova etichetta",
"addSuccess": "Etichetta aggiunta.",
"createSuccess": "Etichetta creata.",
@ -883,8 +888,8 @@
"relation": {
"add": "Aggiungi Attività Collegata",
"new": "Nuova Attività Collegata",
"searchPlaceholder": "Digita per cercare un'attività da aggiungere come collegata…",
"createPlaceholder": "Aggiungi come attività collegata",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "Nessuna attività collegata.",
"delete": "Elimina Collegamento Attività",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Modalità Ripetizione",
"monthly": "Mensilmente",
"fromCurrentDate": "Dalla Data Attuale",
"fromCurrentDate": "From completion date",
"each": "Ogni",
"specifyAmount": "Specifica una quantità…",
"hours": "Ore",
@ -962,7 +967,7 @@
"title": "Gruppi",
"noTeams": "Non fai parte di nessun gruppo.",
"create": {
"title": "Crea un nuovo gruppo",
"title": "Create a team",
"success": "Gruppo creato."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplica",
"delete": "Elimina",
"unarchive": "Disarchivia",
"setBackground": "Imposta sfondo",
"setBackground": "Background settings",
"share": "Condividi",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "it",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -57,16 +57,17 @@
"logout": "ログアウト",
"emailInvalid": "有効なメールアドレスを入力してください。",
"usernameRequired": "ユーザー名を入力してください。",
"usernameMustNotContainSpace": "The username must not contain spaces.",
"usernameMustNotContainSpace": "ユーザー名にスペースを含めてはいけません。",
"usernameMustNotLookLikeUrl": "The username must not look like a URL.",
"passwordRequired": "パスワードを入力してください。",
"passwordNotMin": "Password must have at least 8 characters.",
"passwordNotMax": "Password must have at most 250 characters.",
"passwordNotMin": "パスワードは8文字以上でなければなりません。",
"passwordNotMax": "パスワードは250文字以内でなければなりません。",
"showPassword": "パスワードの表示",
"hidePassword": "パスワードの非表示",
"noAccountYet": "まだアカウントをお持ちでないですか?",
"alreadyHaveAnAccount": "すでにアカウントをお持ちですか?",
"remember": "ログインしたままにする"
"remember": "ログインしたままにする",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "設定",
@ -95,6 +96,7 @@
"weekStartMonday": "月曜日",
"language": "言語",
"defaultProject": "デフォルトのプロジェクト",
"defaultView": "Default View",
"timezone": "タイムゾーン",
"overdueTasksRemindersTime": "期限切れタスクのリマインダー送信時間",
"filterUsedOnOverview": "概要ページに使用される絞り込み条件を保存しました"
@ -152,8 +154,8 @@
},
"apiTokens": {
"title": "APIトークン",
"general": "API tokens allow you to use Vikunja's API without user credentials.",
"apiDocs": "Check out the api docs",
"general": "APIトークンは、認証されたVikunja APIのリクエストを行うことができます。",
"apiDocs": "詳しくはAPIドキュメントをご確認ください",
"createAToken": "トークンの生成",
"createToken": "トークンの生成",
"30d": "30日",
@ -227,8 +229,8 @@
"title": "「{project}」のアーカイブ",
"archive": "プロジェクトのアーカイブ",
"unarchive": "プロジェクトのアーカイブの取り消し",
"unarchiveText": "新しいタスクの作成や編集を行えるようになります。",
"archiveText": "アーカイブを取り消すまで、このプロジェクトでは新しいタスクの作成や編集を行うことができません。",
"unarchiveText": "タスクの作成や編集を行えるようになります。",
"archiveText": "アーカイブを取り消すまで、このプロジェクトではタスクの作成や編集を行うことができません。",
"success": "プロジェクトは正常にアーカイブされました。"
},
"background": {
@ -277,7 +279,7 @@
"title": "リンクの共有",
"what": "共有リンクとは何ですか?",
"explanation": "共有リンクとは、Vikunjaのアカウントを持たない他のユーザーとプロジェクトを簡単に共有することができる機能です。",
"create": "新しい共有リンクの作成",
"create": "共有リンクの作成",
"name": "名前 (オプション)",
"namePlaceholder": "例: Lorem Ipsum",
"nameExplanation": "この共有リンクで行われた操作はすべてこの名前で表示されるようになります。",
@ -314,12 +316,15 @@
"delete": "削除"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "リスト",
"add": "追加",
"addPlaceholder": "新しいタスクを追加…",
"addPlaceholder": "タスクを追加…",
"empty": "このプロジェクトにはタスクが存在しません。",
"newTaskCta": "新しいタスクを作成してください。",
"newTaskCta": "タスクを作成してください。",
"editTask": "タスクの編集"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "新しいタスク名を入力…",
"addTask": "タスクの追加",
"addAnotherTask": "他のタスクを追加",
"addBucket": "新しいバケットの作成",
"addBucket": "バケットの作成",
"addBucketPlaceholder": "新しいバケット名を入力…",
"deleteHeaderBucket": "バケットの削除",
"deleteBucketText1": "このバケットを削除して本当によろしいですか?",
@ -369,18 +374,18 @@
},
"webhooks": {
"title": "Webhook",
"targetUrl": "Target URL",
"targetUrlInvalid": "Please provide a valid URL.",
"events": "Events",
"eventsHint": "Select all events this webhook should recieve updates for (within the current project).",
"mustSelectEvents": "You must select at least one event.",
"targetUrl": "ターゲットURL",
"targetUrlInvalid": "有効なURLを入力してください。",
"events": "イベント",
"eventsHint": "Webhookが受信する (現在のプロジェクト内での) イベントを選択します。",
"mustSelectEvents": "イベントを少なくとも1つ選択する必要があります。",
"delete": "Webhookの削除",
"deleteText": "Are you sure you want to delete this webhook? External targets will not be notified of its events anymore.",
"deleteText": "このWebhookを削除して本当によろしいですかこのWebhookのターゲットURLにはイベントは送信されなくなります。",
"deleteSuccess": "Webhookは正常に削除されました。",
"create": "Create webhook",
"secret": "Secret",
"secretHint": "If provided, all requests to the webhook target URL will be signed using HMAC.",
"secretDocs": "Check out the docs for more details about how to use secrets."
"create": "Webhookを作成",
"secret": "シークレット",
"secretHint": "シークレットを指定した場合、WebhookターゲットURLへのリクエストはすべてHMAC署名されます。",
"secretDocs": "シークレットに関する詳細はドキュメントをご確認ください。"
},
"views": {
"header": "Edit views",
@ -423,7 +428,7 @@
"create": {
"title": "新しい絞り込み条件の作成",
"description": "絞り込み条件は、複数の条件を組み合わせて保存できる仮想のプロジェクトです。",
"action": "新しい絞り込み条件を作成",
"action": "絞り込み条件を作成",
"titleRequired": "絞り込み条件名を入力してください。"
},
"delete": {
@ -507,7 +512,7 @@
"search": "ラベルのキーワードを入力…",
"create": {
"header": "新しいラベルの作成",
"title": "新しいラベルの作成",
"title": "ラベルの作成",
"titleRequired": "ラベル名を入力してください。",
"success": "ラベルは正常に作成されました。"
},
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "新規作成",
"createPlaceholder": "作成",
"selectPlaceholder": "クリックするかEnterキーを押して選択"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "タスク",
"new": "新しいタスクの作成",
"new": "タスクの作成",
"delete": "タスクの削除",
"createSuccess": "タスクは正常に作成されました。",
"addReminder": "新しいリマイダーを作成…",
"addReminder": "リマイダーを作成…",
"doneSuccess": "タスクを完了にしました。",
"undoneSuccess": "タスクを未完了に戻しました。",
"undo": "元に戻す",
@ -884,7 +889,7 @@
"add": "新しい関連タスクの追加",
"new": "新しい関連タスクの作成",
"searchPlaceholder": "追加する関連タスクのキーワードを入力…",
"createPlaceholder": "新しい関連タスクを追加",
"createPlaceholder": "関連タスクを追加",
"differentProject": "This task belongs to a different project.",
"noneYet": "関連タスクはまだありません。",
"delete": "関連タスクの削除",
@ -922,7 +927,7 @@
"every30d": "30日ごと",
"mode": "繰り返しモード",
"monthly": "毎月",
"fromCurrentDate": "現在時刻からの間隔",
"fromCurrentDate": "完了からの間隔",
"each": "隔",
"specifyAmount": "数字を入力…",
"hours": "時間ごと",
@ -962,7 +967,7 @@
"title": "チーム",
"noTeams": "現在どのチームにも所属していません。",
"create": {
"title": "新しいチームの作成",
"title": "チームの作成",
"success": "チームは正常に作成されました。"
},
"edit": {
@ -1051,8 +1056,8 @@
}
},
"update": {
"available": "There is an update available!",
"do": "Update Now"
"available": "アップデートがあります!",
"do": "アップデート"
},
"menu": {
"edit": "編集",
@ -1064,8 +1069,8 @@
"share": "共有",
"newProject": "新しいプロジェクトの作成",
"createProject": "プロジェクトの作成",
"cantArchiveIsDefault": "You cannot archive this because it is your default project.",
"cantDeleteIsDefault": "You cannot delete this because it is your default project.",
"cantArchiveIsDefault": "デフォルトのプロジェクトのためアーカイブできません。",
"cantDeleteIsDefault": "デフォルトのプロジェクトのため削除できません。",
"views": "Views"
},
"apiConfig": {
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "ja",
"altFormatLong": "Y/n/j H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "Y/n/j"
},
"reaction": {
@ -1146,7 +1151,7 @@
"3005": "The project title cannot be empty.",
"3006": "その共有プロジェクトは存在しません。",
"3007": "A project with this identifier already exists.",
"3008": "The project is archived and can therefore only be accessed read only. This is also true for all tasks associated with this project.",
"3008": "このプロジェクトはアーカイブ済みのため読み取り専用です。またプロジェクトに関連するタスクも同様です。",
"4001": "The project task text cannot be empty.",
"4002": "そのプロジェクトのタスクは存在しません。",
"4003": "All bulk editing tasks must belong to the same project.",
@ -1192,7 +1197,7 @@
},
"about": {
"title": "Vikunjaについて",
"version": "Version: {version}"
"version": "バージョン: {version}"
},
"time": {
"units": {

View File

@ -53,7 +53,7 @@
"loginWith": "{provider}로 로그인",
"authenticating": "인증 처리 중...",
"openIdStateError": "State does not match, refusing to continue!",
"openIdGeneralError": "외부 인증오류가 발생하였습니다.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "로그아웃",
"emailInvalid": "유효한 이메일 주소를 입력하여 주십시오.",
"usernameRequired": "사용자 이름을 입력하세요.",
@ -66,7 +66,8 @@
"hidePassword": "비밀번호 숨김",
"noAccountYet": "아직 계정이 없으신가요?",
"alreadyHaveAnAccount": "이미 계정이 있으신가요?",
"remember": "로그인 상태 유지"
"remember": "로그인 상태 유지",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "환경설정",
@ -95,6 +96,7 @@
"weekStartMonday": "월요일",
"language": "언어",
"defaultProject": "기본 프로젝트",
"defaultView": "Default View",
"timezone": "표준시간대",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "\"{project}\"보관",
"archive": "프로젝트 보관하기",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "링크 공유",
"what": "공유 링크가 무엇인가요?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "새 공유 링크 만들기",
"create": "Create a link share",
"name": "이름 (선택 사항)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "새 할일 등록",
"newTaskCta": "Create a task.",
"editTask": "할 일 편집"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "작업 추가",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "새로 생성하기",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "관계 삭제",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Inloggen met {provider}",
"authenticating": "Authenticeren…",
"openIdStateError": "State does not match, refusing to continue!",
"openIdGeneralError": "An error occured while authenticating against the third party.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Uitloggen",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Instellingen",
@ -95,6 +96,7 @@
"weekStartMonday": "Maandag",
"language": "Taal",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "Nieuw label",
"title": "Nieuwe label maken",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticeren…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "Er is een fout opgetreden.",
"error": "An error occurred.",
"invalidPassword": "Het wachtwoord is ongeldig."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Nieuwe aanmaken",
"createPlaceholder": "Create",
"selectPlaceholder": "Klik of druk op enter om te selecteren"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Taak",
"new": "Creëer een nieuwe taak",
"new": "Create a task",
"delete": "Deze taak verwijderen",
"createSuccess": "De taak is succesvol aangemaakt.",
"addReminder": "Nieuwe herinnering toevoegen…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "De toewijzing van de gebruiker is met succes ingetrokken."
},
"label": {
"placeholder": "Typ om een nieuw label toe te voegen…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Dit toevoegen als nieuw label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"relation": {
"add": "Add a New Task Relation",
"new": "Nieuwe taakrelatie",
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Voeg dit toe als nieuwe gerelateerde taak",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "Nog geen taakrelaties.",
"delete": "Taak relatie verwijderen",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Herhaalmodus",
"monthly": "Maandelijks",
"fromCurrentDate": "Vanaf huidige datum",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Uren",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "Je maakt momenteel geen deel uit van een team.",
"create": {
"title": "Maak een nieuw team",
"title": "Create a team",
"success": "Het team is succesvol aangemaakt."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Dupliceer",
"delete": "Verwijderen",
"unarchive": "Archivering opheffen",
"setBackground": "Achtergrond instellen",
"setBackground": "Background settings",
"share": "Delen",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "nl",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Logg inn med {provider}",
"authenticating": "Autentiserer…",
"openIdStateError": "Staten samsvarer ikke, klikk ikke for å fortsette!",
"openIdGeneralError": "En feil oppstod under autentisering mot tredjepart.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logg ut",
"emailInvalid": "Vennligst oppgi en gyldig e-postadresse.",
"usernameRequired": "Angi et brukernavn.",
@ -66,7 +66,8 @@
"hidePassword": "Skjul passord",
"noAccountYet": "Har du ikke konto ennå?",
"alreadyHaveAnAccount": "Har du allerede en konto?",
"remember": "Hold meg innlogget"
"remember": "Hold meg innlogget",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Innstillinger",
@ -95,6 +96,7 @@
"weekStartMonday": "Mandag",
"language": "Språk",
"defaultProject": "Standard prosjekt",
"defaultView": "Default View",
"timezone": "Tidssone",
"overdueTasksRemindersTime": "Utløpte påminnelses-tid for oppgaver",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Arkiver{project}\"",
"archive": "Arkiver dette prosjektet",
"unarchive": "Av-arkivere dette prosjektet",
"unarchiveText": "Du vil kunne opprette nye oppgaver eller redigere den.",
"archiveText": "Du vil ikke være i stand til å redigere denne listen eller opprette nye oppgaver før du fjerner arkiveringen.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "Prosjektet ble vellykket arkivert."
},
"background": {
@ -277,7 +279,7 @@
"title": "Del link",
"what": "Hva er en lenke for deling?",
"explanation": "Lenker lar deg enkelt dele et prosjekt med andre brukere som ikke har en konto på Vikunja.",
"create": "Opprett en ny lenkedeling",
"create": "Create a link share",
"name": "Navn (valgfritt)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "Alle handlinger utført av denne koblingsdelingen vises med navnet.",
@ -314,12 +316,15 @@
"delete": "Slett"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Liste",
"add": "Legg til",
"addPlaceholder": "Legg til ny oppgave…",
"addPlaceholder": "Add a task…",
"empty": "Dette prosjektet er for øyeblikket tomt.",
"newTaskCta": "Lage en ny oppgave.",
"newTaskCta": "Create a task.",
"editTask": "Endre oppgave"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Angi den nye oppgavens tittel…",
"addTask": "Legg til oppgave",
"addAnotherTask": "Legg til en annen oppgave",
"addBucket": "Lag en ny bøtte",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Angi den nye bøtte tittelen…",
"deleteHeaderBucket": "Slett bøtte",
"deleteBucketText1": "Er du sikker på at du vil slette denne bøtte?",
@ -423,7 +428,7 @@
"create": {
"title": "Nytt lagret filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Opprett nytt filter",
"action": "Create saved filter",
"titleRequired": "Skriv inn en tittel for filteret."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Skriv for å søke etter en etikett…",
"create": {
"header": "Ny etikett",
"title": "Opprett ny etikett",
"title": "Create a label",
"titleRequired": "Angi den nye tittelen.",
"success": "Etiketten ble opprettet."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Autentiserer…",
"passwordRequired": "Denne delte listen krever et passord. Vennligst skriv det nedenfor:",
"error": "En feil oppsto.",
"error": "An error occurred.",
"invalidPassword": "Det oppgitte passordet er ugyldig."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Opprett ny",
"createPlaceholder": "Create",
"selectPlaceholder": "Klikk eller trykk enter for å velge denne listen"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Oppgave",
"new": "Lage en ny oppgave",
"new": "Create a task",
"delete": "Slette denne oppgaven",
"createSuccess": "Oppgaven ble opprettet.",
"addReminder": "Legg til en ny påminnelse…",
"addReminder": "Add a reminder…",
"doneSuccess": "Oppgaven ble markert som ferdig.",
"undoneSuccess": "Oppgaven ble fjernet som ferdig.",
"undo": "Angre",
@ -860,7 +865,7 @@
"unassignSuccess": "Brukeren ble vellykket fjernet."
},
"label": {
"placeholder": "Skriv for å legge til en ny etikett…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Legg til som ny etikett",
"addSuccess": "Etiketten er lagt til.",
"createSuccess": "Denne etiketten har blitt opprettet.",
@ -883,8 +888,8 @@
"relation": {
"add": "Legg til en ny oppgaveforbindelse",
"new": "Ny oppgaveforbindelse",
"searchPlaceholder": "Skriv søk etter en ny oppgave å legge til som relatert…",
"createPlaceholder": "Legg til denne som ny relatert oppgave",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Denne oppgaven tilhører et annet prosjekt.",
"noneYet": "Ingen arbeidsrelasjoner ennå.",
"delete": "Slett relasjon",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeter modus",
"monthly": "Månedlig",
"fromCurrentDate": "Fra gjeldende dato",
"fromCurrentDate": "From completion date",
"each": "Hver",
"specifyAmount": "Angi beløp…",
"hours": "Timer",
@ -962,7 +967,7 @@
"title": "Grupper",
"noTeams": "Du er for øyeblikket ikke en del av noen gurpper.",
"create": {
"title": "Opprett en ny gruppe",
"title": "Create a team",
"success": "Gruppen ble opprettet."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Dupliser",
"delete": "Slett",
"unarchive": "Av-arkiver",
"setBackground": "Bruk som bakgrunn",
"setBackground": "Background settings",
"share": "Del",
"newProject": "Nytt prosjekt",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "no",
"altFormatLong": "d.m.Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Zaloguj się przez {provider}",
"authenticating": "Uwierzytelnianie…",
"openIdStateError": "Stan się nie zgadza, odmowa kontynuacji!",
"openIdGeneralError": "Wystąpił błąd podczas uwierzytelniania wobec strony trzeciej.",
"openIdGeneralError": "Wystąpił błąd podczas uwierzytelniania wobec aplikacji zewnętrznej.",
"logout": "Wyloguj",
"emailInvalid": "Proszę podać poprawny adres e-mail.",
"usernameRequired": "Proszę podać nazwę użytkownika.",
@ -66,7 +66,8 @@
"hidePassword": "Ukryj hasło",
"noAccountYet": "Nie masz jeszcze konta?",
"alreadyHaveAnAccount": "Masz już konto?",
"remember": "Pozostań zalogowany"
"remember": "Pozostań zalogowany",
"registrationDisabled": "Rejestracja jest wyłączona."
},
"settings": {
"title": "Ustawienia",
@ -95,6 +96,7 @@
"weekStartMonday": "poniedziałku",
"language": "Język",
"defaultProject": "Domyślny projekt",
"defaultView": "Widok domyślny",
"timezone": "Strefa czasowa",
"overdueTasksRemindersTime": "Czas przypomnienia o zaległych zadaniach na e-mail",
"filterUsedOnOverview": "Zapisany filtr używany na stronie przeglądania"
@ -314,12 +316,15 @@
"delete": "Usuń"
}
},
"first": {
"title": "Pierwszy widok"
},
"list": {
"title": "Lista",
"add": "Dodaj",
"addPlaceholder": "Dodaj nowe zadanie…",
"addPlaceholder": "Dodaj zadanie…",
"empty": "Ten projekt jest obecnie pusty.",
"newTaskCta": "Utwórz nowe zadanie.",
"newTaskCta": "Utwórz zadanie.",
"editTask": "Edytuj zadanie"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Wprowadź tytuł nowego zadania…",
"addTask": "Dodaj zadanie",
"addAnotherTask": "Dodaj kolejne zadanie",
"addBucket": "Utwórz nową kolumnę",
"addBucket": "Utwórz nowy zasobnik",
"addBucketPlaceholder": "Wprowadź tytuł nowej kolumny…",
"deleteHeaderBucket": "Usuń kolumnę",
"deleteBucketText1": "Czy na pewno chcesz usunąć tę kolumnę?",
@ -423,7 +428,7 @@
"create": {
"title": "Nowy filtr stały",
"description": "Zapisany filtr to wirtualny projekt, który jest obliczany na podstawie zestawu filtrów za każdym razem, gdy jest dostępny.",
"action": "Utwórz nowy filtr stały",
"action": "Create saved filter",
"titleRequired": "Podaj tytuł dla filtra."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Wpisz, aby wyszukać etykietę…",
"create": {
"header": "Nowa etykieta",
"title": "Utwórz nową etykietę",
"title": "Utwórz etykietę",
"titleRequired": "Proszę, podaj tytuł.",
"success": "Etykieta została pomyślnie utworzona."
},
@ -642,7 +647,7 @@
"placeholder": "Wpisz tekst lub naciśnij '/', aby zobaczyć więcej opcji…"
},
"multiselect": {
"createPlaceholder": "Utwórz nowy",
"createPlaceholder": "Utwórz",
"selectPlaceholder": "Kliknij lub naciśnij Enter, aby wybrać"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Zadanie",
"new": "Utwórz nowe zadanie",
"new": "Utwórz zadanie",
"delete": "Usuń to zadanie",
"createSuccess": "Zadanie zostało pomyślnie utworzone.",
"addReminder": "Dodaj nowe przypomnienie…",
"addReminder": "Dodaj przypomnienie…",
"doneSuccess": "Zadanie zostało pomyślnie oznaczone jako ukończone.",
"undoneSuccess": "Zadanie zostało pomyślnie otwarte ponownie.",
"undo": "Cofnij",
@ -860,7 +865,7 @@
"unassignSuccess": "Użytkownik został pomyślnie usunięty."
},
"label": {
"placeholder": "Wpisz, aby dodać nową etykietę…",
"placeholder": "Wpisz, aby dodać etykietę…",
"createPlaceholder": "Dodaj jako nową etykietę",
"addSuccess": "Etykieta została pomyślnie dodana.",
"createSuccess": "Etykieta została pomyślnie utworzona.",
@ -922,7 +927,7 @@
"every30d": "Co 30 dni",
"mode": "Tryb powtarzania",
"monthly": "Miesięczny",
"fromCurrentDate": "Od bieżącej daty",
"fromCurrentDate": "Od daty zakończenia",
"each": "Co",
"specifyAmount": "Określ ilość…",
"hours": "Godziny",
@ -962,7 +967,7 @@
"title": "Zespoły",
"noTeams": "Obecnie nie należysz do żadnego zespołu.",
"create": {
"title": "Utwórz nowy zespół",
"title": "Utwórz zespół",
"success": "Zespół został pomyślnie utworzony."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplikuj",
"delete": "Usuń",
"unarchive": "Cofnij archiwizację",
"setBackground": "Ustaw tło",
"setBackground": "Ustawienie tła",
"share": "Udostępnij",
"newProject": "Nowy projekt",
"createProject": "Utwórz projekt",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "pl",
"altFormatLong": "j M Y H:i",
"altFormatLong": "d.m.Y H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Faça o login com {provider}",
"authenticating": "Autenticando…",
"openIdStateError": "O Estado não se iguala, recusando-se a continuar!",
"openIdGeneralError": "Ocorreu um erro ao autenticar contra uma entidade externa.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Sair",
"emailInvalid": "Por favor, insira um endereço de e-mail válido.",
"usernameRequired": "Por favor, insira um nome de usuário.",
@ -66,7 +66,8 @@
"hidePassword": "Ocultar senha",
"noAccountYet": "Não possui uma conta ainda?",
"alreadyHaveAnAccount": "Já possui uma conta?",
"remember": "Permanecer conectado"
"remember": "Permanecer conectado",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Configurações",
@ -95,6 +96,7 @@
"weekStartMonday": "Segunda-feira",
"language": "Idioma",
"defaultProject": "Projeto Padrão",
"defaultView": "Default View",
"timezone": "Fuso horário",
"overdueTasksRemindersTime": "Horário do e-mail de lembrete de tarefas pendentes",
"filterUsedOnOverview": "Salvo filtro utilizado na visão geral"
@ -227,8 +229,8 @@
"title": "Arquivar \"{project}\"",
"archive": "Arquivar este projeto",
"unarchive": "Desarquivar este projeto",
"unarchiveText": "Você será capaz de criar novas tarefas ou editá-las.",
"archiveText": "Você não poderá editar este projeto ou criar novas tarefas até desarquivá-lo.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "O projeto foi arquivado com sucesso."
},
"background": {
@ -277,7 +279,7 @@
"title": "Compartilhar Link",
"what": "O que é um link de compartilhamento?",
"explanation": "Compartilhar Links permite que você compartilhe facilmente uma lista com outros usuários que não têm uma conta na Vikunja.",
"create": "Criar novo link de compartilhamento",
"create": "Create a link share",
"name": "Nome (opcional)",
"namePlaceholder": "ex. Lorem Ipsum",
"nameExplanation": "Todas as ações feitas por este compartilhamento de link aparecerão com o nome.",
@ -314,12 +316,15 @@
"delete": "Excluir"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Lista",
"add": "Adicionar",
"addPlaceholder": "Adicionar uma nova tarefa…",
"addPlaceholder": "Add a task…",
"empty": "Este projeto está vazio no momento.",
"newTaskCta": "Criar uma nova tarefa.",
"newTaskCta": "Create a task.",
"editTask": "Editar Tarefa"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Digite o título da tarefa…",
"addTask": "Adicionar uma tarefa",
"addAnotherTask": "Adicionar outra tarefa",
"addBucket": "Criar um novo bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Digite o título do novo bucket…",
"deleteHeaderBucket": "Excluir o bucket",
"deleteBucketText1": "Tem certeza que deseja excluir este bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "Novo filtro salvo",
"description": "Um filtro salvo é um projeto virtual que é calculado a partir de um conjunto de filtros cada vez que ele é acessado.",
"action": "Criar novo filtro salvo",
"action": "Create saved filter",
"titleRequired": "Por favor, forneça um título para o filtro."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Digite para procurar por uma etiqueta…",
"create": {
"header": "Nova etiqueta",
"title": "Criar uma nova etiqueta",
"title": "Create a label",
"titleRequired": "Por favor, especifique um título.",
"success": "A etiqueta foi criada com sucesso."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Autenticando…",
"passwordRequired": "Este projeto compartilhado requer uma senha. Por favor, digite-a abaixo:",
"error": "Ocorreu um erro.",
"error": "An error occurred.",
"invalidPassword": "A senha é inválida."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Digite algum texto ou toque em '/' para ver mais opções…"
},
"multiselect": {
"createPlaceholder": "Criar novo",
"createPlaceholder": "Create",
"selectPlaceholder": "Clique ou pressione Enter para selecionar"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Tarefa",
"new": "Criar uma nova tarefa",
"new": "Create a task",
"delete": "Excluir esta tarefa",
"createSuccess": "A tarefa foi criada com sucesso.",
"addReminder": "Adicionar um novo lembrete…",
"addReminder": "Add a reminder…",
"doneSuccess": "A tarefa foi marcada como feita com sucesso.",
"undoneSuccess": "A tarefa foi desmarcada como feita com sucesso.",
"undo": "Desfazer",
@ -860,7 +865,7 @@
"unassignSuccess": "O usuário foi desatribuído com sucesso."
},
"label": {
"placeholder": "Digite para adicionar uma nova etiqueta…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Adicionar como nova etiqueta",
"addSuccess": "A etiqueta foi adicionada com sucesso.",
"createSuccess": "A etiqueta foi criada com sucesso.",
@ -883,8 +888,8 @@
"relation": {
"add": "Adicionar uma nova relação de tarefas",
"new": "Nova Relação de Tarefas",
"searchPlaceholder": "Digite a busca por uma nova tarefa para adicionar como relacionada…",
"createPlaceholder": "Adicionar como uma nova tarefa relacionada",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Esta tarefa pertence a um projeto diferente.",
"noneYet": "Ainda não há relações de tarefas.",
"delete": "Excluir Relação Entre Tarefas",
@ -922,7 +927,7 @@
"every30d": "A cada 30 dias",
"mode": "Modo repetição",
"monthly": "Mensalmente",
"fromCurrentDate": "Data atual",
"fromCurrentDate": "From completion date",
"each": "Cada",
"specifyAmount": "Especifique uma quantidade…",
"hours": "Horas",
@ -962,7 +967,7 @@
"title": "Equipes",
"noTeams": "Atualmente você não faz parte de nenhuma equipe.",
"create": {
"title": "Criar uma equipe",
"title": "Create a team",
"success": "A equipe foi criada com sucesso."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicar",
"delete": "Excluir",
"unarchive": "Desarquivar",
"setBackground": "Definir plano de fundo",
"setBackground": "Background settings",
"share": "Compartilhar",
"newProject": "Novo projeto",
"createProject": "Criar projeto",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "pt-br",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Iniciar sessão com {provider}",
"authenticating": "A autenticar…",
"openIdStateError": "O estado não coincide, a recusar continuar!",
"openIdGeneralError": "Ocorreu um erro na autenticação perante a entidade externa.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Terminar Sessão",
"emailInvalid": "Por favor, insire um endereço de e-mail válido.",
"usernameRequired": "Por favor, fornece um nome de utilizador.",
@ -66,7 +66,8 @@
"hidePassword": "Esconder a palavra-passe",
"noAccountYet": "Ainda não tens uma conta?",
"alreadyHaveAnAccount": "Já tens uma conta?",
"remember": "Permanecer autenticado"
"remember": "Permanecer autenticado",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Definições",
@ -95,6 +96,7 @@
"weekStartMonday": "Segunda-Feira",
"language": "Idioma",
"defaultProject": "Projeto Padrão",
"defaultView": "Default View",
"timezone": "Fuso Horário",
"overdueTasksRemindersTime": "Horário do e-mail de lembrete de tarefas pendentes",
"filterUsedOnOverview": "Salvo filtro utilizado na vista geral"
@ -227,8 +229,8 @@
"title": "Arquivar \"{project}\"",
"archive": "Arquivar este projeto",
"unarchive": "Desarquivar este projeto",
"unarchiveText": "Vais ser capaz de criar novas tarefas ou editá-las.",
"archiveText": "Não poderás editar este projeto ou criar novas tarefas até o desarquivares.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "Este projeto foi arquivado com sucesso."
},
"background": {
@ -277,7 +279,7 @@
"title": "Links Partilhados",
"what": "Como funcionam os links partilhados?",
"explanation": "Links Partilhados permite-lhe partilhar facilmente um projeto com outros utilizadores que não têm uma conta no Vikunja.",
"create": "Criar um novo link partilhado",
"create": "Create a link share",
"name": "Nome (opcional)",
"namePlaceholder": "ex.: Lorem Ipsum",
"nameExplanation": "Todas as ações realizadas através deste link partilhado vão aparecer com este nome.",
@ -314,12 +316,15 @@
"delete": "Eliminar"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "Lista",
"add": "Adicionar",
"addPlaceholder": "Adicionar uma nova tarefa…",
"addPlaceholder": "Add a task…",
"empty": "Este projeto está atualmente vazio.",
"newTaskCta": "Cria uma nova tarefa.",
"newTaskCta": "Create a task.",
"editTask": "Editar Tarefa"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Introduz o título da nova tarefa…",
"addTask": "Adicionar uma tarefa",
"addAnotherTask": "Adicionar outra tarefa",
"addBucket": "Criar um novo conjunto",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Introduz o título do novo conjunto…",
"deleteHeaderBucket": "Eliminar o conjunto",
"deleteBucketText1": "Tens a certeza que pretendes eliminar este conjunto?",
@ -423,7 +428,7 @@
"create": {
"title": "Novo Filtro Memorizado",
"description": "Um filtro memorizado é um projeto virtual que é compilado a partir de um conjunto de filtros de cada vez que é acedido.",
"action": "Criar novo filtro memorizado",
"action": "Create saved filter",
"titleRequired": "Por favor, insere um título para o filtro."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Escreve para pesquisar uma etiqueta…",
"create": {
"header": "Nova etiqueta",
"title": "Cria uma nova etiqueta",
"title": "Create a label",
"titleRequired": "Por favor, especifica um título.",
"success": "A etiqueta foi criada com sucesso."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "A autenticar…",
"passwordRequired": "Este projeto partilhado requer uma palavra-passe. Por favor, introduz-a abaixo:",
"error": "Ocorreu um erro.",
"error": "An error occurred.",
"invalidPassword": "A palavra-passe é inválida."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Insere algum texto ou pressiona '/' para ver mais opções…"
},
"multiselect": {
"createPlaceholder": "Criar novo",
"createPlaceholder": "Create",
"selectPlaceholder": "Clica ou pressiona Enter para selecionar"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Tarefa",
"new": "Criar uma nova tarefa",
"new": "Create a task",
"delete": "Eliminar esta tarefa",
"createSuccess": "A tarefa for criada com sucesso.",
"addReminder": "Adicionar um novo lembrete…",
"addReminder": "Add a reminder…",
"doneSuccess": "A tarefa foi marcada como concluída.",
"undoneSuccess": "A tarefa foi desmarcada como concluída.",
"undo": "Desfazer",
@ -860,7 +865,7 @@
"unassignSuccess": "O utilizador foi desatribuido com sucesso."
},
"label": {
"placeholder": "Escreve para adicionar uma nova etiqueta…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Adicionar isto como nova etiqueta",
"addSuccess": "A etiqueta foi adicionada com sucesso.",
"createSuccess": "A etiqueta foi criada com sucesso.",
@ -883,8 +888,8 @@
"relation": {
"add": "Adicionar Nova Relação Entre Tarefas",
"new": "Nova Relação Entre Tarefas",
"searchPlaceholder": "Escreve para pesquisar uma tarefa a adicionar como relacionada…",
"createPlaceholder": "Adicionar como nova tarefa relacionada",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "Esta tarefa pertence a um projeto diferente.",
"noneYet": "Ainda sem tarefas relacionadas.",
"delete": "Eliminar Relação Entre Tarefas",
@ -922,7 +927,7 @@
"every30d": "A cada 30 Dias",
"mode": "Modo de repetição",
"monthly": "Mensal",
"fromCurrentDate": "Da Data Atual",
"fromCurrentDate": "From completion date",
"each": "Cada",
"specifyAmount": "Especifica uma quantidade…",
"hours": "Horas",
@ -962,7 +967,7 @@
"title": "Equipas",
"noTeams": "Atualmente não fazes parte de nenhuma equipa.",
"create": {
"title": "Cria uma nova equipa",
"title": "Create a team",
"success": "A equipa foi criada com sucesso."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicar",
"delete": "Eliminar",
"unarchive": "Desarquivar",
"setBackground": "Definir Fundo",
"setBackground": "Background settings",
"share": "Partilhar",
"newProject": "Novo projeto",
"createProject": "Criar projeto",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "pt-PT",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -5,8 +5,8 @@
"welcomeDay": "Привет, {username}!",
"welcomeEvening": "Добрый вечер, {username}!",
"lastViewed": "Последние просмотренные",
"addToHomeScreen": "Add this app to your home screen for faster access and improved experience.",
"goToOverview": "Go to overview",
"addToHomeScreen": "Добавьте это приложение на домашний экран для быстрого доступа и удобной работы.",
"goToOverview": "Перейти к обзору",
"project": {
"importText": "Импортировать проекты и задачи из других сервисов в Vikunja:",
"import": "Импорт данных в Vikunja"
@ -53,20 +53,21 @@
"loginWith": "Войти через {provider}",
"authenticating": "Аутентификация…",
"openIdStateError": "State does not match, refusing to continue!",
"openIdGeneralError": "Произошла ошибка при аутентификации с помощью третьей стороны.",
"openIdGeneralError": "Произошла ошибка при аутентификации через сторонний сервис.",
"logout": "Выйти",
"emailInvalid": "Введите корректный email адрес.",
"usernameRequired": "Введите имя пользователя.",
"usernameMustNotContainSpace": "The username must not contain spaces.",
"usernameMustNotLookLikeUrl": "The username must not look like a URL.",
"usernameMustNotContainSpace": "Имя пользователя не должно содержать пробелы.",
"usernameMustNotLookLikeUrl": "Имя пользователя не должно быть похожим на URL.",
"passwordRequired": "Введите пароль.",
"passwordNotMin": "Password must have at least 8 characters.",
"passwordNotMax": "Password must have at most 250 characters.",
"passwordNotMin": "Пароль должен содержать не меньше 8 символов.",
"passwordNotMax": "Пароль должен содержать не больше 250 символов.",
"showPassword": "Показать пароль",
"hidePassword": "Скрыть пароль",
"noAccountYet": "Ещё нет аккаунта?",
"alreadyHaveAnAccount": "Уже есть аккаунт?",
"remember": "Оставаться в системе"
"remember": "Оставаться в системе",
"registrationDisabled": "Регистрация отключена."
},
"settings": {
"title": "Настройки",
@ -95,6 +96,7 @@
"weekStartMonday": "Понедельник",
"language": "Язык",
"defaultProject": "Проект по умолчанию",
"defaultView": "Представление по умолчанию",
"timezone": "Часовой пояс",
"overdueTasksRemindersTime": "Время напоминания о невыполненных задачах",
"filterUsedOnOverview": "Сохранённый фильтр, используемый на странице обзора"
@ -172,7 +174,7 @@
},
"attributes": {
"title": "Название",
"titlePlaceholder": "Enter a title you will recognize later",
"titlePlaceholder": "Введите название, по которому вы сможете узнать этот токен",
"expiresAt": "Срок действия",
"permissions": "Разрешения"
}
@ -213,9 +215,9 @@
"parent": "Родительский проект",
"search": "Введите запрос для поиска проекта…",
"searchSelect": "Кликните или нажмите Enter для выбора этого проекта",
"shared": "Shared Projects",
"shared": "Общие проекты",
"noDescriptionAvailable": "Описание проекта отсутствует.",
"inboxTitle": "Inbox",
"inboxTitle": "Входящие",
"create": {
"header": "Создать проект",
"titlePlaceholder": "Введите название проекта…",
@ -227,8 +229,8 @@
"title": "Архивирование «{project}»",
"archive": "Архивирование проекта",
"unarchive": "Возвращение проекта из архива",
"unarchiveText": "Вы сможете создавать новые задачи или изменять их.",
"archiveText": "Вы не сможете изменять этот проект или создавать в нём новые задачи, пока не вернёте его из архива.",
"unarchiveText": "Вы сможете создавать задачи или изменять их.",
"archiveText": "Вы не сможете изменять этот проект или создавать в нём задачи, пока не вернёте его из архива.",
"success": "Проект архивирован."
},
"background": {
@ -248,7 +250,7 @@
"text2": "Это включает в себя все задачи, и отменить это будет нельзя!",
"success": "Проект успешно удалён.",
"tasksToDelete": "Это безвозвратно удалит примерно {count} задач.",
"tasksAndChildProjectsToDelete": "This will irrevocably remove approx. {tasks} tasks and {projects} projects.",
"tasksAndChildProjectsToDelete": "Это безвозвратно удалит примерно {tasks} задач и {projects} проектов.",
"noTasksToDelete": "В этом проекте нет никаких задач, можно спокойно удалять."
},
"duplicate": {
@ -265,7 +267,7 @@
"identifier": "Идентификатор проекта",
"identifierPlaceholder": "Введите идентификатор проекта…",
"description": "Описание",
"descriptionPlaceholder": "Enter a description for this project, hit '/' for more options…",
"descriptionPlaceholder": "Введите описание проекта, нажмите '/' для дополнительных параметров…",
"color": "Цвет",
"success": "Проект успешно обновлён."
},
@ -277,7 +279,7 @@
"title": "Ссылки для обмена",
"what": "Что такое ссылка для обмена?",
"explanation": "Ссылка для обмена позволяет поделиться проектом с теми, у кого нет аккаунта в Vikunja.",
"create": "Создать новую ссылку для обмена",
"create": "Создать ссылку для обмена",
"name": "Имя (необязательно)",
"namePlaceholder": "напр. Lorem Ipsum",
"nameExplanation": "Все действия, выполненные через эту ссылку, будут подписаны этим именем.",
@ -314,12 +316,15 @@
"delete": "Удалить"
}
},
"first": {
"title": "Первое представление"
},
"list": {
"title": "Список",
"add": "Добавить",
"addPlaceholder": "Добавить новую задачу…",
"addPlaceholder": "Добавить задачу…",
"empty": "Проект сейчас пуст.",
"newTaskCta": "Создать новую задачу.",
"newTaskCta": "Создать задачу.",
"editTask": "Изменить задачу"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Введите название задачи…",
"addTask": "Добавить задачу",
"addAnotherTask": "Добавить ещё задачу",
"addBucket": "Создать новую колонку",
"addBucket": "Создать колонку",
"addBucketPlaceholder": "Введите название новой колонки…",
"deleteHeaderBucket": "Удаление колонки",
"deleteBucketText1": "Удалить эту колонку?",
@ -383,32 +388,32 @@
"secretDocs": "Подробнее об использовании секретов в документации."
},
"views": {
"header": "Edit views",
"title": "Title",
"actions": "Actions",
"kind": "Kind",
"bucketConfigMode": "Bucket configuration mode",
"bucketConfig": "Bucket configuration",
"bucketConfigManual": "Manual",
"filter": "Filter",
"create": "Create view",
"createSuccess": "The view was created successfully.",
"titleRequired": "Please provide a title.",
"delete": "Delete this view",
"deleteText": "Are you sure you want to remove this view? It will no longer be possible to use it to view tasks in this project. This action won't delete any tasks. This cannot be undone!",
"deleteSuccess": "The view was successfully deleted",
"onlyAdminsCanEdit": "Only project admins can edit views."
"header": "Изменить представления",
"title": "Название",
"actions": "Действия",
"kind": "Вид",
"bucketConfigMode": "Режим конфигурации колонок",
"bucketConfig": "Конфигурация колонок",
"bucketConfigManual": "Ручная",
"filter": "По фильтрам",
"create": "Создать представление",
"createSuccess": "Представление создано.",
"titleRequired": "Пожалуйста, укажите название.",
"delete": "Удалить представление",
"deleteText": "Удалить это представление? После удаления его не получится использовать для просмотра задач в этом проекте. Сами задачи останутся. Это действие отменить нельзя!",
"deleteSuccess": "Представление удалено",
"onlyAdminsCanEdit": "Только администраторы проекта могут изменять представления."
}
},
"filters": {
"title": "Фильтры",
"clear": "Сбросить фильтры",
"showResults": "Show results",
"showResults": "Применить",
"attributes": {
"title": "Название",
"titlePlaceholder": "Введите название сохранённого фильтра…",
"description": "Описание",
"descriptionPlaceholder": "Add a description for this filter here, hit '/' for more options…",
"descriptionPlaceholder": "Введите описание фильтра, нажмите '/' для дополнительных параметров…",
"includeNulls": "Включать задачи, у которых не установлено значение",
"requireAll": "Для отображения задачи требовать истинность всех фильтров",
"showDoneTasks": "Показывать завершённые задачи",
@ -417,13 +422,13 @@
"enablePercentDone": "Включить фильтр по прогрессу",
"dueDateRange": "Диапазон срока",
"startDateRange": "Диапазон даты начала",
"endDateRange": "Диапазон даты завершения",
"endDateRange": "Диапазон даты окончания",
"reminderRange": "Диапазон даты напоминания"
},
"create": {
"title": "Создать сохранённый фильтр",
"description": "Сохранённый фильтр — это виртуальный проект, содержимое которого выбирается с помощью фильтров в момент его просмотра.",
"action": "Создать новый сохранённый фильтр",
"action": "Создать сохранённый фильтр",
"titleRequired": "Укажите название фильтра."
},
"delete": {
@ -436,48 +441,48 @@
"success": "Фильтр сохранён."
},
"query": {
"title": "Query",
"placeholder": "Type a search or filter query…",
"title": "Запрос",
"placeholder": "Введите запрос для поиска или фильтрации…",
"help": {
"intro": "To filter tasks, you can use a query syntax similar to SQL. The available fields for filtering include:",
"link": "How does this work?",
"canUseDatemath": "You can date math to set relative dates. Click on the date value in a query to find out more.",
"intro": "Для фильтрации задач можно использовать синтаксис, похожий на SQL. Можно фильтровать по следующим полям:",
"link": "Как это работает?",
"canUseDatemath": "Можно использовать математические выражения для указания относительных дат. Нажмите на значение даты в запросе для подробностей.",
"fields": {
"done": "Whether the task is completed or not",
"priority": "The priority level of the task (1-5)",
"percentDone": "The percentage of completion for the task (0-100)",
"dueDate": "The due date of the task",
"startDate": "The start date of the task",
"endDate": "The end date of the task",
"doneAt": "The date and time when the task was completed",
"assignees": "The assignees of the task",
"labels": "The labels associated with the task",
"project": "The project the task belongs to (only available for saved filters, not on a project level)"
"done": "Выполнена ли задача или нет",
"priority": "Приоритет задачи (1-5)",
"percentDone": "Процент выполнения задачи (0-100)",
"dueDate": "Срок задачи",
"startDate": "Дата начала задачи",
"endDate": "Дата окончания задачи",
"doneAt": "Дата и время, когда задача была завершена",
"assignees": "Пользователи, которым назначена задача",
"labels": "Метки, связанные с задачей",
"project": "Проект, в котором находится задача (только для сохранённых фильтров, не на уровне проекта)"
},
"operators": {
"intro": "The available operators for filtering include:",
"notEqual": "Not equal to",
"equal": "Equal to",
"greaterThan": "Greater than",
"greaterThanOrEqual": "Greater than or equal to",
"lessThan": "Less than",
"lessThanOrEqual": "Less than or equal to",
"like": "Matches a pattern (using wildcard %)",
"in": "Matches any value in a comma-seperated list of values"
"intro": "Доступны следующие операторы:",
"notEqual": "Не равно",
"equal": "Равно",
"greaterThan": "Больше",
"greaterThanOrEqual": "Больше или равно",
"lessThan": "Меньше",
"lessThanOrEqual": "Меньше или равно",
"like": "Соответствует шаблону (знак подстановки %)",
"in": "Соответствует любому из перечисленных значений, разделённых запятой"
},
"logicalOperators": {
"intro": "To combine multiple conditions, you can use the following logical operators:",
"and": "AND operator, matches if all conditions are true",
"or": "OR operator, matches if any of the conditions are true",
"parentheses": "Parentheses for grouping conditions"
"intro": "Для объединения нескольких условий можно использовать логические операторы:",
"and": "Оператор И — должны выполниться все условия",
"or": "Оператор ИЛИ — должно выполниться любое условие",
"parentheses": "Скобки для группировки условий"
},
"examples": {
"intro": "Here are some examples of filter queries:",
"priorityEqual": "Matches tasks with priority level 4",
"dueDatePast": "Matches tasks with a due date in the past",
"undoneHighPriority": "Matches undone tasks with priority level 3 or higher",
"assigneesIn": "Matches tasks assigned to either \"user1\" or \"user2\"",
"priorityOneOrTwoPastDue": "Matches tasks with priority level 1 or 2 and a due date in the past"
"intro": "Примеры запросов:",
"priorityEqual": "Выбирает задачи с приоритетом 4",
"dueDatePast": "Выбирает задачи со сроком в прошлом (то есть просроченные)",
"undoneHighPriority": "Выбирает невыполненные задачи с приоритетом 3 или выше",
"assigneesIn": "Выбирает задачи, назначенные пользователям «user1» или «user2»",
"priorityOneOrTwoPastDue": "Выбирает задачи с приоритетом 1 или 2 и сроком в прошлом"
}
}
}
@ -496,8 +501,8 @@
"confirm": "Я уверен, давай начнём миграцию!",
"importUpload": "Чтобы импортировать данные из {name} в Vikunja, нажмите кнопку ниже для выбора файла.",
"upload": "Загрузить файл",
"migrationStartedWillReciveEmail": "Vikunja will now import your lists/projects, tasks, notes, reminders and files from {service}. As this will take a while, we will send you an email once done. You can close this window now.",
"migrationInProgress": "A migration is currently in progress. Please wait until it is done."
"migrationStartedWillReciveEmail": "Vikunja импортирует списки/проекты, задачи, заметки, напоминания и файлы из {service}. Это займёт некоторое время, и после завершения вам придёт письмо. Это окно можно закрыть.",
"migrationInProgress": "Идёт процесс миграции. Пожалуйста, подождите до завершения."
},
"label": {
"title": "Метки",
@ -506,8 +511,8 @@
"newCTA": "Меток сейчас нет.",
"search": "Введите запрос для поиска метки…",
"create": {
"header": "Новая метка",
"title": "Создать новую метку",
"header": "Создать метку",
"title": "Создать метку",
"titleRequired": "Пожалуйста, укажите название.",
"success": "Метка успешно создана."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Аутентификация…",
"passwordRequired": "Для доступа к этому проекту нужен пароль. Введите его сюда:",
"error": "Случилась ошибка.",
"error": "Произошла ошибка.",
"invalidPassword": "Неверный пароль."
},
"navigation": {
@ -549,7 +554,7 @@
"copy": "Скопировать в буфер обмена",
"copyError": "Скопировать в буфер обмена не удалось",
"search": "Поиск",
"searchPlaceholder": "Введи запрос для поиска…",
"searchPlaceholder": "Введите запрос для поиска…",
"previous": "Назад",
"next": "Вперёд",
"poweredBy": "При поддержке Vikunja",
@ -568,7 +573,7 @@
"custom": "Настраиваемый",
"id": "ID",
"created": "Дата создания",
"createdBy": "Created by {0}",
"createdBy": "Создатель {0}",
"actions": "Действия",
"cannotBeUndone": "Это действие отменить нельзя!"
},
@ -587,11 +592,11 @@
"edit": "Изменить",
"done": "Готово",
"heading1": "Заголовок 1",
"heading1Tooltip": "Big section heading.",
"heading1Tooltip": "Большой заголовок.",
"heading2": "Заголовок 2",
"heading2Tooltip": "Medium section heading.",
"heading2Tooltip": "Средний заголовок.",
"heading3": "Заголовок 3",
"heading3Tooltip": "Smaller section header.",
"heading3Tooltip": "Маленький заголовок.",
"headingSmaller": "Заголовок меньше",
"headingBigger": "Заголовок больше",
"bold": "Жирный",
@ -599,47 +604,47 @@
"strikethrough": "Зачёркнутый",
"underline": "Подчёркнутый",
"code": "Код",
"codeTooltip": "Capture a code snippet.",
"codeTooltip": "Фрагмент кода.",
"quote": "Цитата",
"quoteTooltip": "Capture a quote.",
"bulletList": "Bullet list",
"bulletListTooltip": "Create a simple bullet list.",
"unorderedList": "Unordered list",
"orderedList": "Ordered list",
"orderedListTooltip": "Create a list with numbering.",
"quoteTooltip": "Цитата.",
"bulletList": "Маркированный список",
"bulletListTooltip": "Создать простой список.",
"unorderedList": "Неупорядоченный список",
"orderedList": "Нумерованный список",
"orderedListTooltip": "Создать нумерованный список.",
"cleanBlock": "Очистить блок",
"link": "Ссылка",
"image": "Изображение",
"imageTooltip": "Upload an image from your computer.",
"imageTooltip": "Загрузить изображение с компьютера.",
"table": {
"title": "Таблица",
"insert": "Insert table",
"addColumnBefore": "Add column before",
"addColumnAfter": "Add column after",
"deleteColumn": "Delete column",
"addRowBefore": "Add row before",
"addRowAfter": "Add row after",
"deleteRow": "Delete row",
"deleteTable": "Delete table",
"mergeCells": "Merge cells",
"splitCell": "Split cell",
"toggleHeaderColumn": "Toggle header column",
"toggleHeaderRow": "Toggle header row",
"toggleHeaderCell": "Toggle header cell",
"mergeOrSplit": "Merge or split",
"fixTables": "Fix tables"
"insert": "Вставить таблицу",
"addColumnBefore": "Добавить столбец слева",
"addColumnAfter": "Добавить столбец справа",
"deleteColumn": "Удалить столбец",
"addRowBefore": "Добавить строку сверху",
"addRowAfter": "Добавить строку снизу",
"deleteRow": "Удалить строку",
"deleteTable": "Удалить таблицу",
"mergeCells": "Объединить ячейки",
"splitCell": "Разделить ячейки",
"toggleHeaderColumn": "Столбец заголовков",
"toggleHeaderRow": "Строка заголовков",
"toggleHeaderCell": "Ячейка с заголовком",
"mergeOrSplit": "Объединить или разделить",
"fixTables": "Исправить таблицы"
},
"horizontalRule": "Разделитель",
"horizontalRuleTooltip": "Divide a section.",
"horizontalRuleTooltip": "Разделитель текста.",
"sideBySide": "Side By Side",
"guide": "Руководство",
"text": "Text",
"textTooltip": "Just start typing with plain text.",
"text": "Текст",
"textTooltip": "Просто начните печатать для ввода обычного текста.",
"taskList": "Список задач",
"taskListTooltip": "Track tasks with a to-do list.",
"taskListTooltip": "Отслеживаемые задачи в виде списка с галочками.",
"undo": "Отменить",
"redo": "Вернуть",
"placeholder": "Type some text or hit '/' to see more options…"
"placeholder": "Введите какой-нибудь текст или нажмите '/' для дополнительных параметров…"
},
"multiselect": {
"createPlaceholder": "Создать",
@ -649,7 +654,7 @@
"to": "По",
"from": "С",
"fromto": "С {from} по {to}",
"date": "Date",
"date": "Дата",
"ranges": {
"today": "Сегодня",
"thisWeek": "Эта неделя",
@ -666,33 +671,33 @@
"restOfThisYear": "Остаток этого года"
},
"values": {
"now": "Now",
"startOfToday": "Start of today",
"endOfToday": "End of today",
"beginningOflastWeek": "Beginning of last week",
"endOfLastWeek": "End of last week",
"beginningOfThisWeek": "Beginning of this week",
"endOfThisWeek": "End of this week",
"startOfNextWeek": "Start of next week",
"endOfNextWeek": "End of next week",
"in7Days": "In 7 days",
"beginningOfLastMonth": "Beginning of last month",
"endOfLastMonth": "End of last month",
"startOfThisMonth": "Start of this month",
"endOfThisMonth": "End of this month",
"startOfNextMonth": "Start of next month",
"endOfNextMonth": "End of next month",
"in30Days": "In 30 days",
"startOfThisYear": "Beginning of this year",
"endOfThisYear": "End of this year"
"now": "Сейчас",
"startOfToday": "Начало дня",
"endOfToday": "Конец дня",
"beginningOflastWeek": "Начало прошлой недели",
"endOfLastWeek": "Конец прошлой недели",
"beginningOfThisWeek": "Начало этой недели",
"endOfThisWeek": "Конец этой недели",
"startOfNextWeek": "Начало следующей недели",
"endOfNextWeek": "Конец этой недели",
"in7Days": "Через 7 дней",
"beginningOfLastMonth": "Начало прошлого месяца",
"endOfLastMonth": "Конец прошлого месяца",
"startOfThisMonth": "Начало этого месяца",
"endOfThisMonth": "Конец этого месяца",
"startOfNextMonth": "Начало следующего месяца",
"endOfNextMonth": "Конец следующего месяца",
"in30Days": "Через 30 дней",
"startOfThisYear": "Начало этого года",
"endOfThisYear": "Конец этого года"
}
},
"datemathHelp": {
"canuse": "You can use date math to filter for relative dates.",
"canuse": "Можно использовать математические выражения для фильтрации по относительным датам.",
"learnhow": "Как это работает",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"title": "Математика дат",
"intro": "Укажите относительные даты, которые Vikunja будет вычислять на лету в момент применения фильтра.",
"expression": "Каждое выражение начинается с опорной даты, которое может быть {0} или конкретной датой, оканчивающейся на {1}. Затем к опорной дате можно добавить одно или несколько математических выражений.",
"similar": "Это похоже на выражения, которые используются в {0} и {1}.",
"add1Day": "Добавить один день",
"minus1Day": "Вычесть один день",
@ -743,7 +748,7 @@
"detail": {
"chooseDueDate": "Нажмите для выбора срока",
"chooseStartDate": "Нажмите для выбора даты начала",
"chooseEndDate": "Нажмите для выбора даты завершения",
"chooseEndDate": "Нажмите для выбора даты окончания",
"move": "Переместить задачу в другой проект",
"done": "Завершено!",
"undone": "Не завершено",
@ -769,7 +774,7 @@
"priority": "Задать приоритет",
"dueDate": "Задать срок",
"startDate": "Задать дату начала",
"endDate": "Задать дату завершения",
"endDate": "Задать дату окончания",
"reminders": "Добавить напоминания",
"repeatAfter": "Задать интервал повтора",
"percentDone": "Задать прогресс",
@ -790,7 +795,7 @@
"description": "Описание",
"done": "Завершено",
"dueDate": "Срок",
"endDate": "Дата завершения",
"endDate": "Дата окончания",
"labels": "Метки",
"percentDone": "Прогресс",
"priority": "Приоритет",
@ -800,7 +805,7 @@
"startDate": "Дата начала",
"title": "Название",
"updated": "Дата изменения",
"doneAt": "Done At"
"doneAt": "Дата завершения"
},
"subscription": {
"subscribedTaskThroughParentProject": "Вы не можете отписаться здесь, потому что вы подписаны эту задачу через её проект.",
@ -836,7 +841,7 @@
"loading": "Загрузка комментариев…",
"edited": "изменено {date}",
"creating": "Комментируем…",
"placeholder": "Add your comment, hit '/' for more options…",
"placeholder": "Введите комментарий, нажмите '/' для дополнительных параметров…",
"comment": "Комментировать",
"delete": "Удалить комментарий",
"deleteText1": "Удалить этот комментарий?",
@ -850,7 +855,7 @@
"1week": "1 неделя"
},
"description": {
"placeholder": "Enter a description, hit '/' for more options…",
"placeholder": "Введите описание, нажмите '/' для дополнительных параметров…",
"empty": "Описания ещё нет."
},
"assignee": {
@ -860,7 +865,7 @@
"unassignSuccess": "Пользователь убран."
},
"label": {
"placeholder": "Введите новую метку…",
"placeholder": "Введите метку…",
"createPlaceholder": "Добавить как новую метку",
"addSuccess": "Метка добавлена.",
"createSuccess": "Метка создана.",
@ -883,7 +888,7 @@
"relation": {
"add": "Добавить новую связанную задачу",
"new": "Новая связанная задача",
"searchPlaceholder": "Введи запрос для поиска задачи, чтобы добавить связь…",
"searchPlaceholder": "Введите запрос для поиска задачи, чтобы добавить связь…",
"createPlaceholder": "Добавить как связанную задачу",
"differentProject": "Эта задача принадлежит другому проекту.",
"noneYet": "Ещё нет связанных задач.",
@ -906,15 +911,15 @@
}
},
"reminder": {
"before": "{amount} {unit} before {type}",
"after": "{amount} {unit} after {type}",
"beforeShort": "before",
"afterShort": "after",
"onDueDate": "On the due date",
"onStartDate": "On the start date",
"onEndDate": "On the end date",
"custom": "Custom",
"dateAndTime": "Date and time"
"before": "{amount} {unit} до {type}",
"after": "{amount} {unit} после {type}",
"beforeShort": "до",
"afterShort": "после",
"onDueDate": "По истечению срока",
"onStartDate": "В дату начала",
"onEndDate": "В дату окончания",
"custom": "Другой вариант",
"dateAndTime": "Конкретное время"
},
"repeat": {
"everyDay": "Каждый день",
@ -922,7 +927,7 @@
"every30d": "Каждые 30 дней",
"mode": "Режим повтора",
"monthly": "Ежемесячно",
"fromCurrentDate": "От сегодняшей даты",
"fromCurrentDate": "С даты завершения",
"each": "Каждые",
"specifyAmount": "Укажите количество…",
"hours": "Часов",
@ -933,7 +938,7 @@
"invalidAmount": "Введите больше чем 0."
},
"quickAddMagic": {
"hint": "Use magic prefixes to define due dates, assignees and other task properties.",
"hint": "Используйте волшебные префиксы, чтобы указать срок, назначить пользователей или задать другие свойства задачи.",
"title": "Волшебное Быстрое Добавление",
"intro": "При создании задачи вы можете использовать специальные ключевые слова для непосредственного добавления атрибутов к создаваемой задаче. Это позволяет добавлять часто используемые атрибуты гораздо быстрее.",
"multiple": "Вы можете использовать это несколько раз.",
@ -1001,11 +1006,11 @@
"namePlaceholder": "Имя команды здесь…",
"nameRequired": "Пожалуйста, укажите имя.",
"description": "Описание",
"descriptionPlaceholder": "Describe the team here, hit '/' for more options…",
"descriptionPlaceholder": "Введите описание команды, нажмите '/' для дополнительных параметров…",
"admin": "Администратор",
"member": "Участник",
"isPublic": "Public Team",
"isPublicDescription": "Make the team publicly discoverable. When enabled, anyone can share projects with this team even when not being a direct member."
"isPublic": "Публичная команда",
"isPublicDescription": "Сделать команду видимой публично. Если включено, кто угодно сможет поделиться проектами с этой командой, даже если он не является её участником."
}
},
"keyboardShortcuts": {
@ -1060,20 +1065,20 @@
"duplicate": "Создать копию",
"delete": "Удалить",
"unarchive": "Вернуть из архива",
"setBackground": "Задать фон",
"setBackground": "Настройки фона",
"share": "Поделиться",
"newProject": "Создать проект",
"createProject": "Создать проект",
"cantArchiveIsDefault": "You cannot archive this because it is your default project.",
"cantDeleteIsDefault": "You cannot delete this because it is your default project.",
"views": "Views"
"cantArchiveIsDefault": "Нельзя архивировать проект по умолчанию.",
"cantDeleteIsDefault": "Нельзя удалять проект по умолчанию.",
"views": "Представления"
},
"apiConfig": {
"url": "Vikunja URL",
"urlPlaceholder": "напр. https://localhost:3456",
"change": "изменить",
"use": "Используется Vikunja на {0}",
"error": "Could not find or use Vikunja installation at \"{domain}\". Please check if the url has the correct format and you can reach it when accessing it directly and try again.",
"error": "Не удалось обратиться к Vikunja по адресу «{domain}». Проверьте, правильный ли адрес и можете ли вы открыть его напрямую, и попробуйте ещё раз.",
"success": "Используется Vikunja на \"{domain}\".",
"urlRequired": "Требуется url."
},
@ -1096,28 +1101,28 @@
"tasks": "Задачи",
"projects": "Проекты",
"teams": "Команды",
"labels": "Labels",
"labels": "Метки",
"newProject": "Введите название проекта…",
"newTask": "Введите название задачи…",
"newTeam": "Введите название новой команды…",
"createTask": "Создать задачу в текущем проекте ({title})",
"createProject": "Создать проект",
"cmds": {
"newTask": "Новая задача",
"newTask": "Создать задачу",
"newProject": "Создать проект",
"newTeam": "Новая команда"
"newTeam": "Создать команду"
}
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {
"reactedWith": "{user} reacted with {value}",
"reactedWithAnd": "{users} and {lastUser} reacted with {value}",
"reactedWithAndMany": "{users} and {num} more reacted reacted with {value}",
"add": "Add your reaction"
"reactedWith": "Реакция от {user}: {value}",
"reactedWithAnd": "Реакции от {users} и {lastUser}: {value}",
"reactedWithAndMany": "Реакции от {users} и ещё {num}: {value}",
"add": "Добавить реакцию"
},
"error": {
"error": "Ошибка",
@ -1192,17 +1197,17 @@
},
"about": {
"title": "О Vikunja",
"version": "Version: {version}"
"version": "Версия: {version}"
},
"time": {
"units": {
"seconds": "second|seconds",
"minutes": "minute|minutes",
"hours": "hour|hours",
"days": "day|days",
"weeks": "week|weeks",
"months": "month|months",
"years": "year|years"
"seconds": "секунда|секунды|секунд",
"minutes": "минута|минуты|минут",
"hours": "час|часа|часов",
"days": "день|дня|дней",
"weeks": "неделя|недели|недель",
"months": "месяц|месяца|месяцев",
"years": "год|года|лет"
}
}
}

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Prijava z {provider}",
"authenticating": "Avtentikacija…",
"openIdStateError": "Stanje se ne ujema, prekinjam!",
"openIdGeneralError": "Med preverjanjem pristnosti preko zunanje aplikacije je prišlo do napake.",
"openIdGeneralError": "Med preverjanjem pristnosti zunanje povezave je prišlo do napake.",
"logout": "Odjava",
"emailInvalid": "Prosim vnesite veljaven e-poštni naslov.",
"usernameRequired": "Prosim vnesite uporabniško ime.",
@ -66,7 +66,8 @@
"hidePassword": "Skrijte geslo",
"noAccountYet": "Še nimate računa?",
"alreadyHaveAnAccount": "Že imate račun?",
"remember": "Ostanite prijavljeni"
"remember": "Ostanite prijavljeni",
"registrationDisabled": "Registracija je onemogočena."
},
"settings": {
"title": "Nastavitve",
@ -95,6 +96,7 @@
"weekStartMonday": "Ponedeljek",
"language": "Jezik",
"defaultProject": "Privzeti projekt",
"defaultView": "Privzeti pogled",
"timezone": "Časovni pas",
"overdueTasksRemindersTime": "Ura e-poštnega opomnika za zapadla naloge",
"filterUsedOnOverview": "Shranjen filter, ki bo uporabljen na strani s pregledom"
@ -227,8 +229,8 @@
"title": "Arhiviraj \"{project}\"",
"archive": "Arhiviraj projekt",
"unarchive": "Odstrani projekt iz arhiva",
"unarchiveText": "Ustvarili boste lahko nove naloge ali jih uredili.",
"archiveText": "Dokler ga ne odstranite iz arhiva, tega projekta ne boste mogli urejati ali ustvarjati novih nalog.",
"unarchiveText": "Ustvarili boste lahko naloge ali jih urejali.",
"archiveText": "Tega projekta ne boste mogli urejati ali ustvarjati opravil, dokler ga ne odstranite iz arhiva.",
"success": "Projekt je bil uspešno arhiviran."
},
"background": {
@ -314,12 +316,15 @@
"delete": "Izbriši"
}
},
"first": {
"title": "Prvi pogled"
},
"list": {
"title": "Seznam",
"add": "Dodaj",
"addPlaceholder": "Dodaj novo nalogo…",
"addPlaceholder": "Dodaj nalogo…",
"empty": "Projekt je trenutno prazen.",
"newTaskCta": "Ustvari novo nalogo.",
"newTaskCta": "Ustvari nalogo.",
"editTask": "Uredi nalogo"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Vnesite nov naslov naloge…",
"addTask": "Dodaj nalogo",
"addAnotherTask": "Dodaj še eno nalogo",
"addBucket": "Ustvari novo vedro",
"addBucket": "Ustvari vedro",
"addBucketPlaceholder": "Vnesi nov naslov vedra…",
"deleteHeaderBucket": "Izbriši vedro",
"deleteBucketText1": "Ali ste prepričani, da želite izbrisati to vedro?",
@ -507,7 +512,7 @@
"search": "Začni tipkati za iskanje oznake…",
"create": {
"header": "Nova oznaka",
"title": "Ustvari novo oznako",
"title": "Ustvari oznako",
"titleRequired": "Prosim določite naslov.",
"success": "Oznaka je bila uspešno ustvarjena."
},
@ -642,7 +647,7 @@
"placeholder": "Začni tipkati besedilo ali pritisni '/', da vidiš več možnosti…"
},
"multiselect": {
"createPlaceholder": "Ustvari novo",
"createPlaceholder": "Ustvari",
"selectPlaceholder": "Za izbiro kliknite ali pritisnite enter"
},
"datepickerRange": {
@ -721,7 +726,7 @@
},
"task": {
"task": "Naloga",
"new": "Ustvari novo nalogo",
"new": "Ustvari opravilo",
"delete": "Izbriši nalogo",
"createSuccess": "Naloga je bila uspešno ustvarjena.",
"addReminder": "Dodaj nov opomnik…",
@ -883,8 +888,8 @@
"relation": {
"add": "Dodajte novo povezavo naloge",
"new": "Nova povezava naloge",
"searchPlaceholder": "Novo nalogo, ki jo želite dodati kot povezano, poiščite s tipkanjem…",
"createPlaceholder": "Dodaj kot novo povezavo naloge",
"searchPlaceholder": "Vnesite iskanje za nalogo, ki jo želite dodati kot povezano…",
"createPlaceholder": "Dodaj kot povezavo naloge",
"differentProject": "Ta naloga pripada drugemu projektu.",
"noneYet": "Naloge še nimajo povezav.",
"delete": "Izbriši povezavo nalog",
@ -922,7 +927,7 @@
"every30d": "Vsakih 30 dni",
"mode": "Način ponavljanja",
"monthly": "Mesečno",
"fromCurrentDate": "Od trenutnega datuma",
"fromCurrentDate": "Od datuma dokončanja",
"each": "Vsak",
"specifyAmount": "Določi znesek…",
"hours": "Ur",
@ -962,7 +967,7 @@
"title": "Ekipe",
"noTeams": "Trenutno niste del nobene ekipe.",
"create": {
"title": "Ustvari novo ekipo",
"title": "Ustvari ekipo",
"success": "Ekipa je bila uspešno ustvarjena."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Podvoji",
"delete": "Izbriši",
"unarchive": "Odstrani iz arhiva",
"setBackground": "Nastavi ozadje",
"setBackground": "Nastavitve ozadja",
"share": "Skupna raba",
"newProject": "Nov projekt",
"createProject": "Ustvari projekt",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "sl",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Logga in med {provider}",
"authenticating": "Autentiserar…",
"openIdStateError": "State does not match, refusing to continue!",
"openIdGeneralError": "An error occured while authenticating against the third party.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logga ut",
"emailInvalid": "Vänligen ange en giltig e-postadress.",
"usernameRequired": "Vänligen ange ett användarnamn.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Har du inget konto än?",
"alreadyHaveAnAccount": "Har du redan ett konto?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Inställningar",
@ -95,6 +96,7 @@
"weekStartMonday": "Måndag",
"language": "Språk",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Tidszon",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Arkivera \"{project}\"",
"archive": "Arkivera detta projekt",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Namn (valfritt)",
"namePlaceholder": "t. ex. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Radera"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Lägg till",
"addPlaceholder": "Lägg till en ny uppgift…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Skapa en ny uppgift.",
"newTaskCta": "Create a task.",
"editTask": "Redigera uppgift"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Lägg till en uppgift",
"addAnotherTask": "Lägg till ytterligare en uppgift",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Skriv för att söka efter en etikett…",
"create": {
"header": "Ny etikett",
"title": "Skapa ny etikett",
"title": "Create a label",
"titleRequired": "Vänligen ange en titel.",
"success": "Etiketten har skapats."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Autentiserar…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "Ett fel har inträffat.",
"error": "An error occurred.",
"invalidPassword": "Lösenordet är ogiltigt."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Skapa",
"selectPlaceholder": "Klicka eller tryck på enter för att välja"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Uppgift",
"new": "Skapa en ny uppgift",
"new": "Skapa en uppgift",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Lägg till ny påminnelse…",
"addReminder": "Lägg till en påminnelse…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Ångra",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Skriv för att lägga till en ny etikett…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Lägg till som ny etikett",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Timmar",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicera",
"delete": "Radera",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Dela",
"newProject": "Nytt projekt",
"createProject": "Skapa projekt",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "Đăng nhập với {provider}",
"authenticating": "Đang xác thực…",
"openIdStateError": "Trạng thái không khớp, từ chối tiếp tục!",
"openIdGeneralError": "Đã xảy ra lỗi khi xác thực với bên thứ ba.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Đăng xuất",
"emailInvalid": "Vui lòng nhập một địa chỉ email hợp lệ.",
"usernameRequired": "Vui lòng cung cấp tên người dùng.",
@ -66,7 +66,8 @@
"hidePassword": "Ẩn mật khẩu",
"noAccountYet": "Bạn chưa có tài khoản?",
"alreadyHaveAnAccount": "Đã có tài khoản?",
"remember": "Duy trì đăng nhập"
"remember": "Duy trì đăng nhập",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Cài đặt",
@ -95,6 +96,7 @@
"weekStartMonday": "Thứ hai",
"language": "Ngôn ngữ",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Múi giờ",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "Bộ lọc đã lưu mới",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Tạo thêm bộ lọc sẵn",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Gõ để tìm kiếm nhãn…",
"create": {
"header": "Nhãn mới",
"title": "Tạo một nhãn mới",
"title": "Create a label",
"titleRequired": "Hãy đặt một tiêu đề.",
"success": "Nhãn đã được tạo thành công."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Đang xác thực…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "Đã xảy ra lỗi.",
"error": "An error occurred.",
"invalidPassword": "Mật khẩu không hợp lệ."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Tạo mới",
"createPlaceholder": "Create",
"selectPlaceholder": "Nhấp hoặc nhấn enter để chọn"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Công việc",
"new": "Tạo một công việc mới",
"new": "Create a task",
"delete": "Xóa công việc này",
"createSuccess": "Công việc đã được tạo thành công.",
"addReminder": "Thêm lời nhắc mới…",
"addReminder": "Add a reminder…",
"doneSuccess": "Công việc đã được đánh dấu Hoàn thành.",
"undoneSuccess": "Công việc đã được bỏ đánh dấu Hoàn thành.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "Bỏ chỉ định thành công."
},
"label": {
"placeholder": "Nhập để thêm nhãn mới…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Thêm nhãn mới này",
"addSuccess": "Nhãn đã được thêm thành công.",
"createSuccess": "Nhãn đã được thêm thành công.",
@ -883,8 +888,8 @@
"relation": {
"add": "Thêm một Công việc liên quan",
"new": "Công việc liên quan mới",
"searchPlaceholder": "Gõ tìm kiếm một công việc để thêm dưới dạng liên quan…",
"createPlaceholder": "Thêm điều này làm công việc liên quan mới",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "Không có công việc liên quan nào.",
"delete": "Xóa công việc liên quan",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Chế độ lặp lại",
"monthly": "Hàng tháng",
"fromCurrentDate": "Từ ngày hiện tại",
"fromCurrentDate": "From completion date",
"each": "Mỗi",
"specifyAmount": "Chỉ định một số lượng…",
"hours": "Giờ",
@ -962,7 +967,7 @@
"title": "Team",
"noTeams": "Bạn chưa thuộc bất kỳ Team nào.",
"create": {
"title": "Thêm một Team mới",
"title": "Create a team",
"success": "Team đã được tạo thành công."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Nhân bản",
"delete": "Xóa",
"unarchive": "Bỏ lưu trữ",
"setBackground": "Cài hình nền",
"setBackground": "Background settings",
"share": "Chia sẻ",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"loginWith": "以 {provider} 身份登录",
"authenticating": "验证中",
"openIdStateError": "状态不匹配,无法继续!",
"openIdGeneralError": "在验证第三方时出错。",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "注销",
"emailInvalid": "请输入有效的电子邮件地址。",
"usernameRequired": "请输入用户名",
@ -66,7 +66,8 @@
"hidePassword": "隐藏密码",
"noAccountYet": "还没有账号?",
"alreadyHaveAnAccount": "已有账户?",
"remember": "保持登录状态"
"remember": "保持登录状态",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "设置",
@ -95,6 +96,7 @@
"weekStartMonday": "星期一",
"language": "语言设置",
"defaultProject": "默认项目",
"defaultView": "Default View",
"timezone": "时区",
"overdueTasksRemindersTime": "逾期任务提醒邮件时间",
"filterUsedOnOverview": "概述页面上使用已保存过滤器"
@ -227,8 +229,8 @@
"title": "存档 \"{project}\"",
"archive": "存档此项目",
"unarchive": "取消存档此项目",
"unarchiveText": "您将能够创建新任务或编辑此项目",
"archiveText": "在您取消归档之前,您将无法编辑此项目或创建新任务。",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "项目已成功归档。"
},
"background": {
@ -277,7 +279,7 @@
"title": "共享链接",
"what": "什么是共享链接?",
"explanation": "共享链接使您能够轻松地与其他未注册账户的访客共享一个列表。",
"create": "创建一个新的共享链接",
"create": "Create a link share",
"name": "共享链接名称 (可选)",
"namePlaceholder": "例如Lorem Ipsum",
"nameExplanation": "此共享链接中的所有动作都将显示该名称。",
@ -314,12 +316,15 @@
"delete": "删除"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "列表",
"add": "添加",
"addPlaceholder": "添加新任务",
"addPlaceholder": "Add a task…",
"empty": "此项目目前为空。",
"newTaskCta": "新建任务。",
"newTaskCta": "Create a task.",
"editTask": "编辑任务"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "输入新任务标题…",
"addTask": "添加任务",
"addAnotherTask": "添加另一个任务",
"addBucket": "创建一个新的存储桶。",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "输入新的存储桶标题…",
"deleteHeaderBucket": "删除存储桶",
"deleteBucketText1": "您确定要删除此存储桶吗?",
@ -423,7 +428,7 @@
"create": {
"title": "新保存的过滤器",
"description": "保存的过滤器是一个虚拟工程,每次访问时都从一组过滤器中计算。",
"action": "创建新保存的过滤器",
"action": "Create saved filter",
"titleRequired": "请为该过滤器提供名称。"
},
"delete": {
@ -507,7 +512,7 @@
"search": "输入以搜索标签…",
"create": {
"header": "新建标记",
"title": "创建标签",
"title": "Create a label",
"titleRequired": "请指定标题",
"success": "已新建标签"
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "验证中……",
"passwordRequired": "此共享项目需要密码。请在下面输入:",
"error": "发生错误",
"error": "An error occurred.",
"invalidPassword": "密码错误"
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "输入一些文本或点击“/”查看更多选项…"
},
"multiselect": {
"createPlaceholder": "创建新的",
"createPlaceholder": "Create",
"selectPlaceholder": "点击或按 Enter 选择"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "任务",
"new": "新建任务",
"new": "Create a task",
"delete": "删除此任务",
"createSuccess": "成功创建任务",
"addReminder": "添加一个新的提醒…",
"addReminder": "Add a reminder…",
"doneSuccess": "待办事项已标记为完成。",
"undoneSuccess": "待办事项已标记为未完成。",
"undo": "撤销",
@ -860,7 +865,7 @@
"unassignSuccess": "已成功取消分配用户。"
},
"label": {
"placeholder": "添加一个新标签…",
"placeholder": "Type to add a label…",
"createPlaceholder": "将此添加为新标签",
"addSuccess": "已成功添加标签。",
"createSuccess": "已成功创建标签。",
@ -883,8 +888,8 @@
"relation": {
"add": "添加新任务关系",
"new": "新任务关系",
"searchPlaceholder": "输入以搜索要添加关联的新任务...",
"createPlaceholder": "添加为新的关联任务",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "此任务属于另一个项目。",
"noneYet": "还没有任务关联。",
"delete": "删除关联",
@ -922,7 +927,7 @@
"every30d": "每 30 天",
"mode": "重复模式",
"monthly": "每月",
"fromCurrentDate": "从当前日期",
"fromCurrentDate": "From completion date",
"each": "每个",
"specifyAmount": "指定数量…",
"hours": "小时",
@ -962,7 +967,7 @@
"title": "团队",
"noTeams": "你目前不属于任何团队。",
"create": {
"title": "创建一个新团队。",
"title": "Create a team",
"success": "团队已成功创建。"
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "复制",
"delete": "删除",
"unarchive": "取消存档",
"setBackground": "设置背景",
"setBackground": "Background settings",
"share": "共享",
"newProject": "新项目",
"createProject": "创建项目",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "中文",
"altFormatLong": "Y M d H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -53,7 +53,7 @@
"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.",
"openIdGeneralError": "An error occurred while authenticating against the third party.",
"logout": "Logout",
"emailInvalid": "Please enter a valid email address.",
"usernameRequired": "Please provide a username.",
@ -66,7 +66,8 @@
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"remember": "Stay logged in"
"remember": "Stay logged in",
"registrationDisabled": "Registration is disabled."
},
"settings": {
"title": "Settings",
@ -95,6 +96,7 @@
"weekStartMonday": "Monday",
"language": "Language",
"defaultProject": "Default Project",
"defaultView": "Default View",
"timezone": "Time Zone",
"overdueTasksRemindersTime": "Overdue tasks reminder email time",
"filterUsedOnOverview": "Saved filter used on the overview page"
@ -227,8 +229,8 @@
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"unarchiveText": "You will be able to create tasks or edit it.",
"archiveText": "You won't be able to edit this project or create tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
@ -277,7 +279,7 @@
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"create": "Create a link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
@ -314,12 +316,15 @@
"delete": "Delete"
}
},
"first": {
"title": "First View"
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"addPlaceholder": "Add a task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"newTaskCta": "Create a task.",
"editTask": "Edit Task"
},
"gantt": {
@ -352,7 +357,7 @@
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucket": "Create a bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
@ -423,7 +428,7 @@
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"action": "Create saved filter",
"titleRequired": "Please provide a title for the filter."
},
"delete": {
@ -507,7 +512,7 @@
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"title": "Create a label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
@ -528,7 +533,7 @@
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "An error occured.",
"error": "An error occurred.",
"invalidPassword": "The password is invalid."
},
"navigation": {
@ -642,7 +647,7 @@
"placeholder": "Type some text or hit '/' to see more options…"
},
"multiselect": {
"createPlaceholder": "Create new",
"createPlaceholder": "Create",
"selectPlaceholder": "Click or press enter to select"
},
"datepickerRange": {
@ -721,10 +726,10 @@
},
"task": {
"task": "Task",
"new": "Create a new task",
"new": "Create a task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"addReminder": "Add a reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"undo": "Undo",
@ -860,7 +865,7 @@
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"placeholder": "Type to add a label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
@ -883,8 +888,8 @@
"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",
"searchPlaceholder": "Type search for a task to add as related…",
"createPlaceholder": "Add this as related task",
"differentProject": "This task belongs to a different project.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
@ -922,7 +927,7 @@
"every30d": "Every 30 Days",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"fromCurrentDate": "From completion date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
@ -962,7 +967,7 @@
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"title": "Create a team",
"success": "The team was successfully created."
},
"edit": {
@ -1060,7 +1065,7 @@
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"setBackground": "Background settings",
"share": "Share",
"newProject": "New project",
"createProject": "Create project",
@ -1110,7 +1115,7 @@
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatLong": "j M Y, H:i",
"altFormatShort": "j M Y"
},
"reaction": {

View File

@ -23,6 +23,7 @@ export const DAYJS_LOCALE_MAPPING = {
'ar-SA': 'ar-sa',
'sl-SI': 'sl',
'pt-BR': 'pt',
'hr-HR': 'hr',
} as Record<SupportedLocale, ISOLanguage>
export const DAYJS_LANGUAGE_IMPORTS = {

View File

@ -1,8 +1,19 @@
import type {IAbstract} from './IAbstract'
import type {IProject} from '@/modelTypes/IProject'
export const PROJECT_VIEW_KINDS = ['list', 'gantt', 'table', 'kanban']
export type ProjectViewKind = typeof PROJECT_VIEW_KINDS[number]
export const PROJECT_VIEW_KINDS = {
LIST: 'list',
GANTT: 'gantt',
TABLE: 'table',
KANBAN: 'kanban',
} as const
export type ProjectViewKind = typeof PROJECT_VIEW_KINDS[keyof typeof PROJECT_VIEW_KINDS]
export const DEFAULT_PROJECT_VIEW_SETTINGS = {
FIRST: 'first',
...PROJECT_VIEW_KINDS,
} as const
export type DefaultProjectViewKind = typeof DEFAULT_PROJECT_VIEW_SETTINGS[keyof typeof DEFAULT_PROJECT_VIEW_SETTINGS]
export const PROJECT_VIEW_BUCKET_CONFIGURATION_MODES = ['none', 'manual', 'filter']
export type ProjectViewBucketConfigurationMode = typeof PROJECT_VIEW_BUCKET_CONFIGURATION_MODES[number]

View File

@ -45,7 +45,6 @@ export interface ITask extends IAbstract {
subscription: ISubscription
position: number
kanbanPosition: number
reactions: IReactionPerEntity

View File

@ -4,12 +4,14 @@ import type {IProject} from './IProject'
import type {PrefixMode} from '@/modules/parseTaskText'
import type {BasicColorSchema} from '@vueuse/core'
import type {SupportedLocale} from '@/i18n'
import type {DefaultProjectViewKind} from '@/modelTypes/IProjectView'
export interface IFrontendSettings {
playSoundWhenDone: boolean
quickAddMagicMode: PrefixMode
colorSchema: BasicColorSchema
filterIdUsedOnOverview: IProject['id'] | null
defaultView?: DefaultProjectViewKind
}
export interface IUserSettings extends IAbstract {
@ -22,6 +24,6 @@ export interface IUserSettings extends IAbstract {
defaultProjectId: undefined | IProject['id']
weekStart: 0 | 1 | 2 | 3 | 4 | 5 | 6
timezone: string
language: SupportedLocale
language: SupportedLocale | null
frontendSettings: IFrontendSettings
}

View File

@ -85,7 +85,6 @@ export default class TaskModel extends AbstractModel<ITask> implements ITask {
subscription: ISubscription = null
position = 0
kanbanPosition = 0
reactions = {}

View File

@ -3,6 +3,7 @@ import AbstractModel from './abstractModel'
import type {IFrontendSettings, IUserSettings} from '@/modelTypes/IUserSettings'
import {getBrowserLanguage} from '@/i18n'
import {PrefixMode} from '@/modules/parseTaskText'
import {DEFAULT_PROJECT_VIEW_SETTINGS} from '@/modelTypes/IProjectView'
export default class UserSettingsModel extends AbstractModel<IUserSettings> implements IUserSettings {
name = ''
@ -19,6 +20,7 @@ export default class UserSettingsModel extends AbstractModel<IUserSettings> impl
playSoundWhenDone: true,
quickAddMagicMode: PrefixMode.Default,
colorSchema: 'auto',
defaultView: DEFAULT_PROJECT_VIEW_SETTINGS.FIRST,
}
constructor(data: Partial<IUserSettings> = {}) {

View File

@ -804,6 +804,17 @@ describe('Parse Task Text', () => {
expect(result?.repeats?.type).toBe(cases[c].type)
expect(result?.repeats?.amount).toBe(cases[c].amount)
})
it(`should parse ${c} as recurring date every ${cases[c].amount} ${cases[c].type} at 11:42`, () => {
const result = parseTaskText(`Lorem Ipsum ${c} at 11:42`)
expect(result.text).toBe('Lorem Ipsum')
expect(result?.repeats?.type).toBe(cases[c].type)
expect(result?.repeats?.amount).toBe(cases[c].amount)
const now = new Date()
expect(`${result?.date?.getFullYear()}-${result?.date?.getMonth()}-${result?.date?.getDate()}`).toBe(`${now.getFullYear()}-${now.getMonth()}-${now.getDate()}`)
expect(`${result?.date?.getHours()}:${result?.date?.getMinutes()}`).toBe('11:42')
})
}
const wordCases = [

View File

@ -261,9 +261,14 @@ const getRepeats = (text: string): repeatParsedResult => {
break
}
}
let matchedText = results[0]
if(matchedText.endsWith(' ')) {
matchedText = matchedText.substring(0, matchedText.length - 1)
}
return {
textWithoutMatched: text.replace(results[0], ''),
textWithoutMatched: text.replace(matchedText, ''),
repeats: {
amount,
type,

View File

@ -52,12 +52,16 @@ export default class ProjectService extends AbstractService<IProject> {
return window.URL.createObjectURL(new Blob([response.data]))
}
async removeBackground(project: Pick<IProject, 'id'>) {
async removeBackground(project: IProject) {
const cancel = this.setLoading()
try {
const response = await this.http.delete(`/projects/${project.id}/background`, project)
return response.data
await this.http.delete(`/projects/${project.id}/background`)
return {
...project,
backgroundInformation: null,
backgroundBlurHash: '',
}
} finally {
cancel()
}

View File

@ -5,13 +5,14 @@ import type {ITask} from '@/modelTypes/ITask'
import BucketModel from '@/models/bucket'
export interface TaskFilterParams {
sort_by: ('start_date' | 'end_date' | 'due_date' | 'done' | 'id' | 'position' | 'kanban_position')[],
sort_by: ('start_date' | 'end_date' | 'due_date' | 'done' | 'id' | 'position')[],
order_by: ('asc' | 'desc')[],
filter: string,
filter_include_nulls: boolean,
filter_timezone?: string,
s: string,
per_page?: number,
expand?: 'subtasks' | null,
}
export function getDefaultTaskFilterParams(): TaskFilterParams {
@ -22,6 +23,7 @@ export function getDefaultTaskFilterParams(): TaskFilterParams {
filter_include_nulls: false,
filter_timezone: '',
s: '',
expand: 'subtasks',
}
}

View File

@ -37,6 +37,8 @@ function redirectToProviderIfNothingElseIsEnabled() {
}
export const useAuthStore = defineStore('auth', () => {
const configStore = useConfigStore()
const authenticated = ref(false)
const isLinkShareAuth = ref(false)
const needsTotpPasscode = ref(false)
@ -185,8 +187,7 @@ export const useAuthStore = defineStore('auth', () => {
const HTTP = HTTPFactory()
setIsLoading(true)
const {auth} = useConfigStore()
const fullProvider: IProvider = auth.openidConnect.providers.find((p: IProvider) => p.key === provider)
const fullProvider: IProvider = configStore.auth.openidConnect.providers.find((p: IProvider) => p.key === provider)
const data = {
code: code,
@ -357,8 +358,15 @@ export const useAuthStore = defineStore('auth', () => {
const cancel = setModuleLoading(setIsLoadingGeneralSettings)
try {
const updateSettingsPromise = userSettingsService.update(settings)
setUserSettings({...settings})
let settingsUpdate = {...settings}
if (configStore.demoModeEnabled) {
settingsUpdate = {
...settingsUpdate,
language: null,
}
}
const updateSettingsPromise = userSettingsService.update(settingsUpdate)
setUserSettings(settingsUpdate)
await setLanguage(settings.language)
await updateSettingsPromise
if (showMessage) {
@ -403,13 +411,12 @@ export const useAuthStore = defineStore('auth', () => {
await checkAuth()
// if configured, redirect to OIDC Provider on logout
const {auth} = useConfigStore()
if (
auth.local.enabled === false &&
auth.openidConnect.enabled &&
auth.openidConnect.providers?.length === 1)
configStore.auth.local.enabled === false &&
configStore.auth.openidConnect.enabled &&
configStore.auth.openidConnect.providers?.length === 1)
{
redirectToProviderOnLogout(auth.openidConnect.providers[0])
redirectToProviderOnLogout(configStore.auth.openidConnect.providers[0])
}
}

View File

@ -14,33 +14,4 @@
border-radius: $radius !important;
}
}
}
.link-share-container {
&.project\.gantt-view,
&.project\.kanban-view {
.container {
max-width: 100vw;
.column {
width: 100%;
margin: 0;
}
}
}
}
.link-share-container:not(.has-background) {
.list-view {
max-width: 100%;
}
.loader-container, .gantt-chart-container > .card {
box-shadow: none !important;
border: none;
.task-add {
padding: 1rem 0 0;
}
}
}

View File

@ -8,6 +8,8 @@ import ProjectList from '@/components/project/views/ProjectList.vue'
import ProjectGantt from '@/components/project/views/ProjectGantt.vue'
import ProjectTable from '@/components/project/views/ProjectTable.vue'
import ProjectKanban from '@/components/project/views/ProjectKanban.vue'
import {useAuthStore} from '@/stores/auth'
import {DEFAULT_PROJECT_VIEW_SETTINGS} from '@/modelTypes/IProjectView'
const {
projectId,
@ -19,6 +21,7 @@ const {
const router = useRouter()
const projectStore = useProjectStore()
const authStore = useAuthStore()
const currentView = computed(() => {
const project = projectStore.projects[projectId]
@ -26,17 +29,27 @@ const currentView = computed(() => {
return project?.views.find(v => v.id === viewId)
})
function redirectToFirstViewIfNecessary() {
function redirectToDefaultViewIfNecessary() {
if (viewId === 0 || !projectStore.projects[projectId]?.views.find(v => v.id === viewId)) {
// Ideally, we would do that in the router redirect, but the projects (and therefore, the views)
// are not always loaded then.
const firstViewId = projectStore.projects[projectId]?.views[0].id
if (firstViewId) {
let view
if (authStore.settings.frontendSettings.defaultView !== DEFAULT_PROJECT_VIEW_SETTINGS.FIRST) {
view = projectStore.projects[projectId]?.views.find(v => v.viewKind === authStore.settings.frontendSettings.defaultView)
}
// Use the first view as fallback if the default view is not available
if (view === undefined && projectStore.projects[projectId]?.views?.length > 0) {
view = projectStore.projects[projectId]?.views[0]
}
if (view) {
router.replace({
name: 'project.view',
params: {
projectId,
viewId: firstViewId,
viewId: view.id,
},
})
}
@ -45,13 +58,13 @@ function redirectToFirstViewIfNecessary() {
watch(
() => viewId,
redirectToFirstViewIfNecessary,
redirectToDefaultViewIfNecessary,
{immediate: true},
)
watch(
() => projectStore.projects[projectId],
redirectToFirstViewIfNecessary,
redirectToDefaultViewIfNecessary,
)
// using a watcher instead of beforeEnter because beforeEnter is not called when only the viewId changes

View File

@ -162,7 +162,7 @@ const configStore = useConfigStore()
const unsplashBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('unsplash'))
const uploadBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('upload'))
const currentProject = computed(() => baseStore.currentProject)
const hasBackground = computed(() => baseStore.background !== null)
const hasBackground = computed(() => !!currentProject.value.backgroundInformation)
// Show the default collection of backgrounds
newBackgroundSearch()

View File

@ -111,6 +111,7 @@ async function saveView() {
>
<XButton
:loading="projectViewService.loading"
:disabled="showCreateForm && newView.title === ''"
@click="createView"
>
{{ $t('project.views.create') }}
@ -144,22 +145,11 @@ async function saveView() {
<ViewEditForm
v-model="viewToEdit"
class="mb-4"
:loading="projectViewService.loading"
:show-save-buttons="true"
@cancel="viewToEdit = null"
@update:modelValue="saveView"
/>
<div class="is-flex is-justify-content-end">
<XButton
variant="tertiary"
class="mr-2"
@click="viewToEdit = null"
>
{{ $t('misc.cancel') }}
</XButton>
<XButton
:loading="projectViewService.loading"
@click="saveView"
>
{{ $t('misc.save') }}
</XButton>
</div>
</td>
</template>
<template v-else>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div v-if="configStore.registrationEnabled">
<Message
v-if="errorMessage !== ''"
variant="danger"
@ -107,6 +107,12 @@
</p>
</form>
</div>
<Message
v-else
variant="warning"
>
{{ $t('user.auth.registrationDisabled') }}
</Message>
</template>
<script setup lang="ts">
@ -160,17 +166,17 @@ const validateUsername = useDebounceFn(() => {
usernameValid.value = t('user.auth.usernameRequired')
return
}
if(credentials.username.indexOf(' ') !== -1) {
if (credentials.username.indexOf(' ') !== -1) {
usernameValid.value = t('user.auth.usernameMustNotContainSpace')
return
}
if(credentials.username.indexOf('://') !== -1) {
if (credentials.username.indexOf('://') !== -1) {
usernameValid.value = t('user.auth.usernameMustNotLookLikeUrl')
return
}
usernameValid.value = true
}, DEBOUNCE_TIME)

View File

@ -47,7 +47,17 @@ const flatPickerConfig = computed(() => ({
onMounted(async () => {
tokens.value = await service.getAll()
availableRoutes.value = await service.getAvailableRoutes()
const allRoutes = await service.getAvailableRoutes()
const routesAvailable = {}
const keys = Object.keys(allRoutes)
keys.sort((a, b) => (a === 'other' ? 1 : b === 'other' ? -1 : 0))
keys.forEach(key => {
routesAvailable[key] = allRoutes[key]
})
availableRoutes.value = routesAvailable
resetPermissions()
})

View File

@ -26,6 +26,22 @@
</label>
<ProjectSearch v-model="defaultProject" />
</div>
<div class="field">
<label class="label">
{{ $t('user.settings.general.defaultView') }}
</label>
<div class="select">
<select v-model="settings.frontendSettings.defaultView">
<option
v-for="view in DEFAULT_PROJECT_VIEW_SETTINGS"
:key="view"
:value="view"
>
{{ $t(`project.${view}.title`) }}
</option>
</select>
</div>
</div>
<div
v-if="hasFilters"
class="field"
@ -221,6 +237,7 @@ import {useProjectStore} from '@/stores/projects'
import {useAuthStore} from '@/stores/auth'
import type {IUserSettings} from '@/modelTypes/IUserSettings'
import {isSavedFilter} from '@/services/savedFilter'
import {DEFAULT_PROJECT_VIEW_SETTINGS} from '@/modelTypes/IProjectView'
const {t} = useI18n({useScope: 'global'})
useTitle(() => `${t('user.settings.general.title')} - ${t('user.settings.title')}`)
@ -253,12 +270,15 @@ function useAvailableTimezones() {
const availableTimezones = useAvailableTimezones()
const authStore = useAuthStore()
const settings = ref<IUserSettings>({
...authStore.settings,
frontendSettings: {
// Sub objects get exported as read only as well, so we need to
// explicitly spread the object here to allow modification
...authStore.settings.frontendSettings,
// Add fallback for old settings that don't have the default view set
defaultView: authStore.settings.frontendSettings.defaultView ?? DEFAULT_PROJECT_VIEW_SETTINGS.FIRST,
},
})
const id = ref(createRandomID())

4
go.mod
View File

@ -68,7 +68,7 @@ require (
github.com/ulule/limiter/v3 v3.11.2
github.com/wneessen/go-mail v0.4.0
github.com/yuin/goldmark v1.7.1
golang.org/x/crypto v0.22.0
golang.org/x/crypto v0.23.0
golang.org/x/image v0.16.0
golang.org/x/oauth2 v0.20.0
golang.org/x/sync v0.7.0
@ -190,4 +190,4 @@ replace github.com/samedi/caldav-go => github.com/kolaente/caldav-go v3.0.1-0.20
go 1.21
toolchain go1.21.2
toolchain go1.22.3

2
go.sum
View File

@ -574,6 +574,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=

View File

@ -21,14 +21,16 @@ import (
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(indexCmd)
rootCmd.AddCommand(partialReindexCmd)
}
var indexPartialFlag bool
var indexCmd = &cobra.Command{
Use: "index",
Short: "Reindex all of Vikunja's data into Typesense. This will remove any existing index.",
@ -41,48 +43,31 @@ var indexCmd = &cobra.Command{
return
}
log.Infof("Indexing… This may take a while.")
err := models.CreateTypesenseCollections()
if err != nil {
log.Criticalf("Could not create Typesense collections: %s", err.Error())
return
}
err = models.ReindexAllTasks()
if err != nil {
log.Criticalf("Could not reindex all tasks into Typesense: %s", err.Error())
return
if indexPartialFlag {
log.Infof("Indexing changed tasks… This may take a while.")
err = models.SyncUpdatedTasksIntoTypesense()
if err != nil {
log.Criticalf("Could not reindex all changed tasks into Typesense: %s", err.Error())
return
}
} else {
log.Infof("Indexing all tasks… This may take a while.")
err = models.ReindexAllTasks()
if err != nil {
log.Criticalf("Could not reindex all tasks into Typesense: %s", err.Error())
return
}
}
log.Infof("Done!")
},
}
var partialReindexCmd = &cobra.Command{
Use: "partial-index",
Short: "Reindex any tasks which were not indexed yet into Typesense. This will not remove any existing index.",
PreRun: func(_ *cobra.Command, _ []string) {
initialize.FullInitWithoutAsync()
},
Run: func(_ *cobra.Command, _ []string) {
if config.TypesenseURL.GetString() == "" {
log.Error("Typesense not configured")
return
}
log.Infof("Indexing… This may take a while.")
err := models.CreateTypesenseCollections()
if err != nil {
log.Criticalf("Could not create Typesense collections: %s", err.Error())
return
}
err = models.SyncUpdatedTasksIntoTypesense()
if err != nil {
log.Criticalf("Could not reindex all changed tasks into Typesense: %s", err.Error())
return
}
log.Infof("Done!")
},
func init() {
indexCmd.Flags().BoolVarP(&indexPartialFlag, "partial", "p", false, "If provided, Vikunja will only index those tasks which are not present in the index. It will not remove any existing tasks.")
}

View File

@ -23,7 +23,7 @@ import (
)
type buckets20240315093418 struct {
ID int64 `xorm:"bigint autoincr not null unique pk"`
ID int64 `xorm:"bigint autoincr not null"`
ProjectID int64 `xorm:"bigint not null"`
ProjectViewID int64 `xorm:"bigint not null default 0"`
}

View File

@ -0,0 +1,84 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-present Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public Licensee as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"regexp"
"strings"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
func convertChecklistInDescription(tx *xorm.Engine, table string, column string) (err error) {
items := []map[string]interface{}{}
err = tx.Table(table).
Select("id, " + column).
Find(&items)
if err != nil {
return
}
for _, item := range items {
if !strings.Contains(item[column].(string), "<li>[") {
continue
}
var re = regexp.MustCompile(`<ul>(\n)?<li>`)
item[column] = re.ReplaceAllString(item[column].(string), `<ul data-type="taskList"><li>`)
item[column] = strings.ReplaceAll(item[column].(string), "<li>[ ] ", `<li data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label>`)
item[column] = strings.ReplaceAll(item[column].(string), "<li>[x] ", `<li data-checked="true" data-type="taskItem"><label><input type="checkbox" checked="checked"><span></span></label>`)
_, err = tx.Where("id = ?", item["id"]).
Table(table).
Cols(column).
Update(item)
if err != nil {
return
}
}
return nil
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20240603172746",
Description: "Convert unconverted checklists to proper html",
Migrate: func(tx *xorm.Engine) (err error) {
for _, table := range []string{
"tasks",
"labels",
"projects",
"saved_filters",
"teams",
} {
err = convertChecklistInDescription(tx, table, "description")
if err != nil {
return
}
}
err = convertChecklistInDescription(tx, "task_comments", "comment")
return
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -18,6 +18,8 @@ package models
import (
"net/http"
"reflect"
"runtime"
"strings"
"code.vikunja.io/api/pkg/log"
@ -25,28 +27,22 @@ import (
"github.com/labstack/echo/v4"
)
var apiTokenRoutes = map[string]*APITokenRoute{}
var apiTokenRoutes = map[string]APITokenRoute{}
func init() {
apiTokenRoutes = make(map[string]*APITokenRoute)
apiTokenRoutes = make(map[string]APITokenRoute)
}
type APITokenRoute struct {
Create *RouteDetail `json:"create,omitempty"`
ReadOne *RouteDetail `json:"read_one,omitempty"`
ReadAll *RouteDetail `json:"read_all,omitempty"`
Update *RouteDetail `json:"update,omitempty"`
Delete *RouteDetail `json:"delete,omitempty"`
}
type APITokenRoute map[string]*RouteDetail
type RouteDetail struct {
Path string `json:"path"`
Method string `json:"method"`
}
func getRouteGroupName(path string) string {
func getRouteGroupName(path string) (finalName string, filteredParts []string) {
parts := strings.Split(strings.TrimPrefix(path, "/api/v1/"), "/")
filteredParts := []string{}
filteredParts = []string{}
for _, part := range parts {
if strings.HasPrefix(part, ":") {
continue
@ -55,63 +51,116 @@ func getRouteGroupName(path string) string {
filteredParts = append(filteredParts, part)
}
finalName := strings.Join(filteredParts, "_")
finalName = strings.Join(filteredParts, "_")
switch finalName {
case "projects_tasks":
fallthrough
case "tasks_all":
return "tasks"
return "tasks", []string{"tasks"}
default:
return finalName
return finalName, filteredParts
}
}
// CollectRoutesForAPITokenUsage gets called for every added APITokenRoute and builds a list of all routes we can use for the api tokens.
func CollectRoutesForAPITokenUsage(route echo.Route) {
func CollectRoutesForAPITokenUsage(route echo.Route, middlewares []echo.MiddlewareFunc) {
if !strings.Contains(route.Name, "(*WebHandler)") && !strings.Contains(route.Name, "Attachment") {
if route.Method == "echo_route_not_found" {
return
}
routeGroupName := getRouteGroupName(route.Path)
seenJWT := false
for _, middleware := range middlewares {
if strings.Contains(runtime.FuncForPC(reflect.ValueOf(middleware).Pointer()).Name(), "github.com/labstack/echo-jwt/") {
seenJWT = true
}
}
if routeGroupName == "subscriptions" ||
if !seenJWT {
return
}
routeGroupName, routeParts := getRouteGroupName(route.Path)
if routeGroupName == "user" ||
routeGroupName == "tokenTest" ||
routeGroupName == "subscriptions" ||
routeGroupName == "tokens" ||
routeGroupName == "*" ||
strings.HasPrefix(routeGroupName, "user_") ||
strings.HasSuffix(routeGroupName, "_bulk") {
return
}
if !strings.Contains(route.Name, "(*WebHandler)") && !strings.Contains(route.Name, "Attachment") {
routeDetail := &RouteDetail{
Path: route.Path,
Method: route.Method,
}
// We're trying to add routes to the routes of a matching "parent" - for
// example, projects_background should show up under "projects".
// To do this, we check if the route is a sub route of some other route
// and if that's the case, add it to its parent instead.
// Otherwise, we add it to the "other" key.
if len(routeParts) == 1 {
if _, has := apiTokenRoutes["other"]; !has {
apiTokenRoutes["other"] = make(APITokenRoute)
}
_, exists := apiTokenRoutes["other"][routeGroupName]
if exists {
routeGroupName += "_" + strings.ToLower(route.Method)
}
apiTokenRoutes["other"][routeGroupName] = routeDetail
return
}
subkey := strings.Join(routeParts[1:], "_")
if _, has := apiTokenRoutes[routeParts[0]]; !has {
apiTokenRoutes[routeParts[0]] = make(APITokenRoute)
}
if _, has := apiTokenRoutes[routeParts[0]][subkey]; has {
subkey += "_" + strings.ToLower(route.Method)
}
apiTokenRoutes[routeParts[0]][subkey] = routeDetail
return
}
_, has := apiTokenRoutes[routeGroupName]
if !has {
apiTokenRoutes[routeGroupName] = &APITokenRoute{}
apiTokenRoutes[routeGroupName] = make(APITokenRoute)
}
if strings.Contains(route.Name, "CreateWeb") {
apiTokenRoutes[routeGroupName].Create = &RouteDetail{
apiTokenRoutes[routeGroupName]["create"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
}
if strings.Contains(route.Name, "ReadOneWeb") {
apiTokenRoutes[routeGroupName].ReadOne = &RouteDetail{
apiTokenRoutes[routeGroupName]["read_one"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
}
if strings.Contains(route.Name, "ReadAllWeb") {
apiTokenRoutes[routeGroupName].ReadAll = &RouteDetail{
apiTokenRoutes[routeGroupName]["read_all"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
}
if strings.Contains(route.Name, "UpdateWeb") {
apiTokenRoutes[routeGroupName].Update = &RouteDetail{
apiTokenRoutes[routeGroupName]["update"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
}
if strings.Contains(route.Name, "DeleteWeb") {
apiTokenRoutes[routeGroupName].Delete = &RouteDetail{
apiTokenRoutes[routeGroupName]["delete"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
@ -119,13 +168,13 @@ func CollectRoutesForAPITokenUsage(route echo.Route) {
if routeGroupName == "tasks_attachments" {
if strings.Contains(route.Name, "UploadTaskAttachment") {
apiTokenRoutes[routeGroupName].Create = &RouteDetail{
apiTokenRoutes[routeGroupName]["create"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
}
if strings.Contains(route.Name, "GetTaskAttachment") {
apiTokenRoutes[routeGroupName].ReadOne = &RouteDetail{
apiTokenRoutes[routeGroupName]["read_one"] = &RouteDetail{
Path: route.Path,
Method: route.Method,
}
@ -149,37 +198,44 @@ func GetAvailableAPIRoutesForToken(c echo.Context) error {
func CanDoAPIRoute(c echo.Context, token *APIToken) (can bool) {
path := c.Path()
if path == "" {
// c.Path() is empty during testing, but returns the path which the route used during registration
// which is what we need.
// c.Path() is empty during testing, but returns the path which
// the route used during registration which is what we need.
path = c.Request().URL.Path
}
routeGroupName := getRouteGroupName(path)
routeGroupName, routeParts := getRouteGroupName(path)
group, hasGroup := token.Permissions[routeGroupName]
if !hasGroup {
return false
group, hasGroup = token.Permissions[routeParts[0]]
if !hasGroup {
return false
}
}
var route string
routes, has := apiTokenRoutes[routeGroupName]
if !has {
return false
routes, has = apiTokenRoutes[routeParts[0]]
if !has {
return false
}
route = strings.Join(routeParts[1:], "_")
}
if routes.Create != nil && routes.Create.Path == path && routes.Create.Method == c.Request().Method {
if routes["create"] != nil && routes["create"].Path == path && routes["create"].Method == c.Request().Method {
route = "create"
}
if routes.ReadOne != nil && routes.ReadOne.Path == path && routes.ReadOne.Method == c.Request().Method {
if routes["read_one"] != nil && routes["read_one"].Path == path && routes["read_one"].Method == c.Request().Method {
route = "read_one"
}
if routes.ReadAll != nil && routes.ReadAll.Path == path && routes.ReadAll.Method == c.Request().Method {
if routes["read_all"] != nil && routes["read_all"].Path == path && routes["read_all"].Method == c.Request().Method {
route = "read_all"
}
if routes.Update != nil && routes.Update.Path == path && routes.Update.Method == c.Request().Method {
if routes["update"] != nil && routes["update"].Path == path && routes["update"].Method == c.Request().Method {
route = "update"
}
if routes.Delete != nil && routes.Delete.Path == path && routes.Delete.Method == c.Request().Method {
if routes["delete"] != nil && routes["delete"].Path == path && routes["delete"].Method == c.Request().Method {
route = "delete"
}
@ -210,31 +266,7 @@ func PermissionsAreValid(permissions APIPermissions) (err error) {
}
for _, method := range methods {
if method == "create" && routes.Create == nil {
return &ErrInvalidAPITokenPermission{
Group: key,
Permission: method,
}
}
if method == "read_one" && routes.ReadOne == nil {
return &ErrInvalidAPITokenPermission{
Group: key,
Permission: method,
}
}
if method == "read_all" && routes.ReadAll == nil {
return &ErrInvalidAPITokenPermission{
Group: key,
Permission: method,
}
}
if method == "update" && routes.Update == nil {
return &ErrInvalidAPITokenPermission{
Group: key,
Permission: method,
}
}
if method == "delete" && routes.Delete == nil {
if routes[method] == nil {
return &ErrInvalidAPITokenPermission{
Group: key,
Permission: method,

View File

@ -189,11 +189,18 @@ func (la *TaskAssginee) Delete(s *xorm.Session, a web.Auth) (err error) {
return err
}
return events.Dispatch(&TaskAssigneeDeletedEvent{
err = events.Dispatch(&TaskAssigneeDeletedEvent{
Task: &task,
Assignee: &user.User{ID: la.UserID},
Doer: doer,
})
if err != nil {
return err
}
return events.Dispatch(&TaskUpdatedEvent{
Task: &task,
Doer: doer,
})
}
// Create adds a new assignee to a task
@ -281,7 +288,7 @@ func (t *Task) addNewAssigneeByID(s *xorm.Session, newAssigneeID int64, project
return err
}
err = events.Dispatch(&TaskUpdatedEvent{
Task: t,
Task: &task,
Doer: doer,
})
if err != nil {

View File

@ -45,12 +45,21 @@ type TaskCollection struct {
// If set to true, the result will also include null values
FilterIncludeNulls bool `query:"filter_include_nulls" json:"filter_include_nulls"`
// If set to `subtasks`, Vikunja will fetch only tasks which do not have subtasks and then in a
// second step, will fetch all of these subtasks. This may result in more tasks than the
// pagination limit being returned, but all subtasks will be present in the response.
Expand TaskCollectionExpandable `query:"expand" json:"-"`
isSavedFilter bool
web.CRUDable `xorm:"-" json:"-"`
web.Rights `xorm:"-" json:"-"`
}
type TaskCollectionExpandable string
const TaskCollectionExpandSubtasks TaskCollectionExpandable = `subtasks`
func validateTaskField(fieldName string) error {
switch fieldName {
case
@ -181,6 +190,7 @@ func getRelevantProjectsFromCollection(s *xorm.Session, a web.Auth, tf *TaskColl
// @Param filter query string false "The filter query to match tasks by. Check out https://vikunja.io/docs/filters for a full explanation of the feature."
// @Param filter_timezone query string false "The time zone which should be used for date match (statements like "now" resolve to different actual times)"
// @Param filter_include_nulls query string false "If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`."
// @Param expand query string false "If set to `subtasks`, Vikunja will fetch only tasks which do not have subtasks and then in a second step, will fetch all of these subtasks. This may result in more tasks than the pagination limit being returned, but all subtasks will be present in the response. You can only set this to `subtasks`."
// @Security JWTKeyAuth
// @Success 200 {array} models.Task "The tasks"
// @Failure 500 {object} models.Message "Internal error"
@ -251,6 +261,8 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa
opts.search = search
opts.page = page
opts.perPage = perPage
opts.expand = tf.Expand
opts.isSavedFilter = tf.isSavedFilter
if view != nil {
var hasOrderByPosition bool

View File

@ -47,11 +47,8 @@ func (tp *TaskPosition) TableName() string {
}
func (tp *TaskPosition) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
pv, err := GetProjectViewByID(s, tp.ProjectViewID)
if err != nil {
return false, err
}
return pv.CanUpdate(s, a)
t := &Task{ID: tp.TaskID}
return t.CanUpdate(s, a)
}
// Update is the handler to update a task position

View File

@ -255,7 +255,7 @@ func (d *dbTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task, totalCo
builder.Eq{"kind": FavoriteKindTask},
))
favoritesCond = builder.In("id", favCond)
favoritesCond = builder.In("tasks.id", favCond)
}
limit, start := getLimitFromPageIndex(opts.page, opts.perPage)
@ -266,6 +266,10 @@ func (d *dbTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task, totalCo
distinct += ", task_positions.position"
}
if opts.expand == TaskCollectionExpandSubtasks {
cond = builder.And(cond, builder.IsNull{"task_relations.id"})
}
query := d.s.
Distinct(distinct).
Where(cond)
@ -283,6 +287,9 @@ func (d *dbTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task, totalCo
if joinTaskBuckets {
query = query.Join("LEFT", "task_buckets", "task_buckets.task_id = tasks.id")
}
if opts.expand == TaskCollectionExpandSubtasks {
query = query.Join("LEFT", "task_relations", "tasks.id = task_relations.task_id and task_relations.relation_kind = 'parenttask'")
}
tasks = []*Task{}
err = query.
@ -292,10 +299,63 @@ func (d *dbTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task, totalCo
return nil, totalCount, err
}
// fetch subtasks when expanding
if opts.expand == TaskCollectionExpandSubtasks {
subtasks := []*Task{}
taskIDs := []int64{}
for _, task := range tasks {
taskIDs = append(taskIDs, task.ID)
}
inQuery := builder.Dialect(db.GetDialect()).
Select("*").
From("task_relations").
Where(builder.In("task_id", taskIDs))
inSQL, inArgs, err := inQuery.ToSQL()
if err != nil {
return nil, totalCount, err
}
inSQL = strings.TrimPrefix(inSQL, "SELECT * FROM task_relations WHERE")
err = d.s.SQL(`SELECT * FROM tasks WHERE id IN (WITH RECURSIVE sub_tasks AS (
SELECT task_id,
other_task_id,
relation_kind,
created_by_id,
created
FROM task_relations
WHERE `+inSQL+`
AND relation_kind = '`+string(RelationKindSubtask)+`'
UNION ALL
SELECT tr.task_id,
tr.other_task_id,
tr.relation_kind,
tr.created_by_id,
tr.created
FROM task_relations tr
INNER JOIN
sub_tasks st ON tr.task_id = st.other_task_id
WHERE tr.relation_kind = '`+string(RelationKindSubtask)+`')
SELECT other_task_id
FROM sub_tasks)`, inArgs...).Find(&subtasks)
if err != nil {
return nil, totalCount, err
}
tasks = append(tasks, subtasks...)
}
queryCount := d.s.Where(cond)
if joinTaskBuckets {
queryCount = queryCount.Join("LEFT", "task_buckets", "task_buckets.task_id = tasks.id")
}
if opts.expand == TaskCollectionExpandSubtasks {
queryCount = queryCount.Join("LEFT", "task_relations", "tasks.id = task_relations.task_id and task_relations.relation_kind = 'parenttask'")
}
totalCount, err = queryCount.
Select("count(DISTINCT tasks.id)").
Count(&Task{})
@ -450,14 +510,20 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
return nil, 0, err
}
filterBy := []string{
"project_id: [" + strings.Join(projectIDStrings, ", ") + "]",
"(" + filter + ")",
filterBy := []string{"project_id: [" + strings.Join(projectIDStrings, ", ") + "]"}
if filter != "" {
filterBy = append(filterBy, "("+filter+")")
}
var projectViewIDForPosition int64
var sortbyFields []string
for i, param := range opts.sortby {
var usedParams int
for _, param := range opts.sortby {
if opts.isSavedFilter && param.sortBy == taskPropertyPosition {
continue
}
// Validate the params
if err := param.validate(); err != nil {
return nil, totalCount, err
@ -472,16 +538,17 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
if param.sortBy == taskPropertyPosition {
sortBy = "positions.view_" + strconv.FormatInt(param.projectViewID, 10)
projectViewIDForPosition = param.projectViewID
}
sortbyFields = append(sortbyFields, sortBy+"(missing_values:last):"+param.orderBy.String())
if i == 2 {
if usedParams == 2 {
// Typesense supports up to 3 sorting parameters
// https://typesense.org/docs/0.25.0/api/search.html#ranking-and-sorting-parameters
break
}
usedParams++
}
sortby := strings.Join(sortbyFields, ",")
@ -534,11 +601,15 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
}
query := t.s.
Distinct("tasks.*").
In("id", taskIDs).
OrderBy(orderby)
if projectViewIDForPosition != 0 {
query = query.Join("LEFT", "task_positions", "task_positions.task_id = tasks.id AND task_positions.project_view_id = ?", projectViewIDForPosition)
for _, param := range opts.sortby {
if param.sortBy == taskPropertyPosition {
query = query.Join("LEFT", "task_positions", "task_positions.task_id = tasks.id AND task_positions.project_view_id = ?", param.projectViewID)
break
}
}
err = query.Find(&tasks)

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