Compare commits
10 Commits
feat/card-
...
feat/unsub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a3c56730c | ||
|
|
eb3288336f | ||
|
|
56e4c43cfa | ||
|
|
07fc41761b | ||
|
|
50382e9186 | ||
|
|
00be5fb058 | ||
|
|
fc65f53e0c | ||
|
|
64aace6e3b | ||
|
|
1651faae14 | ||
|
|
b472c5ce93 |
@@ -29,6 +29,7 @@ S3_SECRET_ACCESS_KEY=
|
||||
S3_FORCE_PATH_STYLE=
|
||||
NEXT_PUBLIC_STORAGE_URL=
|
||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
|
||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=
|
||||
NEXT_PUBLIC_STORAGE_DOMAIN=
|
||||
|
||||
# Auth config (optional)
|
||||
|
||||
@@ -170,6 +170,7 @@ pnpm dev
|
||||
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
|
||||
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
|
||||
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
|
||||
| `NEXT_PUBLIC_ATTATCHMENTS_BUCKET_NAME` | S3 bucket name for attatchments | For file uploads | `attatchments` |
|
||||
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
|
||||
| `NEXT_PUBLIC_DISABLE_SIGN_UP` | Disable sign up | For authentication | `false` |
|
||||
| `NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY` | Hide “Powered by kan.bn” on public boards (self-host) | For white labelling | `true` |
|
||||
|
||||
@@ -60,6 +60,7 @@ checksums:
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20your%20account%3F/singular: 428b74d781063224c3e63980e1094ec3
|
||||
assigned%20%3C0%3E%7B0%7D%3C%2F0%3E%20to%20the%20card/singular: 9df6d89fa83706123dedd8cba2243d04
|
||||
Assignees/singular: 96fc0e28a783d80decfd4716a440ac08
|
||||
Attachment%20uploaded/singular: c0233f8c2560f95ac0834f35eb07b9e7
|
||||
Awaiting%20Customer/singular: 122c108794f321c10e05a08f09b11457
|
||||
Backlog/singular: 35919fd5b10ad212839a75e72829fe4e
|
||||
Basic%20Kanban/singular: e46ebc406749486f3907436970d4d6c7
|
||||
@@ -108,6 +109,7 @@ checksums:
|
||||
Complete%20control%20and%20ownership%3A/singular: 0d8b682ba873272217425ccfc96aa9cd
|
||||
completed%20a%20checklist%20item/singular: 757b04c6c80cc927e1c597c0ad4fda33
|
||||
completed%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 71ec18acf051fc909a48a07ca3578673
|
||||
Confirm%20your%20email%20preferences%3A/singular: 043c161dd9866231ae2418fdd9f61b9c
|
||||
Confirm%20your%20new%20password/singular: a0d2935d7b63f8dd19d7c0de47524416
|
||||
Connect%20Trello/singular: 4440a0b9e387ef7136e3958e7a089213
|
||||
Connect%20your%20favorite%20tools%20to%20streamline%20your%20workflow./singular: 033c5dcdb059ccb634aef7fe63f2f45d
|
||||
@@ -166,11 +168,13 @@ checksums:
|
||||
Display%20name%20must%20be%20at%20least%203%20characters%20long/singular: 84178b79845a70937af5e26020403052
|
||||
Display%20name%20updated/singular: 4e27503ca24ef5f009713951ca9e5b97
|
||||
Do%20you%20offer%20a%20free%20plan%3F/singular: 3ef16b0994f0d9ae17067782ca9bed1b
|
||||
Do%20you%20want%20to%20unsubscribe%3F/singular: 8173b82c731ba885939d223eeef2e40b
|
||||
docs/singular: 307bff5678ada918da1f1ec3edc76cac
|
||||
Docs/singular: 55fea190a0c0fb32acd3dc986cd3cc91
|
||||
Documentation/singular: 1563fcb5ddb5037b0709ccd3dd384a92
|
||||
Don't%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20up%3C%2F1%3E%3C%2F0%3E/singular: 6ae8282ab8b4a01b4ce87b119e13714b
|
||||
Done/singular: ffd408fa29d5bc9039ef8ea1b9b699bb
|
||||
Download%20failed/singular: 142b391cca3e05f2af9617092f7358c5
|
||||
Edit%20board%20URL/singular: d8276dfc0189f371ec7d80a2047c07aa
|
||||
Edit%20comment/singular: 7e4b46525fcb6b47b71798e31c46e374
|
||||
Edit%20label/singular: 0309e0be1512b1e0b0ceb87c69a53d03
|
||||
@@ -209,6 +213,7 @@ checksums:
|
||||
Failed%20to%20copy%20invite%20link/singular: 635884d5ed8d6ee20b85a003939b4ae7
|
||||
Failed%20to%20create%20board/singular: a746e2afe881c3bf0a8e82a931ca3495
|
||||
Failed%20to%20login%20with%20%7B0%7D.%20Please%20try%20again./singular: 669a4b4247a73f53fb9b8b16e42d166f
|
||||
Failed%20to%20upload%20attachment.%20Please%20try%20again./singular: f8a50d1c8491404f73d3cf701e11f297
|
||||
FAQ/singular: 47e0ee2eb40b4e7e732e05e2233fc71c
|
||||
FAQs/singular: dc36d7992372ccd419b39ef51cf5b16c
|
||||
Fast%20%26%20lightweight/singular: 4f2a80c555a5427b94eef5124aa10775
|
||||
@@ -295,6 +300,7 @@ checksums:
|
||||
Link%20copied/singular: 4a4805700b31ec65bcb3ca962bccfd1b
|
||||
List/singular: 94f13e7ef909a4de9db7abaa1f9f0b61
|
||||
List%20name/singular: e925e2e6ccaf0eb4064a888aaea8d3c2
|
||||
Lists/singular: 9f4a73afc8de321175d71935134ef066
|
||||
Login%20%7C%20kan.bn/singular: 42a6c8dcd73e0d46e652646dc86871eb
|
||||
Logout/singular: 07948fdf20705e04a7bf68ab197512bf
|
||||
Long-term/singular: 51cb6f0b112250c5a091ca5f0866904b
|
||||
@@ -332,6 +338,7 @@ checksums:
|
||||
No%20authentication%20methods%20are%20currently%20available/singular: f718c896810da3612202887f9a4374fa
|
||||
No%20boards%20found/singular: e044088d2c51b6bdf660fafa86ee1e17
|
||||
No%20credit%20card%20required/singular: 2090aa4171dc0b60735069f89b592883
|
||||
No%20download%20URL%20available%20for%20this%20attachment./singular: e367d39420b2242f9d2fd749c87f446a
|
||||
No%20lists/singular: cedf633d99c77ff4356e089f2d98c0a6
|
||||
No%20results%20found%20for%20%22%7BdebouncedQuery%7D%22./singular: 5db6294712528cd897b15ae36f4fd834
|
||||
Offer/singular: 82b4e0c9a3f5b4bd93590847de7c32a1
|
||||
@@ -477,6 +484,7 @@ checksums:
|
||||
Unable%20to%20create%20list/singular: 7fbbf8314f8d08a4123c7daef09fed05
|
||||
Unable%20to%20create%20template/singular: 7495f1434c9188849bffd015811d5337
|
||||
Unable%20to%20create%20workspace/singular: c1c949477e121d73ed6683eddf9cd874
|
||||
Unable%20to%20delete%20attachment/singular: 99d0b17b78d44e15f13d876d155f0efc
|
||||
Unable%20to%20delete%20card/singular: 50ff06aa1265fe464f776aba33f1bef9
|
||||
Unable%20to%20delete%20checklist/singular: d7067e2c009f4919f0cca77df3c228ee
|
||||
Unable%20to%20delete%20checklist%20item/singular: a74144593b625e4d8d7ecf734462c60d
|
||||
@@ -502,6 +510,7 @@ checksums:
|
||||
Unlimited%20lists/singular: 5c418701b27b9acbc5dd199719007362
|
||||
Unlimited%20members/singular: f2949ca2dc18b0063af92e60779abb65
|
||||
Unlimited%20workspaces/singular: b504d01997bf908af1d486d9942fed36
|
||||
Unsubscribe/singular: d1a0b07295687d1f08d4df1c411072dd
|
||||
Update/singular: 079fc039262fd31b10532929685c2d1b
|
||||
Update%20label/singular: 97880b503dfe956941c5f23025a1c102
|
||||
updated%20a%20checklist%20item/singular: 198e1d1d503f4b69b752dd84d0cc0e9d
|
||||
@@ -510,6 +519,7 @@ checksums:
|
||||
updated%20the%20title%20to%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: aca196d729401d8adc5c8ca9d558840e
|
||||
Upgrade%20to%20Pro/singular: 972773025e763ddf53273df6d37a729a
|
||||
Upgrade%20to%20Pro%20(%2429%2Fmonth)/singular: 9a91ea70f5eb55aac96640bf0fd7feff
|
||||
Upload%20failed/singular: 5b7b755f05330164dbfb00096c500ee3
|
||||
Urgent/singular: e79afcd4398e52e10e7e8243a7eecabe
|
||||
URL%20can%20only%20contain%20letters%2C%20numbers%2C%20and%20hyphens/singular: 875d37d2d920f98ef60a314eda8a5d9a
|
||||
URL%20cannot%20exceed%2024%20characters/singular: 395c25732b84ac1f5b63ee310da08e93
|
||||
@@ -526,6 +536,7 @@ checksums:
|
||||
View%20workspace/singular: c9e4b789330b08c18ca8db7044409e5f
|
||||
Visibility/singular: 1ff412f8fcde0f460acbf11153649646
|
||||
We%20are%20using%20the%20%3C0%3EAGPL-3.0%20license%3C%2F0%3E./singular: 08c5ddd938a2a70f61d684e41e18697a
|
||||
We%20couldn't%20update%20your%20preferences.%20Please%20try%20again./singular: 69d1d2575f2e73b08ac622bde0a45b4d
|
||||
We're%20just%20getting%20started.%20/singular: 2dfa121e0ff1914e08068308a81973c0
|
||||
Welcome%20back/singular: 4928884739ba559e6e4b960e80fe1452
|
||||
What%20license%20are%20you%20using%3F/singular: 59d00e1bf28edc21b77fec94875f57ca
|
||||
@@ -558,16 +569,19 @@ checksums:
|
||||
You%20can%20self-host%20by%20following%20the%20instructions%20in%20our%20%3C0%3Erepo%3C%2F0%3E./singular: a6152a41b2d8f64d5a657e5b8bc808a9
|
||||
You%20have%20been%20logged%20in%20successfully./singular: ef8fad1dce13ae4112f17c5258655fea
|
||||
You%20have%20been%20signed%20up%20successfully./singular: f614a6e3b45f5ffb9a3b0fb420fef84b
|
||||
You%20have%20been%20unsubscribed!/singular: e0b9985faa4e7f25b71acc77750923a6
|
||||
You%20have%20unlimited%20seats%20with%20your%20Pro%20Plan.%20There%20is%20no%20additional%20charge%20for%20new%20members!/singular: e3dc59a5ba7211cd3d8516b3a79d85ca
|
||||
You've%20been%20invited%20to%20join%20a%20workspace%20on%20kan.bn./singular: 257b840726f972f384243a72767f880f
|
||||
You've%20been%20invited%20to%20join%20a%20workspace./singular: 24fc6cdc8740f37a83df85f582f03293
|
||||
Your%20account%20has%20been%20deleted./singular: 8c8d944e07388c5877effdb2c2803dcf
|
||||
Your%20boards%20have%20been%20imported./singular: 403972e7a25afc2415762c1c2b1ec868
|
||||
Your%20display%20name%20has%20been%20updated./singular: 15e5fff36c554c16ec5214427fae1bf4
|
||||
Your%20file%20has%20been%20uploaded%20successfully./singular: 19d84e934877efc0fef285ff3d6e7849
|
||||
Your%20password%20has%20been%20changed./singular: 8f730f68d52b7efa727aa0784282ebcb
|
||||
Your%20profile%20image%20has%20been%20updated./singular: 099e1780348cd7bf617721344371a430
|
||||
Your%20Trello%20account%20has%20been%20disconnected./singular: 126aeeb73f7e4cad338056e4c933f39b
|
||||
Your%20Trello%20account%20is%20connected./singular: 0499d193001fce2fbec445ae034ce512
|
||||
Your%20unsubscribe%20link%20is%20missing%20a%20token.%20Please%20open%20the%20latest%20email%20and%20try%20again./singular: 3e4cce96bc1197a1caa2b7fb4d3c7e53
|
||||
Your%20workspace%20description%20has%20been%20updated./singular: 98de6f65c567c6654cc0adce3c9d5656
|
||||
Your%20workspace%20has%20been%20deleted./singular: e7a3efcfc7dd18cb3e917acb67498292
|
||||
Your%20workspace%20name%20has%20been%20updated./singular: a87ea3b0d71e6dc5dd525d77114a9322
|
||||
|
||||
@@ -30,23 +30,50 @@ const config = {
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname:
|
||||
env("S3_FORCE_PATH_STYLE") === "true"
|
||||
? `${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`
|
||||
: `*.${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`,
|
||||
},
|
||||
{
|
||||
protocol: "http",
|
||||
hostname: "localhost",
|
||||
},
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "*.googleusercontent.com",
|
||||
},
|
||||
],
|
||||
remotePatterns: (() => {
|
||||
/** @type {Array<{protocol: "http" | "https", hostname: string}>} */
|
||||
const patterns = [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname:
|
||||
env("S3_FORCE_PATH_STYLE") === "true"
|
||||
? `${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`
|
||||
: `*.${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`,
|
||||
},
|
||||
{
|
||||
protocol: "http",
|
||||
hostname: "localhost",
|
||||
},
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "*.googleusercontent.com",
|
||||
},
|
||||
];
|
||||
|
||||
// Extract root domain from S3_ENDPOINT and add wildcard pattern
|
||||
const s3Endpoint = env("S3_ENDPOINT");
|
||||
if (s3Endpoint) {
|
||||
try {
|
||||
const url = new URL(s3Endpoint);
|
||||
const hostname = url.hostname;
|
||||
const protocol = url.protocol.replace(":", "");
|
||||
|
||||
// Extract root domain (last 2 parts: e.g. cloudflarestorage.com)
|
||||
const parts = hostname.split(".");
|
||||
if (parts.length >= 2) {
|
||||
const rootDomain = parts.slice(-2).join(".");
|
||||
patterns.push({
|
||||
protocol: protocol === "http" ? "http" : "https",
|
||||
hostname: `*.${rootDomain}`,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// If S3_ENDPOINT is not a valid URL, ignore it
|
||||
}
|
||||
}
|
||||
|
||||
return patterns;
|
||||
})(),
|
||||
},
|
||||
webpack(config) {
|
||||
config.module.rules.push({
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@lingui/conf": "^5.3.2",
|
||||
"@lingui/macro": "^5.3.2",
|
||||
"@lingui/react": "^5.3.2",
|
||||
"@novu/api": "^3.11.0",
|
||||
"@t3-oss/env-nextjs": "^0.11.1",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tanstack/react-query": "catalog:",
|
||||
@@ -46,6 +47,7 @@
|
||||
"aws-sdk": "^2.1692.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"geist": "^1.3.1",
|
||||
"jose": "^6.1.2",
|
||||
"next": "^15.3.4",
|
||||
"next-logger": "^5.0.1",
|
||||
"next-runtime-env": "^1.7.2",
|
||||
|
||||
@@ -303,6 +303,10 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
|
||||
const password = watch("password");
|
||||
|
||||
const isMagicLinkAvailable = useMemo(() => {
|
||||
return isCloudEnv || (isEmailSendingEnabled && !isSignUp);
|
||||
}, [isCloudEnv, isEmailSendingEnabled, isSignUp]);
|
||||
|
||||
// Determine if we should operate in magic link mode for current form state (login only)
|
||||
const isMagicLinkMode = useMemo(() => {
|
||||
// Magic link only viable when email sending enabled AND not sign up.
|
||||
@@ -390,7 +394,7 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isCredentialsEnabled && (
|
||||
{(isCredentialsEnabled || isMagicLinkAvailable) && (
|
||||
<>
|
||||
<div>
|
||||
<Input
|
||||
@@ -404,26 +408,28 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
type="password"
|
||||
{...register("password", { required: true })}
|
||||
placeholder={t`Enter your password`}
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="mt-2 text-xs text-red-400">
|
||||
{errors.password.message ??
|
||||
t`Please enter a valid password`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{isCredentialsEnabled && (
|
||||
<div>
|
||||
<Input
|
||||
type="password"
|
||||
{...register("password", { required: true })}
|
||||
placeholder={t`Enter your password`}
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="mt-2 text-xs text-red-400">
|
||||
{errors.password.message ??
|
||||
t`Please enter a valid password`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{loginError && (
|
||||
<p className="mt-2 text-xs text-red-400">{loginError}</p>
|
||||
)}
|
||||
</div>
|
||||
{isCredentialsEnabled && (
|
||||
{(isCredentialsEnabled || isMagicLinkAvailable) && (
|
||||
<div className="mt-[1.5rem] flex items-center gap-4">
|
||||
<Button
|
||||
isLoading={isLoginWithEmailPending}
|
||||
|
||||
@@ -122,10 +122,10 @@ export default function SideNavigation({
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<div className="hidden h-14 items-center justify-between pb-[18px] pt-1.5 md:flex">
|
||||
<div className="hidden h-[45px] items-center justify-between pb-3 md:flex">
|
||||
{!isCollapsed && (
|
||||
<Link href="/" className="block">
|
||||
<h1 className="pl-2 text-lg font-bold tracking-tight text-neutral-900 dark:text-dark-1000">
|
||||
<h1 className="pl-2 text-[16px] font-bold tracking-tight text-neutral-900 dark:text-dark-1000">
|
||||
kan.bn
|
||||
</h1>
|
||||
</Link>
|
||||
|
||||
@@ -51,6 +51,8 @@ export const env = createEnv({
|
||||
VK_CLIENT_SECRET: z.string().optional(),
|
||||
LINKEDIN_CLIENT_ID: z.string().optional(),
|
||||
LINKEDIN_CLIENT_SECRET: z.string().optional(),
|
||||
NOVU_API_KEY: z.string().optional(),
|
||||
EMAIL_UNSUBSCRIBE_SECRET: z.string().optional(),
|
||||
// Generic OIDC Provider
|
||||
OIDC_CLIENT_ID: z.string().optional(),
|
||||
OIDC_CLIENT_SECRET: z.string().optional(),
|
||||
@@ -90,6 +92,7 @@ export const env = createEnv({
|
||||
NEXT_PUBLIC_BASE_URL: z.string().url(),
|
||||
NEXT_PUBLIC_STORAGE_URL: z.string().url().optional(),
|
||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(),
|
||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME: z.string().optional(),
|
||||
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
|
||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
|
||||
.string()
|
||||
@@ -125,6 +128,8 @@ export const env = createEnv({
|
||||
NEXT_PUBLIC_BASE_URL: process.env.NEXT_PUBLIC_BASE_URL,
|
||||
NEXT_PUBLIC_STORAGE_URL: process.env.NEXT_PUBLIC_STORAGE_URL,
|
||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME: process.env.NEXT_PUBLIC_AVATAR_BUCKET_NAME,
|
||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME:
|
||||
process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME,
|
||||
NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN,
|
||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS,
|
||||
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
|
||||
|
||||
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} Labels"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} nicht gefunden"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Konto"
|
||||
msgid "Account deleted"
|
||||
msgstr "Konto gelöscht"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Aktivität"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Element hinzufügen..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Checkliste hinzufügen"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen oder '@' um jemanden zu erwähnen)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "hat <0>{0}</0> der Karte zugewiesen"
|
||||
msgid "Assignees"
|
||||
msgstr "Zugewiesene Personen"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Anhang hochgeladen"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Warten auf Kunden"
|
||||
@@ -304,9 +308,9 @@ msgstr "Abrechnungsportal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blogbeitrag"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Board"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "Der Name des Boards darf 100 Zeichen nicht überschreiten"
|
||||
msgid "Board name is required"
|
||||
msgstr "Boardname ist erforderlich"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Board nicht gefunden"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Board nicht gefunden"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Board-Freigabe & Einladungen"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "Board-URL darf nur Buchstaben, Zahlen und Bindestriche enthalten"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "Board-URL darf 60 Zeichen nicht überschreiten"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "Board-URL in die Zwischenablage kopiert"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "Board-URL muss mindestens 3 Zeichen lang sein"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "Board-URL muss mindestens 3 Zeichen lang sein"
|
||||
msgid "Board visibility"
|
||||
msgstr "Board-Sichtbarkeit"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Board-Sichtbarkeit aktualisiert"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Fehlerbericht"
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Karte"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Karte nicht gefunden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Kartentitel"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Checklistenname"
|
||||
msgid "Checklists"
|
||||
msgstr "Checklisten"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Filter löschen"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "hat ein Checklistenelement abgeschlossen"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "hat Checklistenelement <0>{0}</0> abgeschlossen"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Bestätigen sie ihre e-mail-einstellungen:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Bestätigen Sie Ihr neues Passwort"
|
||||
@@ -519,12 +528,12 @@ msgstr "Kontaktiere uns"
|
||||
msgid "Content Creation"
|
||||
msgstr "Content-Erstellung"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Fortfahren mit "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Fortfahren mit {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "{0} erstellen"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Weitere erstellen"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Weitere erstellen"
|
||||
msgid "Create API key"
|
||||
msgstr "API-Schlüssel erstellen"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Karte erstellen"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Einladungslink erstellen"
|
||||
msgid "Create label"
|
||||
msgstr "Label erstellen"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Liste erstellen"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Neue(n) {0} erstellen"
|
||||
msgid "Create new key"
|
||||
msgstr "Neuen Schlüssel erstellen"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Neues Label erstellen"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Neue Liste erstellen"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Anzeigename aktualisiert"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Bietet ihr einen kostenlosen Plan an?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Möchten sie sich abmelden?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "Dokumente"
|
||||
@@ -769,8 +782,12 @@ msgstr "Du hast noch kein Konto? <0><1>Registrieren</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Erledigt"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Download fehlgeschlagen"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Board-URL bearbeiten"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Kommentar bearbeiten"
|
||||
msgid "Edit label"
|
||||
msgstr "Label bearbeiten"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Workspace-URL bearbeiten"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Workspace-URL bearbeiten"
|
||||
msgid "Editing"
|
||||
msgstr "Bearbeitung"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Geben Sie Ihr aktuelles Passwort ein"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Geben Sie Ihr aktuelles Passwort ein und wählen Sie ein neues sicheres Passwort."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Gib deine E-Mail-Adresse ein"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Gib deinen Namen ein"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Gib deinen Namen ein"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Geben Sie Ihr neues Passwort ein"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Gib dein Passwort ein"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Board konnte nicht erstellt werden"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Anmeldung mit {0} fehlgeschlagen. Bitte versuche es erneut."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Fehler beim Hochladen des Anhangs. Bitte versuchen Sie es erneut."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Feedback"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Feedback gesendet"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Loslegen"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Beginnen Sie, indem Sie eine(n) neue(n) {0} erstellen"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Beginne mit dem Erstellen einer neuen Liste"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Kanban neu gedacht"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Beachten Sie, dass diese Aktion nicht rückgängig gemacht werden kann."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Lizenz"
|
||||
msgid "Light"
|
||||
msgstr "Hell"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Link kopiert"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Liste"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Listenname"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Listen"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Login | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Von Teams weltweit geliebt"
|
||||
msgid "Low Priority"
|
||||
msgstr "Niedrige Priorität"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "Magic Link"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Mittlere Priorität"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Mitglieder"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Neue(r) {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Neuer API-Schlüssel"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Neue Karte"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Neuer Import"
|
||||
msgid "New label"
|
||||
msgstr "Neues Label"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Neue Liste"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Nächste Schritte"
|
||||
msgid "No {0}"
|
||||
msgstr "Keine {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "Derzeit sind keine Authentifizierungsmethoden verfügbar"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "Keine Boards gefunden"
|
||||
msgid "No credit card required"
|
||||
msgstr "Keine Kreditkarte erforderlich"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "Für diesen Anhang ist keine Download-URL verfügbar."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Keine Listen"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "Open Source"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Open-Source-Freunde"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "oder"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Plattform"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Bitte bestätigen Sie Ihr neues Passwort"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Bitte gib eine gültige E-Mail-Adresse ein"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Bitte gib einen gültigen Namen ein"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Bitte gib ein gültiges Passwort ein"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Prioritäts-E-Mail-Support"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Datenschutzrichtlinie"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Privat"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Profilbild aktualisiert"
|
||||
msgid "Profile picture"
|
||||
msgstr "Profilbild"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Öffentlich"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Registrierung deaktiviert"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "Die Registrierung ist derzeit deaktiviert. Bitte versuche es später erneut."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Registrieren mit "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Team-Plan"
|
||||
msgid "Teams"
|
||||
msgstr "Teams"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Vorlage"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "Die open source <0/> alternative zu Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "Die Sichtbarkeit deines Boards wurde auf {0} gesetzt."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Dieser API-Schlüssel wird nur einmal angezeigt. Bitte speichern Sie ihn an einem sicheren Ort."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Dieses Board ist privat oder existiert nicht"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Diese Board-URL ist bereits vergeben"
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "Checklistenelement kann nicht hinzugefügt werden"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Kommentar konnte nicht hinzugefügt werden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Karte konnte nicht erstellt werden"
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "Karte konnte nicht erstellt werden"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Checkliste kann nicht erstellt werden"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Liste konnte nicht erstellt werden"
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "Vorlage konnte nicht erstellt werden"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Workspace konnte nicht erstellt werden"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Anhang kann nicht gelöscht werden"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Karte konnte nicht gelöscht werden"
|
||||
@@ -2151,16 +2186,16 @@ msgstr "Mitglied konnte nicht entfernt werden"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Feedback konnte nicht gesendet werden"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Board-URL kann nicht aktualisiert werden"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Board-Sichtbarkeit konnte nicht aktualisiert werden"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Karte konnte nicht aktualisiert werden"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "Kommentar konnte nicht aktualisiert werden"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Labels konnten nicht aktualisiert werden"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Liste konnte nicht aktualisiert werden"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Unbegrenzte Mitglieder"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Unbegrenzte Workspaces"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Upgrade auf Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Upgrade auf Pro ($29/Monat)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Hochladen fehlgeschlagen"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Verwalte deine Abrechnung und dein Abonnement."
|
||||
msgid "View docs"
|
||||
msgstr "Dokumentation ansehen"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Nur ansehen"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Nur ansehen"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Sieh dir unsere roadmap an."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Workspace anzeigen"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Sichtbarkeit"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Sichtbarkeit"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Wir verwenden die <0>AGPL-3.0 lizenz</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "Wir konnten ihre einstellungen nicht aktualisieren. Bitte versuchen sie es erneut."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Wir stehen erst am anfang. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Warum ein open source Trello entwickeln?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Arbeitsbereich"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Sie haben sich erfolgreich angemeldet."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Sie haben sich erfolgreich registriert."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "Sie wurden abgemeldet!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Sie haben unbegrenzte Plätze mit Ihrem Pro-Plan. Für neue Mitglieder fallen keine zusätzlichen Kosten an!"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Deine Boards wurden importiert."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Dein Anzeigename wurde aktualisiert."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Ihre Datei wurde erfolgreich hochgeladen."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Ihr Passwort wurde geändert."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Dein Trello-Konto wurde getrennt."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Dein Trello-Konto ist verbunden."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Ihrem abmeldelink fehlt ein token. Bitte öffnen sie die neueste e-mail und versuchen sie es erneut."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "Deine Workspace-Beschreibung wurde aktualisiert."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} labels"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} not found"
|
||||
|
||||
@@ -91,8 +91,12 @@ msgstr "Account"
|
||||
msgid "Account deleted"
|
||||
msgstr "Account deleted"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/providers/keyboard-shortcuts.tsx:55
|
||||
#~ msgid "Actions"
|
||||
#~ msgstr "Actions"
|
||||
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Activity"
|
||||
|
||||
@@ -121,7 +125,7 @@ msgstr "Add an item..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Add checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Add description... (type '/' to open commands or '@' to mention)"
|
||||
|
||||
@@ -306,6 +310,10 @@ msgstr "assigned <0>{0}</0> to the card"
|
||||
msgid "Assignees"
|
||||
msgstr "Assignees"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Attachment uploaded"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Awaiting Customer"
|
||||
@@ -344,9 +352,9 @@ msgstr "Billing portal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blog Post"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Board"
|
||||
|
||||
@@ -372,7 +380,7 @@ msgstr "Board name cannot exceed 100 characters"
|
||||
msgid "Board name is required"
|
||||
msgstr "Board name is required"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Board not found"
|
||||
|
||||
@@ -380,19 +388,19 @@ msgstr "Board not found"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Board sharing & invites"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "Board URL can only contain letters, numbers, and hyphens"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "Board URL cannot exceed 60 characters"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "Board URL copied to clipboard"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "Board URL must be at least 3 characters long"
|
||||
|
||||
@@ -401,7 +409,7 @@ msgstr "Board URL must be at least 3 characters long"
|
||||
msgid "Board visibility"
|
||||
msgstr "Board visibility"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Board visibility updated"
|
||||
|
||||
@@ -444,15 +452,16 @@ msgstr "Bug Report"
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Card"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Card not found"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Card title"
|
||||
|
||||
@@ -489,7 +498,7 @@ msgstr "Checklist name"
|
||||
msgid "Checklists"
|
||||
msgstr "Checklists"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Clear filters"
|
||||
|
||||
@@ -554,6 +563,10 @@ msgstr "completed checklist item <0>{0}</0>"
|
||||
#~ msgid "Confirm URL change"
|
||||
#~ msgstr "Confirm URL change"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Confirm your email preferences:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirm your new password"
|
||||
@@ -584,12 +597,12 @@ msgstr "Contact us"
|
||||
msgid "Content Creation"
|
||||
msgstr "Content Creation"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Continue with "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Continue with {0}"
|
||||
|
||||
@@ -607,8 +620,8 @@ msgid "Create {0}"
|
||||
msgstr "Create {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Create another"
|
||||
|
||||
@@ -624,7 +637,7 @@ msgstr "Create API key"
|
||||
#~ msgid "Create board"
|
||||
#~ msgstr "Create board"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Create card"
|
||||
|
||||
@@ -640,7 +653,7 @@ msgstr "Create invite link"
|
||||
msgid "Create label"
|
||||
msgstr "Create label"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Create list"
|
||||
|
||||
@@ -657,12 +670,12 @@ msgstr "Create new {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Create new key"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Create new label"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Create new list"
|
||||
|
||||
@@ -832,6 +845,10 @@ msgstr "Display name updated"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Do you offer a free plan?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Do you want to unsubscribe?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "docs"
|
||||
@@ -858,8 +875,12 @@ msgstr "Don't have an account? <0><1>Sign up</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Done"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Download failed"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Edit board URL"
|
||||
|
||||
@@ -871,7 +892,7 @@ msgstr "Edit comment"
|
||||
msgid "Edit label"
|
||||
msgstr "Edit label"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Edit workspace URL"
|
||||
|
||||
@@ -879,7 +900,7 @@ msgstr "Edit workspace URL"
|
||||
msgid "Editing"
|
||||
msgstr "Editing"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
@@ -899,11 +920,11 @@ msgstr "Enter your current password"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Enter your current password and choose a new secure password."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Enter your email address"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Enter your name"
|
||||
|
||||
@@ -911,7 +932,7 @@ msgstr "Enter your name"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Enter your new password"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Enter your password"
|
||||
|
||||
@@ -1020,6 +1041,11 @@ msgstr "Failed to create board"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Failed to login with {0}. Please try again."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Failed to upload attachment. Please try again."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -1063,7 +1089,7 @@ msgstr "Feedback"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Feedback sent"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
@@ -1108,6 +1134,10 @@ msgstr "Full-time"
|
||||
msgid "Fun"
|
||||
msgstr "Fun"
|
||||
|
||||
#: src/providers/keyboard-shortcuts.tsx:53
|
||||
#~ msgid "General"
|
||||
#~ msgstr "General"
|
||||
|
||||
#: src/views/auth/signup/index.tsx:69
|
||||
#: src/views/home/components/Cta.tsx:61
|
||||
#: src/views/home/components/Header.tsx:106
|
||||
@@ -1131,7 +1161,7 @@ msgstr "Get started by creating a new {0}"
|
||||
#~ msgid "Get started by creating a new board"
|
||||
#~ msgstr "Get started by creating a new board"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Get started by creating a new list"
|
||||
|
||||
@@ -1165,6 +1195,22 @@ msgstr "Go Home"
|
||||
msgid "Go to app"
|
||||
msgstr "Go to app"
|
||||
|
||||
#: src/components/SideNavigation.tsx:105
|
||||
#~ msgid "Go to boards"
|
||||
#~ msgstr "Go to boards"
|
||||
|
||||
#: src/components/SideNavigation.tsx:129
|
||||
#~ msgid "Go to members"
|
||||
#~ msgstr "Go to members"
|
||||
|
||||
#: src/components/SideNavigation.tsx:141
|
||||
#~ msgid "Go to settings"
|
||||
#~ msgstr "Go to settings"
|
||||
|
||||
#: src/components/SideNavigation.tsx:117
|
||||
#~ msgid "Go to templates"
|
||||
#~ msgstr "Go to templates"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:18
|
||||
msgid "High Priority"
|
||||
msgstr "High Priority"
|
||||
@@ -1353,9 +1399,13 @@ msgstr "Kanban reimagined"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Keep in mind that this action is irreversible."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/providers/keyboard-shortcuts.tsx:320
|
||||
#~ msgid "Keyboard Shortcuts"
|
||||
#~ msgstr "Keyboard Shortcuts"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
|
||||
@@ -1405,18 +1455,22 @@ msgstr "License"
|
||||
msgid "Light"
|
||||
msgstr "Light"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Link copied"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "List"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "List name"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Lists"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Login | kan.bn"
|
||||
@@ -1437,7 +1491,7 @@ msgstr "Loved by teams worldwide"
|
||||
msgid "Low Priority"
|
||||
msgstr "Low Priority"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "magic link"
|
||||
|
||||
@@ -1459,9 +1513,9 @@ msgid "Medium Priority"
|
||||
msgstr "Medium Priority"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Members"
|
||||
@@ -1504,6 +1558,10 @@ msgstr "moved the card to another list"
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: src/providers/keyboard-shortcuts.tsx:54
|
||||
#~ msgid "Navigation"
|
||||
#~ msgstr "Navigation"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:95
|
||||
msgid "Need help?"
|
||||
msgstr "Need help?"
|
||||
@@ -1526,7 +1584,7 @@ msgstr "New API key"
|
||||
#~ msgid "New board"
|
||||
#~ msgstr "New board"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "New card"
|
||||
|
||||
@@ -1542,8 +1600,8 @@ msgstr "New import"
|
||||
msgid "New label"
|
||||
msgstr "New label"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "New list"
|
||||
|
||||
@@ -1584,7 +1642,7 @@ msgstr "Next Steps"
|
||||
msgid "No {0}"
|
||||
msgstr "No {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "No authentication methods are currently available"
|
||||
|
||||
@@ -1600,7 +1658,15 @@ msgstr "No boards found"
|
||||
msgid "No credit card required"
|
||||
msgstr "No credit card required"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "No download URL available for this attachment."
|
||||
|
||||
#: src/providers/keyboard-shortcuts.tsx:333
|
||||
#~ msgid "No keyboard shortcuts registered."
|
||||
#~ msgstr "No keyboard shortcuts registered."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "No lists"
|
||||
|
||||
@@ -1624,6 +1690,14 @@ msgstr "Once you delete your account, there is no going back. This action cannot
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
|
||||
#: src/components/WorkspaceMenu.tsx:31
|
||||
#~ msgid "Open command menu"
|
||||
#~ msgstr "Open command menu"
|
||||
|
||||
#: src/providers/keyboard-shortcuts.tsx:171
|
||||
#~ msgid "Open keyboard shortcuts"
|
||||
#~ msgstr "Open keyboard shortcuts"
|
||||
|
||||
#: src/views/pricing/components/FeatureComparisonTable.tsx:150
|
||||
msgid "Open source"
|
||||
msgstr "Open source"
|
||||
@@ -1632,7 +1706,7 @@ msgstr "Open source"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Open Source Friends"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "or"
|
||||
|
||||
@@ -1714,15 +1788,15 @@ msgstr "Platform"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Please confirm your new password"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Please enter a valid email address"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Please enter a valid name"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Please enter a valid password"
|
||||
|
||||
@@ -1733,15 +1807,16 @@ msgstr "Please select a file to upload."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1755,7 +1830,7 @@ msgstr "Please select a file to upload."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1799,7 +1874,7 @@ msgstr "Priority email support"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Privacy policy"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Private"
|
||||
|
||||
@@ -1819,7 +1894,7 @@ msgstr "Profile image updated"
|
||||
msgid "Profile picture"
|
||||
msgstr "Profile picture"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Public"
|
||||
|
||||
@@ -2016,6 +2091,10 @@ msgstr "Settings | Workspace"
|
||||
#~ msgid "Share invite link"
|
||||
#~ msgstr "Share invite link"
|
||||
|
||||
#: src/components/UserMenu.tsx:184
|
||||
#~ msgid "Shortcuts"
|
||||
#~ msgstr "Shortcuts"
|
||||
|
||||
#: src/views/home/components/Header.tsx:104
|
||||
msgid "Sign in"
|
||||
msgstr "Sign in"
|
||||
@@ -2041,7 +2120,7 @@ msgstr "Sign up disabled"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "Sign up is currently disabled. Please try again later."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Sign up with "
|
||||
|
||||
@@ -2108,8 +2187,8 @@ msgstr "Team Plan"
|
||||
msgid "Teams"
|
||||
msgstr "Teams"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Template"
|
||||
|
||||
@@ -2159,7 +2238,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "The open source <0/> alternative to Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "The visibility of your board has been set to {0}."
|
||||
|
||||
@@ -2183,11 +2262,11 @@ msgstr "This action can't be undone."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "This API key will only be shown once. Please save it in a secure location."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "This board is private or does not exist"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "This board URL has already been taken"
|
||||
|
||||
@@ -2265,7 +2344,7 @@ msgstr "Unable to add checklist item"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Unable to add comment"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Unable to create card"
|
||||
|
||||
@@ -2273,7 +2352,7 @@ msgstr "Unable to create card"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Unable to create checklist"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Unable to create list"
|
||||
|
||||
@@ -2286,6 +2365,10 @@ msgstr "Unable to create template"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Unable to create workspace"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Unable to delete attachment"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Unable to delete card"
|
||||
@@ -2310,16 +2393,16 @@ msgstr "Unable to remove member"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Unable to send feedback"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Unable to update board URL"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Unable to update board visibility"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Unable to update card"
|
||||
|
||||
@@ -2339,7 +2422,7 @@ msgstr "Unable to update comment"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Unable to update labels"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Unable to update list"
|
||||
@@ -2399,7 +2482,12 @@ msgstr "Unlimited members"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Unlimited workspaces"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Unsubscribe"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2450,6 +2538,11 @@ msgstr "Upgrade to Pro ($29/month)"
|
||||
#~ msgid "Upgrade to Team Plan"
|
||||
#~ msgstr "Upgrade to Team Plan"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Upload failed"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2499,7 +2592,7 @@ msgstr "View and manage your billing and subscription."
|
||||
msgid "View docs"
|
||||
msgstr "View docs"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "View only"
|
||||
|
||||
@@ -2507,11 +2600,11 @@ msgstr "View only"
|
||||
msgid "View our roadmap."
|
||||
msgstr "View our roadmap."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "View workspace"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Visibility"
|
||||
|
||||
@@ -2519,6 +2612,10 @@ msgstr "Visibility"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "We are using the <0>AGPL-3.0 license</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "We couldn't update your preferences. Please try again."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "We're just getting started. "
|
||||
@@ -2556,10 +2653,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Why make an open source Trello?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Workspace"
|
||||
@@ -2669,6 +2766,10 @@ msgstr "You have been logged in successfully."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "You have been signed up successfully."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "You have been unsubscribed!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
@@ -2693,6 +2794,10 @@ msgstr "Your boards have been imported."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Your display name has been updated."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Your file has been uploaded successfully."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Your password has been changed."
|
||||
@@ -2709,6 +2814,10 @@ msgstr "Your Trello account has been disconnected."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Your Trello account is connected."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "Your workspace description has been updated."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} etiquetas"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} no encontrado"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Cuenta"
|
||||
msgid "Account deleted"
|
||||
msgstr "Cuenta eliminada"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Actividad"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Añadir un elemento..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Añadir lista de verificación"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Añadir descripción... (escribe '/' para abrir comandos o '@' para mencionar)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "asignó <0>{0}</0> a la tarjeta"
|
||||
msgid "Assignees"
|
||||
msgstr "Asignados"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Archivo adjunto subido"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Esperando al cliente"
|
||||
@@ -304,9 +308,9 @@ msgstr "Portal de facturación"
|
||||
msgid "Blog Post"
|
||||
msgstr "Entrada de blog"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Tablero"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "El nombre del tablero no puede exceder los 100 caracteres"
|
||||
msgid "Board name is required"
|
||||
msgstr "El nombre del tablero es obligatorio"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Tablero no encontrado"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Tablero no encontrado"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Compartir tablero e invitaciones"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "La URL del tablero solo puede contener letras, números y guiones"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "La URL del tablero no puede exceder los 60 caracteres"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "URL del tablero copiada al portapapeles"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "La URL del tablero debe tener al menos 3 caracteres"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "La URL del tablero debe tener al menos 3 caracteres"
|
||||
msgid "Board visibility"
|
||||
msgstr "Visibilidad del tablero"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Visibilidad del tablero actualizada"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Informe de error"
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Tarjeta"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Tarjeta no encontrada"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Título de la tarjeta"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Nombre de la lista de verificación"
|
||||
msgid "Checklists"
|
||||
msgstr "Listas de verificación"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Borrar filtros"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "completó un elemento de la lista de verificación"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "completó el elemento <0>{0}</0> de la lista de verificación"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Confirma tus preferencias de correo electrónico:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirma tu nueva contraseña"
|
||||
@@ -519,12 +528,12 @@ msgstr "Contáctanos"
|
||||
msgid "Content Creation"
|
||||
msgstr "Creación de contenido"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Continuar con "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Continuar con {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "Crear {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Crear otro"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Crear otro"
|
||||
msgid "Create API key"
|
||||
msgstr "Crear clave API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Crear tarjeta"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Crear enlace de invitación"
|
||||
msgid "Create label"
|
||||
msgstr "Crear etiqueta"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Crear lista"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Crear nuevo {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Crear nueva clave"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Crear nueva etiqueta"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Crear nueva lista"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Nombre visible actualizado"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "¿Ofrecen un plan gratuito?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "¿Quieres darte de baja?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "documentos"
|
||||
@@ -769,8 +782,12 @@ msgstr "¿No tienes una cuenta? <0><1>Regístrate</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Terminado"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Error en la descarga"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Editar URL del tablero"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Editar comentario"
|
||||
msgid "Edit label"
|
||||
msgstr "Editar etiqueta"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Editar URL del espacio de trabajo"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Editar URL del espacio de trabajo"
|
||||
msgid "Editing"
|
||||
msgstr "Editando"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "correo electrónico"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Introduce tu contraseña actual"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Introduce tu contraseña actual y elige una nueva contraseña segura."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Introduce tu dirección de correo electrónico"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Introduce tu nombre"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Introduce tu nombre"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Introduce tu nueva contraseña"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Introduce tu contraseña"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Error al crear el tablero"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Error al iniciar sesión con {0}. Por favor, inténtalo de nuevo."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Error al subir el archivo adjunto. Por favor, inténtalo de nuevo."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Comentarios"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Comentarios enviados"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filtrar"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Comenzar"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Comienza creando un nuevo {0}"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Comienza creando una nueva lista"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Kanban reinventado"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Ten en cuenta que esta acción es irreversible."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Licencia"
|
||||
msgid "Light"
|
||||
msgstr "Claro"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Enlace copiado"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Lista"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Nombre de la lista"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Listas"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Iniciar sesión | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Amado por equipos en todo el mundo"
|
||||
msgid "Low Priority"
|
||||
msgstr "Prioridad baja"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "enlace mágico"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Prioridad media"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Miembros"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Nuevo {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Nueva clave API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Nueva tarjeta"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Nueva importación"
|
||||
msgid "New label"
|
||||
msgstr "Nueva etiqueta"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Nueva lista"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Próximos pasos"
|
||||
msgid "No {0}"
|
||||
msgstr "Sin {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "No hay métodos de autenticación disponibles actualmente"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "No se encontraron tableros"
|
||||
msgid "No credit card required"
|
||||
msgstr "No se requiere tarjeta de crédito"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "No hay URL de descarga disponible para este archivo adjunto."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Sin listas"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "Código abierto"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Amigos de código abierto"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "o"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Plataforma"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Por favor, confirma tu nueva contraseña"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Por favor, introduce una dirección de correo electrónico válida"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Por favor, introduce un nombre válido"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Por favor, introduce una contraseña válida"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Por favor selecciona un archivo para subir."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Por favor selecciona un archivo para subir."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Soporte prioritario por email"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Política de privacidad"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Privado"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Imagen de perfil actualizada"
|
||||
msgid "Profile picture"
|
||||
msgstr "Foto de perfil"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Público"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Registro deshabilitado"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "El registro está actualmente deshabilitado. Por favor, inténtalo de nuevo más tarde."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Registrarse con "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Plan de Equipo"
|
||||
msgid "Teams"
|
||||
msgstr "Equipos"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Plantilla"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "La alternativa de código abierto <0/> a Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "La visibilidad de tu tablero ha sido establecida a {0}."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Esta acción no se puede deshacer."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Esta clave API solo se mostrará una vez. Por favor, guárdala en un lugar seguro."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Este tablero es privado o no existe"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Esta URL de tablero ya ha sido utilizada"
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "No se puede añadir el elemento a la lista de verificación"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "No se puede añadir el comentario"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "No se puede crear la tarjeta"
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "No se puede crear la tarjeta"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "No se puede crear la lista de verificación"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "No se puede crear la lista"
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "No se puede crear la plantilla"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "No se puede crear el espacio de trabajo"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "No se puede eliminar el archivo adjunto"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "No se puede eliminar la tarjeta"
|
||||
@@ -2151,16 +2186,16 @@ msgstr "No se puede eliminar al miembro"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "No se pudieron enviar los comentarios"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "No se puede actualizar la URL del tablero"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "No se puede actualizar la visibilidad del tablero"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "No se puede actualizar la tarjeta"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "No se puede actualizar el comentario"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "No se pueden actualizar las etiquetas"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "No se puede actualizar la lista"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Miembros ilimitados"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Espacios de trabajo ilimitados"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Darse de baja"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Actualizar a Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Actualizar a Pro ($29/mes)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Error al subir"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Ver y gestionar tu facturación y suscripción."
|
||||
msgid "View docs"
|
||||
msgstr "Ver documentación"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Solo visualización"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Solo visualización"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Ver nuestra hoja de ruta."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Ver espacio de trabajo"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Visibilidad"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Visibilidad"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Estamos usando la <0>licencia AGPL-3.0</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "No pudimos actualizar tus preferencias. Por favor, inténtalo de nuevo."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Apenas estamos comenzando. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "¿Por qué crear un Trello de código abierto?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Espacio de trabajo"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Has iniciado sesión correctamente."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Te has registrado correctamente."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "¡Te has dado de baja!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Tienes plazas ilimitadas con tu Plan Pro. ¡No hay cargos adicionales por nuevos miembros!"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Tus tableros han sido importados."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Tu nombre de visualización ha sido actualizado."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Tu archivo se ha subido correctamente."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Tu contraseña ha sido cambiada."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Tu cuenta de Trello ha sido desconectada."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Tu cuenta de Trello está conectada."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "A tu enlace de baja le falta un token. Por favor, abre el último correo electrónico e inténtalo de nuevo."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "La descripción de tu espacio de trabajo ha sido actualizada."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} étiquettes"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} introuvable"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Compte"
|
||||
msgid "Account deleted"
|
||||
msgstr "Compte supprimé"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Activité"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Ajouter un élément..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Ajouter une checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes ou '@' pour mentionner)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "a assigné <0>{0}</0> à la carte"
|
||||
msgid "Assignees"
|
||||
msgstr "Assignés"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Pièce jointe téléversée"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "En attente du client"
|
||||
@@ -304,9 +308,9 @@ msgstr "Portail de facturation"
|
||||
msgid "Blog Post"
|
||||
msgstr "Article de blog"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Tableau"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "Le nom du tableau ne peut pas dépasser 100 caractères"
|
||||
msgid "Board name is required"
|
||||
msgstr "Le nom du tableau est requis"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Tableau introuvable"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Tableau introuvable"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Partage de tableau & invitations"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "L'URL du tableau ne peut contenir que des lettres, des chiffres et des traits d'union"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "L'URL du tableau ne peut pas dépasser 60 caractères"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "URL du tableau copiée dans le presse-papiers"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "L'URL du tableau doit comporter au moins 3 caractères"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "L'URL du tableau doit comporter au moins 3 caractères"
|
||||
msgid "Board visibility"
|
||||
msgstr "Visibilité du tableau"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Visibilité du tableau mise à jour"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Rapport de bug"
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Carte"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Carte introuvable"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Titre de la carte"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Nom de la checklist"
|
||||
msgid "Checklists"
|
||||
msgstr "Listes de contrôle"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Effacer les filtres"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "a terminé un élément de la checklist"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "a terminé l'élément <0>{0}</0> de la checklist"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Confirmez vos préférences d'e-mail :"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirmez votre nouveau mot de passe"
|
||||
@@ -519,12 +528,12 @@ msgstr "Contactez-nous"
|
||||
msgid "Content Creation"
|
||||
msgstr "Création de contenu"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Continuer avec "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Continuer avec {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "Créer {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Créer un autre"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Créer un autre"
|
||||
msgid "Create API key"
|
||||
msgstr "Créer une clé API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Créer une carte"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Créer un lien d'invitation"
|
||||
msgid "Create label"
|
||||
msgstr "Créer une étiquette"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Créer une liste"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Créer un nouveau {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Créer une nouvelle clé"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Créer une nouvelle étiquette"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Créer une nouvelle liste"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Nom d'affichage mis à jour"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Proposez-vous un plan gratuit ?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Voulez-vous vous désabonner ?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "documentation"
|
||||
@@ -769,8 +782,12 @@ msgstr "Vous n'avez pas de compte ? <0><1>Inscrivez-vous</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Fait"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Échec du téléchargement"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Modifier l'URL du tableau"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Modifier le commentaire"
|
||||
msgid "Edit label"
|
||||
msgstr "Modifier l'étiquette"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Modifier l'URL de l'espace de travail"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Modifier l'URL de l'espace de travail"
|
||||
msgid "Editing"
|
||||
msgstr "Édition"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "e-mail"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Saisissez votre mot de passe actuel"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Saisissez votre mot de passe actuel et choisissez un nouveau mot de passe sécurisé."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Saisissez votre adresse e-mail"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Saisissez votre nom"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Saisissez votre nom"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Saisissez votre nouveau mot de passe"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Saisissez votre mot de passe"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Échec de la création du tableau"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Échec de connexion avec {0}. Veuillez réessayer."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Échec du téléversement de la pièce jointe. Veuillez réessayer."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Commentaires"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Commentaires envoyés"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filtrer"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Commencer"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Commencez par créer un nouveau {0}"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Commencez par créer une nouvelle liste"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Kanban réinventé"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Gardez à l'esprit que cette action est irréversible."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Étiquettes"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Licence"
|
||||
msgid "Light"
|
||||
msgstr "Clair"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Lien copié"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Liste"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Nom de la liste"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Listes"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Connexion | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Adoré par les équipes du monde entier"
|
||||
msgid "Low Priority"
|
||||
msgstr "Priorité basse"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "lien magique"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Priorité moyenne"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Membres"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Nouveau {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Nouvelle clé API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Nouvelle carte"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Nouvel import"
|
||||
msgid "New label"
|
||||
msgstr "Nouvelle étiquette"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Nouvelle liste"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Prochaines étapes"
|
||||
msgid "No {0}"
|
||||
msgstr "Aucun {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "Aucune méthode d'authentification n'est actuellement disponible"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "Aucun tableau trouvé"
|
||||
msgid "No credit card required"
|
||||
msgstr "Aucune carte de crédit requise"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "Aucune URL de téléchargement disponible pour cette pièce jointe."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Aucune liste"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "Open source"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Amis Open Source"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "ou"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Plateforme"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Veuillez confirmer votre nouveau mot de passe"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Veuillez saisir une adresse e-mail valide"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Veuillez saisir un nom valide"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Veuillez saisir un mot de passe valide"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Support par e-mail prioritaire"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Politique de confidentialité"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Privé"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Image de profil mise à jour"
|
||||
msgid "Profile picture"
|
||||
msgstr "Photo de profil"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Public"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Inscription désactivée"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "L'inscription est actuellement désactivée. Veuillez réessayer plus tard."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "S'inscrire avec "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Forfait d'équipe"
|
||||
msgid "Teams"
|
||||
msgstr "Équipes"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Modèle"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "L'alternative open source <0/> à Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "La visibilité de votre tableau a été définie sur {0}."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Cette action ne peut pas être annulée."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Cette clé API ne sera affichée qu'une seule fois. Veuillez la sauvegarder dans un emplacement sécurisé."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Ce tableau est privé ou n'existe pas"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Cette URL de tableau est déjà utilisée"
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "Impossible d'ajouter l'élément à la liste de contrôle"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Impossible d'ajouter un commentaire"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Impossible de créer la carte"
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "Impossible de créer la carte"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Impossible de créer la liste de contrôle"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Impossible de créer une liste"
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "Impossible de créer le modèle"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Impossible de créer l'espace de travail"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Impossible de supprimer la pièce jointe"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Impossible de supprimer la carte"
|
||||
@@ -2151,16 +2186,16 @@ msgstr "Impossible de supprimer le membre"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Impossible d'envoyer les commentaires"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Impossible de mettre à jour l'URL du tableau"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Impossible de mettre à jour la visibilité du tableau"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Impossible de mettre à jour la carte"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "Impossible de mettre à jour le commentaire"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Impossible de mettre à jour les étiquettes"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Impossible de mettre à jour la liste"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Membres illimités"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Espaces de travail illimités"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Se désabonner"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Passer à Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Passer à Pro (29 $/mois)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Échec du téléversement"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Consultez et gérez votre facturation et votre abonnement."
|
||||
msgid "View docs"
|
||||
msgstr "Voir la documentation"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Affichage uniquement"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Affichage uniquement"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Consultez notre feuille de route."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Voir l'espace de travail"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Visibilité"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Visibilité"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Nous utilisons la <0>licence AGPL-3.0</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "Nous n'avons pas pu mettre à jour vos préférences. Veuillez réessayer."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Nous ne faisons que commencer. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Pourquoi créer un Trello open source ?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Espace de travail"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Vous vous êtes connecté avec succès."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Vous vous êtes inscrit avec succès."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "Vous avez été désabonné !"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Vous disposez de places illimitées avec votre Plan Pro. Il n'y a pas de frais supplémentaires pour les nouveaux membres !"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Vos tableaux ont été importés."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Votre nom d'affichage a été mis à jour."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Votre fichier a été téléversé avec succès."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Votre mot de passe a été modifié."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Votre compte Trello a été déconnecté."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Votre compte Trello est connecté."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Votre lien de désabonnement ne contient pas de jeton. Veuillez ouvrir le dernier e-mail reçu et réessayer."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "La description de votre espace de travail a été mise à jour."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} etichette"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} non trovato"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Account"
|
||||
msgid "Account deleted"
|
||||
msgstr "Account eliminato"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Attività"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Aggiungi un elemento..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Aggiungi checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi o '@' per menzionare)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "ha assegnato <0>{0}</0> alla scheda"
|
||||
msgid "Assignees"
|
||||
msgstr "Assegnatari"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Allegato caricato"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "In attesa del cliente"
|
||||
@@ -304,9 +308,9 @@ msgstr "Portale di fatturazione"
|
||||
msgid "Blog Post"
|
||||
msgstr "Post del blog"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Bacheca"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "Il nome della bacheca non può superare i 100 caratteri"
|
||||
msgid "Board name is required"
|
||||
msgstr "Il nome della bacheca è obbligatorio"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Bacheca non trovata"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Bacheca non trovata"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Condivisione bacheca & inviti"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "L'URL della bacheca può contenere solo lettere, numeri e trattini"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "L'URL della bacheca non può superare i 60 caratteri"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "URL della bacheca copiato negli appunti"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "L'URL della bacheca deve contenere almeno 3 caratteri"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "L'URL della bacheca deve contenere almeno 3 caratteri"
|
||||
msgid "Board visibility"
|
||||
msgstr "Visibilità bacheca"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Visibilità della bacheca aggiornata"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Segnalazione bug"
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Carta"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Carta non trovata"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Titolo della carta"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Nome della checklist"
|
||||
msgid "Checklists"
|
||||
msgstr "Checklist"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Cancella filtri"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "ha completato un elemento della checklist"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "ha completato l'elemento <0>{0}</0> della checklist"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Conferma le tue preferenze email:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Conferma la tua nuova password"
|
||||
@@ -519,12 +528,12 @@ msgstr "Contattaci"
|
||||
msgid "Content Creation"
|
||||
msgstr "Creazione contenuti"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Continua con "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Continua con {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "Crea {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Crea un altro"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Crea un altro"
|
||||
msgid "Create API key"
|
||||
msgstr "Crea chiave API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Crea carta"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Crea link di invito"
|
||||
msgid "Create label"
|
||||
msgstr "Crea etichetta"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Crea lista"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Crea nuovo {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Crea nuova chiave"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Crea nuova etichetta"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Crea nuova lista"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Nome visualizzato aggiornato"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Offrite un piano gratuito?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Vuoi annullare l'iscrizione?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "documenti"
|
||||
@@ -769,8 +782,12 @@ msgstr "Non hai un account? <0><1>Registrati</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Fatto"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Download fallito"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Modifica URL della bacheca"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Modifica commento"
|
||||
msgid "Edit label"
|
||||
msgstr "Modifica etichetta"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Modifica URL dell'area di lavoro"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Modifica URL dell'area di lavoro"
|
||||
msgid "Editing"
|
||||
msgstr "Modifica"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Inserisci la tua password attuale"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Inserisci la tua password attuale e scegli una nuova password sicura."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Inserisci il tuo indirizzo email"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Inserisci il tuo nome"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Inserisci il tuo nome"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Inserisci la tua nuova password"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Inserisci la tua password"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Impossibile creare la bacheca"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Accesso con {0} fallito. Riprova."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Impossibile caricare l'allegato. Riprova."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Feedback"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Feedback inviato"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filtra"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Inizia ora"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Inizia creando un nuovo {0}"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Inizia creando una nuova lista"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Kanban reinventato"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Tieni presente che questa azione è irreversibile."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Etichette"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Licenza"
|
||||
msgid "Light"
|
||||
msgstr "Chiaro"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Link copiato"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Lista"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Nome lista"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Liste"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Login | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Amato dai team di tutto il mondo"
|
||||
msgid "Low Priority"
|
||||
msgstr "Bassa priorità"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "link magico"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Media priorità"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Membri"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Nuovo {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Nuova chiave API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Nuova carta"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Nuova importazione"
|
||||
msgid "New label"
|
||||
msgstr "Nuova etichetta"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Nuova lista"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Prossimi passi"
|
||||
msgid "No {0}"
|
||||
msgstr "Nessun {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "Nessun metodo di autenticazione è attualmente disponibile"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "Nessuna bacheca trovata"
|
||||
msgid "No credit card required"
|
||||
msgstr "Nessuna carta di credito richiesta"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "Nessun URL di download disponibile per questo allegato."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Nessuna lista"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "Open source"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Amici Open Source"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "o"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Piattaforma"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Conferma la tua nuova password"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Inserisci un indirizzo email valido"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Inserisci un nome valido"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Inserisci una password valida"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Seleziona un file da caricare."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Seleziona un file da caricare."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Supporto email prioritario"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Informativa sulla privacy"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Privato"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Immagine del profilo aggiornata"
|
||||
msgid "Profile picture"
|
||||
msgstr "Immagine del profilo"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Pubblico"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Registrazione disabilitata"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "La registrazione è attualmente disabilitata. Riprova più tardi."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Registrati con "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Piano Team"
|
||||
msgid "Teams"
|
||||
msgstr "Team"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Template"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "L'alternativa open source <0/> a Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "La visibilità della tua bacheca è stata impostata su {0}."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Questa azione non può essere annullata."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Questa chiave API verrà mostrata una sola volta. Salvala in un luogo sicuro."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Questa bacheca è privata o non esiste"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Questo URL della bacheca è già stato utilizzato"
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "Impossibile aggiungere l'elemento della checklist"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Impossibile aggiungere il commento"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Impossibile creare la scheda"
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "Impossibile creare la scheda"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Impossibile creare la checklist"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Impossibile creare la lista"
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "Impossibile creare il template"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Impossibile creare lo spazio di lavoro"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Impossibile eliminare l'allegato"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Impossibile eliminare la scheda"
|
||||
@@ -2151,16 +2186,16 @@ msgstr "Impossibile rimuovere il membro"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Impossibile inviare feedback"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Impossibile aggiornare l'URL della bacheca"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Impossibile aggiornare la visibilità della bacheca"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Impossibile aggiornare la scheda"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "Impossibile aggiornare il commento"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Impossibile aggiornare le etichette"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Impossibile aggiornare la lista"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Membri illimitati"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Aree di lavoro illimitate"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Annulla iscrizione"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Passa a Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Passa a Pro ($29/mese)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Caricamento fallito"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Visualizza e gestisci la tua fatturazione e abbonamento."
|
||||
msgid "View docs"
|
||||
msgstr "Visualizza documenti"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Solo visualizzazione"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Solo visualizzazione"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Visualizza la nostra roadmap."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Visualizza spazio di lavoro"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Visibilità"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Visibilità"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Utilizziamo la <0>licenza AGPL-3.0</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "Non siamo riusciti ad aggiornare le tue preferenze. Riprova."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Siamo solo all'inizio. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Perché creare un Trello open source?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Spazio di lavoro"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Hai effettuato l'accesso con successo."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Ti sei registrato con successo."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "La tua iscrizione è stata annullata!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Hai posti illimitati con il tuo Piano Pro. Non ci sono costi aggiuntivi per i nuovi membri!"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Le tue bacheche sono state importate."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Il tuo nome visualizzato è stato aggiornato."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Il tuo file è stato caricato con successo."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "La tua password è stata modificata."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Il tuo account Trello è stato disconnesso."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Il tuo account Trello è connesso."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Il tuo link per annullare l'iscrizione non contiene un token. Apri l'email più recente e riprova."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "La descrizione della tua area di lavoro è stata aggiornata."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} labels"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} niet gevonden"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Account"
|
||||
msgid "Account deleted"
|
||||
msgstr "Account verwijderd"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Activiteit"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Voeg een item toe..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Checklist toevoegen"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Beschrijving toevoegen... (typ '/' om commando's te openen of '@' om te vermelden)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "heeft <0>{0}</0> aan de kaart toegewezen"
|
||||
msgid "Assignees"
|
||||
msgstr "Toegewezen personen"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Bijlage geüpload"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Wachten op klant"
|
||||
@@ -304,9 +308,9 @@ msgstr "Factureringsportaal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blogbericht"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Bord"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "Bordnaam mag niet langer zijn dan 100 tekens"
|
||||
msgid "Board name is required"
|
||||
msgstr "Bordnaam is verplicht"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Bord niet gevonden"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Bord niet gevonden"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Bord delen & uitnodigingen"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "Board URL kan alleen letters, cijfers en koppeltekens bevatten"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "Board URL mag niet langer zijn dan 60 tekens"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "Board URL gekopieerd naar klembord"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "Board URL moet minimaal 3 tekens lang zijn"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "Board URL moet minimaal 3 tekens lang zijn"
|
||||
msgid "Board visibility"
|
||||
msgstr "Bordzichtbaarheid"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Zichtbaarheid van bord bijgewerkt"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Bugrapport"
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Kaart"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Kaart niet gevonden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Kaarttitel"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Naam checklist"
|
||||
msgid "Checklists"
|
||||
msgstr "Checklists"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Filters wissen"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "heeft een checklistitem voltooid"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "heeft checklistitem <0>{0}</0> voltooid"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Bevestig je e-mailvoorkeuren:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Bevestig je nieuwe wachtwoord"
|
||||
@@ -519,12 +528,12 @@ msgstr "Neem contact op"
|
||||
msgid "Content Creation"
|
||||
msgstr "Content creatie"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Doorgaan met "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Doorgaan met {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "{0} maken"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Maak nog een"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Maak nog een"
|
||||
msgid "Create API key"
|
||||
msgstr "API-sleutel aanmaken"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Maak kaart"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Uitnodigingslink maken"
|
||||
msgid "Create label"
|
||||
msgstr "Maak label"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Lijst maken"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Nieuwe {0} maken"
|
||||
msgid "Create new key"
|
||||
msgstr "Nieuwe sleutel aanmaken"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Maak nieuw label"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Maak nieuwe lijst"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Weergavenaam bijgewerkt"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Bieden jullie een gratis abonnement aan?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Wil je je uitschrijven?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "docs"
|
||||
@@ -769,8 +782,12 @@ msgstr "Heb je geen account? <0><1>Registreer je</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Klaar"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Download mislukt"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Board URL bewerken"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Reactie bewerken"
|
||||
msgid "Edit label"
|
||||
msgstr "Label bewerken"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Werkruimte-URL bewerken"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Werkruimte-URL bewerken"
|
||||
msgid "Editing"
|
||||
msgstr "Bewerken"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "e-mail"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Voer je huidige wachtwoord in"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Voer je huidige wachtwoord in en kies een nieuw veilig wachtwoord."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Voer je e-mailadres in"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Voer je naam in"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Voer je naam in"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Voer je nieuwe wachtwoord in"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Voer je wachtwoord in"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Bord maken mislukt"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Inloggen met {0} is mislukt. Probeer het opnieuw."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Bijlage uploaden mislukt. Probeer het opnieuw."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Feedback"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Feedback verzonden"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Aan de slag"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Begin door een nieuwe {0} te maken"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Begin door een nieuwe lijst te maken"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Kanban opnieuw uitgevonden"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Houd er rekening mee dat deze actie onomkeerbaar is."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Licentie"
|
||||
msgid "Light"
|
||||
msgstr "Licht"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Link gekopieerd"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Lijst"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Lijstnaam"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Lijsten"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Login | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Geliefd door teams wereldwijd"
|
||||
msgid "Low Priority"
|
||||
msgstr "Lage prioriteit"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "magische link"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Gemiddelde prioriteit"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Leden"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Nieuwe {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Nieuwe API-sleutel"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Nieuwe kaart"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Nieuwe import"
|
||||
msgid "New label"
|
||||
msgstr "Nieuw label"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Nieuwe lijst"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Volgende stappen"
|
||||
msgid "No {0}"
|
||||
msgstr "Geen {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "Er zijn momenteel geen authenticatiemethoden beschikbaar"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "Geen borden gevonden"
|
||||
msgid "No credit card required"
|
||||
msgstr "Geen creditcard vereist"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "Geen download-URL beschikbaar voor deze bijlage."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Geen lijsten"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "Open source"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Open Source Vrienden"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "of"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Platform"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Bevestig je nieuwe wachtwoord"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Voer een geldig e-mailadres in"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Voer een geldige naam in"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Voer een geldig wachtwoord in"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Selecteer een bestand om te uploaden."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Selecteer een bestand om te uploaden."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Prioriteit e-mailondersteuning"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Privacybeleid"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Privé"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Profielafbeelding bijgewerkt"
|
||||
msgid "Profile picture"
|
||||
msgstr "Profielfoto"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Openbaar"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Registreren uitgeschakeld"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "Registreren is momenteel uitgeschakeld. Probeer het later opnieuw."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Registreren met "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Teamplan"
|
||||
msgid "Teams"
|
||||
msgstr "Teams"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Sjabloon"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "Het open source <0/> alternatief voor Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "De zichtbaarheid van je bord is ingesteld op {0}."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Deze actie kan niet ongedaan worden gemaakt."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Deze API-sleutel wordt slechts één keer getoond. Bewaar deze op een veilige plaats."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Dit bord is privé of bestaat niet"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Deze board URL is al in gebruik"
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "Kan checklistitem niet toevoegen"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Kan geen reactie toevoegen"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Kan kaart niet aanmaken"
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "Kan kaart niet aanmaken"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Kan checklist niet maken"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Kan geen lijst maken"
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "Kan sjabloon niet maken"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Kan werkruimte niet aanmaken"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Kan bijlage niet verwijderen"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Kan kaart niet verwijderen"
|
||||
@@ -2151,16 +2186,16 @@ msgstr "Kan lid niet verwijderen"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Feedback kon niet worden verzonden"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Kan board URL niet bijwerken"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Kan bordzichtbaarheid niet bijwerken"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Kan kaart niet bijwerken"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "Kan reactie niet bijwerken"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Kan labels niet bijwerken"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Kan lijst niet bijwerken"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Onbeperkt aantal leden"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Onbeperkte werkruimtes"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Uitschrijven"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Upgraden naar Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Upgrade naar Pro ($29/maand)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Uploaden mislukt"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Bekijk en beheer je facturering en abonnement."
|
||||
msgid "View docs"
|
||||
msgstr "Bekijk documentatie"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Alleen bekijken"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Alleen bekijken"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Bekijk onze roadmap."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Werkruimte bekijken"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Zichtbaarheid"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Zichtbaarheid"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "We gebruiken de <0>AGPL-3.0 licentie</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "We konden je voorkeuren niet bijwerken. Probeer het opnieuw."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "We zijn nog maar net begonnen. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Waarom een open source Trello maken?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Werkruimte"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Je bent succesvol ingelogd."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Je bent succesvol geregistreerd."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "Je bent uitgeschreven!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Je hebt onbeperkte plaatsen met je Pro Plan. Er zijn geen extra kosten voor nieuwe leden!"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Je borden zijn geïmporteerd."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Je weergavenaam is bijgewerkt."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Je bestand is succesvol geüpload."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Je wachtwoord is gewijzigd."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Je Trello-account is ontkoppeld."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Je Trello-account is verbonden."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Je uitschrijflink mist een token. Open de meest recente e-mail en probeer het opnieuw."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "Je werkruimtebeschrijving is bijgewerkt."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -36,17 +36,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} etykiety"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} nie znaleziono"
|
||||
|
||||
@@ -84,8 +84,8 @@ msgstr "Konto"
|
||||
msgid "Account deleted"
|
||||
msgstr "Konto zostało usunięte"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Aktywność"
|
||||
|
||||
@@ -114,7 +114,7 @@ msgstr "Dodaj element..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Dodaj listę kontrolną"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Dodaj opis... (wpisz '/' aby otworzyć polecenia lub '@' aby wspomnieć)"
|
||||
|
||||
@@ -275,6 +275,10 @@ msgstr "przypisano <0>{0}</0> do karty"
|
||||
msgid "Assignees"
|
||||
msgstr "Osoby przypisane"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Załącznik został przesłany"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Oczekuje na klienta"
|
||||
@@ -309,9 +313,9 @@ msgstr "Portal rozliczeniowy"
|
||||
msgid "Blog Post"
|
||||
msgstr "Post na blogu"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Tablica"
|
||||
|
||||
@@ -328,7 +332,7 @@ msgstr "Nazwa tablicy nie może przekraczać 100 znaków"
|
||||
msgid "Board name is required"
|
||||
msgstr "Nazwa tablicy jest wymagana"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Tablica nie została znaleziona"
|
||||
|
||||
@@ -336,19 +340,19 @@ msgstr "Tablica nie została znaleziona"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Udostępnianie tablicy i zaproszenia"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "Adres URL tablicy może zawierać tylko litery, cyfry i myślniki"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "Adres URL tablicy nie może przekraczać 60 znaków"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "Adres URL tablicy został skopiowany do schowka"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "Adres URL tablicy musi mieć co najmniej 3 znaki"
|
||||
|
||||
@@ -357,7 +361,7 @@ msgstr "Adres URL tablicy musi mieć co najmniej 3 znaki"
|
||||
msgid "Board visibility"
|
||||
msgstr "Widoczność tablicy"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Widoczność tablicy została zaktualizowana"
|
||||
|
||||
@@ -392,15 +396,16 @@ msgstr "Zgłoszenie błędu"
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Karta"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Nie można było znaleźć karty"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Tytuł karty"
|
||||
|
||||
@@ -433,7 +438,7 @@ msgstr "Nazwa listy kontrolnej"
|
||||
msgid "Checklists"
|
||||
msgstr "Listy kontrolne"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Wyczyść filtry"
|
||||
|
||||
@@ -494,6 +499,10 @@ msgstr "ukończono element listy kontrolnej"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "ukończono element listy kontrolnej <0>{0}</0>"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Potwierdź swoje preferencje dotyczące e-maili:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Potwierdź swoje nowe hasło"
|
||||
@@ -524,12 +533,12 @@ msgstr "Skontaktuj się z nami"
|
||||
msgid "Content Creation"
|
||||
msgstr "Tworzenie treści"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Kontynuuj z "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Kontynuuj z {0}"
|
||||
|
||||
@@ -547,8 +556,8 @@ msgid "Create {0}"
|
||||
msgstr "Utwórz {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Utwórz kolejny"
|
||||
|
||||
@@ -556,7 +565,7 @@ msgstr "Utwórz kolejny"
|
||||
msgid "Create API key"
|
||||
msgstr "Utwórz klucz API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Utwórz kartę"
|
||||
|
||||
@@ -572,7 +581,7 @@ msgstr "Utwórz link zaproszenia"
|
||||
msgid "Create label"
|
||||
msgstr "Utwórz etykietę"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Utwórz listę"
|
||||
|
||||
@@ -585,12 +594,12 @@ msgstr "Utwórz nowy {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Utwórz nowy klucz"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Utwórz nową etykietę"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Utwórz nową listę"
|
||||
|
||||
@@ -748,6 +757,10 @@ msgstr "Zaktualizowano wyświetlaną nazwę"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Czy oferujecie darmowy plan?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Czy chcesz się wypisać?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "dokumentacja"
|
||||
@@ -774,8 +787,12 @@ msgstr "Nie masz konta? <0><1>Zarejestruj się</1></0>"
|
||||
msgid "Done"
|
||||
msgstr "Gotowe"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Pobieranie nie powiodło się"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Edytuj URL tablicy"
|
||||
|
||||
@@ -787,7 +804,7 @@ msgstr "Edytuj komentarz"
|
||||
msgid "Edit label"
|
||||
msgstr "Edytuj etykietę"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Edytuj URL przestrzeni roboczej"
|
||||
|
||||
@@ -795,7 +812,7 @@ msgstr "Edytuj URL przestrzeni roboczej"
|
||||
msgid "Editing"
|
||||
msgstr "Edycja"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
@@ -815,11 +832,11 @@ msgstr "Wprowadź swoje obecne hasło"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Wprowadź swoje obecne hasło i wybierz nowe, bezpieczne hasło."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Wprowadź swój adres e-mail"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Wprowadź swoje imię"
|
||||
|
||||
@@ -827,7 +844,7 @@ msgstr "Wprowadź swoje imię"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Wprowadź swoje nowe hasło"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Wprowadź swoje hasło"
|
||||
|
||||
@@ -936,6 +953,11 @@ msgstr "Nie udało się utworzyć tablicy"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Nie udało się zalogować za pomocą {0}. Spróbuj ponownie."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Nie udało się przesłać załącznika. Proszę spróbować ponownie."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -979,7 +1001,7 @@ msgstr "Opinie"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Opinia wysłana"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Filtr"
|
||||
|
||||
@@ -1033,7 +1055,7 @@ msgstr "Rozpocznij"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Rozpocznij, tworząc nowy {0}"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Rozpocznij, tworząc nową listę"
|
||||
|
||||
@@ -1247,9 +1269,9 @@ msgstr "Kanban wymyślony na nowo"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Pamiętaj, że ta akcja jest nieodwracalna."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Etykiety"
|
||||
|
||||
@@ -1299,18 +1321,22 @@ msgstr "Licencja"
|
||||
msgid "Light"
|
||||
msgstr "Jasny"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Link skopiowany"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Lista"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Nazwa listy"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Listy"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Zaloguj się | kan.bn"
|
||||
@@ -1331,7 +1357,7 @@ msgstr "Uwielbiane przez zespoły na całym świecie"
|
||||
msgid "Low Priority"
|
||||
msgstr "Niski priorytet"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "magiczny link"
|
||||
|
||||
@@ -1353,9 +1379,9 @@ msgid "Medium Priority"
|
||||
msgstr "Średni priorytet"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Członkowie"
|
||||
@@ -1408,7 +1434,7 @@ msgstr "Nowy {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Nowy klucz API"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Nowa karta"
|
||||
|
||||
@@ -1424,8 +1450,8 @@ msgstr "Nowy import"
|
||||
msgid "New label"
|
||||
msgstr "Nowa etykieta"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Nowa lista"
|
||||
|
||||
@@ -1462,7 +1488,7 @@ msgstr "Następne kroki"
|
||||
msgid "No {0}"
|
||||
msgstr "Brak {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "Obecnie brak dostępnych metod uwierzytelniania"
|
||||
|
||||
@@ -1474,7 +1500,11 @@ msgstr "Nie znaleziono tablic"
|
||||
msgid "No credit card required"
|
||||
msgstr "Nie wymagana karta kredytowa"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "Brak dostępnego URL do pobrania tego załącznika."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Brak list"
|
||||
|
||||
@@ -1506,7 +1536,7 @@ msgstr "Otwartoźródłowe"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Przyjaciele Open Source"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "lub"
|
||||
|
||||
@@ -1588,15 +1618,15 @@ msgstr "Platforma"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Proszę potwierdzić nowe hasło"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Proszę wprowadzić prawidłowy adres e-mail"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Proszę wprowadzić poprawne imię"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Proszę wprowadzić poprawne hasło"
|
||||
|
||||
@@ -1607,15 +1637,16 @@ msgstr "Proszę wybrać plik do przesłania."
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1629,7 +1660,7 @@ msgstr "Proszę wybrać plik do przesłania."
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1673,7 +1704,7 @@ msgstr "Priorytetowe wsparcie e-mail"
|
||||
msgid "Privacy policy"
|
||||
msgstr "Polityka prywatności"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Prywatne"
|
||||
|
||||
@@ -1693,7 +1724,7 @@ msgstr "Zaktualizowano zdjęcie profilowe"
|
||||
msgid "Profile picture"
|
||||
msgstr "Zdjęcie profilowe"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Publiczne"
|
||||
|
||||
@@ -1895,7 +1926,7 @@ msgstr "Rejestracja wyłączona"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "Rejestracja jest obecnie wyłączona. Spróbuj ponownie później."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Zarejestruj się za pomocą "
|
||||
|
||||
@@ -1962,8 +1993,8 @@ msgstr "Plan zespołowy"
|
||||
msgid "Teams"
|
||||
msgstr "Zespoły"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Szablon"
|
||||
|
||||
@@ -2013,7 +2044,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "Otwarta alternatywa <0/> dla Trello"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "Widoczność Twojej tablicy została ustawiona na {0}."
|
||||
|
||||
@@ -2037,11 +2068,11 @@ msgstr "Tej akcji nie można cofnąć."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Ten klucz API zostanie wyświetlony tylko raz. Proszę zapisać go w bezpiecznym miejscu."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Ta tablica jest prywatna lub nie istnieje"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Ten adres URL tablicy jest już zajęty"
|
||||
|
||||
@@ -2111,7 +2142,7 @@ msgstr "Nie można dodać elementu listy kontrolnej"
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Nie można dodać komentarza"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Nie można utworzyć karty"
|
||||
|
||||
@@ -2119,7 +2150,7 @@ msgstr "Nie można utworzyć karty"
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Nie można utworzyć listy kontrolnej"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Nie można utworzyć listy"
|
||||
|
||||
@@ -2132,6 +2163,10 @@ msgstr "Nie można utworzyć szablonu"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Nie można utworzyć przestrzeni roboczej"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Nie można usunąć załącznika"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Nie można usunąć karty"
|
||||
@@ -2156,16 +2191,16 @@ msgstr "Nie można usunąć członka"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Nie można wysłać opinii"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Nie można zaktualizować adresu URL tablicy"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Nie można zaktualizować widoczności tablicy"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Nie można zaktualizować karty"
|
||||
|
||||
@@ -2185,7 +2220,7 @@ msgstr "Nie można zaktualizować komentarza"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Nie można zaktualizować etykiet"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Nie można zaktualizować listy"
|
||||
@@ -2241,7 +2276,12 @@ msgstr "Nieograniczona liczba członków"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Nieograniczona liczba przestrzeni roboczych"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Wypisz się"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2280,6 +2320,11 @@ msgstr "Ulepsz do planu Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Ulepsz do planu Pro (29 USD/miesiąc)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Przesyłanie nie powiodło się"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2329,7 +2374,7 @@ msgstr "Zobacz i zarządzaj swoimi płatnościami i subskrypcją."
|
||||
msgid "View docs"
|
||||
msgstr "Zobacz dokumentację"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Tylko podgląd"
|
||||
|
||||
@@ -2337,11 +2382,11 @@ msgstr "Tylko podgląd"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Zobacz nasz plan ulepszeń."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Zobacz obszar roboczy"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Widoczność"
|
||||
|
||||
@@ -2349,6 +2394,10 @@ msgstr "Widoczność"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Używamy licencji <0>AGPL-3.0</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "Nie udało się zaktualizować twoich preferencji. Spróbuj ponownie."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Dopiero zaczynamy. "
|
||||
@@ -2378,10 +2427,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Dlaczego próbujecie stworzyć Trello w wersji otwartoźródłowej?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Obszar roboczy"
|
||||
@@ -2487,6 +2536,10 @@ msgstr "Zostałeś pomyślnie zalogowany."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Zostałeś pomyślnie zarejestrowany."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "Zostałeś wypisany!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "Masz nielimitowaną liczbę miejsc w swoim planie Pro. Nie ma dodatkowych opłat za nowych członków!"
|
||||
@@ -2511,6 +2564,10 @@ msgstr "Twoje tablice zostały zaimportowane."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Twoja nazwa wyświetlana została zaktualizowana."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Twój plik został pomyślnie przesłany."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Twoje hasło zostało zmienione."
|
||||
@@ -2527,6 +2584,10 @@ msgstr "Twoje konto Trello zostało odłączone."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Twoje konto Trello jest połączone."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "Twój link do wypisania się nie zawiera tokena. Otwórz najnowszy e-mail i spróbuj ponownie."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "Opis twojej przestrzeni roboczej został zaktualizowany."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,17 +31,17 @@ msgstr "{0}"
|
||||
#. placeholder {1}: board?.name ?? t`Board`
|
||||
#. placeholder {1}: workspace.name ?? t`Workspace`
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:442
|
||||
#: src/views/board/components/NewCardForm.tsx:443
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} метки"
|
||||
|
||||
#. placeholder {0}: isTemplate ? "Template" : "Board"
|
||||
#: src/views/board/index.tsx:387
|
||||
#: src/views/board/index.tsx:389
|
||||
msgid "{0} not found"
|
||||
msgstr "{0} не найден"
|
||||
|
||||
@@ -79,8 +79,8 @@ msgstr "Аккаунт"
|
||||
msgid "Account deleted"
|
||||
msgstr "Аккаунт удалён"
|
||||
|
||||
#: src/views/card/index.tsx:291
|
||||
#: src/views/public/board/CardModal.tsx:143
|
||||
#: src/views/card/index.tsx:343
|
||||
#: src/views/public/board/CardModal.tsx:157
|
||||
msgid "Activity"
|
||||
msgstr "Активность"
|
||||
|
||||
@@ -109,7 +109,7 @@ msgstr "Добавить элемент..."
|
||||
msgid "Add checklist"
|
||||
msgstr "Добавить чек-лист"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
#: src/components/Editor.tsx:451
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Добавить описание... (введите '/' для открытия команд или '@' для упоминания)"
|
||||
|
||||
@@ -270,6 +270,10 @@ msgstr "назначено <0>{0}</0> к карточке"
|
||||
msgid "Assignees"
|
||||
msgstr "Исполнители"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:25
|
||||
msgid "Attachment uploaded"
|
||||
msgstr "Вложение загружено"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:47
|
||||
msgid "Awaiting Customer"
|
||||
msgstr "Ожидание клиента"
|
||||
@@ -304,9 +308,9 @@ msgstr "Портал выставления счетов"
|
||||
msgid "Blog Post"
|
||||
msgstr "Пост в блоге"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/card/index.tsx:229
|
||||
#: src/views/public/board/index.tsx:101
|
||||
msgid "Board"
|
||||
msgstr "Доска"
|
||||
|
||||
@@ -323,7 +327,7 @@ msgstr "Название доски не может превышать 100 си
|
||||
msgid "Board name is required"
|
||||
msgstr "Название доски обязательно"
|
||||
|
||||
#: src/views/public/board/index.tsx:151
|
||||
#: src/views/public/board/index.tsx:153
|
||||
msgid "Board not found"
|
||||
msgstr "Доска не найдена"
|
||||
|
||||
@@ -331,19 +335,19 @@ msgstr "Доска не найдена"
|
||||
msgid "Board sharing & invites"
|
||||
msgstr "Общий доступ к доске и приглашения"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:45
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:46
|
||||
msgid "Board URL can only contain letters, numbers, and hyphens"
|
||||
msgstr "URL доски может содержать только буквы, цифры и дефисы"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:43
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:44
|
||||
msgid "Board URL cannot exceed 60 characters"
|
||||
msgstr "URL доски не может превышать 60 символов"
|
||||
|
||||
#: src/views/public/board/index.tsx:67
|
||||
#: src/views/public/board/index.tsx:68
|
||||
msgid "Board URL copied to clipboard"
|
||||
msgstr "URL доски скопирован в буфер обмена"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:42
|
||||
msgid "Board URL must be at least 3 characters long"
|
||||
msgstr "URL доски должен содержать не менее 3 символов"
|
||||
|
||||
@@ -352,7 +356,7 @@ msgstr "URL доски должен содержать не менее 3 сим
|
||||
msgid "Board visibility"
|
||||
msgstr "Видимость доски"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:45
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
msgid "Board visibility updated"
|
||||
msgstr "Видимость доски обновлена"
|
||||
|
||||
@@ -387,15 +391,16 @@ msgstr "Отчет об ошибке"
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
#: src/views/card/index.tsx:216
|
||||
#: src/views/card/index.tsx:229
|
||||
msgid "Card"
|
||||
msgstr "Карточка"
|
||||
|
||||
#: src/views/card/index.tsx:262
|
||||
#: src/views/card/index.tsx:263
|
||||
#: src/views/card/index.tsx:299
|
||||
msgid "Card not found"
|
||||
msgstr "Карточка не найдена"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:309
|
||||
#: src/views/board/components/NewCardForm.tsx:310
|
||||
msgid "Card title"
|
||||
msgstr "Название карточки"
|
||||
|
||||
@@ -428,7 +433,7 @@ msgstr "Название контрольного списка"
|
||||
msgid "Checklists"
|
||||
msgstr "Контрольные списки"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
#: src/views/board/components/Filters.tsx:180
|
||||
msgid "Clear filters"
|
||||
msgstr "Очистить фильтры"
|
||||
|
||||
@@ -489,6 +494,10 @@ msgstr "завершил элемент контрольного списка"
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "завершил элемент контрольного списка <0>{0}</0>"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:81
|
||||
msgid "Confirm your email preferences:"
|
||||
msgstr "Подтвердите ваши настройки электронной почты:"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Подтвердите ваш новый пароль"
|
||||
@@ -519,12 +528,12 @@ msgstr "Свяжитесь с нами"
|
||||
msgid "Content Creation"
|
||||
msgstr "Создание контента"
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Continue with "
|
||||
msgstr "Продолжить с "
|
||||
|
||||
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
|
||||
#: src/components/AuthForm.tsx:351
|
||||
#: src/components/AuthForm.tsx:355
|
||||
msgid "Continue with {0}"
|
||||
msgstr "Продолжить с {0}"
|
||||
|
||||
@@ -542,8 +551,8 @@ msgid "Create {0}"
|
||||
msgstr "Создать {0}"
|
||||
|
||||
#: src/components/LabelForm.tsx:213
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:469
|
||||
#: src/views/board/components/NewListForm.tsx:141
|
||||
msgid "Create another"
|
||||
msgstr "Создать ещё одну"
|
||||
|
||||
@@ -551,7 +560,7 @@ msgstr "Создать ещё одну"
|
||||
msgid "Create API key"
|
||||
msgstr "Создать API-ключ"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:478
|
||||
#: src/views/board/components/NewCardForm.tsx:479
|
||||
msgid "Create card"
|
||||
msgstr "Создать карточку"
|
||||
|
||||
@@ -567,7 +576,7 @@ msgstr "Создать ссылку-приглашение"
|
||||
msgid "Create label"
|
||||
msgstr "Создать метку"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:152
|
||||
#: src/views/board/components/NewListForm.tsx:153
|
||||
msgid "Create list"
|
||||
msgstr "Создать список"
|
||||
|
||||
@@ -580,12 +589,12 @@ msgstr "Создать новый {0}"
|
||||
msgid "Create new key"
|
||||
msgstr "Создать новый ключ"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:404
|
||||
#: src/views/board/components/NewCardForm.tsx:405
|
||||
#: src/views/card/components/LabelSelector.tsx:97
|
||||
msgid "Create new label"
|
||||
msgstr "Создать новую метку"
|
||||
|
||||
#: src/views/board/index.tsx:475
|
||||
#: src/views/board/index.tsx:478
|
||||
msgid "Create new list"
|
||||
msgstr "Создать новый список"
|
||||
|
||||
@@ -743,6 +752,10 @@ msgstr "Отображаемое имя обновлено"
|
||||
msgid "Do you offer a free plan?"
|
||||
msgstr "Вы предлагаете бесплатный план?"
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:78
|
||||
msgid "Do you want to unsubscribe?"
|
||||
msgstr "Вы хотите отписаться?"
|
||||
|
||||
#: src/components/FeedbackModal.tsx:109
|
||||
msgid "docs"
|
||||
msgstr "документы"
|
||||
@@ -769,8 +782,12 @@ msgstr "Нет аккаунта? <0><1>Зарегистрируйтесь</1></0
|
||||
msgid "Done"
|
||||
msgstr "Готово"
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:141
|
||||
msgid "Download failed"
|
||||
msgstr "Не удалось загрузить"
|
||||
|
||||
#: src/views/board/components/BoardDropdown.tsx:41
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:115
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:116
|
||||
msgid "Edit board URL"
|
||||
msgstr "Изменить URL доски"
|
||||
|
||||
@@ -782,7 +799,7 @@ msgstr "Редактировать комментарий"
|
||||
msgid "Edit label"
|
||||
msgstr "Редактировать метку"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:161
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:162
|
||||
msgid "Edit workspace URL"
|
||||
msgstr "Редактировать URL рабочей области"
|
||||
|
||||
@@ -790,7 +807,7 @@ msgstr "Редактировать URL рабочей области"
|
||||
msgid "Editing"
|
||||
msgstr "Редактирование"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
@@ -810,11 +827,11 @@ msgstr "Введите ваш текущий пароль"
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Введите ваш текущий пароль и выберите новый безопасный пароль."
|
||||
|
||||
#: src/components/AuthForm.tsx:398
|
||||
#: src/components/AuthForm.tsx:402
|
||||
msgid "Enter your email address"
|
||||
msgstr "Введите ваш адрес электронной почты"
|
||||
|
||||
#: src/components/AuthForm.tsx:384
|
||||
#: src/components/AuthForm.tsx:388
|
||||
msgid "Enter your name"
|
||||
msgstr "Введите ваше имя"
|
||||
|
||||
@@ -822,7 +839,7 @@ msgstr "Введите ваше имя"
|
||||
msgid "Enter your new password"
|
||||
msgstr "Введите ваш новый пароль"
|
||||
|
||||
#: src/components/AuthForm.tsx:411
|
||||
#: src/components/AuthForm.tsx:416
|
||||
msgid "Enter your password"
|
||||
msgstr "Введите ваш пароль"
|
||||
|
||||
@@ -931,6 +948,11 @@ msgstr "Не удалось создать доску"
|
||||
msgid "Failed to login with {0}. Please try again."
|
||||
msgstr "Не удалось войти с {0}. Пожалуйста, попробуйте снова."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:33
|
||||
#: src/views/card/components/AttachmentUpload.tsx:79
|
||||
msgid "Failed to upload attachment. Please try again."
|
||||
msgstr "Не удалось загрузить вложение. Пожалуйста, попробуйте еще раз."
|
||||
|
||||
#: src/views/home/components/Header.tsx:41
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
@@ -974,7 +996,7 @@ msgstr "Обратная связь"
|
||||
msgid "Feedback sent"
|
||||
msgstr "Обратная связь отправлена"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:149
|
||||
#: src/views/board/components/Filters.tsx:174
|
||||
msgid "Filter"
|
||||
msgstr "Фильтр"
|
||||
|
||||
@@ -1028,7 +1050,7 @@ msgstr "Начать"
|
||||
msgid "Get started by creating a new {0}"
|
||||
msgstr "Начните с создания нового {0}"
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
#: src/views/board/index.tsx:470
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Начните с создания нового списка"
|
||||
|
||||
@@ -1242,9 +1264,9 @@ msgstr "Канбан переосмыслен"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Имейте в виду, что это действие необратимо."
|
||||
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
#: src/views/board/components/NewCardForm.tsx:408
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/Filters.tsx:115
|
||||
#: src/views/board/components/NewCardForm.tsx:409
|
||||
#: src/views/card/index.tsx:119
|
||||
msgid "Labels"
|
||||
msgstr "Метки"
|
||||
|
||||
@@ -1294,18 +1316,22 @@ msgstr "Лицензия"
|
||||
msgid "Light"
|
||||
msgstr "Светлый"
|
||||
|
||||
#: src/views/public/board/index.tsx:65
|
||||
#: src/views/public/board/index.tsx:66
|
||||
msgid "Link copied"
|
||||
msgstr "Ссылка скопирована"
|
||||
|
||||
#: src/views/card/index.tsx:109
|
||||
#: src/views/card/index.tsx:111
|
||||
msgid "List"
|
||||
msgstr "Список"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:128
|
||||
#: src/views/board/components/NewListForm.tsx:129
|
||||
msgid "List name"
|
||||
msgstr "Название списка"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:123
|
||||
msgid "Lists"
|
||||
msgstr "Списки"
|
||||
|
||||
#: src/views/auth/login/index.tsx:33
|
||||
msgid "Login | kan.bn"
|
||||
msgstr "Вход | kan.bn"
|
||||
@@ -1326,7 +1352,7 @@ msgstr "Любим командами по всему миру"
|
||||
msgid "Low Priority"
|
||||
msgstr "Низкий приоритет"
|
||||
|
||||
#: src/components/AuthForm.tsx:435
|
||||
#: src/components/AuthForm.tsx:441
|
||||
msgid "magic link"
|
||||
msgstr "магическая ссылка"
|
||||
|
||||
@@ -1348,9 +1374,9 @@ msgid "Medium Priority"
|
||||
msgstr "Средний приоритет"
|
||||
|
||||
#: src/components/SideNavigation.tsx:101
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/views/board/components/NewCardForm.tsx:366
|
||||
#: src/views/card/index.tsx:126
|
||||
#: src/views/board/components/Filters.tsx:107
|
||||
#: src/views/board/components/NewCardForm.tsx:367
|
||||
#: src/views/card/index.tsx:128
|
||||
#: src/views/members/index.tsx:178
|
||||
msgid "Members"
|
||||
msgstr "Участники"
|
||||
@@ -1403,7 +1429,7 @@ msgstr "Новый {0}"
|
||||
msgid "New API key"
|
||||
msgstr "Новый API-ключ"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:292
|
||||
#: src/views/board/components/NewCardForm.tsx:293
|
||||
msgid "New card"
|
||||
msgstr "Новая карточка"
|
||||
|
||||
@@ -1419,8 +1445,8 @@ msgstr "Новый импорт"
|
||||
msgid "New label"
|
||||
msgstr "Новая метка"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
#: src/views/board/index.tsx:439
|
||||
#: src/views/board/components/NewListForm.tsx:113
|
||||
#: src/views/board/index.tsx:442
|
||||
msgid "New list"
|
||||
msgstr "Новый список"
|
||||
|
||||
@@ -1457,7 +1483,7 @@ msgstr "Следующие шаги"
|
||||
msgid "No {0}"
|
||||
msgstr "Нет {0}"
|
||||
|
||||
#: src/components/AuthForm.tsx:365
|
||||
#: src/components/AuthForm.tsx:369
|
||||
msgid "No authentication methods are currently available"
|
||||
msgstr "В настоящее время нет доступных методов аутентификации"
|
||||
|
||||
@@ -1469,7 +1495,11 @@ msgstr "Доски не найдены"
|
||||
msgid "No credit card required"
|
||||
msgstr "Кредитная карта не требуется"
|
||||
|
||||
#: src/views/board/index.tsx:464
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:142
|
||||
msgid "No download URL available for this attachment."
|
||||
msgstr "URL для загрузки этого вложения недоступен."
|
||||
|
||||
#: src/views/board/index.tsx:467
|
||||
msgid "No lists"
|
||||
msgstr "Нет списков"
|
||||
|
||||
@@ -1501,7 +1531,7 @@ msgstr "С открытым исходным кодом"
|
||||
msgid "Open Source Friends"
|
||||
msgstr "Друзья с открытым исходным кодом"
|
||||
|
||||
#: src/components/AuthForm.tsx:374
|
||||
#: src/components/AuthForm.tsx:378
|
||||
msgid "or"
|
||||
msgstr "или"
|
||||
|
||||
@@ -1583,15 +1613,15 @@ msgstr "Платформа"
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Пожалуйста, подтвердите новый пароль"
|
||||
|
||||
#: src/components/AuthForm.tsx:402
|
||||
#: src/components/AuthForm.tsx:406
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Пожалуйста, введите действительный адрес электронной почты"
|
||||
|
||||
#: src/components/AuthForm.tsx:388
|
||||
#: src/components/AuthForm.tsx:392
|
||||
msgid "Please enter a valid name"
|
||||
msgstr "Пожалуйста, введите действительное имя"
|
||||
|
||||
#: src/components/AuthForm.tsx:416
|
||||
#: src/components/AuthForm.tsx:421
|
||||
msgid "Please enter a valid password"
|
||||
msgstr "Пожалуйста, введите действительный пароль"
|
||||
|
||||
@@ -1602,15 +1632,16 @@ msgstr "Пожалуйста, выберите файл для загрузки.
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/NewWorkspaceForm.tsx:158
|
||||
#: src/views/board/components/NewCardForm.tsx:176
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:177
|
||||
#: src/views/board/components/NewListForm.tsx:79
|
||||
#: src/views/board/components/NewTemplateForm.tsx:61
|
||||
#: src/views/board/components/NewTemplateForm.tsx:77
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/index.tsx:149
|
||||
#: src/views/board/index.tsx:205
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:54
|
||||
#: src/views/board/index.tsx:151
|
||||
#: src/views/board/index.tsx:207
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:73
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
@@ -1624,7 +1655,7 @@ msgstr "Пожалуйста, выберите файл для загрузки.
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/index.tsx:175
|
||||
#: src/views/card/index.tsx:177
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/members/components/InviteMemberForm.tsx:104
|
||||
#: src/views/members/components/InviteMemberForm.tsx:241
|
||||
@@ -1668,7 +1699,7 @@ msgstr "Приоритетная поддержка по электронной
|
||||
msgid "Privacy policy"
|
||||
msgstr "Политика конфиденциальности"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:73
|
||||
#: src/views/board/components/VisibilityButton.tsx:74
|
||||
msgid "Private"
|
||||
msgstr "Личное"
|
||||
|
||||
@@ -1688,7 +1719,7 @@ msgstr "Изображение профиля обновлено"
|
||||
msgid "Profile picture"
|
||||
msgstr "Фотография профиля"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:68
|
||||
#: src/views/board/components/VisibilityButton.tsx:69
|
||||
msgid "Public"
|
||||
msgstr "Публичное"
|
||||
|
||||
@@ -1890,7 +1921,7 @@ msgstr "Регистрация отключена"
|
||||
msgid "Sign up is currently disabled. Please try again later."
|
||||
msgstr "Регистрация в настоящее время отключена. Пожалуйста, попробуйте позже."
|
||||
|
||||
#: src/components/AuthForm.tsx:434
|
||||
#: src/components/AuthForm.tsx:440
|
||||
msgid "Sign up with "
|
||||
msgstr "Зарегистрироваться с "
|
||||
|
||||
@@ -1957,8 +1988,8 @@ msgstr "Командный план"
|
||||
msgid "Teams"
|
||||
msgstr "Команды"
|
||||
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:396
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/board/index.tsx:398
|
||||
msgid "Template"
|
||||
msgstr "Шаблон"
|
||||
|
||||
@@ -2008,7 +2039,7 @@ msgid "The open source <0/> alternative to Trello"
|
||||
msgstr "Альтернатива Trello с открытым исходным кодом <0/>"
|
||||
|
||||
#. placeholder {0}: isPublic ? "public" : "private"
|
||||
#: src/views/board/components/VisibilityButton.tsx:46
|
||||
#: src/views/board/components/VisibilityButton.tsx:47
|
||||
msgid "The visibility of your board has been set to {0}."
|
||||
msgstr "Видимость вашей доски установлена на {0}."
|
||||
|
||||
@@ -2032,11 +2063,11 @@ msgstr "Это действие нельзя будет отменить."
|
||||
msgid "This API key will only be shown once. Please save it in a secure location."
|
||||
msgstr "Этот API-ключ будет показан только один раз. Пожалуйста, сохраните его в безопасном месте."
|
||||
|
||||
#: src/views/public/board/index.tsx:154
|
||||
#: src/views/public/board/index.tsx:156
|
||||
msgid "This board is private or does not exist"
|
||||
msgstr "Эта доска является приватной или не существует."
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:135
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:136
|
||||
msgid "This board URL has already been taken"
|
||||
msgstr "Этот URL доски уже занят."
|
||||
|
||||
@@ -2106,7 +2137,7 @@ msgstr "Не удалось добавить элемент контрольно
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Не удалось добавить комментарий."
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:173
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
msgid "Unable to create card"
|
||||
msgstr "Не удалось создать карточку."
|
||||
|
||||
@@ -2114,7 +2145,7 @@ msgstr "Не удалось создать карточку."
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Не удалось создать контрольный список."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
msgid "Unable to create list"
|
||||
msgstr "Не удалось создать список."
|
||||
|
||||
@@ -2127,6 +2158,10 @@ msgstr "Не удалось создать шаблон"
|
||||
msgid "Unable to create workspace"
|
||||
msgstr "Не удалось создать рабочее пространство."
|
||||
|
||||
#: src/views/card/components/AttachmentThumbnails.tsx:72
|
||||
msgid "Unable to delete attachment"
|
||||
msgstr "Не удалось удалить вложение"
|
||||
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:51
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Не удалось удалить карточку."
|
||||
@@ -2151,16 +2186,16 @@ msgstr "Не удалось удалить участника"
|
||||
msgid "Unable to send feedback"
|
||||
msgstr "Не удалось отправить отзыв"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:71
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
msgid "Unable to update board URL"
|
||||
msgstr "Не удалось обновить URL доски"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:52
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Не удалось обновить видимость доски"
|
||||
|
||||
#: src/views/board/index.tsx:204
|
||||
#: src/views/card/index.tsx:174
|
||||
#: src/views/board/index.tsx:206
|
||||
#: src/views/card/index.tsx:176
|
||||
msgid "Unable to update card"
|
||||
msgstr "Не удалось обновить карточку"
|
||||
|
||||
@@ -2180,7 +2215,7 @@ msgstr "Не удалось обновить комментарий"
|
||||
msgid "Unable to update labels"
|
||||
msgstr "Не удалось обновить метки"
|
||||
|
||||
#: src/views/board/index.tsx:148
|
||||
#: src/views/board/index.tsx:150
|
||||
#: src/views/card/components/ListSelector.tsx:51
|
||||
msgid "Unable to update list"
|
||||
msgstr "Не удалось обновить список"
|
||||
@@ -2236,7 +2271,12 @@ msgstr "Неограниченное количество участников"
|
||||
msgid "Unlimited workspaces"
|
||||
msgstr "Неограниченное количество рабочих пространств"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:174
|
||||
#: src/pages/unsubscribe/index.tsx:68
|
||||
#: src/pages/unsubscribe/index.tsx:93
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Отписаться"
|
||||
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:175
|
||||
#: src/views/settings/components/UpdateDisplayNameForm.tsx:80
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
|
||||
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
|
||||
@@ -2275,6 +2315,11 @@ msgstr "Обновить до Pro"
|
||||
msgid "Upgrade to Pro ($29/month)"
|
||||
msgstr "Обновить до Pro ($29/месяц)"
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:32
|
||||
#: src/views/card/components/AttachmentUpload.tsx:78
|
||||
msgid "Upload failed"
|
||||
msgstr "Не удалось загрузить"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:38
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Urgent"
|
||||
@@ -2324,7 +2369,7 @@ msgstr "Просмотр и управление вашими счетами и
|
||||
msgid "View docs"
|
||||
msgstr "Просмотреть документацию"
|
||||
|
||||
#: src/views/public/board/index.tsx:128
|
||||
#: src/views/public/board/index.tsx:129
|
||||
msgid "View only"
|
||||
msgstr "Только просмотр"
|
||||
|
||||
@@ -2332,11 +2377,11 @@ msgstr "Только просмотр"
|
||||
msgid "View our roadmap."
|
||||
msgstr "Просмотреть нашу дорожную карту."
|
||||
|
||||
#: src/views/public/board/index.tsx:157
|
||||
#: src/views/public/board/index.tsx:159
|
||||
msgid "View workspace"
|
||||
msgstr "Просмотреть рабочее пространство"
|
||||
|
||||
#: src/views/board/components/VisibilityButton.tsx:91
|
||||
#: src/views/board/components/VisibilityButton.tsx:92
|
||||
msgid "Visibility"
|
||||
msgstr "Видимость"
|
||||
|
||||
@@ -2344,6 +2389,10 @@ msgstr "Видимость"
|
||||
msgid "We are using the <0>AGPL-3.0 license</0>."
|
||||
msgstr "Мы используем лицензию <0>AGPL-3.0</0>."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:63
|
||||
msgid "We couldn't update your preferences. Please try again."
|
||||
msgstr "Мы не смогли обновить ваши настройки. Пожалуйста, попробуйте снова."
|
||||
|
||||
#: src/views/home/components/Features.tsx:152
|
||||
msgid "We're just getting started. "
|
||||
msgstr "Мы только начинаем. "
|
||||
@@ -2373,10 +2422,10 @@ msgid "Why make an open source Trello?"
|
||||
msgstr "Зачем создавать Trello с открытым исходным кодом?"
|
||||
|
||||
#: src/components/SettingsLayout.tsx:39
|
||||
#: src/views/board/index.tsx:361
|
||||
#: src/views/board/index.tsx:363
|
||||
#: src/views/boards/index.tsx:22
|
||||
#: src/views/members/index.tsx:173
|
||||
#: src/views/public/board/index.tsx:100
|
||||
#: src/views/public/board/index.tsx:101
|
||||
#: src/views/public/boards/index.tsx:66
|
||||
msgid "Workspace"
|
||||
msgstr "Рабочее пространство"
|
||||
@@ -2482,6 +2531,10 @@ msgstr "Вы успешно вошли в систему."
|
||||
msgid "You have been signed up successfully."
|
||||
msgstr "Вы успешно зарегистрировались."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:98
|
||||
msgid "You have been unsubscribed!"
|
||||
msgstr "Вы успешно отписались!"
|
||||
|
||||
#: src/views/members/components/InviteMemberForm.tsx:326
|
||||
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
|
||||
msgstr "В вашем профессиональном плане неограниченное количество мест. За новых участников дополнительная плата не взимается!"
|
||||
@@ -2506,6 +2559,10 @@ msgstr "Ваши доски были импортированы."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Ваше отображаемое имя было обновлено."
|
||||
|
||||
#: src/views/card/components/AttachmentUpload.tsx:26
|
||||
msgid "Your file has been uploaded successfully."
|
||||
msgstr "Ваш файл успешно загружен."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Ваш пароль был изменён."
|
||||
@@ -2522,6 +2579,10 @@ msgstr "Ваш аккаунт Trello был отключён."
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Ваш аккаунт Trello подключён."
|
||||
|
||||
#: src/pages/unsubscribe/index.tsx:33
|
||||
msgid "Your unsubscribe link is missing a token. Please open the latest email and try again."
|
||||
msgstr "В вашей ссылке для отписки отсутствует токен. Пожалуйста, откройте последнее письмо и попробуйте снова."
|
||||
|
||||
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:49
|
||||
msgid "Your workspace description has been updated."
|
||||
msgstr "Описание вашего рабочего пространства было обновлено."
|
||||
|
||||
File diff suppressed because one or more lines are too long
48
apps/web/src/pages/api/download/attatchment.ts
Normal file
48
apps/web/src/pages/api/download/attatchment.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ message: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { url, filename } = req.query;
|
||||
|
||||
if (!url || typeof url !== "string") {
|
||||
return res.status(400).json({
|
||||
message: "url parameter is required",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const downloadUrl = decodeURIComponent(url);
|
||||
const downloadFilename =
|
||||
(typeof filename === "string" ? decodeURIComponent(filename) : null) ??
|
||||
"attachment";
|
||||
|
||||
const upstream = await fetch(downloadUrl);
|
||||
|
||||
if (!upstream.ok) {
|
||||
return res.status(upstream.status).json({
|
||||
message: "Failed to fetch attachment",
|
||||
});
|
||||
}
|
||||
|
||||
const contentType =
|
||||
upstream.headers.get("Content-Type") ?? "application/octet-stream";
|
||||
|
||||
res.setHeader("Content-Type", contentType);
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="${downloadFilename}"`,
|
||||
);
|
||||
|
||||
const buffer = await upstream.arrayBuffer();
|
||||
return res.send(Buffer.from(buffer));
|
||||
} catch (error) {
|
||||
console.error("Error downloading attachment:", error);
|
||||
return res.status(500).json({ message: "Failed to download attachment" });
|
||||
}
|
||||
}
|
||||
104
apps/web/src/pages/api/unsubscribe.ts
Normal file
104
apps/web/src/pages/api/unsubscribe.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { Novu } from "@novu/api";
|
||||
import { jwtVerify } from "jose";
|
||||
import { z } from "zod";
|
||||
|
||||
import { env } from "~/env";
|
||||
|
||||
const requestSchema = z.object({
|
||||
token: z.string().min(1),
|
||||
});
|
||||
|
||||
const tokenPayloadSchema = z.object({
|
||||
subscriberId: z.string(),
|
||||
});
|
||||
|
||||
type ResponseData =
|
||||
| { success: true }
|
||||
| { success: false; error: string; code?: string };
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<ResponseData>,
|
||||
) {
|
||||
if (process.env.NEXT_PUBLIC_KAN_ENV !== "cloud") {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Unsubscribe endpoint is not available.",
|
||||
code: "UNAVAILABLE",
|
||||
});
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
res.setHeader("Allow", "POST");
|
||||
return res.status(405).json({
|
||||
success: false,
|
||||
error: "Method not allowed.",
|
||||
code: "METHOD_NOT_ALLOWED",
|
||||
});
|
||||
}
|
||||
|
||||
const parsedBody = requestSchema.safeParse(req.body);
|
||||
|
||||
if (!parsedBody.success) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: "Invalid request payload.",
|
||||
code: "BAD_REQUEST",
|
||||
});
|
||||
}
|
||||
|
||||
if (!env.EMAIL_UNSUBSCRIBE_SECRET || !env.NOVU_API_KEY) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: "Unsubscribe service is not configured.",
|
||||
code: "NOT_CONFIGURED",
|
||||
});
|
||||
}
|
||||
|
||||
let payload: z.infer<typeof tokenPayloadSchema>;
|
||||
|
||||
try {
|
||||
const verified = await jwtVerify(
|
||||
parsedBody.data.token,
|
||||
textEncoder.encode(env.EMAIL_UNSUBSCRIBE_SECRET),
|
||||
{
|
||||
// We intentionally do not use exp/iat claims –
|
||||
// tokens are long-lived and validated only by signature + payload.
|
||||
clockTolerance: "0s",
|
||||
},
|
||||
);
|
||||
payload = tokenPayloadSchema.parse(verified.payload);
|
||||
} catch {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: "Your unsubscribe link is invalid or has expired.",
|
||||
code: "INVALID_TOKEN",
|
||||
});
|
||||
}
|
||||
|
||||
const novu = new Novu({ secretKey: env.NOVU_API_KEY });
|
||||
|
||||
try {
|
||||
await novu.subscribers.preferences.update(
|
||||
{
|
||||
channels: {
|
||||
email: false,
|
||||
},
|
||||
},
|
||||
payload.subscriberId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to update Novu preferences", error);
|
||||
return res.status(502).json({
|
||||
success: false,
|
||||
error:
|
||||
"We could not update your email preferences right now. Please try again later.",
|
||||
code: "NOVU_ERROR",
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({ success: true });
|
||||
}
|
||||
110
apps/web/src/pages/unsubscribe/index.tsx
Normal file
110
apps/web/src/pages/unsubscribe/index.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import { useRouter } from "next/router";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { PageHead } from "~/components/PageHead";
|
||||
import PatternedBackground from "~/components/PatternedBackground";
|
||||
|
||||
type UnsubscribeStatus = "idle" | "processing" | "success" | "error";
|
||||
|
||||
export default function UnsubscribePage() {
|
||||
const router = useRouter();
|
||||
const [token, setToken] = useState("");
|
||||
const [status, setStatus] = useState<UnsubscribeStatus>("idle");
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!router.isReady) return;
|
||||
const value = router.query.token;
|
||||
if (typeof value === "string") {
|
||||
setToken(value);
|
||||
} else if (Array.isArray(value)) {
|
||||
setToken(value[0] ?? "");
|
||||
} else {
|
||||
setToken("");
|
||||
}
|
||||
}, [router.isReady, router.query.token]);
|
||||
|
||||
const handleUnsubscribe = async () => {
|
||||
if (!token) {
|
||||
setStatus("error");
|
||||
setErrorMessage(
|
||||
t`Your unsubscribe link is missing a token. Please open the latest email and try again.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("processing");
|
||||
setErrorMessage(null);
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/unsubscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const payload = (await response.json().catch(() => null)) as {
|
||||
error?: string;
|
||||
} | null;
|
||||
|
||||
throw new Error(
|
||||
payload?.error ??
|
||||
"We couldn't update your preferences. Please try again.",
|
||||
);
|
||||
}
|
||||
|
||||
setStatus("success");
|
||||
} catch (error) {
|
||||
setStatus("error");
|
||||
setErrorMessage(
|
||||
t`We couldn't update your preferences. Please try again.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const title = t`Unsubscribe`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHead title={`${title} | kan.bn`} />
|
||||
<div className="relative flex min-h-screen items-center justify-center px-4 py-12 sm:px-6 lg:px-8">
|
||||
<PatternedBackground />
|
||||
<div className="z-10 w-full max-w-md space-y-6">
|
||||
<div>
|
||||
<h1 className="mt-6 text-center text-3xl font-bold tracking-tight text-light-1000 dark:text-dark-1000">
|
||||
{t`Do you want to unsubscribe?`}
|
||||
</h1>
|
||||
<p className="mt-4 text-center text-sm text-light-900 dark:text-dark-800">
|
||||
{t`Confirm your email preferences:`}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
onClick={handleUnsubscribe}
|
||||
disabled={status === "success"}
|
||||
isLoading={status === "processing"}
|
||||
variant="primary"
|
||||
size="md"
|
||||
>
|
||||
{t`Unsubscribe`}
|
||||
</Button>
|
||||
</div>
|
||||
{status === "success" && (
|
||||
<p className="text-center text-sm text-light-900 dark:text-dark-800">
|
||||
{t`You have been unsubscribed!`}
|
||||
</p>
|
||||
)}
|
||||
{status === "error" && (
|
||||
<p className="mx-auto max-w-[300px] text-center text-sm font-medium text-red-600 dark:text-red-400">
|
||||
{errorMessage}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { HiOutlinePaperClip } from "react-icons/hi";
|
||||
import { HiBars3BottomLeft, HiChatBubbleLeft } from "react-icons/hi2";
|
||||
|
||||
import Avatar from "~/components/Avatar";
|
||||
@@ -13,6 +14,7 @@ const Card = ({
|
||||
checklists,
|
||||
description,
|
||||
comments,
|
||||
attachments,
|
||||
}: {
|
||||
title: string;
|
||||
labels: { name: string; colourCode: string | null }[];
|
||||
@@ -33,6 +35,7 @@ const Card = ({
|
||||
}[];
|
||||
description: string | null;
|
||||
comments: { publicId: string }[];
|
||||
attachments?: { publicId: string }[];
|
||||
}) => {
|
||||
const completedItems = checklists.reduce((acc, checklist) => {
|
||||
return acc + checklist.items.filter((item) => item.completed).length;
|
||||
@@ -47,6 +50,7 @@ const Card = ({
|
||||
|
||||
const hasDescription =
|
||||
description && description.replace(/<[^>]*>/g, "").trim().length > 0;
|
||||
const hasAttachments = attachments && attachments.length > 0;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col rounded-md border border-light-200 bg-light-50 px-3 py-2 text-sm text-neutral-900 dark:border-dark-200 dark:bg-dark-200 dark:text-dark-1000 dark:hover:bg-dark-300">
|
||||
@@ -55,7 +59,8 @@ const Card = ({
|
||||
members.length ||
|
||||
checklists.length > 0 ||
|
||||
hasDescription ||
|
||||
comments.length > 0 ? (
|
||||
comments.length > 0 ||
|
||||
hasAttachments ? (
|
||||
<div className="mt-2 flex flex-col justify-end">
|
||||
<div className="space-x-0.5">
|
||||
{labels.map((label) => (
|
||||
@@ -77,6 +82,11 @@ const Card = ({
|
||||
<HiChatBubbleLeft className="h-4 w-4" />
|
||||
</div>
|
||||
)}
|
||||
{hasAttachments && (
|
||||
<div className="flex items-center gap-1 text-light-700 dark:text-dark-800">
|
||||
<HiOutlinePaperClip className="h-4 w-4" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
{checklists.length > 0 && (
|
||||
|
||||
@@ -553,6 +553,7 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
card.description ?? null
|
||||
}
|
||||
comments={card.comments ?? []}
|
||||
attachments={card.attachments}
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
462
apps/web/src/views/card/components/AttachmentThumbnails.tsx
Normal file
462
apps/web/src/views/card/components/AttachmentThumbnails.tsx
Normal file
@@ -0,0 +1,462 @@
|
||||
import Image from "next/image";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import {
|
||||
HiArrowDownTray,
|
||||
HiChevronLeft,
|
||||
HiChevronRight,
|
||||
HiDocumentText,
|
||||
HiOutlineTrash,
|
||||
HiXMark,
|
||||
} from "react-icons/hi2";
|
||||
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
interface Attachment {
|
||||
publicId: string;
|
||||
contentType: string;
|
||||
url: string | null;
|
||||
originalFilename: string | null;
|
||||
s3Key: string;
|
||||
size?: number | null;
|
||||
}
|
||||
|
||||
export function AttachmentThumbnails({
|
||||
attachments,
|
||||
cardPublicId,
|
||||
isReadOnly = false,
|
||||
}: {
|
||||
attachments?: Attachment[];
|
||||
cardPublicId: string;
|
||||
isReadOnly?: boolean;
|
||||
}) {
|
||||
const { showPopup } = usePopup();
|
||||
const utils = api.useUtils();
|
||||
const imageAttachments =
|
||||
attachments?.filter(
|
||||
(attachment) =>
|
||||
attachment.contentType.startsWith("image/") && attachment.url,
|
||||
) ?? [];
|
||||
|
||||
const nonImageAttachments =
|
||||
attachments?.filter(
|
||||
(attachment) =>
|
||||
!attachment.contentType.startsWith("image/") && attachment.url,
|
||||
) ?? [];
|
||||
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
|
||||
|
||||
const deleteAttachment = api.attachment.delete.useMutation({
|
||||
onMutate: async (args) => {
|
||||
if (isReadOnly) return;
|
||||
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const currentState = utils.card.byId.getData({ cardPublicId });
|
||||
|
||||
utils.card.byId.setData({ cardPublicId }, (oldCard) => {
|
||||
if (!oldCard) return oldCard;
|
||||
const updatedAttachments = oldCard.attachments.filter(
|
||||
(attachment) => attachment.publicId !== args.attachmentPublicId,
|
||||
);
|
||||
return { ...oldCard, attachments: updatedAttachments };
|
||||
});
|
||||
|
||||
return { previousState: currentState };
|
||||
},
|
||||
onError: (_error, _args, context) => {
|
||||
if (isReadOnly) return;
|
||||
utils.card.byId.setData({ cardPublicId }, context?.previousState);
|
||||
showPopup({
|
||||
header: t`Unable to delete attachment`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
if (isReadOnly) return;
|
||||
// Close viewer if the deleted image was being viewed
|
||||
setSelectedIndex(null);
|
||||
},
|
||||
onSettled: async () => {
|
||||
if (isReadOnly) return;
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
// Keyboard navigation
|
||||
useEffect(() => {
|
||||
if (selectedIndex === null) return;
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
setSelectedIndex(null);
|
||||
} else if (e.key === "ArrowLeft") {
|
||||
setSelectedIndex((prev) => {
|
||||
if (prev === null) return null;
|
||||
return prev === 0 ? imageAttachments.length - 1 : prev - 1;
|
||||
});
|
||||
} else if (e.key === "ArrowRight") {
|
||||
setSelectedIndex((prev) => {
|
||||
if (prev === null) return null;
|
||||
return prev === imageAttachments.length - 1 ? 0 : prev + 1;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [selectedIndex, imageAttachments.length]);
|
||||
|
||||
if (imageAttachments.length === 0 && nonImageAttachments.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const openViewer = (index: number) => {
|
||||
setSelectedIndex(index);
|
||||
};
|
||||
|
||||
const closeViewer = () => {
|
||||
setSelectedIndex(null);
|
||||
};
|
||||
|
||||
const goToPrevious = () => {
|
||||
if (selectedIndex === null) return;
|
||||
const newIndex =
|
||||
selectedIndex === 0 ? imageAttachments.length - 1 : selectedIndex - 1;
|
||||
setSelectedIndex(newIndex);
|
||||
};
|
||||
|
||||
const goToNext = () => {
|
||||
if (selectedIndex === null) return;
|
||||
const newIndex =
|
||||
selectedIndex === imageAttachments.length - 1 ? 0 : selectedIndex + 1;
|
||||
setSelectedIndex(newIndex);
|
||||
};
|
||||
|
||||
const handleDownload = (attachment: Attachment) => {
|
||||
if (!attachment.url) {
|
||||
showPopup({
|
||||
header: t`Download failed`,
|
||||
message: t`No download URL available for this attachment.`,
|
||||
icon: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const downloadUrl = `/api/download/attatchment?url=${encodeURIComponent(attachment.url)}&filename=${encodeURIComponent(attachment.originalFilename ?? "attachment")}`;
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.style.display = "none";
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
};
|
||||
|
||||
const selectedAttachment =
|
||||
selectedIndex !== null ? imageAttachments[selectedIndex] : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-3 flex flex-wrap gap-2 pt-1">
|
||||
{imageAttachments.map((attachment, index) => {
|
||||
if (!attachment.url) return null;
|
||||
return (
|
||||
<AttachmentThumbnail
|
||||
key={attachment.publicId}
|
||||
attachment={{
|
||||
publicId: attachment.publicId,
|
||||
url: attachment.url,
|
||||
originalFilename: attachment.originalFilename ?? "",
|
||||
contentType: attachment.contentType,
|
||||
}}
|
||||
onClick={() => openViewer(index)}
|
||||
isImage={true}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{nonImageAttachments.length > 0 && (
|
||||
<div className="mb-3 flex flex-col gap-2">
|
||||
{nonImageAttachments.map((attachment) => {
|
||||
if (!attachment.url) return null;
|
||||
return (
|
||||
<FileListItem
|
||||
key={attachment.publicId}
|
||||
attachment={attachment}
|
||||
onDownload={() => handleDownload(attachment)}
|
||||
onDelete={
|
||||
isReadOnly
|
||||
? undefined
|
||||
: () => {
|
||||
deleteAttachment.mutate({
|
||||
attachmentPublicId: attachment.publicId,
|
||||
});
|
||||
}
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Transition.Root show={selectedIndex !== null} as={Fragment}>
|
||||
<Dialog
|
||||
as="div"
|
||||
className="relative z-50"
|
||||
onClose={() => {
|
||||
// Dialog closing is handled by the background overlay click
|
||||
}}
|
||||
static
|
||||
>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
className="fixed inset-0 bg-light-50 transition-opacity dark:bg-dark-50"
|
||||
onClick={(e) => {
|
||||
// Only close if clicking directly on the background, not on buttons
|
||||
if (e.target === e.currentTarget) {
|
||||
closeViewer();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||
{selectedIndex !== null && selectedAttachment && (
|
||||
<div
|
||||
className="fixed left-2 top-2 z-20 flex gap-1"
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{!isReadOnly && (
|
||||
<button
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
deleteAttachment.mutate({
|
||||
attachmentPublicId: selectedAttachment.publicId,
|
||||
});
|
||||
}}
|
||||
className="rounded-full bg-light-50 p-1.5 text-light-1000 transition-colors hover:bg-light-100 focus:outline-none dark:bg-dark-50 dark:text-dark-1000 dark:hover:bg-dark-100"
|
||||
aria-label="Delete image"
|
||||
disabled={deleteAttachment.isPending}
|
||||
>
|
||||
<HiOutlineTrash className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
handleDownload(selectedAttachment);
|
||||
}}
|
||||
className="rounded-full bg-light-50 p-1.5 text-light-1000 transition-colors hover:bg-light-100 focus:outline-none dark:bg-dark-50 dark:text-dark-1000 dark:hover:bg-dark-100"
|
||||
aria-label="Download image"
|
||||
>
|
||||
<HiArrowDownTray className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="fixed right-2 top-2 z-20 flex gap-1">
|
||||
{imageAttachments.length > 1 && selectedIndex !== null && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
goToPrevious();
|
||||
}}
|
||||
className="rounded-full bg-light-50 p-1.5 text-light-1000 transition-colors hover:bg-light-100 focus:outline-none dark:bg-dark-50 dark:text-dark-1000 dark:hover:bg-dark-100"
|
||||
aria-label="Previous image"
|
||||
>
|
||||
<HiChevronLeft className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{imageAttachments.length > 1 && selectedIndex !== null && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
goToNext();
|
||||
}}
|
||||
className="rounded-full bg-light-50 p-1.5 text-light-1000 transition-colors hover:bg-light-100 focus:outline-none dark:bg-dark-50 dark:text-dark-1000 dark:hover:bg-dark-100"
|
||||
aria-label="Next image"
|
||||
>
|
||||
<HiChevronRight className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{selectedIndex !== null && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
closeViewer();
|
||||
}}
|
||||
className="rounded-full bg-light-50 p-1.5 text-light-1000 transition-colors hover:bg-light-100 focus:outline-none dark:bg-dark-50 dark:text-dark-1000 dark:hover:bg-dark-100"
|
||||
aria-label="Close"
|
||||
>
|
||||
<HiXMark className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel
|
||||
className="relative w-full max-w-7xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{selectedAttachment?.url && (
|
||||
<div className="relative">
|
||||
<div className="relative mx-auto max-h-[90vh] w-full">
|
||||
<Image
|
||||
src={selectedAttachment.url}
|
||||
alt={
|
||||
selectedAttachment.originalFilename ?? "Attachment"
|
||||
}
|
||||
width={1920}
|
||||
height={1080}
|
||||
className="mx-auto max-h-[90vh] w-auto object-contain"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
|
||||
{imageAttachments.length > 1 && (
|
||||
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-3 py-1.5 text-[10px] text-white">
|
||||
{selectedIndex !== null && selectedIndex + 1} /{" "}
|
||||
{imageAttachments.length}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function AttachmentThumbnail({
|
||||
attachment,
|
||||
onClick,
|
||||
isImage,
|
||||
}: {
|
||||
attachment: {
|
||||
publicId: string;
|
||||
url: string;
|
||||
originalFilename: string;
|
||||
contentType: string;
|
||||
};
|
||||
onClick: () => void;
|
||||
isImage: boolean;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="relative h-16 w-16 overflow-hidden rounded-xl border border-light-300 transition-transform hover:scale-105 dark:border-dark-300"
|
||||
aria-label={`View ${attachment.originalFilename}`}
|
||||
>
|
||||
{isImage ? (
|
||||
<Image
|
||||
src={attachment.url}
|
||||
alt={attachment.originalFilename}
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="64px"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center bg-light-100 dark:bg-dark-100">
|
||||
<HiDocumentText className="h-6 w-6 text-light-700 dark:text-dark-700" />
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function formatFileSize(bytes: number | null | undefined): string {
|
||||
if (!bytes || bytes === 0 || isNaN(bytes)) return "0 B";
|
||||
const k = 1024;
|
||||
const sizes = ["B", "KB", "MB", "GB"];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i] ?? "B"}`;
|
||||
}
|
||||
|
||||
function FileListItem({
|
||||
attachment,
|
||||
onDownload,
|
||||
onDelete,
|
||||
}: {
|
||||
attachment: Attachment;
|
||||
onDownload: () => void;
|
||||
onDelete?: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="group flex w-full items-center gap-3 rounded-lg border border-light-300 bg-light-50 px-3 py-2 dark:border-dark-200 dark:bg-dark-100">
|
||||
<div className="flex-shrink-0">
|
||||
<HiDocumentText className="h-5 w-5 text-light-700 dark:text-dark-700" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 truncate text-sm text-light-1000 dark:text-dark-1000">
|
||||
{attachment.originalFilename ?? "File"}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<div className="text-xs text-light-500 dark:text-dark-900">
|
||||
{attachment.size != null &&
|
||||
!isNaN(attachment.size) &&
|
||||
`${formatFileSize(attachment.size)}`}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDownload();
|
||||
}}
|
||||
className="flex-shrink-0 rounded-full bg-light-100 p-1.5 text-light-1000 transition-colors hover:bg-light-200 focus:outline-none dark:bg-dark-100 dark:text-dark-950 dark:hover:bg-dark-300"
|
||||
aria-label={`Download ${attachment.originalFilename}`}
|
||||
>
|
||||
<HiArrowDownTray className="h-4 w-4" />
|
||||
</button>
|
||||
{onDelete && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDelete();
|
||||
}}
|
||||
className="flex-shrink-0 rounded-full bg-light-100 p-1.5 text-light-1000 transition-colors hover:bg-light-200 focus:outline-none dark:bg-dark-100 dark:text-dark-950 dark:hover:bg-dark-300"
|
||||
aria-label={`Delete ${attachment.originalFilename}`}
|
||||
>
|
||||
<HiXMark className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
174
apps/web/src/views/card/components/AttachmentUpload.tsx
Normal file
174
apps/web/src/views/card/components/AttachmentUpload.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useRef, useState } from "react";
|
||||
import { HiOutlinePaperClip } from "react-icons/hi";
|
||||
import { HiCheckBadge } from "react-icons/hi2";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
export function AttachmentUpload({ cardPublicId }: { cardPublicId: string }) {
|
||||
const { openModal } = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
const utils = api.useUtils();
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const generateUploadUrl = api.attachment.generateUploadUrl.useMutation();
|
||||
const confirmAttachment = api.attachment.confirm.useMutation({
|
||||
onSuccess: async () => {
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
showPopup({
|
||||
header: t`Attachment uploaded`,
|
||||
message: t`Your file has been uploaded successfully.`,
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
showPopup({
|
||||
header: t`Upload failed`,
|
||||
message: t`Failed to upload attachment. Please try again.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: () => {
|
||||
setUploading(false);
|
||||
},
|
||||
});
|
||||
|
||||
const uploadFile = async (file: File) => {
|
||||
setUploading(true);
|
||||
|
||||
try {
|
||||
// Generate presigned URL
|
||||
const { url, key } = await generateUploadUrl.mutateAsync({
|
||||
cardPublicId,
|
||||
filename: file.name,
|
||||
contentType: file.type,
|
||||
size: file.size,
|
||||
});
|
||||
|
||||
// Upload file to S3
|
||||
const uploadResponse = await fetch(url, {
|
||||
method: "PUT",
|
||||
body: file,
|
||||
headers: {
|
||||
"Content-Type": file.type,
|
||||
},
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error("Upload failed");
|
||||
}
|
||||
|
||||
// Confirm attachment in database
|
||||
await confirmAttachment.mutateAsync({
|
||||
cardPublicId,
|
||||
s3Key: key,
|
||||
filename: file.name,
|
||||
originalFilename: file.name,
|
||||
contentType: file.type,
|
||||
size: file.size,
|
||||
});
|
||||
} catch {
|
||||
showPopup({
|
||||
header: t`Upload failed`,
|
||||
message: t`Failed to upload attachment. Please try again.`,
|
||||
icon: "error",
|
||||
});
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileSelect = async (
|
||||
event: React.ChangeEvent<HTMLInputElement>,
|
||||
) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
// Reset input
|
||||
event.target.value = "";
|
||||
|
||||
await uploadFile(file);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!uploading) {
|
||||
setIsDragging(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragLeave = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
const handleDrop = async (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
|
||||
if (uploading) return;
|
||||
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
if (files.length === 0) return;
|
||||
|
||||
// Upload the first file (or could upload all files)
|
||||
await uploadFile(files[0] ?? new File([], ""));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
id="attachment-upload"
|
||||
className="hidden"
|
||||
onChange={handleFileSelect}
|
||||
disabled={uploading}
|
||||
/>
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={twMerge(
|
||||
"rounded-lg border-2 border-dashed transition-colors",
|
||||
isDragging
|
||||
? "border-light-300 bg-light-100 dark:border-dark-300 dark:bg-dark-100"
|
||||
: "border-transparent",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between p-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
iconLeft={
|
||||
<HiCheckBadge className="h-4 w-4 text-light-950 dark:text-dark-950" />
|
||||
}
|
||||
iconOnly
|
||||
size="sm"
|
||||
onClick={() => openModal("ADD_CHECKLIST")}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
iconLeft={
|
||||
<HiOutlinePaperClip className="h-4 w-4 text-light-950 dark:text-dark-950" />
|
||||
}
|
||||
isLoading={uploading}
|
||||
disabled={uploading}
|
||||
iconOnly
|
||||
size="sm"
|
||||
onClick={() => inputRef.current?.click()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export default function BoardDropdown() {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<HiEllipsisHorizontal className="h-6 w-6 text-dark-900" />
|
||||
<HiEllipsisHorizontal className="h-5 w-5 text-dark-900" />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import { api } from "~/utils/api";
|
||||
import { formatMemberDisplayName, getAvatarUrl } from "~/utils/helpers";
|
||||
import { DeleteLabelConfirmation } from "../../components/DeleteLabelConfirmation";
|
||||
import ActivityList from "./components/ActivityList";
|
||||
import { AttachmentThumbnails } from "./components/AttachmentThumbnails";
|
||||
import { AttachmentUpload } from "./components/AttachmentUpload";
|
||||
import Checklists from "./components/Checklists";
|
||||
import { DeleteCardConfirmation } from "./components/DeleteCardConfirmation";
|
||||
import { DeleteChecklistConfirmation } from "./components/DeleteChecklistConfirmation";
|
||||
@@ -105,7 +107,7 @@ export function CardRightPanel({ isTemplate }: { isTemplate?: boolean }) {
|
||||
|
||||
return (
|
||||
<div className="h-full w-[360px] border-l-[1px] border-light-300 bg-light-50 p-8 text-light-900 dark:border-dark-300 dark:bg-dark-50 dark:text-dark-900">
|
||||
<div className="mb-4 flex w-full flex-row">
|
||||
<div className="mb-4 flex w-full flex-row pt-[18px]">
|
||||
<p className="my-2 mb-2 w-[100px] text-sm font-medium">{t`List`}</p>
|
||||
<ListSelector
|
||||
cardPublicId={cardId ?? ""}
|
||||
@@ -208,6 +210,17 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
}
|
||||
}, [card, getModalState, clearModalState]);
|
||||
|
||||
// Auto-resize title textarea
|
||||
useEffect(() => {
|
||||
const titleTextarea = document.getElementById(
|
||||
"title",
|
||||
) as HTMLTextAreaElement;
|
||||
if (titleTextarea) {
|
||||
titleTextarea.style.height = "auto";
|
||||
titleTextarea.style.height = `${titleTextarea.scrollHeight}px`;
|
||||
}
|
||||
}, [card]);
|
||||
|
||||
if (!cardId) return <></>;
|
||||
|
||||
return (
|
||||
@@ -215,47 +228,71 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
<PageHead
|
||||
title={t`${card?.title ?? t`Card`} | ${board?.name ?? t`Board`}`}
|
||||
/>
|
||||
<div className="flex h-full flex-1 flex-row overflow-hidden">
|
||||
<div className="flex h-full flex-1 flex-col overflow-hidden">
|
||||
{/* Full-width top strip with board link and dropdown */}
|
||||
<div className="flex w-full items-center justify-between border-b-[1px] border-light-300 bg-light-50 px-8 py-2 dark:border-dark-300 dark:bg-dark-50">
|
||||
{!card && isLoading && (
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-[1.5rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
</div>
|
||||
)}
|
||||
{card && (
|
||||
<>
|
||||
<div className="flex items-center gap-1">
|
||||
<Link
|
||||
className="whitespace-nowrapleading-[1.5rem] text-sm font-bold text-light-900 dark:text-dark-950"
|
||||
href={`${isTemplate ? "/templates" : "/boards"}`}
|
||||
>
|
||||
{workspace.name}
|
||||
</Link>
|
||||
<IoChevronForwardSharp className="h-[10px] w-[10px] text-light-900 dark:text-dark-900" />
|
||||
<Link
|
||||
className="whitespace-nowrap text-sm font-bold leading-[1.5rem] text-light-900 dark:text-dark-950"
|
||||
href={`${isTemplate ? "/templates" : "/boards"}/${board?.publicId}`}
|
||||
>
|
||||
{board?.name}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Dropdown />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!card && !isLoading && (
|
||||
<p className="block p-0 py-0 font-bold leading-[1.5rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1rem]">
|
||||
{t`Card not found`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="scrollbar-thumb-rounded-[4px] scrollbar-track-rounded-[4px] w-full flex-1 overflow-y-auto scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 hover:scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300 dark:hover:scrollbar-thumb-dark-300">
|
||||
<div className="p-auto mx-auto flex h-full w-full max-w-[800px] flex-col">
|
||||
<div className="p-6 md:p-8">
|
||||
<div className="mb-8 flex w-full items-center justify-between md:mt-6">
|
||||
<div className="mb-8 md:mt-4">
|
||||
{!card && isLoading && (
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
<div className="h-[2.3rem] w-[300px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
</div>
|
||||
)}
|
||||
{card && (
|
||||
<>
|
||||
<Link
|
||||
className="whitespace-nowrap font-bold leading-[2.3rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1.2rem]"
|
||||
href={`${isTemplate ? "/templates" : "/boards"}/${board?.publicId}`}
|
||||
>
|
||||
{board?.name}
|
||||
</Link>
|
||||
<IoChevronForwardSharp
|
||||
size={18}
|
||||
className="mx-2 text-light-900 dark:text-dark-900"
|
||||
/>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
{...register("title")}
|
||||
onBlur={handleSubmit(onSubmit)}
|
||||
className="block w-full border-0 bg-transparent p-0 py-0 font-bold tracking-tight text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex">
|
||||
<Dropdown />
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div>
|
||||
<textarea
|
||||
id="title"
|
||||
{...register("title")}
|
||||
onBlur={handleSubmit(onSubmit)}
|
||||
rows={1}
|
||||
className="block w-full resize-none overflow-hidden border-0 bg-transparent p-0 py-0 font-bold leading-relaxed text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
|
||||
onInput={(e) => {
|
||||
const target = e.target as HTMLTextAreaElement;
|
||||
target.style.height = "auto";
|
||||
target.style.height = `${target.scrollHeight}px`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</form>
|
||||
)}
|
||||
{!card && !isLoading && (
|
||||
<p className="block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
|
||||
@@ -286,6 +323,21 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
activeChecklistForm={activeChecklistForm}
|
||||
setActiveChecklistForm={setActiveChecklistForm}
|
||||
/>
|
||||
{!isTemplate && (
|
||||
<>
|
||||
{card?.attachments.length > 0 && (
|
||||
<div className="mt-6">
|
||||
<AttachmentThumbnails
|
||||
attachments={card.attachments}
|
||||
cardPublicId={cardId ?? ""}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-6">
|
||||
<AttachmentUpload cardPublicId={cardId} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="border-t-[1px] border-light-300 pt-12 dark:border-dark-300">
|
||||
<h2 className="text-md pb-4 font-medium text-light-1000 dark:text-dark-1000">
|
||||
{t`Activity`}
|
||||
|
||||
@@ -9,6 +9,7 @@ import LabelIcon from "~/components/LabelIcon";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { api } from "~/utils/api";
|
||||
import ActivityList from "~/views/card/components/ActivityList";
|
||||
import { AttachmentThumbnails } from "~/views/card/components/AttachmentThumbnails";
|
||||
import Checklists from "~/views/card/components/Checklists";
|
||||
|
||||
export function CardModal({
|
||||
@@ -126,11 +127,24 @@ export function CardModal({
|
||||
<Editor
|
||||
content={data.description}
|
||||
readOnly
|
||||
workspaceMembers={data?.list.board.workspace.members ?? []}
|
||||
workspaceMembers={
|
||||
data?.list.board.workspace.members ?? []
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{data?.attachments &&
|
||||
data.attachments.length > 0 &&
|
||||
cardPublicId && (
|
||||
<div className="mb-10 max-w-2xl">
|
||||
<AttachmentThumbnails
|
||||
attachments={data.attachments}
|
||||
cardPublicId={cardPublicId}
|
||||
isReadOnly
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{data?.checklists && data.checklists.length > 0 && (
|
||||
<Checklists
|
||||
checklists={data.checklists}
|
||||
|
||||
@@ -189,6 +189,7 @@ export default function PublicBoardView() {
|
||||
members={[]}
|
||||
description={card.description}
|
||||
comments={card.comments ?? []}
|
||||
attachments={card.attachments}
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
@@ -35,8 +35,11 @@ services:
|
||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||
- SMTP_SECURE=${SMTP_SECURE}
|
||||
- EMAIL_FROM=${EMAIL_FROM}
|
||||
- PLUNK_API_KEY=${PLUNK_API_KEY}
|
||||
- PLUNK_API_URL=${PLUNK_API_URL}
|
||||
|
||||
# Notifications
|
||||
- NOVU_API_KEY=${NOVU_API_KEY}
|
||||
- DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL}
|
||||
- EMAIL_UNSUBSCRIBE_SECRET=${EMAIL_UNSUBSCRIBE_SECRET}
|
||||
|
||||
# S3 storage
|
||||
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
|
||||
@@ -46,6 +49,7 @@ services:
|
||||
- S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE}
|
||||
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
|
||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||
|
||||
# Auth config
|
||||
|
||||
@@ -36,6 +36,7 @@ services:
|
||||
- S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE}
|
||||
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
|
||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||
|
||||
# White label
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.802.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.812.0",
|
||||
"@kan/auth": "workspace:*",
|
||||
"@kan/db": "workspace:*",
|
||||
"@kan/email": "workspace:^",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { attachmentRouter } from "./routers/attachment";
|
||||
import { boardRouter } from "./routers/board";
|
||||
import { cardRouter } from "./routers/card";
|
||||
import { checklistRouter } from "./routers/checklist";
|
||||
@@ -12,6 +13,7 @@ import { workspaceRouter } from "./routers/workspace";
|
||||
import { createTRPCRouter } from "./trpc";
|
||||
|
||||
export const appRouter = createTRPCRouter({
|
||||
attachment: attachmentRouter,
|
||||
board: boardRouter,
|
||||
card: cardRouter,
|
||||
checklist: checklistRouter,
|
||||
|
||||
205
packages/api/src/routers/attachment.ts
Normal file
205
packages/api/src/routers/attachment.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import * as cardRepo from "@kan/db/repository/card.repo";
|
||||
import * as cardActivityRepo from "@kan/db/repository/cardActivity.repo";
|
||||
import * as cardAttachmentRepo from "@kan/db/repository/cardAttachment.repo";
|
||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { assertUserInWorkspace } from "../utils/auth";
|
||||
import { generateUploadUrl } from "../utils/s3";
|
||||
|
||||
export const attachmentRouter = createTRPCRouter({
|
||||
generateUploadUrl: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Generate presigned URL for attachment upload",
|
||||
method: "POST",
|
||||
path: "/cards/{cardPublicId}/attachments/upload-url",
|
||||
description:
|
||||
"Generates a presigned URL for uploading an attachment to S3",
|
||||
tags: ["Attachments"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
cardPublicId: z.string().min(12),
|
||||
filename: z.string().min(1).max(255),
|
||||
contentType: z.string(),
|
||||
size: z
|
||||
.number()
|
||||
.positive()
|
||||
.max(50 * 1024 * 1024), // 50MB max
|
||||
}),
|
||||
)
|
||||
.output(z.object({ url: z.string(), key: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const card = await cardRepo.getWorkspaceAndCardIdByCardPublicId(
|
||||
ctx.db,
|
||||
input.cardPublicId,
|
||||
);
|
||||
|
||||
if (!card)
|
||||
throw new TRPCError({
|
||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
|
||||
// Get workspace publicId
|
||||
const workspace = await workspaceRepo.getById(ctx.db, card.workspaceId);
|
||||
if (!workspace)
|
||||
throw new TRPCError({
|
||||
message: `Workspace not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
const bucket = process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME;
|
||||
if (!bucket)
|
||||
throw new TRPCError({
|
||||
message: `Attachments bucket not configured`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
// Sanitize filename
|
||||
const sanitizedFilename = input.filename
|
||||
.replace(/[^a-zA-Z0-9._-]/g, "_")
|
||||
.substring(0, 200);
|
||||
|
||||
const s3Key = `${workspace.publicId}/${input.cardPublicId}/${generateUID()}-${sanitizedFilename}`;
|
||||
|
||||
const url = await generateUploadUrl(
|
||||
bucket,
|
||||
s3Key,
|
||||
input.contentType,
|
||||
3600, // 1 hour
|
||||
);
|
||||
|
||||
return { url, key: s3Key };
|
||||
}),
|
||||
confirm: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Confirm attachment upload and save to database",
|
||||
method: "POST",
|
||||
path: "/cards/{cardPublicId}/attachments/confirm",
|
||||
description:
|
||||
"Confirms an attachment upload and saves the record to the database",
|
||||
tags: ["Attachments"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
cardPublicId: z.string().min(12),
|
||||
s3Key: z.string(),
|
||||
filename: z.string(),
|
||||
originalFilename: z.string(),
|
||||
contentType: z.string(),
|
||||
size: z.number().positive(),
|
||||
}),
|
||||
)
|
||||
.output(z.custom<Awaited<ReturnType<typeof cardAttachmentRepo.create>>>())
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const card = await cardRepo.getWorkspaceAndCardIdByCardPublicId(
|
||||
ctx.db,
|
||||
input.cardPublicId,
|
||||
);
|
||||
|
||||
if (!card)
|
||||
throw new TRPCError({
|
||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
|
||||
const attachment = await cardAttachmentRepo.create(ctx.db, {
|
||||
cardId: card.id,
|
||||
filename: input.filename,
|
||||
originalFilename: input.originalFilename,
|
||||
contentType: input.contentType,
|
||||
size: input.size,
|
||||
s3Key: input.s3Key,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.attachment.added",
|
||||
cardId: card.id,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return attachment;
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Delete an attachment",
|
||||
method: "DELETE",
|
||||
path: "/attachments/{attachmentPublicId}",
|
||||
description: "Soft deletes an attachment",
|
||||
tags: ["Attachments"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(z.object({ attachmentPublicId: z.string().min(12) }))
|
||||
.output(z.object({ success: z.boolean() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const attachment = await cardAttachmentRepo.getByPublicId(
|
||||
ctx.db,
|
||||
input.attachmentPublicId,
|
||||
);
|
||||
|
||||
if (!attachment || attachment.deletedAt)
|
||||
throw new TRPCError({
|
||||
message: `Attachment with public ID ${input.attachmentPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
const workspaceId = attachment.card.list.board.workspaceId;
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, workspaceId);
|
||||
|
||||
await cardAttachmentRepo.softDelete(ctx.db, {
|
||||
attachmentId: attachment.id,
|
||||
deletedAt: new Date(),
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.attachment.removed",
|
||||
cardId: attachment.cardId,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
@@ -10,6 +10,7 @@ import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||
import { assertUserInWorkspace } from "../utils/auth";
|
||||
import { generateDownloadUrl } from "../utils/s3";
|
||||
|
||||
export const cardRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
@@ -574,7 +575,21 @@ export const cardRouter = createTRPCRouter({
|
||||
.input(z.object({ cardPublicId: z.string().min(12) }))
|
||||
.output(
|
||||
z.custom<
|
||||
Awaited<ReturnType<typeof cardRepo.getWithListAndMembersByPublicId>>
|
||||
Omit<
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof cardRepo.getWithListAndMembersByPublicId>>
|
||||
>,
|
||||
"attachments"
|
||||
> & {
|
||||
attachments: {
|
||||
publicId: string;
|
||||
contentType: string;
|
||||
s3Key: string;
|
||||
originalFilename: string | null;
|
||||
size?: number | null;
|
||||
url: string | null;
|
||||
}[];
|
||||
}
|
||||
>(),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
@@ -612,7 +627,46 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
return result;
|
||||
// Generate URLs for all attachments
|
||||
const bucket = process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME;
|
||||
if (result.attachments && Array.isArray(result.attachments)) {
|
||||
const attachments = result.attachments as {
|
||||
publicId: string;
|
||||
contentType: string;
|
||||
s3Key: string;
|
||||
originalFilename: string | null;
|
||||
size?: number | null;
|
||||
}[];
|
||||
|
||||
const attachmentsWithUrls = await Promise.all(
|
||||
attachments.map(async (attachment) => {
|
||||
const base = {
|
||||
publicId: attachment.publicId,
|
||||
contentType: attachment.contentType,
|
||||
s3Key: attachment.s3Key,
|
||||
originalFilename: attachment.originalFilename,
|
||||
size: attachment.size,
|
||||
};
|
||||
if (!bucket || !attachment.s3Key) {
|
||||
return { ...base, url: null };
|
||||
}
|
||||
try {
|
||||
const url = await generateDownloadUrl(
|
||||
bucket,
|
||||
attachment.s3Key,
|
||||
86400, // 24 hours expiration
|
||||
);
|
||||
return { ...base, url };
|
||||
} catch {
|
||||
// If URL generation fails, return attachment with url: null
|
||||
return { ...base, url: null };
|
||||
}
|
||||
}),
|
||||
);
|
||||
return { ...result, attachments: attachmentsWithUrls };
|
||||
}
|
||||
|
||||
return { ...result, attachments: [] };
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.meta({
|
||||
|
||||
@@ -476,7 +476,7 @@ export const memberRouter = createTRPCRouter({
|
||||
openapi: {
|
||||
summary: "Get invite information by code",
|
||||
method: "GET",
|
||||
path: "/workspaces/{workspacePublicId}/invites/{inviteCode}",
|
||||
path: "/invites/{inviteCode}",
|
||||
description: "Get invite information by invite code",
|
||||
tags: ["Invites"],
|
||||
protect: false,
|
||||
@@ -521,7 +521,7 @@ export const memberRouter = createTRPCRouter({
|
||||
openapi: {
|
||||
summary: "Accept an invite link",
|
||||
method: "POST",
|
||||
path: "/workspaces/{workspacePublicId}/invites/accept",
|
||||
path: "/invites/accept",
|
||||
description: "Accepts an invitation via invite link",
|
||||
tags: ["Invites"],
|
||||
protect: false,
|
||||
|
||||
53
packages/api/src/utils/s3.ts
Normal file
53
packages/api/src/utils/s3.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
GetObjectCommand,
|
||||
PutObjectCommand,
|
||||
S3Client,
|
||||
} from "@aws-sdk/client-s3";
|
||||
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
||||
|
||||
export function createS3Client() {
|
||||
return new S3Client({
|
||||
region: process.env.S3_REGION ?? "",
|
||||
endpoint: process.env.S3_ENDPOINT ?? "",
|
||||
forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true",
|
||||
credentials: {
|
||||
accessKeyId: process.env.S3_ACCESS_KEY_ID ?? "",
|
||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY ?? "",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function generateUploadUrl(
|
||||
bucket: string,
|
||||
key: string,
|
||||
contentType: string,
|
||||
expiresIn = 3600,
|
||||
) {
|
||||
const client = createS3Client();
|
||||
return getSignedUrl(
|
||||
client,
|
||||
new PutObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
ContentType: contentType,
|
||||
// Don't set ACL for private files
|
||||
}),
|
||||
{ expiresIn },
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateDownloadUrl(
|
||||
bucket: string,
|
||||
key: string,
|
||||
expiresIn = 3600,
|
||||
) {
|
||||
const client = createS3Client();
|
||||
return getSignedUrl(
|
||||
client,
|
||||
new GetObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
}),
|
||||
{ expiresIn },
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { Subscription } from "@better-auth/stripe";
|
||||
import type Stripe from "stripe";
|
||||
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
||||
import { stripe } from "@better-auth/stripe";
|
||||
import { ChatOrPushProviderEnum } from "@novu/api/models/components";
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
|
||||
@@ -14,7 +17,8 @@ import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
|
||||
import * as userRepo from "@kan/db/repository/user.repo";
|
||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
import * as schema from "@kan/db/schema";
|
||||
import { cloudMailerClient, sendEmail } from "@kan/email";
|
||||
import { notificationClient, sendEmail } from "@kan/email";
|
||||
import { createEmailUnsubscribeLink } from "@kan/shared";
|
||||
import { createStripeClient } from "@kan/stripe";
|
||||
|
||||
export const configuredProviders = socialProviderList.reduce<
|
||||
@@ -129,6 +133,11 @@ export const initAuth = (db: dbClient) => {
|
||||
user: schema.users,
|
||||
},
|
||||
}),
|
||||
session: {
|
||||
expiresIn: 60 * 60 * 24 * 30, // 30 days
|
||||
updateAge: 60 * 60 * 24 * 2, // Update session expiry every 48 hours if user is active
|
||||
freshAge: 0,
|
||||
},
|
||||
emailAndPassword: {
|
||||
enabled: env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true",
|
||||
disableSignUp:
|
||||
@@ -173,19 +182,17 @@ export const initAuth = (db: dbClient) => {
|
||||
freeTrial: {
|
||||
days: 14,
|
||||
onTrialStart: async (subscription) => {
|
||||
// Called when a trial starts
|
||||
// @todo: send trial start email
|
||||
// await sendTrialStartEmail(subscription.referenceId);
|
||||
await triggerWorkflow(db, "trial-start", subscription);
|
||||
},
|
||||
onTrialEnd: async ({ subscription }, request) => {
|
||||
// Called when a trial ends
|
||||
// @todo: send trial end email
|
||||
// await sendTrialEndEmail(user.email);
|
||||
onTrialEnd: async ({ subscription }) => {
|
||||
await triggerWorkflow(db, "trial-end", subscription);
|
||||
},
|
||||
onTrialExpired: async (subscription) => {
|
||||
// Called when a trial expires without conversion
|
||||
// @todo: send trial expired email
|
||||
// await sendTrialExpiredEmail(subscription.referenceId);
|
||||
await triggerWorkflow(
|
||||
db,
|
||||
"trial-expired",
|
||||
subscription,
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -197,19 +204,17 @@ export const initAuth = (db: dbClient) => {
|
||||
freeTrial: {
|
||||
days: 14,
|
||||
onTrialStart: async (subscription) => {
|
||||
// Called when a trial starts
|
||||
// @todo: send trial start email
|
||||
// await sendTrialStartEmail(subscription.referenceId);
|
||||
await triggerWorkflow(db, "trial-start", subscription);
|
||||
},
|
||||
onTrialEnd: async ({ subscription }, request) => {
|
||||
// Called when a trial ends
|
||||
// @todo: send trial end email
|
||||
// await sendTrialEndEmail(user.email);
|
||||
onTrialEnd: async ({ subscription }) => {
|
||||
await triggerWorkflow(db, "trial-end", subscription);
|
||||
},
|
||||
onTrialExpired: async (subscription) => {
|
||||
// Called when a trial expires without conversion
|
||||
// @todo: send trial expired email
|
||||
// await sendTrialExpiredEmail(subscription.referenceId);
|
||||
await triggerWorkflow(
|
||||
db,
|
||||
"trial-expired",
|
||||
subscription,
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -343,17 +348,7 @@ export const initAuth = (db: dbClient) => {
|
||||
return Promise.resolve(true);
|
||||
},
|
||||
async after(user) {
|
||||
if (cloudMailerClient) {
|
||||
await cloudMailerClient.events.track({
|
||||
event: "user-signup",
|
||||
email: user.email,
|
||||
data: {
|
||||
name: user.name,
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let avatarKey = user.image;
|
||||
if (
|
||||
user.image &&
|
||||
!user.image.includes(process.env.NEXT_PUBLIC_STORAGE_DOMAIN!)
|
||||
@@ -386,6 +381,9 @@ export const initAuth = (db: dbClient) => {
|
||||
ACL: "public-read",
|
||||
}),
|
||||
);
|
||||
|
||||
avatarKey = key;
|
||||
|
||||
await userRepo.update(db, user.id, {
|
||||
image: key,
|
||||
});
|
||||
@@ -393,6 +391,58 @@ export const initAuth = (db: dbClient) => {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (notificationClient) {
|
||||
try {
|
||||
const [firstName, ...rest] = user.name
|
||||
.split(" ")
|
||||
.filter(Boolean);
|
||||
const lastName = rest.length ? rest.join(" ") : undefined;
|
||||
const avatarUrl = avatarKey
|
||||
? `${env("NEXT_PUBLIC_STORAGE_URL")}/${env("NEXT_PUBLIC_AVATAR_BUCKET_NAME")}/${avatarKey}`
|
||||
: undefined;
|
||||
|
||||
const unsubscribeUrl = await createEmailUnsubscribeLink(
|
||||
user.id,
|
||||
);
|
||||
|
||||
await notificationClient.trigger({
|
||||
to: {
|
||||
subscriberId: user.id,
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
email: user.email,
|
||||
avatar: avatarUrl,
|
||||
data: {
|
||||
emailVerified: user.emailVerified,
|
||||
stripeCustomerId: user.stripeCustomerId,
|
||||
createdAt: user.createdAt,
|
||||
updatedAt: user.updatedAt,
|
||||
},
|
||||
},
|
||||
payload: {
|
||||
emailUnsubscribeUrl: unsubscribeUrl,
|
||||
},
|
||||
workflowId: "user-signup",
|
||||
});
|
||||
|
||||
await notificationClient.subscribers.credentials.update(
|
||||
{
|
||||
providerId: ChatOrPushProviderEnum.Discord,
|
||||
credentials: {
|
||||
webhookUrl: process.env.DISCORD_WEBHOOK_URL!,
|
||||
},
|
||||
integrationIdentifier: "discord",
|
||||
},
|
||||
user.id,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Error adding user to notification client",
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -430,3 +480,37 @@ export const initAuth = (db: dbClient) => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function triggerWorkflow(
|
||||
db: dbClient,
|
||||
workflowId: string,
|
||||
subscription: Subscription,
|
||||
cancellationDetails?: Stripe.Subscription.CancellationDetails | null,
|
||||
) {
|
||||
try {
|
||||
if (!subscription.stripeCustomerId || !notificationClient) return;
|
||||
|
||||
const user = await userRepo.getByStripeCustomerId(
|
||||
db,
|
||||
subscription.stripeCustomerId,
|
||||
);
|
||||
|
||||
if (!user || !notificationClient) return;
|
||||
|
||||
const unsubscribeUrl = await createEmailUnsubscribeLink(user.id);
|
||||
|
||||
await notificationClient.trigger({
|
||||
to: {
|
||||
subscriberId: user.id,
|
||||
},
|
||||
payload: {
|
||||
...subscription,
|
||||
cancellationDetails,
|
||||
emailUnsubscribeUrl: unsubscribeUrl,
|
||||
},
|
||||
workflowId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error triggering workflow", error);
|
||||
}
|
||||
}
|
||||
|
||||
29
packages/db/migrations/20251110204423_AddCardAttachments.sql
Normal file
29
packages/db/migrations/20251110204423_AddCardAttachments.sql
Normal file
@@ -0,0 +1,29 @@
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.attachment.added' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.attachment.removed' BEFORE 'card.archived';--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "card_attachment" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"publicId" varchar(12) NOT NULL,
|
||||
"cardId" bigint NOT NULL,
|
||||
"filename" varchar(255) NOT NULL,
|
||||
"originalFilename" varchar(255) NOT NULL,
|
||||
"contentType" varchar(100) NOT NULL,
|
||||
"size" bigint NOT NULL,
|
||||
"s3Key" varchar(500) NOT NULL,
|
||||
"createdBy" uuid,
|
||||
"createdAt" timestamp DEFAULT now() NOT NULL,
|
||||
"deletedAt" timestamp,
|
||||
CONSTRAINT "card_attachment_publicId_unique" UNIQUE("publicId")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_attachment" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_attachment" ADD CONSTRAINT "card_attachment_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "public"."card"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_attachment" ADD CONSTRAINT "card_attachment_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
2954
packages/db/migrations/meta/20251110204423_snapshot.json
Normal file
2954
packages/db/migrations/meta/20251110204423_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -134,6 +134,13 @@
|
||||
"when": 1760044396109,
|
||||
"tag": "20251009211316_AddBoardSourceIdToCardActivity",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 19,
|
||||
"version": "7",
|
||||
"when": 1762807463569,
|
||||
"tag": "20251110204423_AddCardAttachments",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import type { BoardVisibilityStatus } from "@kan/db/schema";
|
||||
import {
|
||||
boards,
|
||||
cardActivities,
|
||||
cardAttachments,
|
||||
cards,
|
||||
cardsToLabels,
|
||||
cardToWorkspaceMembers,
|
||||
@@ -196,6 +197,13 @@ export const getByPublicId = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
attachments: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
},
|
||||
where: isNull(cardAttachments.deletedAt),
|
||||
orderBy: asc(cardAttachments.createdAt),
|
||||
},
|
||||
checklists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
@@ -358,6 +366,13 @@ export const getBySlug = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
attachments: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
},
|
||||
where: isNull(cardAttachments.deletedAt),
|
||||
orderBy: asc(cardAttachments.createdAt),
|
||||
},
|
||||
comments: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { and, asc, desc, eq, gt, inArray, isNull, sql } from "drizzle-orm";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import {
|
||||
cardActivities,
|
||||
cardAttachments,
|
||||
cards,
|
||||
cardsToLabels,
|
||||
cardToWorkspaceMembers,
|
||||
@@ -409,6 +410,17 @@ export const getWithListAndMembersByPublicId = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
attachments: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
contentType: true,
|
||||
s3Key: true,
|
||||
originalFilename: true,
|
||||
size: true,
|
||||
},
|
||||
where: isNull(cardAttachments.deletedAt),
|
||||
orderBy: asc(cardAttachments.createdAt),
|
||||
},
|
||||
checklists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
|
||||
99
packages/db/src/repository/cardAttachment.repo.ts
Normal file
99
packages/db/src/repository/cardAttachment.repo.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { cardAttachments } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: dbClient,
|
||||
attachmentInput: {
|
||||
cardId: number;
|
||||
filename: string;
|
||||
originalFilename: string;
|
||||
contentType: string;
|
||||
size: number;
|
||||
s3Key: string;
|
||||
createdBy: string;
|
||||
},
|
||||
) => {
|
||||
const [result] = await db
|
||||
.insert(cardAttachments)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
cardId: attachmentInput.cardId,
|
||||
filename: attachmentInput.filename,
|
||||
originalFilename: attachmentInput.originalFilename,
|
||||
contentType: attachmentInput.contentType,
|
||||
size: attachmentInput.size,
|
||||
s3Key: attachmentInput.s3Key,
|
||||
createdBy: attachmentInput.createdBy,
|
||||
})
|
||||
.returning({
|
||||
id: cardAttachments.id,
|
||||
publicId: cardAttachments.publicId,
|
||||
filename: cardAttachments.filename,
|
||||
originalFilename: cardAttachments.originalFilename,
|
||||
contentType: cardAttachments.contentType,
|
||||
size: cardAttachments.size,
|
||||
s3Key: cardAttachments.s3Key,
|
||||
createdBy: cardAttachments.createdBy,
|
||||
createdAt: cardAttachments.createdAt,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const getByPublicId = (db: dbClient, publicId: string) => {
|
||||
return db.query.cardAttachments.findFirst({
|
||||
where: eq(cardAttachments.publicId, publicId),
|
||||
with: {
|
||||
card: {
|
||||
columns: {
|
||||
id: true,
|
||||
publicId: true,
|
||||
},
|
||||
with: {
|
||||
list: {
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
with: {
|
||||
board: {
|
||||
columns: {
|
||||
id: true,
|
||||
workspaceId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllByCardId = (db: dbClient, cardId: number) => {
|
||||
return db.query.cardAttachments.findMany({
|
||||
where: and(
|
||||
eq(cardAttachments.cardId, cardId),
|
||||
isNull(cardAttachments.deletedAt),
|
||||
),
|
||||
orderBy: (attachments, { desc }) => [desc(attachments.createdAt)],
|
||||
});
|
||||
};
|
||||
|
||||
export const softDelete = async (
|
||||
db: dbClient,
|
||||
args: {
|
||||
attachmentId: number;
|
||||
deletedAt: Date;
|
||||
},
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(cardAttachments)
|
||||
.set({ deletedAt: args.deletedAt })
|
||||
.where(eq(cardAttachments.id, args.attachmentId))
|
||||
.returning({ id: cardAttachments.id });
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -28,6 +28,15 @@ export const getById = async (db: dbClient, userId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const getByStripeCustomerId = async (
|
||||
db: dbClient,
|
||||
stripeCustomerId: string,
|
||||
) => {
|
||||
return await db.query.users.findFirst({
|
||||
where: eq(users.stripeCustomerId, stripeCustomerId),
|
||||
});
|
||||
};
|
||||
|
||||
export const getByEmail = (db: dbClient, email: string) => {
|
||||
return db.query.users.findFirst({
|
||||
columns: {
|
||||
|
||||
@@ -42,6 +42,8 @@ export const activityTypes = [
|
||||
"card.updated.checklist.item.completed",
|
||||
"card.updated.checklist.item.uncompleted",
|
||||
"card.updated.checklist.item.deleted",
|
||||
"card.updated.attachment.added",
|
||||
"card.updated.attachment.removed",
|
||||
"card.archived",
|
||||
] as const;
|
||||
|
||||
@@ -96,6 +98,7 @@ export const cardsRelations = relations(cards, ({ one, many }) => ({
|
||||
comments: many(comments),
|
||||
activities: many(cardActivities),
|
||||
checklists: many(checklists),
|
||||
attachments: many(cardAttachments),
|
||||
}));
|
||||
|
||||
export const cardActivities = pgTable("card_activity", {
|
||||
@@ -273,3 +276,37 @@ export const commentsRelations = relations(comments, ({ one }) => ({
|
||||
relationName: "commentsDeletedByUser",
|
||||
}),
|
||||
}));
|
||||
|
||||
export const cardAttachments = pgTable("card_attachment", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
cardId: bigint("cardId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => cards.id, { onDelete: "cascade" }),
|
||||
filename: varchar("filename", { length: 255 }).notNull(),
|
||||
originalFilename: varchar("originalFilename", { length: 255 }).notNull(),
|
||||
contentType: varchar("contentType", { length: 100 }).notNull(),
|
||||
size: bigint("size", { mode: "number" }).notNull(),
|
||||
s3Key: varchar("s3Key", { length: 500 }).notNull(),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
}).enableRLS();
|
||||
|
||||
export const cardAttachmentsRelations = relations(
|
||||
cardAttachments,
|
||||
({ one }) => ({
|
||||
card: one(cards, {
|
||||
fields: [cardAttachments.cardId],
|
||||
references: [cards.id],
|
||||
relationName: "cardAttachmentsCard",
|
||||
}),
|
||||
createdBy: one(users, {
|
||||
fields: [cardAttachments.createdBy],
|
||||
references: [users.id],
|
||||
relationName: "cardAttachmentsCreatedByUser",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@plunk/node": "^3.0.3",
|
||||
"@novu/api": "^3.11.0",
|
||||
"@react-email/components": "^0.0.25",
|
||||
"nodemailer": "^7.0.3",
|
||||
"react-email": "^3.0.1"
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import Plunk from "@plunk/node";
|
||||
|
||||
export const cloudMailerClient =
|
||||
process.env.NEXT_PUBLIC_KAN_ENV === "cloud" &&
|
||||
process.env.PLUNK_API_KEY &&
|
||||
process.env.PLUNK_API_URL
|
||||
? new Plunk(process.env.PLUNK_API_KEY ?? "", {
|
||||
baseUrl: process.env.PLUNK_API_URL,
|
||||
})
|
||||
: null;
|
||||
@@ -1,4 +1,4 @@
|
||||
export const name = "email";
|
||||
|
||||
export { sendEmail } from "./sendEmail";
|
||||
export { cloudMailerClient } from "./cloudMailerClient";
|
||||
export { notificationClient } from "./notificationClient";
|
||||
|
||||
6
packages/email/src/notificationClient.tsx
Normal file
6
packages/email/src/notificationClient.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Novu } from "@novu/api";
|
||||
|
||||
export const notificationClient =
|
||||
process.env.NEXT_PUBLIC_KAN_ENV === "cloud" && process.env.NOVU_API_KEY
|
||||
? new Novu({ secretKey: process.env.NOVU_API_KEY })
|
||||
: null;
|
||||
@@ -1,7 +1,6 @@
|
||||
import { render } from "@react-email/render";
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
import { cloudMailerClient } from "./cloudMailerClient";
|
||||
import JoinWorkspaceTemplate from "./templates/join-workspace";
|
||||
import MagicLinkTemplate from "./templates/magic-link";
|
||||
import ResetPasswordTemplate from "./templates/reset-password";
|
||||
@@ -45,15 +44,6 @@ export const sendEmail = async (
|
||||
html,
|
||||
};
|
||||
|
||||
// if (cloudMailerClient) {
|
||||
// const response = await cloudMailerClient.emails.send({
|
||||
// ...options,
|
||||
// body: html,
|
||||
// });
|
||||
|
||||
// return response;
|
||||
// }
|
||||
|
||||
const response = await transporter.sendMail(options);
|
||||
|
||||
if (!response.accepted.length) {
|
||||
|
||||
31
packages/shared/src/utils/email.ts
Normal file
31
packages/shared/src/utils/email.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { SignJWT } from "jose";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
/**
|
||||
* Creates a long‑lived unsubscribe link for a given user/subscriber.
|
||||
*
|
||||
* `${NEXT_PUBLIC_BASE_URL}/unsubscribe?token=<jwt>`
|
||||
*
|
||||
* The JWT payload only contains the subscriberId. There is no expiry
|
||||
* on purpose – unsubscribe links should remain valid indefinitely.
|
||||
*
|
||||
*/
|
||||
export async function createEmailUnsubscribeLink(
|
||||
userId: string,
|
||||
): Promise<string | null> {
|
||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
|
||||
const secret = process.env.EMAIL_UNSUBSCRIBE_SECRET;
|
||||
|
||||
if (!baseUrl || !secret) {
|
||||
// Environment not configured for unsubscribe links.
|
||||
return null;
|
||||
}
|
||||
|
||||
const token = await new SignJWT({ subscriberId: userId })
|
||||
.setProtectedHeader({ alg: "HS256" })
|
||||
// No expiration on purpose; unsubscribe links are long‑lived.
|
||||
.sign(encoder.encode(secret));
|
||||
|
||||
return `${baseUrl}/unsubscribe?token=${encodeURIComponent(token)}`;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./generateUID";
|
||||
export * from "./generateSlug";
|
||||
export * from "./subscriptions";
|
||||
export * from "./email";
|
||||
|
||||
@@ -71,4 +71,13 @@ export const updateSubscriptionSeats = async (
|
||||
return updatedSubscription;
|
||||
};
|
||||
|
||||
export const getCancellationDetails = async (
|
||||
stripeSubscriptionId: string,
|
||||
): Promise<Stripe.Subscription.CancellationDetails | null> => {
|
||||
const stripe = createStripeClient();
|
||||
const stripeSubscription =
|
||||
await stripe.subscriptions.retrieve(stripeSubscriptionId);
|
||||
return stripeSubscription.cancellation_details ?? null;
|
||||
};
|
||||
|
||||
export { createStripeClient };
|
||||
|
||||
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@@ -115,6 +115,9 @@ importers:
|
||||
'@lingui/react':
|
||||
specifier: ^5.3.2
|
||||
version: 5.4.1(@lingui/babel-plugin-lingui-macro@5.4.1(typescript@5.9.2))(react@18.3.1)
|
||||
'@novu/api':
|
||||
specifier: ^3.11.0
|
||||
version: 3.11.0
|
||||
'@t3-oss/env-nextjs':
|
||||
specifier: ^0.11.1
|
||||
version: 0.11.1(typescript@5.9.2)(zod@3.25.76)
|
||||
@@ -166,6 +169,9 @@ importers:
|
||||
geist:
|
||||
specifier: ^1.3.1
|
||||
version: 1.4.2(next@15.5.2(@babel/core@7.28.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
jose:
|
||||
specifier: ^6.1.2
|
||||
version: 6.1.2
|
||||
next:
|
||||
specifier: ^15.3.4
|
||||
version: 15.5.2(@babel/core@7.28.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -293,6 +299,12 @@ importers:
|
||||
|
||||
packages/api:
|
||||
dependencies:
|
||||
'@aws-sdk/client-s3':
|
||||
specifier: ^3.802.0
|
||||
version: 3.879.0
|
||||
'@aws-sdk/s3-request-presigner':
|
||||
specifier: ^3.812.0
|
||||
version: 3.879.0
|
||||
'@kan/auth':
|
||||
specifier: workspace:*
|
||||
version: link:../auth
|
||||
@@ -434,9 +446,9 @@ importers:
|
||||
|
||||
packages/email:
|
||||
dependencies:
|
||||
'@plunk/node':
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3
|
||||
'@novu/api':
|
||||
specifier: ^3.11.0
|
||||
version: 3.11.0
|
||||
'@react-email/components':
|
||||
specifier: ^0.0.25
|
||||
version: 0.0.25(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -2677,6 +2689,9 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@novu/api@3.11.0':
|
||||
resolution: {integrity: sha512-8u0mB5VThL7MhdxoN0UoA4CS9eu2k3Xa6iulauMhCHENuJNxUNuirJWq5t8jDoH4bFTQTfMN0VRkC0qodKR2qA==}
|
||||
|
||||
'@octokit/auth-token@3.0.4':
|
||||
resolution: {integrity: sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -2756,9 +2771,6 @@ packages:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@plunk/node@3.0.3':
|
||||
resolution: {integrity: sha512-f3NT418/EdLjebQ4arAwR64cnz7d5H7i1CeKh8+B0cVBrwzHvF+Q+QkhutF+FAp49yuI/BYc71qQH+RFc2fxxQ==}
|
||||
|
||||
'@popperjs/core@2.11.8':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
|
||||
@@ -5548,6 +5560,9 @@ packages:
|
||||
jose@5.10.0:
|
||||
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
|
||||
|
||||
jose@6.1.2:
|
||||
resolution: {integrity: sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==}
|
||||
|
||||
joycon@3.1.1:
|
||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -10220,6 +10235,10 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.19.1
|
||||
|
||||
'@novu/api@3.11.0':
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
'@octokit/auth-token@3.0.4': {}
|
||||
|
||||
'@octokit/core@4.2.4':
|
||||
@@ -10339,10 +10358,6 @@ snapshots:
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@plunk/node@3.0.3':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@popperjs/core@2.11.8': {}
|
||||
|
||||
'@posthog/core@1.0.2': {}
|
||||
@@ -13643,6 +13658,8 @@ snapshots:
|
||||
|
||||
jose@5.10.0: {}
|
||||
|
||||
jose@6.1.2: {}
|
||||
|
||||
joycon@3.1.1: {}
|
||||
|
||||
js-beautify@1.15.4:
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
"NEXT_PUBLIC_KAN_ENV",
|
||||
"NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY",
|
||||
"STRIPE_SECRET_KEY",
|
||||
"DISCORD_WEBHOOK_URL",
|
||||
"STRIPE_WEBHOOK_SECRET",
|
||||
"STRIPE_WEBHOOK_SECRET_LEGACY",
|
||||
"STRIPE_PRO_PLAN_MONTHLY_PRICE_ID",
|
||||
@@ -108,6 +109,7 @@
|
||||
"NEXT_PUBLIC_STORAGE_DOMAIN",
|
||||
"NEXT_PUBLIC_STORAGE_URL",
|
||||
"NEXT_PUBLIC_AVATAR_BUCKET_NAME",
|
||||
"NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME",
|
||||
"NEXT_PUBLIC_ALLOW_CREDENTIALS",
|
||||
"NEXT_PUBLIC_DISABLE_SIGN_UP",
|
||||
"NEXT_PUBLIC_USE_STANDALONE_OUTPUT",
|
||||
@@ -119,8 +121,8 @@
|
||||
"PORT",
|
||||
"BETTER_AUTH_SECRET",
|
||||
"BETTER_AUTH_TRUSTED_ORIGINS",
|
||||
"PLUNK_API_KEY",
|
||||
"PLUNK_API_URL"
|
||||
"NOVU_API_KEY",
|
||||
"EMAIL_UNSUBSCRIBE_SECRET"
|
||||
],
|
||||
"globalPassThroughEnv": [
|
||||
"NODE_ENV",
|
||||
|
||||
Reference in New Issue
Block a user