Compare commits

...

21 Commits

Author SHA1 Message Date
Henry
b00c47952c chore: add translations 2025-09-26 22:11:18 +01:00
Henry
aa931ddcbe feat: only allow admin users to create links 2025-09-26 22:08:52 +01:00
Henry
73b9ac7cb5 feat(cloud): update subscription for cloud 2025-09-26 22:00:20 +01:00
Henry
01e0140e6a refactor: tweak light mode styles 2025-09-26 21:45:49 +01:00
Henry
f22a0332ab feat: switch to workspace on invite success 2025-09-26 21:38:05 +01:00
Henry
bd97362d90 feat: add invite page 2025-09-25 23:11:02 +01:00
Henry
3b3b4f89ba feat: redirect to next param on authentication 2025-09-25 22:06:18 +01:00
Henry
17f876160d feat: add repo funcs and share link toggle 2025-09-23 22:58:59 +01:00
Henry
dd1bd9b7cc feat: update workspace invite schema 2025-09-23 22:51:33 +01:00
Henry
7d9746be20 feat: add workspace invite links schema 2025-09-23 21:42:37 +01:00
Morfixx
fed24d1960 fix: bulkCreate to stop imports with duplicate indices (#190)
* fix(db): normalize/compact indices to prevent import duplicates

- bulkCreate now assigns sequential indices per board (preserves order; ignores incoming indices).
- Auto-compact indices after create/insert if duplicates exist, keeping active lists unique and gap-free.
- Prevents reorder errors caused by duplicate indices from Trello imports.

* feat(db): normalize/compact indices with fail-safe duplicate recheck
2025-09-20 22:17:41 +01:00
Morfixx
2a0220ce6f feat: added docs to website (#186)
* feat(docs): self-hosting s3 minio guide

* feat(docs): self-hosting introduction guide

* fix: build error

* refactor: use kan over kan.bn

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
2025-09-19 21:08:59 +01:00
Morfixx
7ccd2ac1e0 feat(web): added image cropping to avatar uploads (#185)
* feat(web): added image cropping to avatar uploads

* chore: add translations

* refactor: move react crop css import to avatar component

* refactor: remove duplicate interface

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
2025-09-19 20:44:20 +01:00
Henry
cea5cf84c8 feat(cloud): pause/reactivate members (#184)
* feat: add paused member status

* feat: add paused badge to member table

* chore: add translations

* feat: unpause all members on pro activation
2025-09-18 22:09:42 +01:00
Henry
6738fddc5f feat(localisation): add russian language support (#183) 2025-09-18 20:50:01 +01:00
Henry
dc1f78df55 fix: set correct grid size for boards on desktop viewports (#180) 2025-09-14 21:12:35 +01:00
Henry
87e02fdcb0 chore: add missing translations 2025-09-14 20:46:11 +01:00
Henry
7073cd5931 feat: only render table if api keys exist 2025-09-14 20:28:38 +01:00
LovelessCodes
3e21b23f0a refactor: reorganize settings page with tabbed interface (#57)
* refactor: reorganize settings page with tabbed interface

* feat: revamp API key management with new list view and confirmation modals

* refactor: update tab styling

* refactor: tweak UI/UX for managing API keys

* refactor: only show update button when change has been made

* refactor: only show update button when content of display name has been updated

* feat: store tab state in params

* refactor: remove focus state from tabs

* refactor: tweak styling on mobile select

* refactor: simplify settings pages

* feat: open upgrade modal if upgrade=pro is in params

* feat: add scroll to api key list on mobile

* chore: add translations

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
2025-09-14 15:48:55 +01:00
Henry
793baa8325 fix: update modal z-index to ensure proper layering (#177) 2025-09-12 20:14:41 +01:00
Henry
63e639e337 fix: show correct active workspace and truncate name (#175) 2025-09-11 23:02:48 +01:00
79 changed files with 12557 additions and 1361 deletions

View File

@@ -0,0 +1,140 @@
---
title: "Introduction"
description: "Overview and quick start to run Kan on your own infrastructure using Docker Compose."
mode: "wide"
tag: "NEW"
---
This guide introduces how to self-host Kan. It starts with the minimal Docker Compose setup (web + PostgreSQL) and points you to optional features like email and S3-based file storage.
## What youll set up
<CardGroup cols={2}>
<Card title="Kan" icon="globe" color="#0284c7" horizontal>
Next.js application served on port 3000.
</Card>
<Card title="PostgreSQL 15" icon="database" color="#65a30d" horizontal>
Primary database for Kan data.
</Card>
</CardGroup>
<Note>
For file uploads (avatars), OAuth, and other advanced options, see the
Environment Variables section in the README and the dedicated [S3
guide](/guides/self-hosting/s3). The [full
compose](https://github.com/kanbn/kan/blob/main/docker-compose.yml) in the
repo includes a richer configuration via <code>.env</code>.
</Note>
## Prerequisites
- Docker and Docker Compose
- A long random string for <code>BETTER_AUTH_SECRET</code> (32+ chars)
## Quick start
<Steps>
<Step title="Create a docker-compose.yml">
Paste the following minimal configuration into a new <code>docker-compose.yml</code> file:
```yaml
services:
web:
image: ghcr.io/kanbn/kan:latest
container_name: kan-web
ports:
- "3000:3000"
networks:
- kan-network
environment:
NEXT_PUBLIC_BASE_URL: http://localhost:3000
BETTER_AUTH_SECRET: your_auth_secret
POSTGRES_URL: postgresql://kan:your_postgres_password@postgres:5432/kan_db
NEXT_PUBLIC_ALLOW_CREDENTIALS: true
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:15
container_name: kan-db
environment:
POSTGRES_DB: kan_db
POSTGRES_USER: kan
POSTGRES_PASSWORD: your_postgres_password
ports:
- 5432:5432
volumes:
- kan_postgres_data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- kan-network
networks:
kan-network:
volumes:
kan_postgres_data:
```
<Tip>
The example above is intentionally minimal. The repository provides a more feature-complete compose file at [docker-compose.yml](https://github.com/kanbn/kan/blob/main/docker-compose.yml) if you want environment-based configuration, OAuth, S3, and more.
</Tip>
</Step>
<Step title="Start the stack">
Bring everything up in detached mode:
```bash
docker compose up -d
```
Once started, open [http://localhost:3000](http://localhost:3000).
</Step>
<Step title="Manage the containers">
Useful commands while developing or testing:
- Stop the containers: <code>docker compose down</code>
- View logs: <code>docker compose logs -f</code>
- Restart: <code>docker compose restart</code>
</Step>
<Step title="Configure environment (optional)">
For a production-like setup and more features (email, OAuth, file uploads, etc.), create a <code>.env</code> file and set the relevant variables shown in the READMEs Environment Variables section.
<Accordion title="Common variables">
```bash
# Required
NEXT_PUBLIC_BASE_URL=http://localhost:3000
BETTER_AUTH_SECRET=replace_with_long_random_string
POSTGRES_URL=postgresql://kan:your_postgres_password@postgres:5432/kan_db
# Optional: Email
EMAIL_FROM="Kan <hello@mail.kan.bn>"
SMTP_HOST=smtp.resend.com
SMTP_PORT=465
SMTP_USER=resend
SMTP_PASSWORD=re_xxxx
SMTP_SECURE=true
# Optional: Auth toggles
NEXT_PUBLIC_ALLOW_CREDENTIALS=true
NEXT_PUBLIC_DISABLE_SIGN_UP=false
```
<Note type="warning">
If you plan to enable file uploads (avatars, etc.), youll also need S3 variables (<code>S3_ENDPOINT</code>, <code>S3_ACCESS_KEY_ID</code>, <code>S3_SECRET_ACCESS_KEY</code>, <code>NEXT_PUBLIC_STORAGE_URL</code>, <code>NEXT_PUBLIC_STORAGE_DOMAIN</code>, …). See the S3 guide linked at the top.
</Note>
</Accordion>
</Step>
</Steps>
## Reference
- [GitHub README](https://github.com/kanbn/kan/blob/main/README.md#self-hosting-)
- [GitHub docker-compose.yml](https://github.com/kanbn/kan/blob/main/docker-compose.yml)

View File

@@ -0,0 +1,397 @@
---
title: "Kan + MinIO (S3)"
mode: "wide"
tag: "NEW"
---
Deploy Kan with PostgreSQL and MinIO (S3-compatible storage) using Docker Compose, with clear steps and production notes.
## What youll set up
<CardGroup cols={2}>
<Card title="Kan" icon="globe" color="#0284c7" horizontal>
Kan web app (Next.js), on port 3000.
</Card>
<Card title="PostgreSQL 15" icon="database" color="#65a30d" horizontal>
PostgreSQL database for Kan.
</Card>
</CardGroup>
<Card title="MinIO (S3-compatible)" icon="cloud" color="#ca8a04" horizontal>
MinIO object storage (console port 9001, S3 API port 9000).
</Card>
## How it works
- Kan stores data in PostgreSQL.
- Kan uploads files (e.g., avatars) to MinIO over the S3 API.
- The browser fetches public files directly from MinIOs public URL.
- The Next.js image optimizer in Kan must be explicitly allowed to fetch from your storage host.
Key domain settings:
- <code>NEXT_PUBLIC_BASE_URL</code> → the Kan site
- <code>NEXT_PUBLIC_STORAGE_URL</code> → the public S3 base URL
- <code>NEXT_PUBLIC_STORAGE_DOMAIN</code> → the exact S3 hostname (no scheme)
## Prerequisites
- Docker and Docker Compose
- Open local ports: 3000 (Kan), 5432 (Postgres), 9000/9001 (MinIO)
- A long random string for <code>BETTER_AUTH_SECRET</code> (32+ chars)
<Note type="warning">
For production youll want a reverse proxy (Traefik/Nginx/Caddy), valid TLS
certificates, and DNS for your domains (e.g., <code>kan.example.com</code>,{" "}
<code>s3.example.com</code>).
</Note>
## Quick start
<Tip type="info">
Why <code>localtest.me</code>? It resolves to <code>127.0.0.1</code>{" "}
automatically, so you can test domain-based configs locally without editing
hosts.
</Tip>
<Steps>
<Step title="Set environment variables">
Provide the minimum required configuration (local example):
```bash
NEXT_PUBLIC_BASE_URL=http://kan.localtest.me:3000
BETTER_AUTH_SECRET=<long random string>
POSTGRES_URL=postgresql://kan:<password>@postgres:5432/kan_db
# MinIO/S3
S3_ENDPOINT=http://s3.localtest.me:9000
S3_ACCESS_KEY_ID=<minio-access-key>
S3_SECRET_ACCESS_KEY=<minio-secret-key>
S3_REGION=none
S3_FORCE_PATH_STYLE=true
# Public storage access
NEXT_PUBLIC_STORAGE_URL=http://s3.localtest.me:9000
NEXT_PUBLIC_STORAGE_DOMAIN=s3.localtest.me
NEXT_PUBLIC_AVATAR_BUCKET_NAME=kan
```
<Note type="info">
Issue #109 fix: make sure <code>NEXT_PUBLIC_STORAGE_DOMAIN</code> exactly
equals the hostname that serves your images (no scheme, no port).
</Note>
Optional (see README for full list): Email (`EMAIL_FROM`, `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_SECURE`), OAuth/OIDC (`GOOGLE_*`, `GITHUB_*`, `OIDC_*`), auth toggles, Trello import, etc.
</Step>
<Step title="Create or review Docker Compose files">
You can start from the minimal compose at the repository root (<code>docker-compose.yml</code>) and review the production-oriented settings in <code>cloud/docker-compose.yml</code>.
Start with the minimal setup (web + postgres + minio) and ensure environment variables are passed to the web service.
<Accordion title="Docker Compose example">
```yaml
services:
postgres:
image: postgres:15
container_name: kan-db
ports:
- "5432:5432"
environment:
POSTGRES_USER: kan
POSTGRES_PASSWORD: changeme
POSTGRES_DB: kan_db
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: kan-minio
command: server /data --console-address ":9001"
ports:
- "9000:9000" # S3 API
- "9001:9001" # Console
environment:
# Use the same credentials in your .env
# as S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio123456789
volumes:
- minio_data:/data
restart: unless-stopped
web:
image: ghcr.io/kanbn/kan:latest
container_name: kan-web
depends_on:
- postgres
- minio
ports:
- "3000:3000"
# Load variables from .env
# (see the "Set environment variables" step)
env_file:
- .env
restart: unless-stopped
volumes:
pg_data:
minio_data:
```
<Note type="info">
Ensure your <code>.env</code> contains values that match this compose file.
For example:
<ul>
<li>
<code>POSTGRES_URL=postgresql://kan:changeme@postgres:5432/kan_db</code>
</li>
<li>
<code>S3_ENDPOINT=http://s3.localtest.me:9000</code>
</li>
<li>
<code>S3_ACCESS_KEY_ID=minio</code> and{" "}
<code>S3_SECRET_ACCESS_KEY=minio123456789</code>
</li>
<li>
<code>S3_FORCE_PATH_STYLE=true</code>
</li>
<li>
<code>NEXT_PUBLIC_STORAGE_URL=http://s3.localtest.me:9000</code>
</li>
<li>
<code>NEXT_PUBLIC_STORAGE_DOMAIN=s3.localtest.me</code>
</li>
<li>
<code>NEXT_PUBLIC_AVATAR_BUCKET_NAME=kan</code>
</li>
</ul>
</Note>
</Accordion>
</Step>
<Step title="Start services">
```bash
docker compose up -d
```
Then open:
<ul>
<li>
Kan: <a href="http://kan.localtest.me:3000">http://kan.localtest.me:3000</a>
</li>
<li>
MinIO Console:{" "}
<a href="http://minio.localtest.me:9001">http://minio.localtest.me:9001</a>
</li>
<li>
MinIO S3 API:{" "}
<a href="http://s3.localtest.me:9000">http://s3.localtest.me:9000</a>
</li>
</ul>
</Step>
<Step title="Initialize MinIO">
1) Log into the MinIO Console (http://minio.localtest.me:9001).
2. Create a bucket (e.g., <code>kan</code>).
3. For simple public avatars, apply a read-only policy so GET requests are allowed for objects:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": ["*"] },
"Action": ["s3:GetBucketLocation", "s3:ListBucket"],
"Resource": ["arn:aws:s3:::kan"]
},
{
"Effect": "Allow",
"Principal": { "AWS": ["*"] },
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::kan/*"]
}
]
}
```
<Note type="warning">
Alternatively, keep the bucket private and use presigned URLs. In that case,
ensure your server and browser access paths are correctly configured.
</Note>
</Step>
<Step title="Verify the setup">
<ul>
<li>Sign in to Kan and upload an avatar (Settings).</li>
<li>Confirm the object is created in your MinIO bucket.</li>
<li>The avatar should render without errors.</li>
</ul>
If you see a 400 from <code>/\_next/image</code> with “url parameter is not allowed”:
<ul>
<li>
<code>NEXT_PUBLIC_STORAGE_DOMAIN</code> must exactly match the S3 hostname
that serves images.
</li>
<li>
<code>NEXT_PUBLIC_STORAGE_URL</code> should use the same host (with
scheme/port).
</li>
<li>Ensure youre using the latest Kan image.</li>
</ul>
</Step>
</Steps>
## Production setup
<Tabs>
<Tab title="Local">
<ul>
<li><code>NEXT_PUBLIC_BASE_URL=http://kan.localtest.me:3000</code></li>
<li><code>S3_ENDPOINT=http://s3.localtest.me:9000</code></li>
<li><code>NEXT_PUBLIC_STORAGE_URL=http://s3.localtest.me:9000</code></li>
<li><code>NEXT_PUBLIC_STORAGE_DOMAIN=s3.localtest.me</code></li>
<li>Keep <code>S3_FORCE_PATH_STYLE=true</code> for MinIO.</li>
</ul>
</Tab>
<Tab title="Production">
<ul>
<li><code>NEXT_PUBLIC_BASE_URL=https://kan.example.com</code></li>
<li><code>S3_ENDPOINT=https://s3.example.com</code></li>
<li><code>NEXT_PUBLIC_STORAGE_URL=https://s3.example.com</code></li>
<li><code>NEXT_PUBLIC_STORAGE_DOMAIN=s3.example.com</code></li>
<li>Keep <code>S3_FORCE_PATH_STYLE=true</code> for MinIO.</li>
<li>Put Kan and MinIO behind HTTPS with a reverse proxy (Traefik/Nginx) and valid TLS.</li>
</ul>
</Tab>
</Tabs>
## Troubleshooting
<AccordionGroup>
<Accordion title="Files upload but dont display">
<ul>
<li>If public: confirm GET is allowed on objects (bucket policy).</li>
<li>If private: ensure presigned URLs are generated and valid.</li>
<li>403 AccessDenied indicates permissions, not CORS. CORS is not required for simple <code>&lt;img&gt;</code> GETs.</li>
</ul>
</Accordion>
<Accordion title="Make the bucket public (read-only) with mc" defaultOpen>
Use your MinIO root credentials to allow anonymous reads:
```bash
# Replace with your MINIO_ROOT_PASSWORD
MINIO_PASS='<your-minio-password>'
# Point mc at MinIO via the container network (no ports required)
docker run --rm --network container:kan-minio minio/mc \
mc alias set local http://127.0.0.1:9000 minio "$MINIO_PASS"
# Allow public downloads from the bucket
docker run --rm --network container:kan-minio minio/mc \
mc anonymous set download local/kan
# Optional: verify anonymous status
docker run --rm --network container:kan-minio minio/mc \
mc anonymous get local/kan
```
</Accordion>
<Accordion title="Alternative: S3 bucket policy (AWS CLI)">
If you prefer a bucket policy, apply a public-read policy for objects:
```json policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::kan/*"]
}
]
}
```
```bash
# Use your MinIO root credentials
MINIO_PASS='<your-minio-password>'
docker run --rm --network container:kan-minio \
-e AWS_ACCESS_KEY_ID=minio \
-e AWS_SECRET_ACCESS_KEY="$MINIO_PASS" \
-e AWS_DEFAULT_REGION=us-east-1 -e AWS_S3_FORCE_PATH_STYLE=true \
-v "$PWD:/work" amazon/aws-cli \
s3api put-bucket-policy --bucket kan --policy file:///work/policy.json \
--endpoint-url http://127.0.0.1:9000
```
</Accordion>
<Accordion title="Next.js optimizer 400 — url parameter is not allowed">
<ul>
<li>
Exact match on <code>NEXT_PUBLIC_STORAGE_DOMAIN</code> with your storage
host.
</li>
<li>
Same host in <code>NEXT_PUBLIC_STORAGE_URL</code>.
</li>
<li>Update to the latest Kan image.</li>
</ul>
</Accordion>
<Accordion title="Next/Image: “url parameter is valid but upstream response is invalid”">
<ul>
<li>This means Next.js accepted the URL, but the upstream returned a non-image (e.g., 403 HTML/XML).</li>
<li>Fix: make the bucket/object publicly readable (see above), or use presigned URLs.</li>
<li>Sanity test from the web network (replace with your image URL):</li>
</ul>
```bash
IMG_URL="https://s3.example.com/kan/path/to/avatar.jpg"
# Headers/content-type as seen from the app network
docker run --rm --network container:kan-web curlimages/curl:8.9.1 \
-I -L --max-redirs 5 "$IMG_URL"
# Quick status + content-type summary
docker run --rm --network container:kan-web curlimages/curl:8.9.1 \
-s -o /dev/null -w "HTTP:%{http_code} CT:%{content_type} URL:%{url_effective}\n" -L "$IMG_URL"
```
</Accordion>
<Accordion title="Connectivity checks">
<ul>
<li>The Kan container must reach <code>S3_ENDPOINT</code>.</li>
<li>Verify DNS/ports inside the container (e.g., <code>docker exec -it &lt;kan-container&gt; sh</code>).</li>
</ul>
</Accordion>
</AccordionGroup>
## References
- [Kan README](https://github.com/kanbn/kan/blob/main/README.md)
- [Cloud compose reference](https://github.com/kanbn/kan/blob/main/cloud/docker-compose.yml)
- [Kan #109 Issue](https://github.com/kanbn/kan/issues/109)

View File

@@ -44,6 +44,18 @@
"group": "Get Started", "group": "Get Started",
"pages": ["introduction"] "pages": ["introduction"]
}, },
{
"group": "Guides",
"pages": [
{
"group": "Self-Hosting",
"pages": [
"guides/self-hosting/introduction",
"guides/self-hosting/s3"
]
}
]
},
{ {
"group": "Import", "group": "Import",
"pages": ["imports/trello"] "pages": ["imports/trello"]

View File

@@ -2,7 +2,7 @@
"version": 0, "version": 0,
"locale": { "locale": {
"source": "en", "source": "en",
"targets": ["fr", "de", "es", "it", "nl"] "targets": ["fr", "de", "es", "it", "nl", "ru"]
}, },
"buckets": { "buckets": {
"po": { "po": {

View File

@@ -10,6 +10,7 @@ checksums:
"%248%2Fmonth/singular": 4667034934bb2bc3d569c70b94205b51 "%248%2Fmonth/singular": 4667034934bb2bc3d569c70b94205b51
1%20user/singular: 3b547431ab12f0fba84307e6a81109d8 1%20user/singular: 3b547431ab12f0fba84307e6a81109d8
A%20powerful%2C%20flexible%20kanban%20app%20that%20helps%20you%20organise%20work%2C%20track%20progress%2C%20and%20deliver%20results%E2%80%94all%20in%20one%20place./singular: d405b83b0d631cb72f4347c10bcbb643 A%20powerful%2C%20flexible%20kanban%20app%20that%20helps%20you%20organise%20work%2C%20track%20progress%2C%20and%20deliver%20results%E2%80%94all%20in%20one%20place./singular: d405b83b0d631cb72f4347c10bcbb643
Account/singular: 01215c12fb1cdb93bd0c84c1382bef56
Account%20deleted/singular: a25da96a1579c4491be0a95669ef18a4 Account%20deleted/singular: a25da96a1579c4491be0a95669ef18a4
Activity/singular: 1948763de8e531483a798b68195e297e Activity/singular: 1948763de8e531483a798b68195e297e
Activity%20logs/singular: 8b1f0bb96a905646ecfad1cfdfa42168 Activity%20logs/singular: 8b1f0bb96a905646ecfad1cfdfa42168
@@ -29,11 +30,18 @@ checksums:
added%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: bdd202da20b1fffbec21792c5453f90c added%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: bdd202da20b1fffbec21792c5453f90c
added%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: b32be052b3d57de0c9120fa7f9fc86ee added%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: b32be052b3d57de0c9120fa7f9fc86ee
Adding%20a%20new%20member%20will%20cost%20an%20additional%20%7Bprice%7D%20(%7BbillingType%7D)%20per%20seat./singular: 12e88573028306110fbc15ef1e714892 Adding%20a%20new%20member%20will%20cost%20an%20additional%20%7Bprice%7D%20(%7BbillingType%7D)%20per%20seat./singular: 12e88573028306110fbc15ef1e714892
Adjust%20the%20square%20crop%20to%20fit%20your%20avatar./singular: a4df26bbce6f14c6962fac1324db00a8
Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df
All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc
Already%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20in%3C%2F1%3E%3C%2F0%3E/singular: 2959fd276248208b65cb27ed46b20135 Already%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20in%3C%2F1%3E%3C%2F0%3E/singular: 2959fd276248208b65cb27ed46b20135
An%20error%20occurred%20while%20disconnecting%20your%20Trello%20account./singular: 0aa3973b860c1faf8d9123aebf567e40 An%20error%20occurred%20while%20disconnecting%20your%20Trello%20account./singular: 0aa3973b860c1faf8d9123aebf567e40
An%20unexpected%20error%20occurred.%20Please%20try%20again%20later./singular: 1b5749b0cca6a62d75a577bee6804074 An%20unexpected%20error%20occurred.%20Please%20try%20again%20later./singular: 1b5749b0cca6a62d75a577bee6804074
Anyone%20with%20this%20link%20can%20join%20your%20workspace/singular: 2366ed295eb2c03c425559c24cb31606
API/singular: 01d9819514e27056dcc69463194b63d2
API%20key%20created/singular: 8dbb2b60a719b0d120e774d6666c8c45
API%20key%20name/singular: 2d8aeb08b2cce3b750a584bbc5ce6d1d
API%20key%20name%20cannot%20exceed%2030%20characters/singular: 3ea1c7d68e1074a75128017b097b727a
API%20key%20name%20is%20required/singular: 870970743b14cb56e7fb7b410af0e933
API%20keys/singular: 07f3620a30e08136f0b072c9af8d1eef API%20keys/singular: 07f3620a30e08136f0b072c9af8d1eef
API%20Reference/singular: 7dcc877064bfdf889ec55dbc9e06a242 API%20Reference/singular: 7dcc877064bfdf889ec55dbc9e06a242
Applicants/singular: 4babd8331a1441e91087f855f43e57f8 Applicants/singular: 4babd8331a1441e91087f855f43e57f8
@@ -74,11 +82,12 @@ checksums:
Card%20not%20found/singular: 91509e2f92b0b3b11330b6983139fdbf Card%20not%20found/singular: 91509e2f92b0b3b11330b6983139fdbf
Card%20title/singular: 7c34f59f4005e6cb3a6ff546ea0b96e3 Card%20title/singular: 7c34f59f4005e6cb3a6ff546ea0b96e3
Change%20Password/singular: a552fc5c4189ebc3e2e6018edda7d18f Change%20Password/singular: a552fc5c4189ebc3e2e6018edda7d18f
Change%20the%20language%20of%20the%20app./singular: fb20db145e28ed44aba89c146ded7bfc Change%20your%20language%20preferences./singular: 293d49fc3c75e9c425b64bd7126e6b46
Check%20your%20inbox/singular: e9a430fcd298def74212238df0f680d6 Check%20your%20inbox/singular: e9a430fcd298def74212238df0f680d6
Checklist%20name/singular: 5eb5de823f7ca5a4d97bb41e6a3f675a Checklist%20name/singular: 5eb5de823f7ca5a4d97bb41e6a3f675a
Clear%20filters/singular: 8f40ab5af527e4b190da94e7b6221379 Clear%20filters/singular: 8f40ab5af527e4b190da94e7b6221379
Click%20on%20the%20link%20we've%20sent%20to%20%7BmagicLinkRecipient%7D%20to%20sign%20in./singular: 210b6ff8727f976182ec3f29ea3c7667 Click%20on%20the%20link%20we've%20sent%20to%20%7BmagicLinkRecipient%7D%20to%20sign%20in./singular: 210b6ff8727f976182ec3f29ea3c7667
Close/singular: 2c2e22f8424a1031de89063bd0022e16
Code%20Review/singular: a2da6c2339301e7c3ddf068c4ff9f7e8 Code%20Review/singular: a2da6c2339301e7c3ddf068c4ff9f7e8
Collaborate%20seamlessly%20with%20your%20team./singular: c5f10e431aaf8b51519bc009a4a4080c Collaborate%20seamlessly%20with%20your%20team./singular: c5f10e431aaf8b51519bc009a4a4080c
Coming%20soon/singular: ee2b0671e00972773210c5be5a9ccb89 Coming%20soon/singular: ee2b0671e00972773210c5be5a9ccb89
@@ -99,6 +108,7 @@ checksums:
Continue%20with%20%7B0%7D/singular: 2eaf6e1da91e208f7c5fb6bf862fe8a6 Continue%20with%20%7B0%7D/singular: 2eaf6e1da91e208f7c5fb6bf862fe8a6
Control%20who%20can%20view%20and%20edit%20your%20boards./singular: 2a7e0bec29bac26280de707e2fe8bce5 Control%20who%20can%20view%20and%20edit%20your%20boards./singular: 2a7e0bec29bac26280de707e2fe8bce5
Create%20another/singular: 2de8a82a416eb78c0462aa36278edc9a Create%20another/singular: 2de8a82a416eb78c0462aa36278edc9a
Create%20API%20key/singular: 70ed8431c6ed5f7fdef122cc34f75b41
Create%20board/singular: 155b62818bfab0e34f0089e1b34a32f3 Create%20board/singular: 155b62818bfab0e34f0089e1b34a32f3
Create%20card/singular: 32792935dd5837a9433909b04021c22b Create%20card/singular: 32792935dd5837a9433909b04021c22b
Create%20checklist/singular: 5cbca15a7004558c4e6d381f83a34da2 Create%20checklist/singular: 5cbca15a7004558c4e6d381f83a34da2
@@ -111,6 +121,7 @@ checksums:
Create%20workspace/singular: 2e6718e79964ea5ce22d76c2189c77ca Create%20workspace/singular: 2e6718e79964ea5ce22d76c2189c77ca
created%20the%20card/singular: 605475f5aaeb4dbccbf7c4eb9107b43d created%20the%20card/singular: 605475f5aaeb4dbccbf7c4eb9107b43d
Critical/singular: eb327cd411b50aee954f8d1d215d003a Critical/singular: eb327cd411b50aee954f8d1d215d003a
Crop%20your%20avatar/singular: eb25e2d5972ec36a0b40481c8136ab15
Current%20password%20is%20required/singular: 72536bca9598680027f2be8ce80ac280 Current%20password%20is%20required/singular: 72536bca9598680027f2be8ce80ac280
Custom%20domain/singular: b09e7a9c187b7163b4a6cfc78042fe42 Custom%20domain/singular: b09e7a9c187b7163b4a6cfc78042fe42
Custom%20URLs%20require%20upgrading%20to%20a%20Pro%20plan/singular: f7275e3b473b8f7b39dab6b37eb26fea Custom%20URLs%20require%20upgrading%20to%20a%20Pro%20plan/singular: f7275e3b473b8f7b39dab6b37eb26fea
@@ -155,7 +166,10 @@ checksums:
Enter%20your%20name/singular: cd95fbdd0533f2c2e8edf9d9bd9aa8df Enter%20your%20name/singular: cd95fbdd0533f2c2e8edf9d9bd9aa8df
Enter%20your%20new%20password/singular: c67251e3002b68bc20a7cf5de23e43ac Enter%20your%20new%20password/singular: c67251e3002b68bc20a7cf5de23e43ac
Enter%20your%20password/singular: ea4fdd034522dead21bae0c0abb52eae Enter%20your%20password/singular: ea4fdd034522dead21bae0c0abb52eae
Error/singular: 3c95bcb32c2104b99a46f5b3dd015248
Error%20Changing%20Password/singular: ebecb5c1b72ba4b063117241f5ba4f2d Error%20Changing%20Password/singular: ebecb5c1b72ba4b063117241f5ba4f2d
Error%20creating%20invite%20link/singular: cbedc3f3213dfc4fdc8b7503ae1a5cd6
Error%20deactivating%20invite%20link/singular: ccf42cd5aa8481692003e87e836de66c
Error%20deleting%20account/singular: d42965a9bc9e5ec4ed57890268924643 Error%20deleting%20account/singular: d42965a9bc9e5ec4ed57890268924643
Error%20deleting%20label/singular: 94387e3a45ec768ae7715701ae00136e Error%20deleting%20label/singular: 94387e3a45ec768ae7715701ae00136e
Error%20deleting%20workspace/singular: 0aec9bd8170bc84f5ea5c9a47c52ed26 Error%20deleting%20workspace/singular: 0aec9bd8170bc84f5ea5c9a47c52ed26
@@ -172,6 +186,8 @@ checksums:
Everything%20in%20the%20free%20plan%2C%20plus%3A/singular: 62b44c4973b92b806c69a4b15e0256dc Everything%20in%20the%20free%20plan%2C%20plus%3A/singular: 62b44c4973b92b806c69a4b15e0256dc
Everything%20you%20need%2C%20free%20forever.%20Unlimited%20boards%2C%20unlimited%20lists%2C%20unlimited%20cards.%20Upgrade%20any%20time./singular: fa21632ab1468edf10acda2fe7b71323 Everything%20you%20need%2C%20free%20forever.%20Unlimited%20boards%2C%20unlimited%20lists%2C%20unlimited%20cards.%20Upgrade%20any%20time./singular: fa21632ab1468edf10acda2fe7b71323
Execution/singular: cbac4a3c721123cbc6a883560bf29800 Execution/singular: cbac4a3c721123cbc6a883560bf29800
Failed%20to%20accept%20invitation.%20Please%20try%20again%20later%2C%20or%20contact%20customer%20support./singular: e4505a9df3a81e93a8a8b103c6e3ebc4
Failed%20to%20copy%20invite%20link/singular: 635884d5ed8d6ee20b85a003939b4ae7
Failed%20to%20login%20with%20%7B0%7D.%20Please%20try%20again./singular: 669a4b4247a73f53fb9b8b16e42d166f Failed%20to%20login%20with%20%7B0%7D.%20Please%20try%20again./singular: 669a4b4247a73f53fb9b8b16e42d166f
FAQs/singular: dc36d7992372ccd419b39ef51cf5b16c FAQs/singular: dc36d7992372ccd419b39ef51cf5b16c
Feature/singular: 58f5f3f37862b6312a2f20ec1a1fd0e8 Feature/singular: 58f5f3f37862b6312a2f20ec1a1fd0e8
@@ -196,6 +212,7 @@ checksums:
Get%20started%20on%20Cloud/singular: ed926f526266ad2063283c58e6f4284a Get%20started%20on%20Cloud/singular: ed926f526266ad2063283c58e6f4284a
Getting%20started/singular: 8e5e7bd026b5bec46bbfdce02ab9e0b8 Getting%20started/singular: 8e5e7bd026b5bec46bbfdce02ab9e0b8
GitHub/singular: 6e1cf3c00fa6fbe24afcc78ea3b5f3e4 GitHub/singular: 6e1cf3c00fa6fbe24afcc78ea3b5f3e4
Go%20Home/singular: 6251589da1964d55afabdfd64c84c335
Go%20to%20app/singular: 896d0441384dcd2bfb3b23d61ff1944d Go%20to%20app/singular: 896d0441384dcd2bfb3b23d61ff1944d
High%20Priority/singular: 5d231ff8254aabc875f194c4b4f49c97 High%20Priority/singular: 5d231ff8254aabc875f194c4b4f49c97
Hired/singular: e5a9b1bd409b007141fe3d7890022f9a Hired/singular: e5a9b1bd409b007141fe3d7890022f9a
@@ -221,10 +238,14 @@ checksums:
Integrations/singular: 0ccce343287704cd90150c32e2fcad36 Integrations/singular: 0ccce343287704cd90150c32e2fcad36
Interviewing/singular: 4ccdcdc784547e925077c3297bddee95 Interviewing/singular: 4ccdcdc784547e925077c3297bddee95
Invalid%20email%20address/singular: b2d9f25626f2d15c7c63e0281bccc247 Invalid%20email%20address/singular: b2d9f25626f2d15c7c63e0281bccc247
Invalid%20invitation/singular: 4b936a8811a2295a5f58b41473c608f3
Invite/singular: 181884cea804cbde665f160811ee7ad0 Invite/singular: 181884cea804cbde665f160811ee7ad0
Invite%20another/singular: acb543563dab7edbcf46060a53ade3a3 Invite%20link%20copied/singular: 4046f23a78e1cd5166671c3fb8a7ea6e
Invite%20link%20copied%20to%20clipboard/singular: 6fc055a0ea0ed1aa58c5e0c502efe17f
Invite%20member/singular: ade922db1be6b26bc979565ce5de2bc7 Invite%20member/singular: ade922db1be6b26bc979565ce5de2bc7
Inviting%20members%20requires%20a%20Team%20Plan.%20You'll%20be%20redirected%20to%20upgrade%20your%20workspace./singular: 03eeed2d715e770259f722ba48a61ab3 Inviting%20members%20requires%20a%20Team%20Plan.%20You'll%20be%20redirected%20to%20upgrade%20your%20workspace./singular: 03eeed2d715e770259f722ba48a61ab3
Join%20workspace/singular: f5d035df672b05abd760bd022309c719
Join%20workspace%20%7C%20kan.bn/singular: 97855216a0e00214b2dcf917e93164f2
Junior/singular: ed1bd2c59a824fdcdd56fc8a0660fe9f Junior/singular: ed1bd2c59a824fdcdd56fc8a0660fe9f
Kanban%20is%20better%20with%20a%20team.%20Perfect%20for%20small%20and%20growing%20teams%20looking%20to%20collaborate./singular: a77bee43046b260797c8936ad23e9223 Kanban%20is%20better%20with%20a%20team.%20Perfect%20for%20small%20and%20growing%20teams%20looking%20to%20collaborate./singular: a77bee43046b260797c8936ad23e9223
Kanban%20reimagined/singular: 613ccfdd9f54c66cbf68cfa313498766 Kanban%20reimagined/singular: 613ccfdd9f54c66cbf68cfa313498766
@@ -259,6 +280,7 @@ checksums:
Name/singular: 9368b5a047572b6051f334af5aa76819 Name/singular: 9368b5a047572b6051f334af5aa76819
Need%20help%3F/singular: 04e7322f2d3ffb2d73ff2f64b71637c8 Need%20help%3F/singular: 04e7322f2d3ffb2d73ff2f64b71637c8
New/singular: 126d036fae5fb6b629728ecb97e6195b New/singular: 126d036fae5fb6b629728ecb97e6195b
New%20API%20key/singular: db3088aedba6e4a99b46451c5b3d36ed
New%20board/singular: 63f4e979e29a7fc2f5c09ff91fa75966 New%20board/singular: 63f4e979e29a7fc2f5c09ff91fa75966
New%20card/singular: a33f6219a756127f91c2523cfe845a19 New%20card/singular: a33f6219a756127f91c2523cfe845a19
New%20checklist/singular: 58252b71e9693ae0f4d2d0b72108a569 New%20checklist/singular: 58252b71e9693ae0f4d2d0b72108a569
@@ -286,6 +308,7 @@ checksums:
Password%20Changed/singular: 1fcebe9ddb46f722a57f195efddc695d Password%20Changed/singular: 1fcebe9ddb46f722a57f195efddc695d
Password%20must%20be%20at%20least%208%20characters/singular: 4c30501d085eaccea47af34212bb26a7 Password%20must%20be%20at%20least%208%20characters/singular: 4c30501d085eaccea47af34212bb26a7
Passwords%20do%20not%20match/singular: 37ca1f4e0afc9a0b8e9617f767103c92 Passwords%20do%20not%20match/singular: 37ca1f4e0afc9a0b8e9617f767103c92
Paused/singular: edb1f7b7219e1c9b7aa67159090d6991
Payment%20frequency/singular: 63ded0e4ffb462ca8bd33d38e4691d86 Payment%20frequency/singular: 63ded0e4ffb462ca8bd33d38e4691d86
Pending/singular: 030a6f3395d5d4efddd3cc67d6009039 Pending/singular: 030a6f3395d5d4efddd3cc67d6009039
per%20user%2Fmonth/singular: 72af182c1ba6df6732640f4d8a78d360 per%20user%2Fmonth/singular: 72af182c1ba6df6732640f4d8a78d360
@@ -297,6 +320,7 @@ checksums:
Please%20enter%20a%20valid%20password/singular: 4b32c17e19b79bcbf0bb092c06ba310f Please%20enter%20a%20valid%20password/singular: 4b32c17e19b79bcbf0bb092c06ba310f
Please%20select%20a%20file%20to%20upload./singular: de315bf594047f8ef9307a7fa9285844 Please%20select%20a%20file%20to%20upload./singular: de315bf594047f8ef9307a7fa9285844
Please%20try%20again%20later%2C%20or%20contact%20customer%20support./singular: 21ffcf0b00e7cd7b64f7454a95762e1d Please%20try%20again%20later%2C%20or%20contact%20customer%20support./singular: 21ffcf0b00e7cd7b64f7454a95762e1d
Please%20try%20again%20later./singular: 325dea6dd0348a27a6818db2c1340c98
Pricing/singular: ce27f1aeacccc542a174c4b2bce022b0 Pricing/singular: ce27f1aeacccc542a174c4b2bce022b0
Priority%20email%20support/singular: 678538c912a770b1e1416ecdb8e299b1 Priority%20email%20support/singular: 678538c912a770b1e1416ecdb8e299b1
Privacy%20policy/singular: 462c6a536b52873e4498785c66dd48c8 Privacy%20policy/singular: 462c6a536b52873e4498785c66dd48c8
@@ -324,7 +348,6 @@ checksums:
Resolution/singular: 6d8bd9e1bd7dae5ae38c93061d32990e Resolution/singular: 6d8bd9e1bd7dae5ae38c93061d32990e
Resources/singular: ec7fb05ed963bb6781a35782b3475502 Resources/singular: ec7fb05ed963bb6781a35782b3475502
Review/singular: 299f75db25382980b2895622d7712927 Review/singular: 299f75db25382980b2895622d7712927
Revoke/singular: be57685a85b6dfeaeb6eab4e9560b520
Roadmap/singular: c60f4a1acf30e566861bf130f13b9ae7 Roadmap/singular: c60f4a1acf30e566861bf130f13b9ae7
Role/singular: 53743bbb6ca938f5b893552e839d067f Role/singular: 53743bbb6ca938f5b893552e839d067f
Run%20on%20your%20own%20infrastructure/singular: eba804911562b8dbf9d69c3e27f1d708 Run%20on%20your%20own%20infrastructure/singular: eba804911562b8dbf9d69c3e27f1d708
@@ -339,8 +362,15 @@ checksums:
Send%20feedback/singular: 9631cc08d49da04475b30a0d320ce97c Send%20feedback/singular: 9631cc08d49da04475b30a0d320ce97c
Senior/singular: 3fff865dc00435f82896fc302ea45630 Senior/singular: 3fff865dc00435f82896fc302ea45630
Settings/singular: 8df6777277469c1fd88cc18dde2f1cc3 Settings/singular: 8df6777277469c1fd88cc18dde2f1cc3
Settings%20%7C%20%7B0%7D/singular: b8fc73080bc9c8f4f1403b2a69bd1ac5 Settings%20%7C%20Account/singular: 050e18406849ec057edac877c297c3e1
Settings%20%7C%20API/singular: 85101e4b802a09ad9e3f01ff116f0894
Settings%20%7C%20Billing/singular: e44cba741d5414035a0b499c5766c203
Settings%20%7C%20Integrations/singular: d04992e28016452f6d3d7dcc0b592415
Settings%20%7C%20Workspace/singular: 5d0bacf7ff696da940f232df45edfd39
Share%20invite%20link/singular: ec5081a1f4e49fd9d782e770438f703b
Sign%20in/singular: cb8757c7450e17de1e226e82fb0fa4a2 Sign%20in/singular: cb8757c7450e17de1e226e82fb0fa4a2
Sign%20In/singular: ec7b8f314fe9bc6591006707484ede61
Sign%20Up/singular: 0dd2ae69be4618c1f9e615774a4509ca
Sign%20up%20%7C%20kan.bn/singular: f3de2a110c90358e6eac07d0b2f663a6 Sign%20up%20%7C%20kan.bn/singular: f3de2a110c90358e6eac07d0b2f663a6
Sign%20up%20disabled/singular: 9581b1f75b404ac0ecb7e603e0d4189c Sign%20up%20disabled/singular: 9581b1f75b404ac0ecb7e603e0d4189c
Sign%20up%20is%20currently%20disabled.%20Please%20try%20again%20later./singular: c6cb7c455ec053b351a27029158ff166 Sign%20up%20is%20currently%20disabled.%20Please%20try%20again%20later./singular: c6cb7c455ec053b351a27029158ff166
@@ -367,8 +397,10 @@ checksums:
Theme/singular: 21fe00b7a518089576fb83c08631107a Theme/singular: 21fe00b7a518089576fb83c08631107a
They%20won't%20be%20able%20to%20access%20this%20workspace./singular: 93b740350fe3430319fbca85349e41d9 They%20won't%20be%20able%20to%20access%20this%20workspace./singular: 93b740350fe3430319fbca85349e41d9
This%20action%20can't%20be%20undone./singular: cb222ff89715d8c971e8c25d121e1dbd This%20action%20can't%20be%20undone./singular: cb222ff89715d8c971e8c25d121e1dbd
This%20API%20key%20will%20only%20be%20shown%20once.%20Please%20save%20it%20in%20a%20secure%20location./singular: 7df18d2978d317375f780822f8321c4d
This%20board%20is%20private%20or%20does%20not%20exist/singular: a217ff3f04463b4df8c86adb6f83c6bc This%20board%20is%20private%20or%20does%20not%20exist/singular: a217ff3f04463b4df8c86adb6f83c6bc
This%20board%20URL%20has%20already%20been%20taken/singular: 1d8b40332a031b5b77a3658e48dd51ca This%20board%20URL%20has%20already%20been%20taken/singular: 1d8b40332a031b5b77a3658e48dd51ca
This%20invitation%20link%20is%20invalid%20or%20has%20expired./singular: 11cc7ef8f1512e7e058e1fbbe5644001
This%20will%20result%20in%20the%20permanent%20deletion%20of%20all%20data%20associated%20with%20this%20workspace./singular: a31141558af793635c1ddd2fa0a33499 This%20will%20result%20in%20the%20permanent%20deletion%20of%20all%20data%20associated%20with%20this%20workspace./singular: a31141558af793635c1ddd2fa0a33499
This%20will%20result%20in%20the%20permanent%20deletion%20of%20all%20data%20associated%20with%20your%20account./singular: b49224632bd6c3b7f5e462912aeb1081 This%20will%20result%20in%20the%20permanent%20deletion%20of%20all%20data%20associated%20with%20your%20account./singular: b49224632bd6c3b7f5e462912aeb1081
This%20workspace%20URL%20has%20already%20been%20taken/singular: b455329e2a71da677acab91d3a00bad6 This%20workspace%20URL%20has%20already%20been%20taken/singular: b455329e2a71da677acab91d3a00bad6
@@ -377,6 +409,7 @@ checksums:
To%20Do/singular: d60813ea824f373462471e092d136eed To%20Do/singular: d60813ea824f373462471e092d136eed
Toggle%20menu/singular: 29dea3e0b6238874f8c7a27619df8e36 Toggle%20menu/singular: 29dea3e0b6238874f8c7a27619df8e36
Track%20all%20card%20changes%20with%20detailed%20activity%20history./singular: 0d3bac559c71ec4b8734f9f212320de5 Track%20all%20card%20changes%20with%20detailed%20activity%20history./singular: 0d3bac559c71ec4b8734f9f212320de5
Trello/singular: b5131f6488b5a439d58db3e22d6de45b
Trello%20disconnected/singular: 54b24a3e6c9a7eedd8c8d1060ab1175d Trello%20disconnected/singular: 54b24a3e6c9a7eedd8c8d1060ab1175d
Trello%20imports/singular: 6827eca403faa8f89891d17827e72af9 Trello%20imports/singular: 6827eca403faa8f89891d17827e72af9
Triaging/singular: 1d40799fcae53a8a27688fdae2a48dee Triaging/singular: 1d40799fcae53a8a27688fdae2a48dee
@@ -468,6 +501,8 @@ checksums:
You%20have%20been%20logged%20in%20successfully./singular: ef8fad1dce13ae4112f17c5258655fea You%20have%20been%20logged%20in%20successfully./singular: ef8fad1dce13ae4112f17c5258655fea
You%20have%20been%20signed%20up%20successfully./singular: f614a6e3b45f5ffb9a3b0fb420fef84b You%20have%20been%20signed%20up%20successfully./singular: f614a6e3b45f5ffb9a3b0fb420fef84b
You%20have%20unlimited%20seats%20with%20your%20Pro%20Plan.%20There%20is%20no%20additional%20charge%20for%20new%20members!/singular: e3dc59a5ba7211cd3d8516b3a79d85ca 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%20account%20has%20been%20deleted./singular: 8c8d944e07388c5877effdb2c2803dcf
Your%20boards%20have%20been%20imported./singular: 403972e7a25afc2415762c1c2b1ec868 Your%20boards%20have%20been%20imported./singular: 403972e7a25afc2415762c1c2b1ec868
Your%20display%20name%20has%20been%20updated./singular: 15e5fff36c554c16ec5214427fae1bf4 Your%20display%20name%20has%20been%20updated./singular: 15e5fff36c554c16ec5214427fae1bf4

View File

@@ -1,7 +1,7 @@
import type { LinguiConfig } from "@lingui/conf"; import type { LinguiConfig } from "@lingui/conf";
const config: LinguiConfig = { const config: LinguiConfig = {
locales: ["en", "fr", "de", "es", "it", "nl"], locales: ["en", "fr", "de", "es", "it", "nl", "ru"],
sourceLocale: "en", sourceLocale: "en",
catalogs: [ catalogs: [
{ {

View File

@@ -52,6 +52,15 @@ const config = {
// instrumentationHook: true, // instrumentationHook: true,
swcPlugins: [["@lingui/swc-plugin", {}]], swcPlugins: [["@lingui/swc-plugin", {}]],
}, },
async rewrites() {
return [
{
source: "/settings",
destination: "/settings/account",
},
];
},
}; };
// Only allow external images when OIDC is configured (for OIDC provider avatars) // Only allow external images when OIDC is configured (for OIDC provider avatars)

View File

@@ -59,6 +59,7 @@
"react-dom": "catalog:react18", "react-dom": "catalog:react18",
"react-hook-form": "^7.51.1", "react-hook-form": "^7.51.1",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-image-crop": "^11.0.10",
"react-lottie-player": "^1.5.5", "react-lottie-player": "^1.5.5",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"superjson": "2.2.1", "superjson": "2.2.1",

View File

@@ -1,4 +1,5 @@
import type { SocialProvider } from "better-auth/social-providers"; import type { SocialProvider } from "better-auth/social-providers";
import { useSearchParams } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro"; import { Trans } from "@lingui/react/macro";
@@ -160,6 +161,9 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
const { showPopup } = usePopup(); const { showPopup } = usePopup();
const oidcProviderName = "OIDC"; const oidcProviderName = "OIDC";
const redirect = useSearchParams().get("next");
const callbackURL = redirect ?? "/boards";
// Safely get environment variables on client side to avoid hydration mismatch // Safely get environment variables on client side to avoid hydration mismatch
useEffect(() => { useEffect(() => {
const credentialsAllowed = const credentialsAllowed =
@@ -195,7 +199,7 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
name, name,
email, email,
password, password,
callbackURL: "/boards", callbackURL,
}, },
{ {
onSuccess: () => onSuccess: () =>
@@ -212,7 +216,7 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
{ {
email, email,
password, password,
callbackURL: "/boards", callbackURL,
}, },
{ {
onSuccess: () => onSuccess: () =>
@@ -229,7 +233,7 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
await authClient.signIn.magicLink( await authClient.signIn.magicLink(
{ {
email, email,
callbackURL: "/boards", callbackURL,
}, },
{ {
onSuccess: () => setIsMagicLinkSent(true, email), onSuccess: () => setIsMagicLinkSent(true, email),
@@ -250,14 +254,14 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
// Use oauth2 signin for OIDC provider // Use oauth2 signin for OIDC provider
const result = await authClient.signIn.oauth2({ const result = await authClient.signIn.oauth2({
providerId: "oidc", providerId: "oidc",
callbackURL: "/boards", callbackURL,
}); });
error = result.error; error = result.error;
} else { } else {
// Use social signin for traditional social providers // Use social signin for traditional social providers
const result = await authClient.signIn.social({ const result = await authClient.signIn.social({
provider, provider,
callbackURL: "/boards", callbackURL,
}); });
error = result.error; error = result.error;
} }

View File

@@ -15,7 +15,7 @@ export default function Dropdown({
<div> <div>
<Menu.Button <Menu.Button
disabled={disabled} disabled={disabled}
className="flex h-7 w-7 items-center justify-center rounded-[5px] hover:bg-light-200 dark:hover:bg-dark-200" className="flex h-7 w-7 items-center justify-center rounded-[5px] hover:bg-light-200 focus:outline-none dark:hover:bg-dark-200"
> >
{children} {children}
</Menu.Button> </Menu.Button>
@@ -30,7 +30,7 @@ export default function Dropdown({
leaveFrom="transform opacity-100 scale-100" leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95" leaveTo="transform opacity-0 scale-95"
> >
<Menu.Items className="absolute right-0 z-30 mt-2 w-56 origin-top-right rounded-md border border-light-200 bg-light-50 p-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-400 dark:bg-dark-300"> <Menu.Items className="absolute right-0 z-50 mt-2 w-56 origin-top-right rounded-md border border-light-200 bg-light-50 p-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-400 dark:bg-dark-300">
<div className="flex flex-col"> <div className="flex flex-col">
{items.map((item) => ( {items.map((item) => (
<Menu.Item key={item.label}> <Menu.Item key={item.label}>

View File

@@ -13,7 +13,7 @@ export function LanguageSelector() {
id="language-select" id="language-select"
value={locale} value={locale}
onChange={(e) => setLocale(e.target.value as any)} onChange={(e) => setLocale(e.target.value as any)}
className="mt-8 block w-full max-w-[180px] rounded-lg border-0 bg-light-50 pl-10 shadow-sm ring-1 ring-inset ring-light-300 focus:ring-2 focus:ring-inset focus:ring-light-400 dark:bg-dark-50 dark:text-dark-1000 dark:ring-dark-300 dark:focus:ring-dark-500 sm:text-sm" className="mt-8 block w-full max-w-[180px] rounded-lg border-0 bg-light-50 pl-10 text-sm shadow-sm ring-1 ring-inset ring-light-300 focus:ring-2 focus:ring-inset focus:ring-light-400 dark:bg-dark-50 dark:text-dark-1000 dark:ring-dark-300 dark:focus:ring-dark-500"
> >
{availableLocales.map((loc) => ( {availableLocales.map((loc) => (
<option key={loc} value={loc}> <option key={loc} value={loc}>

View File

@@ -123,7 +123,7 @@ export function NewWorkspaceForm() {
body: JSON.stringify({ body: JSON.stringify({
slug: slug || undefined, slug: slug || undefined,
workspacePublicId: values.publicId, workspacePublicId: values.publicId,
cancelUrl: "/settings?upgrade=pro", cancelUrl: "/settings/workspace?upgrade=pro",
successUrl: "/boards", successUrl: "/boards",
}), }),
}, },

View File

@@ -0,0 +1,148 @@
import Link from "next/link";
import { useRouter } from "next/router";
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions,
} from "@headlessui/react";
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import { useEffect, useState } from "react";
import {
HiChevronDown,
HiOutlineBanknotes,
HiOutlineCodeBracketSquare,
HiOutlineRectangleGroup,
HiOutlineUser,
} from "react-icons/hi2";
interface SettingsLayoutProps {
children: React.ReactNode;
currentTab: string;
}
export function SettingsLayout({ children, currentTab }: SettingsLayoutProps) {
const router = useRouter();
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const settingsTabs = [
{
key: "account",
icon: <HiOutlineUser />,
label: t`Account`,
condition: true,
},
{
key: "workspace",
icon: <HiOutlineRectangleGroup />,
label: t`Workspace`,
condition: true,
},
{
key: "billing",
label: t`Billing`,
icon: <HiOutlineBanknotes />,
condition: env("NEXT_PUBLIC_KAN_ENV") === "cloud",
},
{
key: "api",
icon: <HiOutlineCodeBracketSquare />,
label: t`API`,
condition: true,
},
{
key: "integrations",
icon: <HiOutlineCodeBracketSquare />,
label: t`Integrations`,
condition: true,
},
];
const availableTabs = settingsTabs.filter((tab) => tab.condition);
// Update selected tab when currentTab prop changes
useEffect(() => {
const tabIndex = availableTabs.findIndex((tab) => tab.key === currentTab);
if (tabIndex !== -1) {
setSelectedTabIndex(tabIndex);
}
}, [currentTab, availableTabs]);
const isTabActive = (tabKey: string) => {
return currentTab === tabKey;
};
return (
<div className="flex h-full w-full flex-col overflow-hidden">
<div className="h-full max-h-[calc(100vdh-3rem)] overflow-y-auto md:max-h-[calc(100vdh-4rem)]">
<div className="m-auto max-w-[1100px] px-5 py-6 md:px-28 md:py-12">
<div className="mb-8 flex w-full justify-between">
<h1 className="font-bold tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
{t`Settings`}
</h1>
</div>
<div className="focus:outline-none">
<div className="sm:hidden">
{/* Mobile dropdown */}
<Listbox
value={selectedTabIndex}
onChange={(index) => {
const tabKey = availableTabs[index]?.key;
if (tabKey) {
void router.push(`/settings/${tabKey}`);
}
}}
>
<div className="relative mb-4">
<ListboxButton className="w-full appearance-none rounded-lg border-0 bg-light-50 py-2 pl-3 pr-10 text-left text-sm text-light-1000 shadow-sm ring-1 ring-inset ring-light-300 focus:ring-2 focus:ring-inset focus:ring-light-400 dark:bg-dark-50 dark:text-dark-1000 dark:ring-dark-300 dark:focus:ring-dark-500">
{availableTabs[selectedTabIndex]?.label || "Select a tab"}
<HiChevronDown
aria-hidden="true"
className="pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-light-900 dark:text-dark-900"
/>
</ListboxButton>
<ListboxOptions className="absolute z-10 mt-1 w-full rounded-lg bg-light-50 py-1 text-sm shadow-lg ring-1 ring-inset ring-light-300 dark:bg-dark-50 dark:ring-dark-300">
{availableTabs.map((tab) => (
<ListboxOption
key={tab.key}
value={availableTabs.indexOf(tab)}
className="relative cursor-pointer select-none py-2 pl-3 pr-9 text-light-1000 dark:text-dark-1000"
>
{tab.label}
</ListboxOption>
))}
</ListboxOptions>
</div>
</Listbox>
</div>
<div className="hidden sm:block">
<div className="border-b border-gray-200 dark:border-white/10">
<nav
aria-label="Tabs"
className="-mb-px flex space-x-8 focus:outline-none"
>
{availableTabs.map((tab) => (
<Link
key={tab.key}
href={`/settings/${tab.key}`}
className={`whitespace-nowrap border-b-2 px-1 py-4 text-sm font-medium transition-colors focus:outline-none ${
isTabActive(tab.key)
? "border-light-1000 text-light-1000 dark:border-dark-1000 dark:text-dark-1000"
: "border-transparent text-light-900 hover:border-light-950 hover:text-light-950 dark:text-dark-900 dark:hover:border-white/20 dark:hover:text-dark-950"
}`}
>
{tab.label}
</Link>
))}
</nav>
</div>
</div>
<div className="focus:outline-none">{children}</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -44,7 +44,7 @@ export default function WorkspaceMenu({
</span> </span>
<span <span
className={twMerge( className={twMerge(
"ml-2 text-sm font-bold text-neutral-900 dark:text-dark-1000", "ml-2 truncate text-sm font-bold text-neutral-900 dark:text-dark-1000",
isCollapsed && "md:hidden", isCollapsed && "md:hidden",
)} )}
> >
@@ -87,17 +87,17 @@ export default function WorkspaceMenu({
onClick={() => switchWorkspace(availableWorkspace)} onClick={() => switchWorkspace(availableWorkspace)}
className="flex w-full items-center justify-between rounded-[5px] px-3 py-2 text-left text-sm text-neutral-900 hover:bg-light-200 dark:text-dark-1000 dark:hover:bg-dark-400" className="flex w-full items-center justify-between rounded-[5px] px-3 py-2 text-left text-sm text-neutral-900 hover:bg-light-200 dark:text-dark-1000 dark:hover:bg-dark-400"
> >
<div> <div className="flex min-w-0 flex-1 items-center">
<span className="inline-flex h-5 w-5 items-center justify-center rounded-[5px] bg-indigo-700"> <span className="inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-[5px] bg-indigo-700">
<span className="text-xs font-medium leading-none text-white"> <span className="text-xs font-medium leading-none text-white">
{availableWorkspace.name.charAt(0).toUpperCase()} {availableWorkspace.name.charAt(0).toUpperCase()}
</span> </span>
</span> </span>
<span className="ml-2 text-xs font-medium"> <span className="ml-2 truncate text-xs font-medium">
{availableWorkspace.name} {availableWorkspace.name}
</span> </span>
</div> </div>
{workspace.name === availableWorkspace.name && ( {workspace.publicId === availableWorkspace.publicId && (
<span> <span>
<HiCheck className="h-4 w-4" aria-hidden="true" /> <HiCheck className="h-4 w-4" aria-hidden="true" />
</span> </span>

View File

@@ -34,7 +34,7 @@ const Modal: React.FC<Props> = ({
return ( return (
<Transition.Root show={shouldShow} as={Fragment}> <Transition.Root show={shouldShow} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}> <Dialog as="div" className="relative z-50" onClose={closeModal}>
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter="ease-out duration-300" enter="ease-out duration-300"
@@ -47,7 +47,7 @@ const Modal: React.FC<Props> = ({
<div className="fixed inset-0 bg-light-50 bg-opacity-40 transition-opacity dark:bg-dark-50 dark:bg-opacity-40" /> <div className="fixed inset-0 bg-light-50 bg-opacity-40 transition-opacity dark:bg-dark-50 dark:bg-opacity-40" />
</Transition.Child> </Transition.Child>
<div className="fixed inset-0 z-10 w-screen overflow-y-auto"> <div className="fixed inset-0 z-50 w-screen overflow-y-auto">
<div className="flex min-h-full items-start justify-center p-4 text-center sm:items-start sm:p-0"> <div className="flex min-h-full items-start justify-center p-4 text-center sm:items-start sm:p-0">
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}

View File

@@ -0,0 +1,36 @@
import { useState } from "react";
export function useClipboard({ timeout = 500 } = {}) {
const [error, setError] = useState<string | Error | null | undefined>(null);
const [copied, setCopied] = useState<boolean>(false);
const [copyTimeout, setCopyTimeout] = useState<number | undefined>(undefined);
const handleCopyResult = (hasError: boolean) => {
clearTimeout(copyTimeout);
setCopyTimeout(
setTimeout(() => setCopied(false), timeout) as unknown as number,
);
setCopied(hasError);
};
const copy = (value: string) => {
if ("clipboard" in navigator) {
navigator.clipboard
.writeText(value)
.then(() => handleCopyResult(true))
.catch((err) => setError(err));
} else {
setError(new Error("Error: navigator.clipboard is not supported"));
}
};
const reset = () => {
setError(null);
setCopied(false);
clearTimeout(copyTimeout);
};
return { copy, reset, error, copied };
}

View File

@@ -36,12 +36,12 @@ msgstr "{0} Labels"
msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}" msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
msgstr "{boardCount, plural, one {Board importieren (1)} other {Boards importieren ({boardCount})}}" msgstr "{boardCount, plural, one {Board importieren (1)} other {Boards importieren ({boardCount})}}"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "$10/Monat" msgstr "$10/Monat"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "$8/Monat" msgstr "$8/Monat"
@@ -53,6 +53,10 @@ msgstr "1 Benutzer"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "Eine leistungsstarke, flexible Kanban-App, die dir hilft, Arbeit zu organisieren, Fortschritte zu verfolgen und Ergebnisse zu liefern alles an einem Ort." msgstr "Eine leistungsstarke, flexible Kanban-App, die dir hilft, Arbeit zu organisieren, Fortschritte zu verfolgen und Ergebnisse zu liefern alles an einem Ort."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Konto"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Konto gelöscht" msgstr "Konto gelöscht"
@@ -91,13 +95,13 @@ msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen oder '@' um
msgid "Add details..." msgid "Add details..."
msgstr "Details hinzufügen..." msgstr "Details hinzufügen..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Label hinzufügen" msgstr "Label hinzufügen"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Mitglied hinzufügen" msgstr "Mitglied hinzufügen"
@@ -132,10 +136,14 @@ msgstr "hat Checklistenelement <0>{0}</0> hinzugefügt"
msgid "added label <0>{0}</0>" msgid "added label <0>{0}</0>"
msgstr "hat Label <0>{0}</0> hinzugefügt" msgstr "hat Label <0>{0}</0> hinzugefügt"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Das Hinzufügen eines neuen Mitglieds kostet zusätzlich {price} ({billingType}) pro Platz." msgstr "Das Hinzufügen eines neuen Mitglieds kostet zusätzlich {price} ({billingType}) pro Platz."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Passe den quadratischen Zuschnitt an deinen Avatar an."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Administratorrollen" msgstr "Administratorrollen"
@@ -144,11 +152,11 @@ msgstr "Administratorrollen"
msgid "All systems operational" msgid "All systems operational"
msgstr "Alle Systeme funktionieren" msgstr "Alle Systeme funktionieren"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Du hast bereits ein Konto? <0><1>Anmelden</1></0>" msgstr "Du hast bereits ein Konto? <0><1>Anmelden</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "Beim Trennen deines Trello-Kontos ist ein Fehler aufgetreten." msgstr "Beim Trennen deines Trello-Kontos ist ein Fehler aufgetreten."
@@ -156,7 +164,31 @@ msgstr "Beim Trennen deines Trello-Kontos ist ein Fehler aufgetreten."
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut." msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Jeder mit diesem Link kann deinem Arbeitsbereich beitreten"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "API-Schlüssel erstellt"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "API-Schlüsselname"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "Der API-Schlüsselname darf 30 Zeichen nicht überschreiten"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "API-Schlüsselname ist erforderlich"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "API-Schlüssel" msgstr "API-Schlüssel"
@@ -218,20 +250,21 @@ msgstr "Backlog"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Einfaches Kanban" msgstr "Einfaches Kanban"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "jährlich abgerechnet" msgstr "jährlich abgerechnet"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "monatlich abgerechnet" msgstr "monatlich abgerechnet"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Abrechnung" msgstr "Abrechnung"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Abrechnungsportal" msgstr "Abrechnungsportal"
@@ -286,12 +319,12 @@ msgid "Board visibility updated"
msgstr "Board-Sichtbarkeit aktualisiert" msgstr "Board-Sichtbarkeit aktualisiert"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Boards" msgstr "Boards"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Boards | {0}" msgstr "Boards | {0}"
@@ -313,6 +346,7 @@ msgstr "Fehlerbericht"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -328,19 +362,19 @@ msgstr "Karte nicht gefunden"
msgid "Card title" msgid "Card title"
msgstr "Kartentitel" msgstr "Kartentitel"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Passwort ändern" msgstr "Passwort ändern"
#: src/views/settings/index.tsx:227 #: src/views/settings/AccountSettings.tsx:45
msgid "Change the language of the app." msgid "Change your language preferences."
msgstr "Ändere die Sprache der App." msgstr "Ändern Sie Ihre Spracheinstellungen."
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Überprüfe deinen Posteingang" msgstr "Überprüfe deinen Posteingang"
@@ -352,11 +386,15 @@ msgstr "Checklistenname"
msgid "Clear filters" msgid "Clear filters"
msgstr "Filter löschen" msgstr "Filter löschen"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Klicke auf den Link, den wir an {magicLinkRecipient} gesendet haben, um dich anzumelden." msgstr "Klicke auf den Link, den wir an {magicLinkRecipient} gesendet haben, um dich anzumelden."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Schließen"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Code-Review" msgstr "Code-Review"
@@ -401,7 +439,7 @@ msgid "Confirm your new password"
msgstr "Bestätigen Sie Ihr neues Passwort" msgstr "Bestätigen Sie Ihr neues Passwort"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Trello verbinden" msgstr "Trello verbinden"
@@ -409,7 +447,7 @@ msgstr "Trello verbinden"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Verbinde deine Lieblingstools, um deinen Arbeitsablauf zu optimieren." msgstr "Verbinde deine Lieblingstools, um deinen Arbeitsablauf zu optimieren."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Verbinde dein Trello-Konto, um Boards zu importieren." msgstr "Verbinde dein Trello-Konto, um Boards zu importieren."
@@ -425,12 +463,12 @@ msgstr "Kontaktiere uns"
msgid "Content Creation" msgid "Content Creation"
msgstr "Content-Erstellung" msgstr "Content-Erstellung"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Fortfahren mit " msgstr "Fortfahren mit "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Fortfahren mit {0}" msgstr "Fortfahren mit {0}"
@@ -444,6 +482,10 @@ msgstr "Kontrolliere, wer deine Boards ansehen und bearbeiten kann."
msgid "Create another" msgid "Create another"
msgstr "Weitere erstellen" msgstr "Weitere erstellen"
#: src/views/settings/components/NewApiKeyModal.tsx:175
msgid "Create API key"
msgstr "API-Schlüssel erstellen"
#: src/views/boards/components/NewBoardForm.tsx:128 #: src/views/boards/components/NewBoardForm.tsx:128
msgid "Create board" msgid "Create board"
msgstr "Board erstellen" msgstr "Board erstellen"
@@ -468,12 +510,12 @@ msgstr "Liste erstellen"
msgid "Create new board" msgid "Create new board"
msgstr "Neues Board erstellen" msgstr "Neues Board erstellen"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Neuen Schlüssel erstellen" msgstr "Neuen Schlüssel erstellen"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Neues Label erstellen" msgstr "Neues Label erstellen"
@@ -494,6 +536,10 @@ msgstr "hat die Karte erstellt"
msgid "Critical" msgid "Critical"
msgstr "Kritisch" msgstr "Kritisch"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Schneide deinen Avatar zu"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Aktuelles Passwort ist erforderlich" msgstr "Aktuelles Passwort ist erforderlich"
@@ -527,9 +573,9 @@ msgstr "Dunkel"
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Konto löschen" msgstr "Konto löschen"
@@ -550,8 +596,8 @@ msgid "Delete list"
msgstr "Liste löschen" msgstr "Liste löschen"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Workspace löschen" msgstr "Workspace löschen"
@@ -577,7 +623,7 @@ msgstr "hat Checklistenelement <0>{0}</0> gelöscht"
msgid "Design" msgid "Design"
msgstr "Design" msgstr "Design"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Trello trennen" msgstr "Trello trennen"
@@ -585,7 +631,7 @@ msgstr "Trello trennen"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Diskutiere und arbeite gemeinsam an Karten." msgstr "Diskutiere und arbeite gemeinsam an Karten."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Anzeigename" msgstr "Anzeigename"
@@ -619,7 +665,7 @@ msgstr "Dokumente"
msgid "Documentation" msgid "Documentation"
msgstr "Dokumentation" msgstr "Dokumentation"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "Du hast noch kein Konto? <0><1>Registrieren</1></0>" msgstr "Du hast noch kein Konto? <0><1>Registrieren</1></0>"
@@ -651,11 +697,11 @@ msgstr "Workspace-URL bearbeiten"
msgid "Editing" msgid "Editing"
msgstr "Bearbeitung" msgstr "Bearbeitung"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "E-Mail" msgstr "E-Mail"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "E-Mail" msgstr "E-Mail"
@@ -671,11 +717,11 @@ msgstr "Geben Sie Ihr aktuelles Passwort ein"
msgid "Enter your current password and choose a new secure password." 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." msgstr "Geben Sie Ihr aktuelles Passwort ein und wählen Sie ein neues sicheres Passwort."
#: src/components/AuthForm.tsx:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Gib deine E-Mail-Adresse ein" msgstr "Gib deine E-Mail-Adresse ein"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Gib deinen Namen ein" msgstr "Gib deinen Namen ein"
@@ -683,14 +729,26 @@ msgstr "Gib deinen Namen ein"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Geben Sie Ihr neues Passwort ein" msgstr "Geben Sie Ihr neues Passwort ein"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Gib dein Passwort ein" msgstr "Gib dein Passwort ein"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Fehler"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Fehler beim Ändern des Passworts" msgstr "Fehler beim Ändern des Passworts"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Fehler beim Erstellen des Einladungslinks"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Fehler beim Deaktivieren des Einladungslinks"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Fehler beim Löschen des Kontos" msgstr "Fehler beim Löschen des Kontos"
@@ -703,12 +761,12 @@ msgstr "Fehler beim Löschen des Labels"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Fehler beim Löschen des Arbeitsbereichs" msgstr "Fehler beim Löschen des Arbeitsbereichs"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Fehler beim Trennen von Trello" msgstr "Fehler beim Trennen von Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Fehler beim Einladen des Mitglieds" msgstr "Fehler beim Einladen des Mitglieds"
@@ -716,7 +774,7 @@ msgstr "Fehler beim Einladen des Mitglieds"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Fehler beim Aktualisieren des Anzeigenamens" msgstr "Fehler beim Aktualisieren des Anzeigenamens"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Fehler beim Aktualisieren des Profilbilds" msgstr "Fehler beim Aktualisieren des Profilbilds"
@@ -732,7 +790,7 @@ msgstr "Fehler beim Aktualisieren des Arbeitsbereichsnamens"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Fehler beim Aktualisieren der Workspace-URL" msgstr "Fehler beim Aktualisieren der Workspace-URL"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Fehler beim Upgrade des Abonnements" msgstr "Fehler beim Upgrade des Abonnements"
@@ -741,8 +799,8 @@ msgstr "Fehler beim Upgrade des Abonnements"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Fehler beim Upgrade auf Pro" msgstr "Fehler beim Upgrade auf Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Fehler beim Hochladen des Profilbilds" msgstr "Fehler beim Hochladen des Profilbilds"
@@ -758,8 +816,16 @@ msgstr "Alles was du brauchst, für immer kostenlos. Unbegrenzte Boards, unbegre
msgid "Execution" msgid "Execution"
msgstr "Ausführung" msgstr "Ausführung"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "Einladung konnte nicht angenommen werden. Bitte versuche es später erneut oder kontaktiere den Kundensupport."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "Einladungslink konnte nicht kopiert werden"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Anmeldung mit {0} fehlgeschlagen. Bitte versuche es erneut." msgstr "Anmeldung mit {0} fehlgeschlagen. Bitte versuche es erneut."
@@ -807,7 +873,7 @@ msgstr "Für langfristige Nachhaltigkeit erkennen wir an, dass alle guten Open-S
msgid "Free" msgid "Free"
msgstr "Kostenlos" msgstr "Kostenlos"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Kostenloser Plan" msgstr "Kostenloser Plan"
@@ -824,7 +890,7 @@ msgstr "Vollzeit"
msgid "Fun" msgid "Fun"
msgstr "Spaß" msgstr "Spaß"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -864,8 +930,13 @@ msgstr "Erste Schritte"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Zur Startseite"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Zur App" msgstr "Zur App"
@@ -917,7 +988,7 @@ msgstr "Ideen"
msgid "Ideas to improve this page..." msgid "Ideas to improve this page..."
msgstr "Ideen zur Verbesserung dieser Seite..." msgstr "Ideen zur Verbesserung dieser Seite..."
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Importieren" msgstr "Importieren"
@@ -955,6 +1026,7 @@ msgstr "In Bearbeitung"
msgid "Individuals" msgid "Individuals"
msgstr "Einzelpersonen" msgstr "Einzelpersonen"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Integrationen" msgstr "Integrationen"
@@ -963,27 +1035,44 @@ msgstr "Integrationen"
msgid "Interviewing" msgid "Interviewing"
msgstr "Vorstellungsgespräch" msgstr "Vorstellungsgespräch"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Ungültige E-Mail-Adresse" msgstr "Ungültige E-Mail-Adresse"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Ungültige Einladung"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Einladen" msgstr "Einladen"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:190
msgid "Invite another" msgid "Invite link copied"
msgstr "Weitere Person einladen" msgstr "Einladungslink kopiert"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:191
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied to clipboard"
msgstr "Einladungslink in die Zwischenablage kopiert"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Mitglied einladen" msgstr "Mitglied einladen"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "Das Einladen von Mitgliedern erfordert einen Team-Plan. Sie werden weitergeleitet, um Ihren Workspace zu upgraden." msgstr "Das Einladen von Mitgliedern erfordert einen Team-Plan. Sie werden weitergeleitet, um Ihren Workspace zu upgraden."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Arbeitsbereich beitreten"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Arbeitsbereich beitreten | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1011,7 +1100,7 @@ msgstr "Labels"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Labels & Filter" msgstr "Labels & Filter"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Sprache" msgstr "Sprache"
@@ -1056,7 +1145,7 @@ msgstr "Liste"
msgid "List name" msgid "List name"
msgstr "Listenname" msgstr "Listenname"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Login | kan.bn" msgstr "Login | kan.bn"
@@ -1072,7 +1161,7 @@ msgstr "Langfristig"
msgid "Low Priority" msgid "Low Priority"
msgstr "Niedrige Priorität" msgstr "Niedrige Priorität"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "Magic Link" msgstr "Magic Link"
@@ -1106,7 +1195,7 @@ msgstr "Mitglieder | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Monatlich" msgstr "Monatlich"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "monatliche Abrechnung" msgstr "monatliche Abrechnung"
@@ -1129,10 +1218,14 @@ msgstr "Name"
msgid "Need help?" msgid "Need help?"
msgstr "Brauchst du Hilfe?" msgstr "Brauchst du Hilfe?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "Neu" msgstr "Neu"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "Neuer API-Schlüssel"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "Neues Board" msgstr "Neues Board"
@@ -1206,15 +1299,15 @@ msgstr "Angebot"
msgid "Onboarding" msgid "Onboarding"
msgstr "Einarbeitung" msgstr "Einarbeitung"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Sobald Sie Ihr Konto löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden." msgstr "Sobald Sie Ihr Konto löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Sobald Sie Ihren Arbeitsbereich löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden." msgstr "Sobald Sie Ihren Arbeitsbereich löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "oder" msgstr "oder"
@@ -1242,6 +1335,10 @@ msgstr "Passwort muss mindestens 8 Zeichen lang sein"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Passwörter stimmen nicht überein" msgstr "Passwörter stimmen nicht überein"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "Pausiert"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Zahlungshäufigkeit" msgstr "Zahlungshäufigkeit"
@@ -1267,19 +1364,19 @@ msgstr "Planung"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Bitte bestätigen Sie Ihr neues Passwort" msgstr "Bitte bestätigen Sie Ihr neues Passwort"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Bitte gib eine gültige E-Mail-Adresse ein" msgstr "Bitte gib eine gültige E-Mail-Adresse ein"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Bitte gib einen gültigen Namen ein" msgstr "Bitte gib einen gültigen Namen ein"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Bitte gib ein gültiges Passwort ein" msgstr "Bitte gib ein gültiges Passwort ein"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Bitte wähle eine Datei zum Hochladen aus." msgstr "Bitte wähle eine Datei zum Hochladen aus."
@@ -1300,18 +1397,18 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1322,6 +1419,11 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Bitte versuche es später noch einmal oder kontaktiere den Kundensupport." msgstr "Bitte versuche es später noch einmal oder kontaktiere den Kundensupport."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Bitte versuche es später erneut."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1345,15 +1447,15 @@ msgstr "Privat"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Pro-Plan" msgstr "Pro-Plan"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro-Plan ∞" msgstr "Pro-Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profilbild aktualisiert" msgstr "Profilbild aktualisiert"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Profilbild" msgstr "Profilbild"
@@ -1436,10 +1538,6 @@ msgstr "Ressourcen"
msgid "Review" msgid "Review"
msgstr "Überprüfung" msgstr "Überprüfung"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke"
msgstr "Widerrufen"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
msgid "Roadmap" msgid "Roadmap"
@@ -1454,6 +1552,7 @@ msgid "Run on your own infrastructure"
msgstr "Auf eigener Infrastruktur betreiben" msgstr "Auf eigener Infrastruktur betreiben"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Speichern" msgstr "Speichern"
@@ -1493,35 +1592,62 @@ msgstr "Feedback senden"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Einstellungen" msgstr "Einstellungen"
#. placeholder {0}: workspace.name ?? "Workspace" #: src/views/settings/AccountSettings.tsx:25
#: src/views/settings/index.tsx:161 msgid "Settings | Account"
msgid "Settings | {0}" msgstr "Einstellungen | Konto"
msgstr "Einstellungen | {0}"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Einstellungen | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Einstellungen | Abrechnung"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Einstellungen | Integrationen"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Einstellungen | Arbeitsbereich"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Einladungslink teilen"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Anmelden" msgstr "Anmelden"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Anmelden"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "Registrieren"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Registrieren | kan.bn" msgstr "Registrieren | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Registrierung deaktiviert" msgstr "Registrierung deaktiviert"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." msgid "Sign up is currently disabled. Please try again later."
msgstr "Die Registrierung ist derzeit deaktiviert. Bitte versuche es später erneut." msgstr "Die Registrierung ist derzeit deaktiviert. Bitte versuche es später erneut."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "Registrieren mit " msgstr "Registrieren mit "
@@ -1545,8 +1671,8 @@ msgstr "Softwareentwicklung"
msgid "Star on Github" msgid "Star on Github"
msgstr "Stern auf Github" msgstr "Stern auf Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Erfolg" msgstr "Erfolg"
@@ -1566,7 +1692,7 @@ msgstr "Unterstütze die Entwicklung des Projekts"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Team-Plan" msgstr "Team-Plan"
@@ -1619,6 +1745,10 @@ msgstr "Sie werden keinen Zugriff mehr auf diesen Workspace haben."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "Diese Aktion kann nicht rückgängig gemacht werden." msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "Dieses Board ist privat oder existiert nicht" msgstr "Dieses Board ist privat oder existiert nicht"
@@ -1627,6 +1757,10 @@ msgstr "Dieses Board ist privat oder existiert nicht"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "Diese Board-URL ist bereits vergeben" msgstr "Diese Board-URL ist bereits vergeben"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "Dieser Einladungslink ist ungültig oder abgelaufen."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "Dies führt zur permanenten Löschung aller mit diesem Workspace verbundenen Daten." msgstr "Dies führt zur permanenten Löschung aller mit diesem Workspace verbundenen Daten."
@@ -1660,7 +1794,11 @@ msgstr "Menü umschalten"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Verfolge alle kartenänderungen mit detaillierter aktivitätshistorie." msgstr "Verfolge alle kartenänderungen mit detaillierter aktivitätshistorie."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello getrennt" msgstr "Trello getrennt"
@@ -1745,16 +1883,16 @@ msgstr "Checklistenelement kann nicht aktualisiert werden"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "Kommentar konnte nicht aktualisiert werden" msgstr "Kommentar konnte nicht aktualisiert werden"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "Labels konnten nicht aktualisiert werden" msgstr "Labels konnten nicht aktualisiert werden"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "Liste konnte nicht aktualisiert werden" msgstr "Liste konnte nicht aktualisiert werden"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "Mitglieder konnten nicht aktualisiert werden" msgstr "Mitglieder konnten nicht aktualisiert werden"
@@ -1797,9 +1935,9 @@ msgid "Unlimited members"
msgstr "Unbegrenzte Mitglieder" msgstr "Unbegrenzte Mitglieder"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Aktualisieren" msgstr "Aktualisieren"
@@ -1830,7 +1968,7 @@ msgid "Upgrade"
msgstr "Upgrade" msgstr "Upgrade"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Upgrade auf Pro" msgstr "Upgrade auf Pro"
@@ -1838,7 +1976,7 @@ msgstr "Upgrade auf Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Upgrade auf Pro ($29/Monat)" msgstr "Upgrade auf Pro ($29/Monat)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Upgrade auf Team-Plan" msgstr "Upgrade auf Team-Plan"
@@ -1870,7 +2008,7 @@ msgstr "Vorlage verwenden"
msgid "User" msgid "User"
msgstr "Benutzer" msgstr "Benutzer"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "Benutzer ist bereits Mitglied dieses Arbeitsbereichs" msgstr "Benutzer ist bereits Mitglied dieses Arbeitsbereichs"
@@ -1878,11 +2016,11 @@ msgstr "Benutzer ist bereits Mitglied dieses Arbeitsbereichs"
msgid "Video" msgid "Video"
msgstr "Video" msgstr "Video"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "API-Schlüssel anzeigen und verwalten." msgstr "API-Schlüssel anzeigen und verwalten."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "Verwalte deine Abrechnung und dein Abonnement." msgstr "Verwalte deine Abrechnung und dein Abonnement."
@@ -1914,7 +2052,7 @@ msgstr "Wir verwenden die <0>AGPL-3.0 lizenz</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "Wir stehen erst am anfang. " msgstr "Wir stehen erst am anfang. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Willkommen zurück" msgstr "Willkommen zurück"
@@ -1934,6 +2072,7 @@ msgstr "Als Trello 2011 auf den markt kam, beeindruckte es alle mit seiner sorgf
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "Warum ein open source Trello entwickeln?" msgstr "Warum ein open source Trello entwickeln?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Arbeitsbereich" msgstr "Arbeitsbereich"
@@ -1946,7 +2085,7 @@ msgstr "Workspace erfolgreich erstellt. Du kannst später in den Einstellungen u
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Workspace gelöscht" msgstr "Workspace gelöscht"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Workspace-Beschreibung" msgstr "Workspace-Beschreibung"
@@ -1968,7 +2107,7 @@ msgid "Workspace members"
msgstr "Workspace-mitglieder" msgstr "Workspace-mitglieder"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Name des Workspaces" msgstr "Name des Workspaces"
@@ -1992,7 +2131,7 @@ msgstr "Workspace-Name aktualisiert"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Workspace-Slug aktualisiert" msgstr "Workspace-Slug aktualisiert"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "Workspace-URL" msgstr "Workspace-URL"
@@ -2012,7 +2151,7 @@ msgstr "Jährlich"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Ja, wir bieten einen dauerhaft kostenlosen plan für die individuelle nutzung an. Keine einschränkungen, keine paywalls, keine limits." msgstr "Ja, wir bieten einen dauerhaft kostenlosen plan für die individuelle nutzung an. Keine einschränkungen, keine paywalls, keine limits."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "Sie sind dabei, Ihr Passwort zu ändern." msgstr "Sie sind dabei, Ihr Passwort zu ändern."
@@ -2028,18 +2167,26 @@ msgstr "Du kannst teammitglieder einladen, indem du auf die schaltfläche \"Einl
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "Sie können selbst hosten, indem sie den anweisungen in unserem <0>repo</0> folgen." msgstr "Sie können selbst hosten, indem sie den anweisungen in unserem <0>repo</0> folgen."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "Sie haben sich erfolgreich angemeldet." msgstr "Sie haben sich erfolgreich angemeldet."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "Sie haben sich erfolgreich registriert." msgstr "Sie haben sich erfolgreich registriert."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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!" msgstr "Sie haben unbegrenzte Plätze mit Ihrem Pro-Plan. Für neue Mitglieder fallen keine zusätzlichen Kosten an!"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "Du wurdest eingeladen, einem Arbeitsbereich auf kan.bn beizutreten."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "Du wurdest eingeladen, einem Arbeitsbereich beizutreten."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Dein Konto wurde gelöscht." msgstr "Dein Konto wurde gelöscht."
@@ -2056,15 +2203,15 @@ msgstr "Dein Anzeigename wurde aktualisiert."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Ihr Passwort wurde geändert." msgstr "Ihr Passwort wurde geändert."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Dein Profilbild wurde aktualisiert." msgstr "Dein Profilbild wurde aktualisiert."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Dein Trello-Konto wurde getrennt." msgstr "Dein Trello-Konto wurde getrennt."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Dein Trello-Konto ist verbunden." msgstr "Dein Trello-Konto ist verbunden."

File diff suppressed because one or more lines are too long

View File

@@ -40,12 +40,12 @@ msgstr "{boardCount, plural, one {Import board (1)} other {Import boards ({board
#~ msgid "#1 Hacker News" #~ msgid "#1 Hacker News"
#~ msgstr "#1 Hacker News" #~ msgstr "#1 Hacker News"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "$10/month" msgstr "$10/month"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "$8/month" msgstr "$8/month"
@@ -65,6 +65,10 @@ msgstr "1 user"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgstr "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Account"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Account deleted" msgstr "Account deleted"
@@ -107,13 +111,13 @@ msgstr "Add description... (type '/' to open commands or '@' to mention)"
msgid "Add details..." msgid "Add details..."
msgstr "Add details..." msgstr "Add details..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Add label" msgstr "Add label"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Add member" msgstr "Add member"
@@ -152,10 +156,14 @@ msgstr "added label <0>{0}</0>"
#~ msgid "added label <0>{label}</0>" #~ msgid "added label <0>{label}</0>"
#~ msgstr "added label <0>{label}</0>" #~ msgstr "added label <0>{label}</0>"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Adding a new member will cost an additional {price} ({billingType}) per seat." msgstr "Adding a new member will cost an additional {price} ({billingType}) per seat."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Adjust the square crop to fit your avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Admin roles" msgstr "Admin roles"
@@ -168,11 +176,11 @@ msgstr "Admin roles"
msgid "All systems operational" msgid "All systems operational"
msgstr "All systems operational" msgstr "All systems operational"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Already have an account? <0><1>Sign in</1></0>" msgstr "Already have an account? <0><1>Sign in</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "An error occurred while disconnecting your Trello account." msgstr "An error occurred while disconnecting your Trello account."
@@ -180,7 +188,31 @@ msgstr "An error occurred while disconnecting your Trello account."
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "An unexpected error occurred. Please try again later." msgstr "An unexpected error occurred. Please try again later."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Anyone with this link can join your workspace"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "API key created"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "API key name"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "API key name cannot exceed 30 characters"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "API key name is required"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "API keys" msgstr "API keys"
@@ -254,20 +286,21 @@ msgstr "Backlog"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Basic Kanban" msgstr "Basic Kanban"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "billed annually" msgstr "billed annually"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "billed monthly" msgstr "billed monthly"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Billing" msgstr "Billing"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Billing portal" msgstr "Billing portal"
@@ -331,12 +364,12 @@ msgid "Board visibility updated"
msgstr "Board visibility updated" msgstr "Board visibility updated"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Boards" msgstr "Boards"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Boards | {0}" msgstr "Boards | {0}"
@@ -362,6 +395,7 @@ msgstr "Bug Report"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -377,19 +411,23 @@ msgstr "Card not found"
msgid "Card title" msgid "Card title"
msgstr "Card title" msgstr "Card title"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Change Password" msgstr "Change Password"
#: src/views/settings/index.tsx:227 #: src/views/settings/index.tsx:227
msgid "Change the language of the app." #~ msgid "Change the language of the app."
msgstr "Change the language of the app." #~ msgstr "Change the language of the app."
#: src/views/auth/login/index.tsx:41 #: src/views/settings/AccountSettings.tsx:45
#: src/views/auth/signup/index.tsx:67 msgid "Change your language preferences."
msgstr "Change your language preferences."
#: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Check your inbox" msgstr "Check your inbox"
@@ -401,11 +439,15 @@ msgstr "Checklist name"
msgid "Clear filters" msgid "Clear filters"
msgstr "Clear filters" msgstr "Clear filters"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Click on the link we've sent to {magicLinkRecipient} to sign in." msgstr "Click on the link we've sent to {magicLinkRecipient} to sign in."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Close"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Code Review" msgstr "Code Review"
@@ -454,7 +496,7 @@ msgid "Confirm your new password"
msgstr "Confirm your new password" msgstr "Confirm your new password"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Connect Trello" msgstr "Connect Trello"
@@ -462,7 +504,7 @@ msgstr "Connect Trello"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Connect your favorite tools to streamline your workflow." msgstr "Connect your favorite tools to streamline your workflow."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Connect your Trello account to import boards." msgstr "Connect your Trello account to import boards."
@@ -478,12 +520,12 @@ msgstr "Contact us"
msgid "Content Creation" msgid "Content Creation"
msgstr "Content Creation" msgstr "Content Creation"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Continue with " msgstr "Continue with "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Continue with {0}" msgstr "Continue with {0}"
@@ -497,9 +539,9 @@ msgstr "Control who can view and edit your boards."
msgid "Create another" msgid "Create another"
msgstr "Create another" msgstr "Create another"
#: src/views/settings/index.tsx:238 #: src/views/settings/components/NewApiKeyModal.tsx:175
#~ msgid "Create API key" msgid "Create API key"
#~ msgstr "Create API key" msgstr "Create API key"
#: src/views/settings/index.tsx:232 #: src/views/settings/index.tsx:232
#~ msgid "Create API keys to access the Kan API." #~ msgid "Create API keys to access the Kan API."
@@ -529,12 +571,12 @@ msgstr "Create list"
msgid "Create new board" msgid "Create new board"
msgstr "Create new board" msgstr "Create new board"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Create new key" msgstr "Create new key"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Create new label" msgstr "Create new label"
@@ -559,6 +601,10 @@ msgstr "created the card"
msgid "Critical" msgid "Critical"
msgstr "Critical" msgstr "Critical"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Crop your avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Current password is required" msgstr "Current password is required"
@@ -600,9 +646,9 @@ msgstr "Dark"
msgid "Delete" msgid "Delete"
msgstr "Delete" msgstr "Delete"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Delete account" msgstr "Delete account"
@@ -623,8 +669,8 @@ msgid "Delete list"
msgstr "Delete list" msgstr "Delete list"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Delete workspace" msgstr "Delete workspace"
@@ -650,7 +696,7 @@ msgstr "deleted checklist item <0>{0}</0>"
msgid "Design" msgid "Design"
msgstr "Design" msgstr "Design"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Disconnect Trello" msgstr "Disconnect Trello"
@@ -658,7 +704,7 @@ msgstr "Disconnect Trello"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Discuss and collaborate on cards." msgstr "Discuss and collaborate on cards."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Display name" msgstr "Display name"
@@ -692,7 +738,7 @@ msgstr "Docs"
msgid "Documentation" msgid "Documentation"
msgstr "Documentation" msgstr "Documentation"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "Don't have an account? <0><1>Sign up</1></0>" msgstr "Don't have an account? <0><1>Sign up</1></0>"
@@ -724,11 +770,11 @@ msgstr "Edit workspace URL"
msgid "Editing" msgid "Editing"
msgstr "Editing" msgstr "Editing"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "email" msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
@@ -744,11 +790,11 @@ msgstr "Enter your current password"
msgid "Enter your current password and choose a new secure password." msgid "Enter your current password and choose a new secure password."
msgstr "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:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Enter your email address" msgstr "Enter your email address"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Enter your name" msgstr "Enter your name"
@@ -756,14 +802,26 @@ msgstr "Enter your name"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Enter your new password" msgstr "Enter your new password"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Enter your password" msgstr "Enter your password"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Error"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Error Changing Password" msgstr "Error Changing Password"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Error creating invite link"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Error deactivating invite link"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Error deleting account" msgstr "Error deleting account"
@@ -776,12 +834,12 @@ msgstr "Error deleting label"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Error deleting workspace" msgstr "Error deleting workspace"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Error disconnecting Trello" msgstr "Error disconnecting Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Error inviting member" msgstr "Error inviting member"
@@ -789,7 +847,7 @@ msgstr "Error inviting member"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Error updating display name" msgstr "Error updating display name"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Error updating profile image" msgstr "Error updating profile image"
@@ -805,7 +863,7 @@ msgstr "Error updating workspace name"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Error updating workspace URL" msgstr "Error updating workspace URL"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Error upgrading subscription" msgstr "Error upgrading subscription"
@@ -814,8 +872,8 @@ msgstr "Error upgrading subscription"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Error upgrading to Pro" msgstr "Error upgrading to Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Error uploading profile image" msgstr "Error uploading profile image"
@@ -831,8 +889,16 @@ msgstr "Everything you need, free forever. Unlimited boards, unlimited lists, un
msgid "Execution" msgid "Execution"
msgstr "Execution" msgstr "Execution"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "Failed to accept invitation. Please try again later, or contact customer support."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "Failed to copy invite link"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Failed to login with {0}. Please try again." msgstr "Failed to login with {0}. Please try again."
@@ -881,7 +947,7 @@ msgstr "For long-term sustainability, we recognise all good open source projects
msgid "Free" msgid "Free"
msgstr "Free" msgstr "Free"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Free Plan" msgstr "Free Plan"
@@ -898,7 +964,7 @@ msgstr "Full-time"
msgid "Fun" msgid "Fun"
msgstr "Fun" msgstr "Fun"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -938,8 +1004,13 @@ msgstr "Getting started"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Go Home"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Go to app" msgstr "Go to app"
@@ -995,7 +1066,7 @@ msgstr "Ideas to improve this page..."
#~ msgid "Ideas, Research, Planning, Execution, Review, Next Steps, Complete" #~ msgid "Ideas, Research, Planning, Execution, Review, Next Steps, Complete"
#~ msgstr "Ideas, Research, Planning, Execution, Review, Next Steps, Complete" #~ msgstr "Ideas, Research, Planning, Execution, Review, Next Steps, Complete"
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Import" msgstr "Import"
@@ -1033,6 +1104,7 @@ msgstr "In Progress"
msgid "Individuals" msgid "Individuals"
msgstr "Individuals" msgstr "Individuals"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Integrations" msgstr "Integrations"
@@ -1041,27 +1113,48 @@ msgstr "Integrations"
msgid "Interviewing" msgid "Interviewing"
msgstr "Interviewing" msgstr "Interviewing"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Invalid email address" msgstr "Invalid email address"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Invalid invitation"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Invite" msgstr "Invite"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:208
msgid "Invite another" #~ msgid "Invite another"
msgstr "Invite another" #~ msgstr "Invite another"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:190
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied"
msgstr "Invite link copied"
#: src/views/members/components/InviteMemberForm.tsx:191
msgid "Invite link copied to clipboard"
msgstr "Invite link copied to clipboard"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Invite member" msgstr "Invite member"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgstr "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Join workspace"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Join workspace | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1089,7 +1182,7 @@ msgstr "Labels"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Labels & Filters" msgstr "Labels & Filters"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Language" msgstr "Language"
@@ -1134,7 +1227,7 @@ msgstr "List"
msgid "List name" msgid "List name"
msgstr "List name" msgstr "List name"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Login | kan.bn" msgstr "Login | kan.bn"
@@ -1150,7 +1243,7 @@ msgstr "Long-term"
msgid "Low Priority" msgid "Low Priority"
msgstr "Low Priority" msgstr "Low Priority"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "magic link" msgstr "magic link"
@@ -1184,7 +1277,7 @@ msgstr "Members | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Monthly" msgstr "Monthly"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "monthly billing" msgstr "monthly billing"
@@ -1215,10 +1308,14 @@ msgstr "Name"
msgid "Need help?" msgid "Need help?"
msgstr "Need help?" msgstr "Need help?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "New" msgstr "New"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "New API key"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "New board" msgstr "New board"
@@ -1296,15 +1393,15 @@ msgstr "Offer"
msgid "Onboarding" msgid "Onboarding"
msgstr "Onboarding" msgstr "Onboarding"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Once you delete your account, there is no going back. This action cannot be undone." msgstr "Once you delete your account, there is no going back. This action cannot be undone."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." 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." msgstr "Once you delete your workspace, there is no going back. This action cannot be undone."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "or" msgstr "or"
@@ -1332,6 +1429,10 @@ msgstr "Password must be at least 8 characters"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Passwords do not match" msgstr "Passwords do not match"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "Paused"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Payment frequency" msgstr "Payment frequency"
@@ -1357,19 +1458,19 @@ msgstr "Planning"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Please confirm your new password" msgstr "Please confirm your new password"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Please enter a valid email address" msgstr "Please enter a valid email address"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Please enter a valid name" msgstr "Please enter a valid name"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Please enter a valid password" msgstr "Please enter a valid password"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Please select a file to upload." msgstr "Please select a file to upload."
@@ -1390,18 +1491,18 @@ msgstr "Please select a file to upload."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1412,6 +1513,11 @@ msgstr "Please select a file to upload."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Please try again later, or contact customer support." msgstr "Please try again later, or contact customer support."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Please try again later."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1435,15 +1541,15 @@ msgstr "Private"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Pro Plan" msgstr "Pro Plan"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro Plan ∞" msgstr "Pro Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profile image updated" msgstr "Profile image updated"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Profile picture" msgstr "Profile picture"
@@ -1531,8 +1637,8 @@ msgid "Review"
msgstr "Review" msgstr "Review"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49 #: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke" #~ msgid "Revoke"
msgstr "Revoke" #~ msgstr "Revoke"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
@@ -1548,6 +1654,7 @@ msgid "Run on your own infrastructure"
msgstr "Run on your own infrastructure" msgstr "Run on your own infrastructure"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Save" msgstr "Save"
@@ -1591,35 +1698,66 @@ msgstr "Send feedback"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Settings" msgstr "Settings"
#. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/settings/index.tsx:161 #: src/views/settings/index.tsx:161
msgid "Settings | {0}" #~ msgid "Settings | {0}"
msgstr "Settings | {0}" #~ msgstr "Settings | {0}"
#: src/views/settings/AccountSettings.tsx:25
msgid "Settings | Account"
msgstr "Settings | Account"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Settings | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Settings | Billing"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Settings | Integrations"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Settings | Workspace"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Share invite link"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Sign in" msgstr "Sign in"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Sign In"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "Sign Up"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Sign up | kan.bn" msgstr "Sign up | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Sign up disabled" msgstr "Sign up disabled"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." msgid "Sign up is currently disabled. Please try again later."
msgstr "Sign up is currently disabled. Please try again later." msgstr "Sign up is currently disabled. Please try again later."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "Sign up with " msgstr "Sign up with "
@@ -1643,8 +1781,8 @@ msgstr "Software Development"
msgid "Star on Github" msgid "Star on Github"
msgstr "Star on Github" msgstr "Star on Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Success" msgstr "Success"
@@ -1664,7 +1802,7 @@ msgstr "Support the development of the project"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Team Plan" msgstr "Team Plan"
@@ -1717,6 +1855,10 @@ msgstr "They won't be able to access this workspace."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "This action can't be undone." msgstr "This action can't be undone."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "This board is private or does not exist" msgstr "This board is private or does not exist"
@@ -1725,6 +1867,10 @@ msgstr "This board is private or does not exist"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "This board URL has already been taken" msgstr "This board URL has already been taken"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "This invitation link is invalid or has expired."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "This will result in the permanent deletion of all data associated with this workspace." msgstr "This will result in the permanent deletion of all data associated with this workspace."
@@ -1762,7 +1908,11 @@ msgstr "Toggle menu"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Track all card changes with detailed activity history." msgstr "Track all card changes with detailed activity history."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello disconnected" msgstr "Trello disconnected"
@@ -1847,16 +1997,16 @@ msgstr "Unable to update checklist item"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "Unable to update comment" msgstr "Unable to update comment"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "Unable to update labels" msgstr "Unable to update labels"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "Unable to update list" msgstr "Unable to update list"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "Unable to update members" msgstr "Unable to update members"
@@ -1903,9 +2053,9 @@ msgid "Unlimited members"
msgstr "Unlimited members" msgstr "Unlimited members"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Update" msgstr "Update"
@@ -1940,7 +2090,7 @@ msgid "Upgrade"
msgstr "Upgrade" msgstr "Upgrade"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Upgrade to Pro" msgstr "Upgrade to Pro"
@@ -1948,7 +2098,7 @@ msgstr "Upgrade to Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Upgrade to Pro ($29/month)" msgstr "Upgrade to Pro ($29/month)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Upgrade to Team Plan" msgstr "Upgrade to Team Plan"
@@ -1980,7 +2130,7 @@ msgstr "Use template"
msgid "User" msgid "User"
msgstr "User" msgstr "User"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "User is already a member of this workspace" msgstr "User is already a member of this workspace"
@@ -1988,11 +2138,11 @@ msgstr "User is already a member of this workspace"
msgid "Video" msgid "Video"
msgstr "Video" msgstr "Video"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "View and manage your API keys." msgstr "View and manage your API keys."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "View and manage your billing and subscription." msgstr "View and manage your billing and subscription."
@@ -2024,7 +2174,7 @@ msgstr "We are using the <0>AGPL-3.0 license</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "We're just getting started. " msgstr "We're just getting started. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Welcome back" msgstr "Welcome back"
@@ -2048,6 +2198,7 @@ msgstr "When Trello launched in 2011, it blew everyone away with its carefully d
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "Why make an open source Trello?" msgstr "Why make an open source Trello?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Workspace" msgstr "Workspace"
@@ -2060,7 +2211,7 @@ msgstr "Workspace created successfully. You can upgrade later in settings."
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Workspace deleted" msgstr "Workspace deleted"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Workspace description" msgstr "Workspace description"
@@ -2082,7 +2233,7 @@ msgid "Workspace members"
msgstr "Workspace members" msgstr "Workspace members"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Workspace name" msgstr "Workspace name"
@@ -2106,7 +2257,7 @@ msgstr "Workspace name updated"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Workspace slug updated" msgstr "Workspace slug updated"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "Workspace URL" msgstr "Workspace URL"
@@ -2126,7 +2277,7 @@ msgstr "Yearly"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgstr "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "You are about to change your password." msgstr "You are about to change your password."
@@ -2142,18 +2293,26 @@ msgstr "You can invite team members by clicking the \"Invite\" button in the top
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "You can self-host by following the instructions in our <0>repo</0>." msgstr "You can self-host by following the instructions in our <0>repo</0>."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "You have been logged in successfully." msgstr "You have been logged in successfully."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "You have been signed up successfully." msgstr "You have been signed up successfully."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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!" msgstr "You have unlimited seats with your Pro Plan. There is no additional charge for new members!"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "You've been invited to join a workspace on kan.bn."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "You've been invited to join a workspace."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Your account has been deleted." msgstr "Your account has been deleted."
@@ -2170,15 +2329,15 @@ msgstr "Your display name has been updated."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Your password has been changed." msgstr "Your password has been changed."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Your profile image has been updated." msgstr "Your profile image has been updated."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Your Trello account has been disconnected." msgstr "Your Trello account has been disconnected."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Your Trello account is connected." msgstr "Your Trello account is connected."

File diff suppressed because one or more lines are too long

View File

@@ -36,12 +36,12 @@ msgstr "{0} etiquetas"
msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}" msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
msgstr "{boardCount, plural, one {Importar tablero (1)} other {Importar tableros ({boardCount})}}" msgstr "{boardCount, plural, one {Importar tablero (1)} other {Importar tableros ({boardCount})}}"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "$10/mes" msgstr "$10/mes"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "$8/mes" msgstr "$8/mes"
@@ -53,6 +53,10 @@ msgstr "1 usuario"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "Una aplicación kanban potente y flexible que te ayuda a organizar el trabajo, seguir el progreso y entregar resultados, todo en un solo lugar." msgstr "Una aplicación kanban potente y flexible que te ayuda a organizar el trabajo, seguir el progreso y entregar resultados, todo en un solo lugar."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Cuenta"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Cuenta eliminada" msgstr "Cuenta eliminada"
@@ -91,13 +95,13 @@ msgstr "Añadir descripción... (escribe '/' para abrir comandos o '@' para menc
msgid "Add details..." msgid "Add details..."
msgstr "Añadir detalles..." msgstr "Añadir detalles..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Añadir etiqueta" msgstr "Añadir etiqueta"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Añadir miembro" msgstr "Añadir miembro"
@@ -132,10 +136,14 @@ msgstr "añadió el elemento <0>{0}</0> a la lista de verificación"
msgid "added label <0>{0}</0>" msgid "added label <0>{0}</0>"
msgstr "añadió la etiqueta <0>{0}</0>" msgstr "añadió la etiqueta <0>{0}</0>"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Añadir un nuevo miembro costará {price} adicionales ({billingType}) por asiento." msgstr "Añadir un nuevo miembro costará {price} adicionales ({billingType}) por asiento."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Ajusta el recorte cuadrado para que se adapte a tu avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Roles de administrador" msgstr "Roles de administrador"
@@ -144,11 +152,11 @@ msgstr "Roles de administrador"
msgid "All systems operational" msgid "All systems operational"
msgstr "Todos los sistemas operativos" msgstr "Todos los sistemas operativos"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "¿Ya tienes una cuenta? <0><1>Iniciar sesión</1></0>" msgstr "¿Ya tienes una cuenta? <0><1>Iniciar sesión</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "Ocurrió un error al desconectar tu cuenta de Trello." msgstr "Ocurrió un error al desconectar tu cuenta de Trello."
@@ -156,7 +164,31 @@ msgstr "Ocurrió un error al desconectar tu cuenta de Trello."
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "Ha ocurrido un error inesperado. Por favor, inténtalo de nuevo más tarde." msgstr "Ha ocurrido un error inesperado. Por favor, inténtalo de nuevo más tarde."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Cualquier persona con este enlace puede unirse a tu espacio de trabajo"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "Clave API creada"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "Nombre de la clave API"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "El nombre de la clave API no puede exceder los 30 caracteres"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "El nombre de la clave API es obligatorio"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "Claves API" msgstr "Claves API"
@@ -218,20 +250,21 @@ msgstr "Pendientes"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Kanban básico" msgstr "Kanban básico"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "facturado anualmente" msgstr "facturado anualmente"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "facturado mensualmente" msgstr "facturado mensualmente"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Facturación" msgstr "Facturación"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Portal de facturación" msgstr "Portal de facturación"
@@ -286,12 +319,12 @@ msgid "Board visibility updated"
msgstr "Visibilidad del tablero actualizada" msgstr "Visibilidad del tablero actualizada"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Tableros" msgstr "Tableros"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Tableros | {0}" msgstr "Tableros | {0}"
@@ -313,6 +346,7 @@ msgstr "Informe de error"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -328,19 +362,19 @@ msgstr "Tarjeta no encontrada"
msgid "Card title" msgid "Card title"
msgstr "Título de la tarjeta" msgstr "Título de la tarjeta"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Cambiar contraseña" msgstr "Cambiar contraseña"
#: src/views/settings/index.tsx:227 #: src/views/settings/AccountSettings.tsx:45
msgid "Change the language of the app." msgid "Change your language preferences."
msgstr "Cambiar el idioma de la aplicación." msgstr "Cambia tus preferencias de idioma."
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Revisa tu bandeja de entrada" msgstr "Revisa tu bandeja de entrada"
@@ -352,11 +386,15 @@ msgstr "Nombre de la lista de verificación"
msgid "Clear filters" msgid "Clear filters"
msgstr "Borrar filtros" msgstr "Borrar filtros"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Haz clic en el enlace que hemos enviado a {magicLinkRecipient} para iniciar sesión." msgstr "Haz clic en el enlace que hemos enviado a {magicLinkRecipient} para iniciar sesión."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Cerrar"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Revisión de código" msgstr "Revisión de código"
@@ -401,7 +439,7 @@ msgid "Confirm your new password"
msgstr "Confirma tu nueva contraseña" msgstr "Confirma tu nueva contraseña"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Conectar Trello" msgstr "Conectar Trello"
@@ -409,7 +447,7 @@ msgstr "Conectar Trello"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Conecta tus herramientas favoritas para agilizar tu flujo de trabajo." msgstr "Conecta tus herramientas favoritas para agilizar tu flujo de trabajo."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Conecta tu cuenta de Trello para importar tableros." msgstr "Conecta tu cuenta de Trello para importar tableros."
@@ -425,12 +463,12 @@ msgstr "Contáctanos"
msgid "Content Creation" msgid "Content Creation"
msgstr "Creación de contenido" msgstr "Creación de contenido"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Continuar con " msgstr "Continuar con "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Continuar con {0}" msgstr "Continuar con {0}"
@@ -444,6 +482,10 @@ msgstr "Controla quién puede ver y editar tus tableros."
msgid "Create another" msgid "Create another"
msgstr "Crear otro" msgstr "Crear otro"
#: src/views/settings/components/NewApiKeyModal.tsx:175
msgid "Create API key"
msgstr "Crear clave API"
#: src/views/boards/components/NewBoardForm.tsx:128 #: src/views/boards/components/NewBoardForm.tsx:128
msgid "Create board" msgid "Create board"
msgstr "Crear tablero" msgstr "Crear tablero"
@@ -468,12 +510,12 @@ msgstr "Crear lista"
msgid "Create new board" msgid "Create new board"
msgstr "Crear nuevo tablero" msgstr "Crear nuevo tablero"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Crear nueva clave" msgstr "Crear nueva clave"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Crear nueva etiqueta" msgstr "Crear nueva etiqueta"
@@ -494,6 +536,10 @@ msgstr "creó la tarjeta"
msgid "Critical" msgid "Critical"
msgstr "Crítico" msgstr "Crítico"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Recorta tu avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Se requiere la contraseña actual" msgstr "Se requiere la contraseña actual"
@@ -527,9 +573,9 @@ msgstr "Oscuro"
msgid "Delete" msgid "Delete"
msgstr "Eliminar" msgstr "Eliminar"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Eliminar cuenta" msgstr "Eliminar cuenta"
@@ -550,8 +596,8 @@ msgid "Delete list"
msgstr "Eliminar lista" msgstr "Eliminar lista"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Eliminar espacio de trabajo" msgstr "Eliminar espacio de trabajo"
@@ -577,7 +623,7 @@ msgstr "eliminó el elemento <0>{0}</0> de la lista de verificación"
msgid "Design" msgid "Design"
msgstr "Diseño" msgstr "Diseño"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Desconectar Trello" msgstr "Desconectar Trello"
@@ -585,7 +631,7 @@ msgstr "Desconectar Trello"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Discute y colabora en las tarjetas." msgstr "Discute y colabora en las tarjetas."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Nombre visible" msgstr "Nombre visible"
@@ -619,7 +665,7 @@ msgstr "Documentos"
msgid "Documentation" msgid "Documentation"
msgstr "Documentación" msgstr "Documentación"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "¿No tienes una cuenta? <0><1>Regístrate</1></0>" msgstr "¿No tienes una cuenta? <0><1>Regístrate</1></0>"
@@ -651,11 +697,11 @@ msgstr "Editar URL del espacio de trabajo"
msgid "Editing" msgid "Editing"
msgstr "Editando" msgstr "Editando"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "correo electrónico" msgstr "correo electrónico"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "Correo electrónico" msgstr "Correo electrónico"
@@ -671,11 +717,11 @@ msgstr "Introduce tu contraseña actual"
msgid "Enter your current password and choose a new secure password." msgid "Enter your current password and choose a new secure password."
msgstr "Introduce tu contraseña actual y elige una nueva contraseña segura." msgstr "Introduce tu contraseña actual y elige una nueva contraseña segura."
#: src/components/AuthForm.tsx:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Introduce tu dirección de correo electrónico" msgstr "Introduce tu dirección de correo electrónico"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Introduce tu nombre" msgstr "Introduce tu nombre"
@@ -683,14 +729,26 @@ msgstr "Introduce tu nombre"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Introduce tu nueva contraseña" msgstr "Introduce tu nueva contraseña"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Introduce tu contraseña" msgstr "Introduce tu contraseña"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Error"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Error al cambiar la contraseña" msgstr "Error al cambiar la contraseña"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Error al crear el enlace de invitación"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Error al desactivar el enlace de invitación"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Error al eliminar la cuenta" msgstr "Error al eliminar la cuenta"
@@ -703,12 +761,12 @@ msgstr "Error al eliminar la etiqueta"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Error al eliminar el espacio de trabajo" msgstr "Error al eliminar el espacio de trabajo"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Error al desconectar Trello" msgstr "Error al desconectar Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Error al invitar al miembro" msgstr "Error al invitar al miembro"
@@ -716,7 +774,7 @@ msgstr "Error al invitar al miembro"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Error al actualizar el nombre visible" msgstr "Error al actualizar el nombre visible"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Error al actualizar la imagen de perfil" msgstr "Error al actualizar la imagen de perfil"
@@ -732,7 +790,7 @@ msgstr "Error al actualizar el nombre del espacio de trabajo"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Error al actualizar la URL del espacio de trabajo" msgstr "Error al actualizar la URL del espacio de trabajo"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Error al actualizar la suscripción" msgstr "Error al actualizar la suscripción"
@@ -741,8 +799,8 @@ msgstr "Error al actualizar la suscripción"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Error al actualizar a Pro" msgstr "Error al actualizar a Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Error al subir la imagen de perfil" msgstr "Error al subir la imagen de perfil"
@@ -758,8 +816,16 @@ msgstr "Todo lo que necesitas, gratis para siempre. Tableros ilimitados, listas
msgid "Execution" msgid "Execution"
msgstr "Ejecución" msgstr "Ejecución"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "No se pudo aceptar la invitación. Por favor, inténtalo de nuevo más tarde o contacta con atención al cliente."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "No se pudo copiar el enlace de invitación"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Error al iniciar sesión con {0}. Por favor, inténtalo de nuevo." msgstr "Error al iniciar sesión con {0}. Por favor, inténtalo de nuevo."
@@ -807,7 +873,7 @@ msgstr "Para la sostenibilidad a largo plazo, reconocemos que todos los buenos p
msgid "Free" msgid "Free"
msgstr "Gratis" msgstr "Gratis"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Plan gratuito" msgstr "Plan gratuito"
@@ -824,7 +890,7 @@ msgstr "Tiempo completo"
msgid "Fun" msgid "Fun"
msgstr "Diversión" msgstr "Diversión"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -864,8 +930,13 @@ msgstr "Primeros pasos"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Ir a inicio"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Ir a la aplicación" msgstr "Ir a la aplicación"
@@ -917,7 +988,7 @@ msgstr "Ideas"
msgid "Ideas to improve this page..." msgid "Ideas to improve this page..."
msgstr "Ideas para mejorar esta página..." msgstr "Ideas para mejorar esta página..."
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Importar" msgstr "Importar"
@@ -955,6 +1026,7 @@ msgstr "En progreso"
msgid "Individuals" msgid "Individuals"
msgstr "Individuos" msgstr "Individuos"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Integraciones" msgstr "Integraciones"
@@ -963,27 +1035,44 @@ msgstr "Integraciones"
msgid "Interviewing" msgid "Interviewing"
msgstr "Entrevistando" msgstr "Entrevistando"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Dirección de correo electrónico no válida" msgstr "Dirección de correo electrónico no válida"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Invitación no válida"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Invitar" msgstr "Invitar"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:190
msgid "Invite another" msgid "Invite link copied"
msgstr "Invitar a otro" msgstr "Enlace de invitación copiado"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:191
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied to clipboard"
msgstr "Enlace de invitación copiado al portapapeles"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Invitar miembro" msgstr "Invitar miembro"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "Invitar miembros requiere un Plan de Equipo. Serás redirigido para actualizar tu espacio de trabajo." msgstr "Invitar miembros requiere un Plan de Equipo. Serás redirigido para actualizar tu espacio de trabajo."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Unirse al espacio de trabajo"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Unirse al espacio de trabajo | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1011,7 +1100,7 @@ msgstr "Etiquetas"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Etiquetas y filtros" msgstr "Etiquetas y filtros"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
@@ -1056,7 +1145,7 @@ msgstr "Lista"
msgid "List name" msgid "List name"
msgstr "Nombre de la lista" msgstr "Nombre de la lista"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Iniciar sesión | kan.bn" msgstr "Iniciar sesión | kan.bn"
@@ -1072,7 +1161,7 @@ msgstr "Largo plazo"
msgid "Low Priority" msgid "Low Priority"
msgstr "Prioridad baja" msgstr "Prioridad baja"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "enlace mágico" msgstr "enlace mágico"
@@ -1106,7 +1195,7 @@ msgstr "Miembros | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Mensual" msgstr "Mensual"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "facturación mensual" msgstr "facturación mensual"
@@ -1129,10 +1218,14 @@ msgstr "Nombre"
msgid "Need help?" msgid "Need help?"
msgstr "¿Necesitas ayuda?" msgstr "¿Necesitas ayuda?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "Nuevo" msgstr "Nuevo"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "Nueva clave API"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "Nuevo tablero" msgstr "Nuevo tablero"
@@ -1206,15 +1299,15 @@ msgstr "Oferta"
msgid "Onboarding" msgid "Onboarding"
msgstr "Incorporación" msgstr "Incorporación"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Una vez que elimines tu cuenta, no hay vuelta atrás. Esta acción no se puede deshacer." msgstr "Una vez que elimines tu cuenta, no hay vuelta atrás. Esta acción no se puede deshacer."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Una vez que elimines tu espacio de trabajo, no hay vuelta atrás. Esta acción no se puede deshacer." msgstr "Una vez que elimines tu espacio de trabajo, no hay vuelta atrás. Esta acción no se puede deshacer."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "o" msgstr "o"
@@ -1242,6 +1335,10 @@ msgstr "La contraseña debe tener al menos 8 caracteres"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Las contraseñas no coinciden" msgstr "Las contraseñas no coinciden"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "Pausado"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Frecuencia de pago" msgstr "Frecuencia de pago"
@@ -1267,19 +1364,19 @@ msgstr "Planificación"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Por favor, confirma tu nueva contraseña" msgstr "Por favor, confirma tu nueva contraseña"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Por favor, introduce una dirección de correo electrónico válida" msgstr "Por favor, introduce una dirección de correo electrónico válida"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Por favor, introduce un nombre válido" msgstr "Por favor, introduce un nombre válido"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Por favor, introduce una contraseña válida" msgstr "Por favor, introduce una contraseña válida"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Por favor selecciona un archivo para subir." msgstr "Por favor selecciona un archivo para subir."
@@ -1300,18 +1397,18 @@ msgstr "Por favor selecciona un archivo para subir."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1322,6 +1419,11 @@ msgstr "Por favor selecciona un archivo para subir."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Por favor, inténtalo de nuevo más tarde o contacta con atención al cliente." msgstr "Por favor, inténtalo de nuevo más tarde o contacta con atención al cliente."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Por favor, inténtalo de nuevo más tarde."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1345,15 +1447,15 @@ msgstr "Privado"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Plan Pro" msgstr "Plan Pro"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Plan Pro ∞" msgstr "Plan Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Imagen de perfil actualizada" msgstr "Imagen de perfil actualizada"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Foto de perfil" msgstr "Foto de perfil"
@@ -1436,10 +1538,6 @@ msgstr "Recursos"
msgid "Review" msgid "Review"
msgstr "Revisión" msgstr "Revisión"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke"
msgstr "Revocar"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
msgid "Roadmap" msgid "Roadmap"
@@ -1454,6 +1552,7 @@ msgid "Run on your own infrastructure"
msgstr "Ejecuta en tu propia infraestructura" msgstr "Ejecuta en tu propia infraestructura"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Guardar" msgstr "Guardar"
@@ -1493,35 +1592,62 @@ msgstr "Enviar comentarios"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Configuración" msgstr "Configuración"
#. placeholder {0}: workspace.name ?? "Workspace" #: src/views/settings/AccountSettings.tsx:25
#: src/views/settings/index.tsx:161 msgid "Settings | Account"
msgid "Settings | {0}" msgstr "Configuración | Cuenta"
msgstr "Configuración | {0}"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Configuración | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Configuración | Facturación"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Configuración | Integraciones"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Configuración | Espacio de trabajo"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Compartir enlace de invitación"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Iniciar sesión" msgstr "Iniciar sesión"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Iniciar sesión"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "Registrarse"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Registrarse | kan.bn" msgstr "Registrarse | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Registro deshabilitado" msgstr "Registro deshabilitado"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." 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." msgstr "El registro está actualmente deshabilitado. Por favor, inténtalo de nuevo más tarde."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "Registrarse con " msgstr "Registrarse con "
@@ -1545,8 +1671,8 @@ msgstr "Desarrollo de software"
msgid "Star on Github" msgid "Star on Github"
msgstr "Estrella en Github" msgstr "Estrella en Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Éxito" msgstr "Éxito"
@@ -1566,7 +1692,7 @@ msgstr "Apoya el desarrollo del proyecto"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Plan de Equipo" msgstr "Plan de Equipo"
@@ -1619,6 +1745,10 @@ msgstr "No podrán acceder a este espacio de trabajo."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "Esta acción no se puede deshacer." msgstr "Esta acción no se puede deshacer."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "Este tablero es privado o no existe" msgstr "Este tablero es privado o no existe"
@@ -1627,6 +1757,10 @@ msgstr "Este tablero es privado o no existe"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "Esta URL de tablero ya ha sido utilizada" msgstr "Esta URL de tablero ya ha sido utilizada"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "Este enlace de invitación no es válido o ha caducado."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "Esto resultará en la eliminación permanente de todos los datos asociados con este espacio de trabajo." msgstr "Esto resultará en la eliminación permanente de todos los datos asociados con este espacio de trabajo."
@@ -1660,7 +1794,11 @@ msgstr "Alternar menú"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Rastrea todos los cambios en las tarjetas con un historial de actividad detallado." msgstr "Rastrea todos los cambios en las tarjetas con un historial de actividad detallado."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello desconectado" msgstr "Trello desconectado"
@@ -1745,16 +1883,16 @@ msgstr "No se puede actualizar el elemento de la lista de verificación"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "No se puede actualizar el comentario" msgstr "No se puede actualizar el comentario"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "No se pueden actualizar las etiquetas" msgstr "No se pueden actualizar las etiquetas"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "No se puede actualizar la lista" msgstr "No se puede actualizar la lista"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "No se pueden actualizar los miembros" msgstr "No se pueden actualizar los miembros"
@@ -1797,9 +1935,9 @@ msgid "Unlimited members"
msgstr "Miembros ilimitados" msgstr "Miembros ilimitados"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Actualizar" msgstr "Actualizar"
@@ -1830,7 +1968,7 @@ msgid "Upgrade"
msgstr "Actualizar" msgstr "Actualizar"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Actualizar a Pro" msgstr "Actualizar a Pro"
@@ -1838,7 +1976,7 @@ msgstr "Actualizar a Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Actualizar a Pro ($29/mes)" msgstr "Actualizar a Pro ($29/mes)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Actualizar al Plan de Equipo" msgstr "Actualizar al Plan de Equipo"
@@ -1870,7 +2008,7 @@ msgstr "Usar plantilla"
msgid "User" msgid "User"
msgstr "Usuario" msgstr "Usuario"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "El usuario ya es miembro de este espacio de trabajo" msgstr "El usuario ya es miembro de este espacio de trabajo"
@@ -1878,11 +2016,11 @@ msgstr "El usuario ya es miembro de este espacio de trabajo"
msgid "Video" msgid "Video"
msgstr "Video" msgstr "Video"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "Ver y gestionar tus claves API." msgstr "Ver y gestionar tus claves API."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "Ver y gestionar tu facturación y suscripción." msgstr "Ver y gestionar tu facturación y suscripción."
@@ -1914,7 +2052,7 @@ msgstr "Estamos usando la <0>licencia AGPL-3.0</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "Apenas estamos comenzando. " msgstr "Apenas estamos comenzando. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Bienvenido de nuevo" msgstr "Bienvenido de nuevo"
@@ -1934,6 +2072,7 @@ msgstr "Cuando Trello se lanzó en 2011, impresionó a todos con su simplicidad
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "¿Por qué crear un Trello de código abierto?" msgstr "¿Por qué crear un Trello de código abierto?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Espacio de trabajo" msgstr "Espacio de trabajo"
@@ -1946,7 +2085,7 @@ msgstr "Espacio de trabajo creado con éxito. Puedes actualizar más tarde en co
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Espacio de trabajo eliminado" msgstr "Espacio de trabajo eliminado"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Descripción del espacio de trabajo" msgstr "Descripción del espacio de trabajo"
@@ -1968,7 +2107,7 @@ msgid "Workspace members"
msgstr "Miembros del espacio de trabajo" msgstr "Miembros del espacio de trabajo"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Nombre del espacio de trabajo" msgstr "Nombre del espacio de trabajo"
@@ -1992,7 +2131,7 @@ msgstr "Nombre del espacio de trabajo actualizado"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Slug del espacio de trabajo actualizado" msgstr "Slug del espacio de trabajo actualizado"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "URL del espacio de trabajo" msgstr "URL del espacio de trabajo"
@@ -2012,7 +2151,7 @@ msgstr "Anual"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Sí, ofrecemos un plan gratuito para siempre para uso individual. Sin restricciones, sin muros de pago, sin límites." msgstr "Sí, ofrecemos un plan gratuito para siempre para uso individual. Sin restricciones, sin muros de pago, sin límites."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "Estás a punto de cambiar tu contraseña." msgstr "Estás a punto de cambiar tu contraseña."
@@ -2028,18 +2167,26 @@ msgstr "Puedes invitar a miembros del equipo haciendo clic en el botón \"Invita
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "Puedes autoalojar siguiendo las instrucciones en nuestro <0>repositorio</0>." msgstr "Puedes autoalojar siguiendo las instrucciones en nuestro <0>repositorio</0>."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "Has iniciado sesión correctamente." msgstr "Has iniciado sesión correctamente."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "Te has registrado correctamente." msgstr "Te has registrado correctamente."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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!" msgstr "Tienes plazas ilimitadas con tu Plan Pro. ¡No hay cargos adicionales por nuevos miembros!"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "Has sido invitado a unirte a un espacio de trabajo en kan.bn."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "Has sido invitado a unirte a un espacio de trabajo."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Tu cuenta ha sido eliminada." msgstr "Tu cuenta ha sido eliminada."
@@ -2056,15 +2203,15 @@ msgstr "Tu nombre de visualización ha sido actualizado."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Tu contraseña ha sido cambiada." msgstr "Tu contraseña ha sido cambiada."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Tu imagen de perfil ha sido actualizada." msgstr "Tu imagen de perfil ha sido actualizada."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Tu cuenta de Trello ha sido desconectada." msgstr "Tu cuenta de Trello ha sido desconectada."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Tu cuenta de Trello está conectada." msgstr "Tu cuenta de Trello está conectada."

File diff suppressed because one or more lines are too long

View File

@@ -36,12 +36,12 @@ msgstr "{0} étiquettes"
msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}" msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
msgstr "{boardCount, plural, one {Importer le tableau (1)} other {Importer les tableaux ({boardCount})}}" msgstr "{boardCount, plural, one {Importer le tableau (1)} other {Importer les tableaux ({boardCount})}}"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "10 $/mois" msgstr "10 $/mois"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "8 $/mois" msgstr "8 $/mois"
@@ -53,6 +53,10 @@ msgstr "1 utilisateur"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "Une application kanban puissante et flexible qui vous aide à organiser le travail, suivre les progrès et livrer des résultats—le tout en un seul endroit." msgstr "Une application kanban puissante et flexible qui vous aide à organiser le travail, suivre les progrès et livrer des résultats—le tout en un seul endroit."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Compte"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Compte supprimé" msgstr "Compte supprimé"
@@ -91,13 +95,13 @@ msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes ou '@' p
msgid "Add details..." msgid "Add details..."
msgstr "Ajouter des détails..." msgstr "Ajouter des détails..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Ajouter une étiquette" msgstr "Ajouter une étiquette"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Ajouter un membre" msgstr "Ajouter un membre"
@@ -132,10 +136,14 @@ msgstr "a ajouté l'élément <0>{0}</0> à la checklist"
msgid "added label <0>{0}</0>" msgid "added label <0>{0}</0>"
msgstr "a ajouté l'étiquette <0>{0}</0>" msgstr "a ajouté l'étiquette <0>{0}</0>"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "L'ajout d'un nouveau membre coûtera {price} supplémentaires ({billingType}) par siège." msgstr "L'ajout d'un nouveau membre coûtera {price} supplémentaires ({billingType}) par siège."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Ajustez le recadrage carré pour adapter votre avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Rôles d'administrateur" msgstr "Rôles d'administrateur"
@@ -144,11 +152,11 @@ msgstr "Rôles d'administrateur"
msgid "All systems operational" msgid "All systems operational"
msgstr "Tous les systèmes opérationnels" msgstr "Tous les systèmes opérationnels"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Vous avez déjà un compte ? <0><1>Connectez-vous</1></0>" msgstr "Vous avez déjà un compte ? <0><1>Connectez-vous</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "Une erreur s'est produite lors de la déconnexion de votre compte Trello." msgstr "Une erreur s'est produite lors de la déconnexion de votre compte Trello."
@@ -156,7 +164,31 @@ msgstr "Une erreur s'est produite lors de la déconnexion de votre compte Trello
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "Une erreur inattendue s'est produite. Veuillez réessayer plus tard." msgstr "Une erreur inattendue s'est produite. Veuillez réessayer plus tard."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Toute personne disposant de ce lien peut rejoindre votre espace de travail"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "Clé API créée"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "Nom de la clé API"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "Le nom de la clé API ne peut pas dépasser 30 caractères"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "Le nom de la clé API est requis"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "Clés API" msgstr "Clés API"
@@ -218,20 +250,21 @@ msgstr "Backlog"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Kanban basique" msgstr "Kanban basique"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "facturation annuelle" msgstr "facturation annuelle"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "facturation mensuelle" msgstr "facturation mensuelle"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Facturation" msgstr "Facturation"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Portail de facturation" msgstr "Portail de facturation"
@@ -286,12 +319,12 @@ msgid "Board visibility updated"
msgstr "Visibilité du tableau mise à jour" msgstr "Visibilité du tableau mise à jour"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Tableaux" msgstr "Tableaux"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Tableaux | {0}" msgstr "Tableaux | {0}"
@@ -313,6 +346,7 @@ msgstr "Rapport de bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -328,19 +362,19 @@ msgstr "Carte introuvable"
msgid "Card title" msgid "Card title"
msgstr "Titre de la carte" msgstr "Titre de la carte"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Modifier le mot de passe" msgstr "Modifier le mot de passe"
#: src/views/settings/index.tsx:227 #: src/views/settings/AccountSettings.tsx:45
msgid "Change the language of the app." msgid "Change your language preferences."
msgstr "Changer la langue de l'application." msgstr "Modifiez vos préférences linguistiques."
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Vérifiez votre boîte de réception" msgstr "Vérifiez votre boîte de réception"
@@ -352,11 +386,15 @@ msgstr "Nom de la checklist"
msgid "Clear filters" msgid "Clear filters"
msgstr "Effacer les filtres" msgstr "Effacer les filtres"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Cliquez sur le lien que nous avons envoyé à {magicLinkRecipient} pour vous connecter." msgstr "Cliquez sur le lien que nous avons envoyé à {magicLinkRecipient} pour vous connecter."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Fermer"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Revue de code" msgstr "Revue de code"
@@ -401,7 +439,7 @@ msgid "Confirm your new password"
msgstr "Confirmez votre nouveau mot de passe" msgstr "Confirmez votre nouveau mot de passe"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Connecter Trello" msgstr "Connecter Trello"
@@ -409,7 +447,7 @@ msgstr "Connecter Trello"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Connectez vos outils favoris pour simplifier votre flux de travail." msgstr "Connectez vos outils favoris pour simplifier votre flux de travail."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Connectez votre compte Trello pour importer des tableaux." msgstr "Connectez votre compte Trello pour importer des tableaux."
@@ -425,12 +463,12 @@ msgstr "Contactez-nous"
msgid "Content Creation" msgid "Content Creation"
msgstr "Création de contenu" msgstr "Création de contenu"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Continuer avec " msgstr "Continuer avec "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Continuer avec {0}" msgstr "Continuer avec {0}"
@@ -444,6 +482,10 @@ msgstr "Contrôlez qui peut voir et modifier vos tableaux."
msgid "Create another" msgid "Create another"
msgstr "Créer un autre" msgstr "Créer un autre"
#: src/views/settings/components/NewApiKeyModal.tsx:175
msgid "Create API key"
msgstr "Créer une clé API"
#: src/views/boards/components/NewBoardForm.tsx:128 #: src/views/boards/components/NewBoardForm.tsx:128
msgid "Create board" msgid "Create board"
msgstr "Créer un tableau" msgstr "Créer un tableau"
@@ -468,12 +510,12 @@ msgstr "Créer une liste"
msgid "Create new board" msgid "Create new board"
msgstr "Créer un nouveau tableau" msgstr "Créer un nouveau tableau"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Créer une nouvelle clé" msgstr "Créer une nouvelle clé"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Créer une nouvelle étiquette" msgstr "Créer une nouvelle étiquette"
@@ -494,6 +536,10 @@ msgstr "a créé la carte"
msgid "Critical" msgid "Critical"
msgstr "Critique" msgstr "Critique"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Recadrez votre avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Le mot de passe actuel est requis" msgstr "Le mot de passe actuel est requis"
@@ -527,9 +573,9 @@ msgstr "Sombre"
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Supprimer le compte" msgstr "Supprimer le compte"
@@ -550,8 +596,8 @@ msgid "Delete list"
msgstr "Supprimer la liste" msgstr "Supprimer la liste"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Supprimer l'espace de travail" msgstr "Supprimer l'espace de travail"
@@ -577,7 +623,7 @@ msgstr "a supprimé l'élément <0>{0}</0> de la checklist"
msgid "Design" msgid "Design"
msgstr "Design" msgstr "Design"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Déconnecter Trello" msgstr "Déconnecter Trello"
@@ -585,7 +631,7 @@ msgstr "Déconnecter Trello"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Discutez et collaborez sur les cartes." msgstr "Discutez et collaborez sur les cartes."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Nom d'affichage" msgstr "Nom d'affichage"
@@ -619,7 +665,7 @@ msgstr "Documentation"
msgid "Documentation" msgid "Documentation"
msgstr "Documentation" msgstr "Documentation"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "Vous n'avez pas de compte ? <0><1>Inscrivez-vous</1></0>" msgstr "Vous n'avez pas de compte ? <0><1>Inscrivez-vous</1></0>"
@@ -651,11 +697,11 @@ msgstr "Modifier l'URL de l'espace de travail"
msgid "Editing" msgid "Editing"
msgstr "Édition" msgstr "Édition"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "e-mail" msgstr "e-mail"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "E-mail" msgstr "E-mail"
@@ -671,11 +717,11 @@ msgstr "Saisissez votre mot de passe actuel"
msgid "Enter your current password and choose a new secure password." 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é." msgstr "Saisissez votre mot de passe actuel et choisissez un nouveau mot de passe sécurisé."
#: src/components/AuthForm.tsx:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Saisissez votre adresse e-mail" msgstr "Saisissez votre adresse e-mail"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Saisissez votre nom" msgstr "Saisissez votre nom"
@@ -683,14 +729,26 @@ msgstr "Saisissez votre nom"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Saisissez votre nouveau mot de passe" msgstr "Saisissez votre nouveau mot de passe"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Saisissez votre mot de passe" msgstr "Saisissez votre mot de passe"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Erreur"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Erreur lors du changement de mot de passe" msgstr "Erreur lors du changement de mot de passe"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Erreur lors de la création du lien d'invitation"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Erreur lors de la désactivation du lien d'invitation"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Erreur lors de la suppression du compte" msgstr "Erreur lors de la suppression du compte"
@@ -703,12 +761,12 @@ msgstr "Erreur lors de la suppression de l'étiquette"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Erreur lors de la suppression de l'espace de travail" msgstr "Erreur lors de la suppression de l'espace de travail"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Erreur lors de la déconnexion de Trello" msgstr "Erreur lors de la déconnexion de Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Erreur lors de l'invitation du membre" msgstr "Erreur lors de l'invitation du membre"
@@ -716,7 +774,7 @@ msgstr "Erreur lors de l'invitation du membre"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Erreur lors de la mise à jour du nom d'affichage" msgstr "Erreur lors de la mise à jour du nom d'affichage"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Erreur lors de la mise à jour de l'image de profil" msgstr "Erreur lors de la mise à jour de l'image de profil"
@@ -732,7 +790,7 @@ msgstr "Erreur lors de la mise à jour du nom de l'espace de travail"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Erreur lors de la mise à jour de l'URL de l'espace de travail" msgstr "Erreur lors de la mise à jour de l'URL de l'espace de travail"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Erreur lors de la mise à niveau de l'abonnement" msgstr "Erreur lors de la mise à niveau de l'abonnement"
@@ -741,8 +799,8 @@ msgstr "Erreur lors de la mise à niveau de l'abonnement"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Erreur lors de la mise à niveau vers Pro" msgstr "Erreur lors de la mise à niveau vers Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Erreur lors du téléchargement de l'image de profil" msgstr "Erreur lors du téléchargement de l'image de profil"
@@ -758,8 +816,16 @@ msgstr "Tout ce dont vous avez besoin, gratuit pour toujours. Tableaux illimité
msgid "Execution" msgid "Execution"
msgstr "Exécution" msgstr "Exécution"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "Échec de l'acceptation de l'invitation. Veuillez réessayer plus tard ou contacter le service client."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "Échec de la copie du lien d'invitation"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Échec de connexion avec {0}. Veuillez réessayer." msgstr "Échec de connexion avec {0}. Veuillez réessayer."
@@ -807,7 +873,7 @@ msgstr "Pour une durabilité à long terme, nous reconnaissons que tous les bons
msgid "Free" msgid "Free"
msgstr "Gratuit" msgstr "Gratuit"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Forfait gratuit" msgstr "Forfait gratuit"
@@ -824,7 +890,7 @@ msgstr "Temps plein"
msgid "Fun" msgid "Fun"
msgstr "Amusant" msgstr "Amusant"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -864,8 +930,13 @@ msgstr "Premiers pas"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Aller à l'accueil"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Accéder à l'application" msgstr "Accéder à l'application"
@@ -917,7 +988,7 @@ msgstr "Idées"
msgid "Ideas to improve this page..." msgid "Ideas to improve this page..."
msgstr "Idées pour améliorer cette page..." msgstr "Idées pour améliorer cette page..."
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Importer" msgstr "Importer"
@@ -955,6 +1026,7 @@ msgstr "En cours"
msgid "Individuals" msgid "Individuals"
msgstr "Particuliers" msgstr "Particuliers"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Intégrations" msgstr "Intégrations"
@@ -963,27 +1035,44 @@ msgstr "Intégrations"
msgid "Interviewing" msgid "Interviewing"
msgstr "Entretien" msgstr "Entretien"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Adresse e-mail invalide" msgstr "Adresse e-mail invalide"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Invitation non valide"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Inviter" msgstr "Inviter"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:190
msgid "Invite another" msgid "Invite link copied"
msgstr "Inviter un autre" msgstr "Lien d'invitation copié"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:191
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied to clipboard"
msgstr "Lien d'invitation copié dans le presse-papiers"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Inviter un membre" msgstr "Inviter un membre"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "L'invitation de membres nécessite un forfait d'équipe. Vous serez redirigé pour mettre à niveau votre espace de travail." msgstr "L'invitation de membres nécessite un forfait d'équipe. Vous serez redirigé pour mettre à niveau votre espace de travail."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Rejoindre l'espace de travail"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Rejoindre l'espace de travail | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1011,7 +1100,7 @@ msgstr "Étiquettes"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Étiquettes & filtres" msgstr "Étiquettes & filtres"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Langue" msgstr "Langue"
@@ -1056,7 +1145,7 @@ msgstr "Liste"
msgid "List name" msgid "List name"
msgstr "Nom de la liste" msgstr "Nom de la liste"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Connexion | kan.bn" msgstr "Connexion | kan.bn"
@@ -1072,7 +1161,7 @@ msgstr "Long terme"
msgid "Low Priority" msgid "Low Priority"
msgstr "Priorité basse" msgstr "Priorité basse"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "lien magique" msgstr "lien magique"
@@ -1106,7 +1195,7 @@ msgstr "Membres | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Mensuel" msgstr "Mensuel"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "facturation mensuelle" msgstr "facturation mensuelle"
@@ -1129,10 +1218,14 @@ msgstr "Nom"
msgid "Need help?" msgid "Need help?"
msgstr "Besoin d'aide ?" msgstr "Besoin d'aide ?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "Nouveau" msgstr "Nouveau"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "Nouvelle clé API"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "Nouveau tableau" msgstr "Nouveau tableau"
@@ -1206,15 +1299,15 @@ msgstr "Offre"
msgid "Onboarding" msgid "Onboarding"
msgstr "Intégration" msgstr "Intégration"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Une fois que vous supprimez votre compte, il n'y a pas de retour possible. Cette action ne peut pas être annulée." msgstr "Une fois que vous supprimez votre compte, il n'y a pas de retour possible. Cette action ne peut pas être annulée."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Une fois que vous supprimez votre espace de travail, il n'y a pas de retour possible. Cette action ne peut pas être annulée." msgstr "Une fois que vous supprimez votre espace de travail, il n'y a pas de retour possible. Cette action ne peut pas être annulée."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "ou" msgstr "ou"
@@ -1242,6 +1335,10 @@ msgstr "Le mot de passe doit comporter au moins 8 caractères"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Les mots de passe ne correspondent pas" msgstr "Les mots de passe ne correspondent pas"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "En pause"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Fréquence de paiement" msgstr "Fréquence de paiement"
@@ -1267,19 +1364,19 @@ msgstr "Planification"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Veuillez confirmer votre nouveau mot de passe" msgstr "Veuillez confirmer votre nouveau mot de passe"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Veuillez saisir une adresse e-mail valide" msgstr "Veuillez saisir une adresse e-mail valide"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Veuillez saisir un nom valide" msgstr "Veuillez saisir un nom valide"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Veuillez saisir un mot de passe valide" msgstr "Veuillez saisir un mot de passe valide"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Veuillez sélectionner un fichier à télécharger." msgstr "Veuillez sélectionner un fichier à télécharger."
@@ -1300,18 +1397,18 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1322,6 +1419,11 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Veuillez réessayer plus tard ou contacter le service client." msgstr "Veuillez réessayer plus tard ou contacter le service client."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Veuillez réessayer plus tard."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1345,15 +1447,15 @@ msgstr "Privé"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Plan Pro" msgstr "Plan Pro"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Plan Pro ∞" msgstr "Plan Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Image de profil mise à jour" msgstr "Image de profil mise à jour"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Photo de profil" msgstr "Photo de profil"
@@ -1436,10 +1538,6 @@ msgstr "Ressources"
msgid "Review" msgid "Review"
msgstr "Révision" msgstr "Révision"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke"
msgstr "Révoquer"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
msgid "Roadmap" msgid "Roadmap"
@@ -1454,6 +1552,7 @@ msgid "Run on your own infrastructure"
msgstr "Exécutez sur votre propre infrastructure" msgstr "Exécutez sur votre propre infrastructure"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Enregistrer" msgstr "Enregistrer"
@@ -1493,35 +1592,62 @@ msgstr "Envoyer des commentaires"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Paramètres" msgstr "Paramètres"
#. placeholder {0}: workspace.name ?? "Workspace" #: src/views/settings/AccountSettings.tsx:25
#: src/views/settings/index.tsx:161 msgid "Settings | Account"
msgid "Settings | {0}" msgstr "Paramètres | Compte"
msgstr "Paramètres | {0}"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Paramètres | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Paramètres | Facturation"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Paramètres | Intégrations"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Paramètres | Espace de travail"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Partager le lien d'invitation"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Se connecter" msgstr "Se connecter"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Se connecter"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "S'inscrire"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Inscription | kan.bn" msgstr "Inscription | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Inscription désactivée" msgstr "Inscription désactivée"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." msgid "Sign up is currently disabled. Please try again later."
msgstr "L'inscription est actuellement désactivée. Veuillez réessayer plus tard." msgstr "L'inscription est actuellement désactivée. Veuillez réessayer plus tard."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "S'inscrire avec " msgstr "S'inscrire avec "
@@ -1545,8 +1671,8 @@ msgstr "Développement logiciel"
msgid "Star on Github" msgid "Star on Github"
msgstr "Étoile sur Github" msgstr "Étoile sur Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Succès" msgstr "Succès"
@@ -1566,7 +1692,7 @@ msgstr "Soutenir le développement du projet"
msgid "System" msgid "System"
msgstr "Système" msgstr "Système"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Forfait d'équipe" msgstr "Forfait d'équipe"
@@ -1619,6 +1745,10 @@ msgstr "Ils ne pourront plus accéder à cet espace de travail."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "Cette action ne peut pas être annulée." msgstr "Cette action ne peut pas être annulée."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "Ce tableau est privé ou n'existe pas" msgstr "Ce tableau est privé ou n'existe pas"
@@ -1627,6 +1757,10 @@ msgstr "Ce tableau est privé ou n'existe pas"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "Cette URL de tableau est déjà utilisée" msgstr "Cette URL de tableau est déjà utilisée"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "Ce lien d'invitation est invalide ou a expiré."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "Cela entraînera la suppression définitive de toutes les données associées à cet espace de travail." msgstr "Cela entraînera la suppression définitive de toutes les données associées à cet espace de travail."
@@ -1660,7 +1794,11 @@ msgstr "Basculer le menu"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Suivez tous les changements de cartes avec un historique d'activité détaillé." msgstr "Suivez tous les changements de cartes avec un historique d'activité détaillé."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello déconnecté" msgstr "Trello déconnecté"
@@ -1745,16 +1883,16 @@ msgstr "Impossible de mettre à jour l'élément de la liste de contrôle"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "Impossible de mettre à jour le commentaire" msgstr "Impossible de mettre à jour le commentaire"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "Impossible de mettre à jour les étiquettes" msgstr "Impossible de mettre à jour les étiquettes"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "Impossible de mettre à jour la liste" msgstr "Impossible de mettre à jour la liste"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "Impossible de mettre à jour les membres" msgstr "Impossible de mettre à jour les membres"
@@ -1797,9 +1935,9 @@ msgid "Unlimited members"
msgstr "Membres illimités" msgstr "Membres illimités"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Mettre à jour" msgstr "Mettre à jour"
@@ -1830,7 +1968,7 @@ msgid "Upgrade"
msgstr "Mettre à niveau" msgstr "Mettre à niveau"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Passer à Pro" msgstr "Passer à Pro"
@@ -1838,7 +1976,7 @@ msgstr "Passer à Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Passer à Pro (29 $/mois)" msgstr "Passer à Pro (29 $/mois)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Passer au forfait d'équipe" msgstr "Passer au forfait d'équipe"
@@ -1870,7 +2008,7 @@ msgstr "Utiliser le modèle"
msgid "User" msgid "User"
msgstr "Utilisateur" msgstr "Utilisateur"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "L'utilisateur est déjà membre de cet espace de travail" msgstr "L'utilisateur est déjà membre de cet espace de travail"
@@ -1878,11 +2016,11 @@ msgstr "L'utilisateur est déjà membre de cet espace de travail"
msgid "Video" msgid "Video"
msgstr "Vidéo" msgstr "Vidéo"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "Consultez et gérez vos clés API." msgstr "Consultez et gérez vos clés API."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "Consultez et gérez votre facturation et votre abonnement." msgstr "Consultez et gérez votre facturation et votre abonnement."
@@ -1914,7 +2052,7 @@ msgstr "Nous utilisons la <0>licence AGPL-3.0</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "Nous ne faisons que commencer. " msgstr "Nous ne faisons que commencer. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Bienvenue à nouveau" msgstr "Bienvenue à nouveau"
@@ -1934,6 +2072,7 @@ msgstr "Quand Trello a été lancé en 2011, il a impressionné tout le monde pa
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "Pourquoi créer un Trello open source ?" msgstr "Pourquoi créer un Trello open source ?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Espace de travail" msgstr "Espace de travail"
@@ -1946,7 +2085,7 @@ msgstr "Espace de travail créé avec succès. Vous pourrez effectuer la mise à
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Espace de travail supprimé" msgstr "Espace de travail supprimé"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Description de l'espace de travail" msgstr "Description de l'espace de travail"
@@ -1968,7 +2107,7 @@ msgid "Workspace members"
msgstr "Membres de l'espace de travail" msgstr "Membres de l'espace de travail"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Nom de l'espace de travail" msgstr "Nom de l'espace de travail"
@@ -1992,7 +2131,7 @@ msgstr "Nom de l'espace de travail mis à jour"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Slug de l'espace de travail mis à jour" msgstr "Slug de l'espace de travail mis à jour"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "URL de l'espace de travail" msgstr "URL de l'espace de travail"
@@ -2012,7 +2151,7 @@ msgstr "Annuel"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Oui, nous proposons un plan gratuit à vie pour un usage individuel. Aucune restriction, aucun paywall, aucune limite." msgstr "Oui, nous proposons un plan gratuit à vie pour un usage individuel. Aucune restriction, aucun paywall, aucune limite."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "Vous êtes sur le point de modifier votre mot de passe." msgstr "Vous êtes sur le point de modifier votre mot de passe."
@@ -2028,18 +2167,26 @@ msgstr "Vous pouvez inviter des membres de l'équipe en cliquant sur le bouton \
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "Vous pouvez auto-héberger en suivant les instructions dans notre <0>dépôt</0>." msgstr "Vous pouvez auto-héberger en suivant les instructions dans notre <0>dépôt</0>."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "Vous vous êtes connecté avec succès." msgstr "Vous vous êtes connecté avec succès."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "Vous vous êtes inscrit avec succès." msgstr "Vous vous êtes inscrit avec succès."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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 !" msgstr "Vous disposez de places illimitées avec votre Plan Pro. Il n'y a pas de frais supplémentaires pour les nouveaux membres !"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "Vous avez été invité à rejoindre un espace de travail sur kan.bn."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "Vous avez été invité à rejoindre un espace de travail."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Votre compte a été supprimé." msgstr "Votre compte a été supprimé."
@@ -2056,15 +2203,15 @@ msgstr "Votre nom d'affichage a été mis à jour."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Votre mot de passe a été modifié." msgstr "Votre mot de passe a été modifié."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Votre image de profil a été mise à jour." msgstr "Votre image de profil a été mise à jour."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Votre compte Trello a été déconnecté." msgstr "Votre compte Trello a été déconnecté."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Votre compte Trello est connecté." msgstr "Votre compte Trello est connecté."

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
export const locales = ["en", "fr", "de", "es", "it", "nl"] as const; export const locales = ["en", "fr", "de", "es", "it", "nl", "ru"] as const;
export type Locale = (typeof locales)[number]; export type Locale = (typeof locales)[number];
@@ -11,4 +11,5 @@ export const localeNames: Record<Locale, string> = {
es: "Español", es: "Español",
it: "Italiano", it: "Italiano",
nl: "Nederlands", nl: "Nederlands",
ru: "Русский",
}; };

View File

@@ -36,12 +36,12 @@ msgstr "{0} etichette"
msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}" msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
msgstr "{boardCount, plural, one {Importa bacheca (1)} other {Importa bacheche ({boardCount})}}" msgstr "{boardCount, plural, one {Importa bacheca (1)} other {Importa bacheche ({boardCount})}}"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "$10/mese" msgstr "$10/mese"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "$8/mese" msgstr "$8/mese"
@@ -53,6 +53,10 @@ msgstr "1 utente"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "Un'app kanban potente e flessibile che ti aiuta a organizzare il lavoro, monitorare i progressi e ottenere risultati, tutto in un unico posto." msgstr "Un'app kanban potente e flessibile che ti aiuta a organizzare il lavoro, monitorare i progressi e ottenere risultati, tutto in un unico posto."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Account"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Account eliminato" msgstr "Account eliminato"
@@ -91,13 +95,13 @@ msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi o '@' per menzi
msgid "Add details..." msgid "Add details..."
msgstr "Aggiungi dettagli..." msgstr "Aggiungi dettagli..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Aggiungi etichetta" msgstr "Aggiungi etichetta"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Aggiungi membro" msgstr "Aggiungi membro"
@@ -132,10 +136,14 @@ msgstr "ha aggiunto l'elemento <0>{0}</0> alla checklist"
msgid "added label <0>{0}</0>" msgid "added label <0>{0}</0>"
msgstr "ha aggiunto l'etichetta <0>{0}</0>" msgstr "ha aggiunto l'etichetta <0>{0}</0>"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "L'aggiunta di un nuovo membro costerà un supplemento di {price} ({billingType}) per posto." msgstr "L'aggiunta di un nuovo membro costerà un supplemento di {price} ({billingType}) per posto."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Regola il ritaglio quadrato per adattarlo al tuo avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Ruoli amministratore" msgstr "Ruoli amministratore"
@@ -144,11 +152,11 @@ msgstr "Ruoli amministratore"
msgid "All systems operational" msgid "All systems operational"
msgstr "Tutti i sistemi operativi" msgstr "Tutti i sistemi operativi"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Hai già un account? <0><1>Accedi</1></0>" msgstr "Hai già un account? <0><1>Accedi</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "Si è verificato un errore durante la disconnessione del tuo account Trello." msgstr "Si è verificato un errore durante la disconnessione del tuo account Trello."
@@ -156,7 +164,31 @@ msgstr "Si è verificato un errore durante la disconnessione del tuo account Tre
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "Si è verificato un errore imprevisto. Riprova più tardi." msgstr "Si è verificato un errore imprevisto. Riprova più tardi."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Chiunque abbia questo link può unirsi al tuo spazio di lavoro"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "Chiave API creata"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "Nome chiave API"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "Il nome della chiave API non può superare i 30 caratteri"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "Il nome della chiave API è obbligatorio"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "Chiavi API" msgstr "Chiavi API"
@@ -218,20 +250,21 @@ msgstr "Backlog"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Kanban base" msgstr "Kanban base"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "fatturato annualmente" msgstr "fatturato annualmente"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "fatturato mensilmente" msgstr "fatturato mensilmente"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Fatturazione" msgstr "Fatturazione"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Portale di fatturazione" msgstr "Portale di fatturazione"
@@ -286,12 +319,12 @@ msgid "Board visibility updated"
msgstr "Visibilità della bacheca aggiornata" msgstr "Visibilità della bacheca aggiornata"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Bacheche" msgstr "Bacheche"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Bacheche | {0}" msgstr "Bacheche | {0}"
@@ -313,6 +346,7 @@ msgstr "Segnalazione bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -328,19 +362,19 @@ msgstr "Carta non trovata"
msgid "Card title" msgid "Card title"
msgstr "Titolo della carta" msgstr "Titolo della carta"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Cambia password" msgstr "Cambia password"
#: src/views/settings/index.tsx:227 #: src/views/settings/AccountSettings.tsx:45
msgid "Change the language of the app." msgid "Change your language preferences."
msgstr "Cambia la lingua dell'app." msgstr "Modifica le tue preferenze di lingua."
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Controlla la tua casella di posta" msgstr "Controlla la tua casella di posta"
@@ -352,11 +386,15 @@ msgstr "Nome della checklist"
msgid "Clear filters" msgid "Clear filters"
msgstr "Cancella filtri" msgstr "Cancella filtri"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Clicca sul link che abbiamo inviato a {magicLinkRecipient} per accedere." msgstr "Clicca sul link che abbiamo inviato a {magicLinkRecipient} per accedere."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Chiudi"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Revisione del codice" msgstr "Revisione del codice"
@@ -401,7 +439,7 @@ msgid "Confirm your new password"
msgstr "Conferma la tua nuova password" msgstr "Conferma la tua nuova password"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Connetti Trello" msgstr "Connetti Trello"
@@ -409,7 +447,7 @@ msgstr "Connetti Trello"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Connetti i tuoi strumenti preferiti per semplificare il tuo flusso di lavoro." msgstr "Connetti i tuoi strumenti preferiti per semplificare il tuo flusso di lavoro."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Connetti il tuo account Trello per importare le bacheche." msgstr "Connetti il tuo account Trello per importare le bacheche."
@@ -425,12 +463,12 @@ msgstr "Contattaci"
msgid "Content Creation" msgid "Content Creation"
msgstr "Creazione contenuti" msgstr "Creazione contenuti"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Continua con " msgstr "Continua con "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Continua con {0}" msgstr "Continua con {0}"
@@ -444,6 +482,10 @@ msgstr "Controlla chi può visualizzare e modificare le tue bacheche."
msgid "Create another" msgid "Create another"
msgstr "Crea un altro" msgstr "Crea un altro"
#: src/views/settings/components/NewApiKeyModal.tsx:175
msgid "Create API key"
msgstr "Crea chiave API"
#: src/views/boards/components/NewBoardForm.tsx:128 #: src/views/boards/components/NewBoardForm.tsx:128
msgid "Create board" msgid "Create board"
msgstr "Crea bacheca" msgstr "Crea bacheca"
@@ -468,12 +510,12 @@ msgstr "Crea lista"
msgid "Create new board" msgid "Create new board"
msgstr "Crea nuova bacheca" msgstr "Crea nuova bacheca"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Crea nuova chiave" msgstr "Crea nuova chiave"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Crea nuova etichetta" msgstr "Crea nuova etichetta"
@@ -494,6 +536,10 @@ msgstr "ha creato la carta"
msgid "Critical" msgid "Critical"
msgstr "Critico" msgstr "Critico"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Ritaglia il tuo avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "La password attuale è obbligatoria" msgstr "La password attuale è obbligatoria"
@@ -527,9 +573,9 @@ msgstr "Scuro"
msgid "Delete" msgid "Delete"
msgstr "Elimina" msgstr "Elimina"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Elimina account" msgstr "Elimina account"
@@ -550,8 +596,8 @@ msgid "Delete list"
msgstr "Elimina lista" msgstr "Elimina lista"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Elimina spazio di lavoro" msgstr "Elimina spazio di lavoro"
@@ -577,7 +623,7 @@ msgstr "ha eliminato l'elemento <0>{0}</0> della checklist"
msgid "Design" msgid "Design"
msgstr "Design" msgstr "Design"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Disconnetti Trello" msgstr "Disconnetti Trello"
@@ -585,7 +631,7 @@ msgstr "Disconnetti Trello"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Discuti e collabora sulle schede." msgstr "Discuti e collabora sulle schede."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Nome visualizzato" msgstr "Nome visualizzato"
@@ -619,7 +665,7 @@ msgstr "Documenti"
msgid "Documentation" msgid "Documentation"
msgstr "Documentazione" msgstr "Documentazione"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "Non hai un account? <0><1>Registrati</1></0>" msgstr "Non hai un account? <0><1>Registrati</1></0>"
@@ -651,11 +697,11 @@ msgstr "Modifica URL dell'area di lavoro"
msgid "Editing" msgid "Editing"
msgstr "Modifica" msgstr "Modifica"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "email" msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
@@ -671,11 +717,11 @@ msgstr "Inserisci la tua password attuale"
msgid "Enter your current password and choose a new secure password." msgid "Enter your current password and choose a new secure password."
msgstr "Inserisci la tua password attuale e scegli una nuova password sicura." msgstr "Inserisci la tua password attuale e scegli una nuova password sicura."
#: src/components/AuthForm.tsx:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Inserisci il tuo indirizzo email" msgstr "Inserisci il tuo indirizzo email"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Inserisci il tuo nome" msgstr "Inserisci il tuo nome"
@@ -683,14 +729,26 @@ msgstr "Inserisci il tuo nome"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Inserisci la tua nuova password" msgstr "Inserisci la tua nuova password"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Inserisci la tua password" msgstr "Inserisci la tua password"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Errore"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Errore durante il cambio della password" msgstr "Errore durante il cambio della password"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Errore durante la creazione del link di invito"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Errore durante la disattivazione del link di invito"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Errore durante l'eliminazione dell'account" msgstr "Errore durante l'eliminazione dell'account"
@@ -703,12 +761,12 @@ msgstr "Errore durante l'eliminazione dell'etichetta"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Errore durante l'eliminazione dell'area di lavoro" msgstr "Errore durante l'eliminazione dell'area di lavoro"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Errore durante la disconnessione da Trello" msgstr "Errore durante la disconnessione da Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Errore durante l'invito del membro" msgstr "Errore durante l'invito del membro"
@@ -716,7 +774,7 @@ msgstr "Errore durante l'invito del membro"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Errore durante l'aggiornamento del nome visualizzato" msgstr "Errore durante l'aggiornamento del nome visualizzato"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Errore durante l'aggiornamento dell'immagine del profilo" msgstr "Errore durante l'aggiornamento dell'immagine del profilo"
@@ -732,7 +790,7 @@ msgstr "Errore durante l'aggiornamento del nome dell'area di lavoro"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Errore durante l'aggiornamento dell'URL dell'area di lavoro" msgstr "Errore durante l'aggiornamento dell'URL dell'area di lavoro"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Errore nell'aggiornamento dell'abbonamento" msgstr "Errore nell'aggiornamento dell'abbonamento"
@@ -741,8 +799,8 @@ msgstr "Errore nell'aggiornamento dell'abbonamento"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Errore durante l'aggiornamento a Pro" msgstr "Errore durante l'aggiornamento a Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Errore durante il caricamento dell'immagine del profilo" msgstr "Errore durante il caricamento dell'immagine del profilo"
@@ -758,8 +816,16 @@ msgstr "Tutto ciò di cui hai bisogno, gratis per sempre. Bacheche illimitate, l
msgid "Execution" msgid "Execution"
msgstr "Esecuzione" msgstr "Esecuzione"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "Impossibile accettare l'invito. Riprova più tardi o contatta l'assistenza clienti."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "Impossibile copiare il link di invito"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Accesso con {0} fallito. Riprova." msgstr "Accesso con {0} fallito. Riprova."
@@ -807,7 +873,7 @@ msgstr "Per la sostenibilità a lungo termine, riconosciamo che tutti i buoni pr
msgid "Free" msgid "Free"
msgstr "Gratuito" msgstr "Gratuito"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Piano gratuito" msgstr "Piano gratuito"
@@ -824,7 +890,7 @@ msgstr "Tempo pieno"
msgid "Fun" msgid "Fun"
msgstr "Divertimento" msgstr "Divertimento"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -864,8 +930,13 @@ msgstr "Primi passi"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Vai alla home"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Vai all'app" msgstr "Vai all'app"
@@ -917,7 +988,7 @@ msgstr "Idee"
msgid "Ideas to improve this page..." msgid "Ideas to improve this page..."
msgstr "Idee per migliorare questa pagina..." msgstr "Idee per migliorare questa pagina..."
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Importa" msgstr "Importa"
@@ -955,6 +1026,7 @@ msgstr "In corso"
msgid "Individuals" msgid "Individuals"
msgstr "Privati" msgstr "Privati"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Integrazioni" msgstr "Integrazioni"
@@ -963,27 +1035,44 @@ msgstr "Integrazioni"
msgid "Interviewing" msgid "Interviewing"
msgstr "Colloquio" msgstr "Colloquio"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Indirizzo email non valido" msgstr "Indirizzo email non valido"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Invito non valido"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Invita" msgstr "Invita"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:190
msgid "Invite another" msgid "Invite link copied"
msgstr "Invita un altro" msgstr "Link di invito copiato"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:191
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied to clipboard"
msgstr "Link di invito copiato negli appunti"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Invita membro" msgstr "Invita membro"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "L'invito di membri richiede un Piano Team. Sarai reindirizzato per aggiornare il tuo spazio di lavoro." msgstr "L'invito di membri richiede un Piano Team. Sarai reindirizzato per aggiornare il tuo spazio di lavoro."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Unisciti allo spazio di lavoro"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Unisciti allo spazio di lavoro | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1011,7 +1100,7 @@ msgstr "Etichette"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Etichette & Filtri" msgstr "Etichette & Filtri"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Lingua" msgstr "Lingua"
@@ -1056,7 +1145,7 @@ msgstr "Lista"
msgid "List name" msgid "List name"
msgstr "Nome lista" msgstr "Nome lista"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Login | kan.bn" msgstr "Login | kan.bn"
@@ -1072,7 +1161,7 @@ msgstr "A lungo termine"
msgid "Low Priority" msgid "Low Priority"
msgstr "Bassa priorità" msgstr "Bassa priorità"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "link magico" msgstr "link magico"
@@ -1106,7 +1195,7 @@ msgstr "Membri | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Mensile" msgstr "Mensile"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "fatturazione mensile" msgstr "fatturazione mensile"
@@ -1129,10 +1218,14 @@ msgstr "Nome"
msgid "Need help?" msgid "Need help?"
msgstr "Hai bisogno di aiuto?" msgstr "Hai bisogno di aiuto?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "Nuovo" msgstr "Nuovo"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "Nuova chiave API"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "Nuova bacheca" msgstr "Nuova bacheca"
@@ -1206,15 +1299,15 @@ msgstr "Offerta"
msgid "Onboarding" msgid "Onboarding"
msgstr "Inserimento" msgstr "Inserimento"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Una volta eliminato il tuo account, non si può tornare indietro. Questa azione non può essere annullata." msgstr "Una volta eliminato il tuo account, non si può tornare indietro. Questa azione non può essere annullata."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Una volta eliminata l'area di lavoro, non si può tornare indietro. Questa azione non può essere annullata." msgstr "Una volta eliminata l'area di lavoro, non si può tornare indietro. Questa azione non può essere annullata."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "o" msgstr "o"
@@ -1242,6 +1335,10 @@ msgstr "La password deve contenere almeno 8 caratteri"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Le password non corrispondono" msgstr "Le password non corrispondono"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "In pausa"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Frequenza di pagamento" msgstr "Frequenza di pagamento"
@@ -1267,19 +1364,19 @@ msgstr "Pianificazione"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Conferma la tua nuova password" msgstr "Conferma la tua nuova password"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Inserisci un indirizzo email valido" msgstr "Inserisci un indirizzo email valido"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Inserisci un nome valido" msgstr "Inserisci un nome valido"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Inserisci una password valida" msgstr "Inserisci una password valida"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Seleziona un file da caricare." msgstr "Seleziona un file da caricare."
@@ -1300,18 +1397,18 @@ msgstr "Seleziona un file da caricare."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1322,6 +1419,11 @@ msgstr "Seleziona un file da caricare."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Riprova più tardi o contatta l'assistenza clienti." msgstr "Riprova più tardi o contatta l'assistenza clienti."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Riprova più tardi."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1345,15 +1447,15 @@ msgstr "Privato"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Piano Pro" msgstr "Piano Pro"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Piano Pro ∞" msgstr "Piano Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Immagine del profilo aggiornata" msgstr "Immagine del profilo aggiornata"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Immagine del profilo" msgstr "Immagine del profilo"
@@ -1436,10 +1538,6 @@ msgstr "Risorse"
msgid "Review" msgid "Review"
msgstr "Revisione" msgstr "Revisione"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke"
msgstr "Revoca"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
msgid "Roadmap" msgid "Roadmap"
@@ -1454,6 +1552,7 @@ msgid "Run on your own infrastructure"
msgstr "Esegui sulla tua infrastruttura" msgstr "Esegui sulla tua infrastruttura"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Salva" msgstr "Salva"
@@ -1493,35 +1592,62 @@ msgstr "Invia feedback"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Impostazioni" msgstr "Impostazioni"
#. placeholder {0}: workspace.name ?? "Workspace" #: src/views/settings/AccountSettings.tsx:25
#: src/views/settings/index.tsx:161 msgid "Settings | Account"
msgid "Settings | {0}" msgstr "Impostazioni | Account"
msgstr "Impostazioni | {0}"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Impostazioni | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Impostazioni | Fatturazione"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Impostazioni | Integrazioni"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Impostazioni | Area di lavoro"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Condividi link di invito"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Accedi" msgstr "Accedi"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Accedi"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "Registrati"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Registrati | kan.bn" msgstr "Registrati | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Registrazione disabilitata" msgstr "Registrazione disabilitata"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." msgid "Sign up is currently disabled. Please try again later."
msgstr "La registrazione è attualmente disabilitata. Riprova più tardi." msgstr "La registrazione è attualmente disabilitata. Riprova più tardi."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "Registrati con " msgstr "Registrati con "
@@ -1545,8 +1671,8 @@ msgstr "Sviluppo software"
msgid "Star on Github" msgid "Star on Github"
msgstr "Metti una stella su Github" msgstr "Metti una stella su Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Operazione riuscita" msgstr "Operazione riuscita"
@@ -1566,7 +1692,7 @@ msgstr "Sostieni lo sviluppo del progetto"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Piano Team" msgstr "Piano Team"
@@ -1619,6 +1745,10 @@ msgstr "Non potranno accedere a questo spazio di lavoro."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "Questa azione non può essere annullata." msgstr "Questa azione non può essere annullata."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "Questa bacheca è privata o non esiste" msgstr "Questa bacheca è privata o non esiste"
@@ -1627,6 +1757,10 @@ msgstr "Questa bacheca è privata o non esiste"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "Questo URL della bacheca è già stato utilizzato" msgstr "Questo URL della bacheca è già stato utilizzato"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "Questo link di invito non è valido o è scaduto."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "Questo comporterà l'eliminazione permanente di tutti i dati associati a questo spazio di lavoro." msgstr "Questo comporterà l'eliminazione permanente di tutti i dati associati a questo spazio di lavoro."
@@ -1660,7 +1794,11 @@ msgstr "Attiva/disattiva menu"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Tieni traccia di tutte le modifiche alle schede con una cronologia dettagliata delle attività." msgstr "Tieni traccia di tutte le modifiche alle schede con una cronologia dettagliata delle attività."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello disconnesso" msgstr "Trello disconnesso"
@@ -1745,16 +1883,16 @@ msgstr "Impossibile aggiornare l'elemento della checklist"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "Impossibile aggiornare il commento" msgstr "Impossibile aggiornare il commento"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "Impossibile aggiornare le etichette" msgstr "Impossibile aggiornare le etichette"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "Impossibile aggiornare la lista" msgstr "Impossibile aggiornare la lista"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "Impossibile aggiornare i membri" msgstr "Impossibile aggiornare i membri"
@@ -1797,9 +1935,9 @@ msgid "Unlimited members"
msgstr "Membri illimitati" msgstr "Membri illimitati"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Aggiorna" msgstr "Aggiorna"
@@ -1830,7 +1968,7 @@ msgid "Upgrade"
msgstr "Aggiorna" msgstr "Aggiorna"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Passa a Pro" msgstr "Passa a Pro"
@@ -1838,7 +1976,7 @@ msgstr "Passa a Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Passa a Pro ($29/mese)" msgstr "Passa a Pro ($29/mese)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Passa al Piano Team" msgstr "Passa al Piano Team"
@@ -1870,7 +2008,7 @@ msgstr "Usa template"
msgid "User" msgid "User"
msgstr "Utente" msgstr "Utente"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "L'utente è già membro di questo spazio di lavoro" msgstr "L'utente è già membro di questo spazio di lavoro"
@@ -1878,11 +2016,11 @@ msgstr "L'utente è già membro di questo spazio di lavoro"
msgid "Video" msgid "Video"
msgstr "Video" msgstr "Video"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "Visualizza e gestisci le tue chiavi API." msgstr "Visualizza e gestisci le tue chiavi API."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "Visualizza e gestisci la tua fatturazione e abbonamento." msgstr "Visualizza e gestisci la tua fatturazione e abbonamento."
@@ -1914,7 +2052,7 @@ msgstr "Utilizziamo la <0>licenza AGPL-3.0</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "Siamo solo all'inizio. " msgstr "Siamo solo all'inizio. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Bentornato" msgstr "Bentornato"
@@ -1934,6 +2072,7 @@ msgstr "Quando Trello fu lanciato nel 2011, stupì tutti con la sua semplicità
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "Perché creare un Trello open source?" msgstr "Perché creare un Trello open source?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Spazio di lavoro" msgstr "Spazio di lavoro"
@@ -1946,7 +2085,7 @@ msgstr "Spazio di lavoro creato con successo. Puoi effettuare l'aggiornamento pi
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Spazio di lavoro eliminato" msgstr "Spazio di lavoro eliminato"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Descrizione dello spazio di lavoro" msgstr "Descrizione dello spazio di lavoro"
@@ -1968,7 +2107,7 @@ msgid "Workspace members"
msgstr "Membri del workspace" msgstr "Membri del workspace"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Nome dello spazio di lavoro" msgstr "Nome dello spazio di lavoro"
@@ -1992,7 +2131,7 @@ msgstr "Nome dello spazio di lavoro aggiornato"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Slug dell'area di lavoro aggiornato" msgstr "Slug dell'area di lavoro aggiornato"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "URL dello spazio di lavoro" msgstr "URL dello spazio di lavoro"
@@ -2012,7 +2151,7 @@ msgstr "Annuale"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Sì, offriamo un piano gratuito per sempre per uso individuale. Nessuna restrizione, nessun paywall, nessun limite." msgstr "Sì, offriamo un piano gratuito per sempre per uso individuale. Nessuna restrizione, nessun paywall, nessun limite."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "Stai per cambiare la tua password." msgstr "Stai per cambiare la tua password."
@@ -2028,18 +2167,26 @@ msgstr "Puoi invitare i membri del team cliccando sul pulsante \"Invita\" nell'a
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "Puoi effettuare il self-hosting seguendo le istruzioni nel nostro <0>repo</0>." msgstr "Puoi effettuare il self-hosting seguendo le istruzioni nel nostro <0>repo</0>."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "Hai effettuato l'accesso con successo." msgstr "Hai effettuato l'accesso con successo."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "Ti sei registrato con successo." msgstr "Ti sei registrato con successo."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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!" msgstr "Hai posti illimitati con il tuo Piano Pro. Non ci sono costi aggiuntivi per i nuovi membri!"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "Sei stato invitato a unirti a uno spazio di lavoro su kan.bn."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "Sei stato invitato a unirti a uno spazio di lavoro."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Il tuo account è stato eliminato." msgstr "Il tuo account è stato eliminato."
@@ -2056,15 +2203,15 @@ msgstr "Il tuo nome visualizzato è stato aggiornato."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "La tua password è stata modificata." msgstr "La tua password è stata modificata."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "La tua immagine del profilo è stata aggiornata." msgstr "La tua immagine del profilo è stata aggiornata."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Il tuo account Trello è stato disconnesso." msgstr "Il tuo account Trello è stato disconnesso."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Il tuo account Trello è connesso." msgstr "Il tuo account Trello è connesso."

File diff suppressed because one or more lines are too long

View File

@@ -36,12 +36,12 @@ msgstr "{0} labels"
msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}" msgid "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
msgstr "{boardCount, plural, one {Bord importeren (1)} other {Borden importeren ({boardCount})}}" msgstr "{boardCount, plural, one {Bord importeren (1)} other {Borden importeren ({boardCount})}}"
#: src/views/members/components/InviteMemberForm.tsx:92 #: src/views/members/components/InviteMemberForm.tsx:146
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$10/month" msgid "$10/month"
msgstr "$10/maand" msgstr "$10/maand"
#: src/views/members/components/InviteMemberForm.tsx:104 #: src/views/members/components/InviteMemberForm.tsx:158
msgid "$8/month" msgid "$8/month"
msgstr "$8/maand" msgstr "$8/maand"
@@ -53,6 +53,10 @@ msgstr "1 gebruiker"
msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place." msgid "A powerful, flexible kanban app that helps you organise work, track progress, and deliver results—all in one place."
msgstr "Een krachtige, flexibele kanban-app die je helpt werk te organiseren, voortgang bij te houden en resultaten te leveren—allemaal op één plek." msgstr "Een krachtige, flexibele kanban-app die je helpt werk te organiseren, voortgang bij te houden en resultaten te leveren—allemaal op één plek."
#: src/components/SettingsLayout.tsx:33
msgid "Account"
msgstr "Account"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:27 #: src/views/settings/components/DeleteAccountConfirmation.tsx:27
msgid "Account deleted" msgid "Account deleted"
msgstr "Account verwijderd" msgstr "Account verwijderd"
@@ -91,13 +95,13 @@ msgstr "Beschrijving toevoegen... (typ '/' om commando's te openen of '@' om te
msgid "Add details..." msgid "Add details..."
msgstr "Details toevoegen..." msgstr "Details toevoegen..."
#: src/views/card/components/LabelSelector.tsx:110 #: src/views/card/components/LabelSelector.tsx:109
#: src/views/card/components/LabelSelector.tsx:118 #: src/views/card/components/LabelSelector.tsx:114
msgid "Add label" msgid "Add label"
msgstr "Label toevoegen" msgstr "Label toevoegen"
#: src/views/card/components/MemberSelector.tsx:130 #: src/views/card/components/MemberSelector.tsx:130
#: src/views/members/components/InviteMemberForm.tsx:147 #: src/views/members/components/InviteMemberForm.tsx:238
msgid "Add member" msgid "Add member"
msgstr "Lid toevoegen" msgstr "Lid toevoegen"
@@ -132,10 +136,14 @@ msgstr "heeft checklistitem <0>{0}</0> toegevoegd"
msgid "added label <0>{0}</0>" msgid "added label <0>{0}</0>"
msgstr "heeft label <0>{0}</0> toegevoegd" msgstr "heeft label <0>{0}</0> toegevoegd"
#: src/views/members/components/InviteMemberForm.tsx:187 #: src/views/members/components/InviteMemberForm.tsx:306
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Het toevoegen van een nieuw lid kost een extra {price} ({billingType}) per plaats." msgstr "Het toevoegen van een nieuw lid kost een extra {price} ({billingType}) per plaats."
#: src/views/settings/components/Avatar.tsx:275
msgid "Adjust the square crop to fit your avatar."
msgstr "Pas de vierkante uitsnede aan zodat je avatar goed past."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Beheerdersrollen" msgstr "Beheerdersrollen"
@@ -144,11 +152,11 @@ msgstr "Beheerdersrollen"
msgid "All systems operational" msgid "All systems operational"
msgstr "Alle systemen operationeel" msgstr "Alle systemen operationeel"
#: src/views/auth/signup/index.tsx:86 #: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>" msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Heb je al een account? <0><1>Log in</1></0>" msgstr "Heb je al een account? <0><1>Log in</1></0>"
#: src/views/settings/index.tsx:127 #: src/views/settings/IntegrationsSettings.tsx:61
msgid "An error occurred while disconnecting your Trello account." msgid "An error occurred while disconnecting your Trello account."
msgstr "Er is een fout opgetreden bij het verbreken van de verbinding met je Trello-account." msgstr "Er is een fout opgetreden bij het verbreken van de verbinding met je Trello-account."
@@ -156,7 +164,31 @@ msgstr "Er is een fout opgetreden bij het verbreken van de verbinding met je Tre
msgid "An unexpected error occurred. Please try again later." msgid "An unexpected error occurred. Please try again later."
msgstr "Er is een onverwachte fout opgetreden. Probeer het later opnieuw." msgstr "Er is een onverwachte fout opgetreden. Probeer het later opnieuw."
#: src/views/settings/index.tsx:296 #: src/views/members/components/InviteMemberForm.tsx:290
msgid "Anyone with this link can join your workspace"
msgstr "Iedereen met deze link kan deelnemen aan je werkruimte"
#: src/components/SettingsLayout.tsx:51
msgid "API"
msgstr "API"
#: src/views/settings/components/NewApiKeyModal.tsx:91
msgid "API key created"
msgstr "API-sleutel aangemaakt"
#: src/views/settings/components/NewApiKeyModal.tsx:161
msgid "API key name"
msgstr "API-sleutelnaam"
#: src/views/settings/components/NewApiKeyModal.tsx:25
msgid "API key name cannot exceed 30 characters"
msgstr "API-sleutelnaam mag niet langer zijn dan 30 tekens"
#: src/views/settings/components/NewApiKeyModal.tsx:24
msgid "API key name is required"
msgstr "API-sleutelnaam is verplicht"
#: src/views/settings/ApiSettings.tsx:22
msgid "API keys" msgid "API keys"
msgstr "API-sleutels" msgstr "API-sleutels"
@@ -218,20 +250,21 @@ msgstr "Backlog"
msgid "Basic Kanban" msgid "Basic Kanban"
msgstr "Basis kanban" msgstr "Basis kanban"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed annually" msgid "billed annually"
msgstr "jaarlijks gefactureerd" msgstr "jaarlijks gefactureerd"
#: src/views/members/components/InviteMemberForm.tsx:105 #: src/views/members/components/InviteMemberForm.tsx:159
msgid "billed monthly" msgid "billed monthly"
msgstr "maandelijks gefactureerd" msgstr "maandelijks gefactureerd"
#: src/components/SettingsLayout.tsx:44
#: src/views/boards/components/TemplateBoards.tsx:55 #: src/views/boards/components/TemplateBoards.tsx:55
#: src/views/settings/index.tsx:235 #: src/views/settings/BillingSettings.tsx:39
msgid "Billing" msgid "Billing"
msgstr "Facturering" msgstr "Facturering"
#: src/views/settings/index.tsx:245 #: src/views/settings/BillingSettings.tsx:49
msgid "Billing portal" msgid "Billing portal"
msgstr "Factureringsportaal" msgstr "Factureringsportaal"
@@ -286,12 +319,12 @@ msgid "Board visibility updated"
msgstr "Zichtbaarheid van bord bijgewerkt" msgstr "Zichtbaarheid van bord bijgewerkt"
#: src/components/SideNavigation.tsx:68 #: src/components/SideNavigation.tsx:68
#: src/views/boards/index.tsx:27 #: src/views/boards/index.tsx:32
msgid "Boards" msgid "Boards"
msgstr "Borden" msgstr "Borden"
#. placeholder {0}: workspace.name ?? "Workspace" #. placeholder {0}: workspace.name ?? "Workspace"
#: src/views/boards/index.tsx:23 #: src/views/boards/index.tsx:28
msgid "Boards | {0}" msgid "Boards | {0}"
msgstr "Borden | {0}" msgstr "Borden | {0}"
@@ -313,6 +346,7 @@ msgstr "Bugrapport"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:306
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -328,19 +362,19 @@ msgstr "Kaart niet gevonden"
msgid "Card title" msgid "Card title"
msgstr "Kaarttitel" msgstr "Kaarttitel"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109 #: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178 #: src/views/settings/components/ChangePasswordConfirmation.tsx:178
#: src/views/settings/index.tsx:328
#: src/views/settings/index.tsx:338
msgid "Change Password" msgid "Change Password"
msgstr "Wachtwoord wijzigen" msgstr "Wachtwoord wijzigen"
#: src/views/settings/index.tsx:227 #: src/views/settings/AccountSettings.tsx:45
msgid "Change the language of the app." msgid "Change your language preferences."
msgstr "Wijzig de taal van de app." msgstr "Wijzig je taalvoorkeuren."
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
msgid "Check your inbox" msgid "Check your inbox"
msgstr "Controleer je inbox" msgstr "Controleer je inbox"
@@ -352,11 +386,15 @@ msgstr "Naam checklist"
msgid "Clear filters" msgid "Clear filters"
msgstr "Filters wissen" msgstr "Filters wissen"
#: src/views/auth/login/index.tsx:46 #: src/views/auth/login/index.tsx:48
#: src/views/auth/signup/index.tsx:72 #: src/views/auth/signup/index.tsx:74
msgid "Click on the link we've sent to {magicLinkRecipient} to sign in." msgid "Click on the link we've sent to {magicLinkRecipient} to sign in."
msgstr "Klik op de link die we naar {magicLinkRecipient} hebben gestuurd om in te loggen." msgstr "Klik op de link die we naar {magicLinkRecipient} hebben gestuurd om in te loggen."
#: src/views/settings/components/NewApiKeyModal.tsx:136
msgid "Close"
msgstr "Sluiten"
#: src/views/boards/components/TemplateBoards.tsx:22 #: src/views/boards/components/TemplateBoards.tsx:22
msgid "Code Review" msgid "Code Review"
msgstr "Code review" msgstr "Code review"
@@ -401,7 +439,7 @@ msgid "Confirm your new password"
msgstr "Bevestig je nieuwe wachtwoord" msgstr "Bevestig je nieuwe wachtwoord"
#: src/views/boards/components/ImportBoardsForm.tsx:157 #: src/views/boards/components/ImportBoardsForm.tsx:157
#: src/views/settings/index.tsx:272 #: src/views/settings/IntegrationsSettings.tsx:93
msgid "Connect Trello" msgid "Connect Trello"
msgstr "Verbind Trello" msgstr "Verbind Trello"
@@ -409,7 +447,7 @@ msgstr "Verbind Trello"
msgid "Connect your favorite tools to streamline your workflow." msgid "Connect your favorite tools to streamline your workflow."
msgstr "Verbind je favoriete tools om je werkstroom te stroomlijnen." msgstr "Verbind je favoriete tools om je werkstroom te stroomlijnen."
#: src/views/settings/index.tsx:259 #: src/views/settings/IntegrationsSettings.tsx:80
msgid "Connect your Trello account to import boards." msgid "Connect your Trello account to import boards."
msgstr "Verbind je Trello-account om borden te importeren." msgstr "Verbind je Trello-account om borden te importeren."
@@ -425,12 +463,12 @@ msgstr "Neem contact op"
msgid "Content Creation" msgid "Content Creation"
msgstr "Content creatie" msgstr "Content creatie"
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Continue with " msgid "Continue with "
msgstr "Doorgaan met " msgstr "Doorgaan met "
#. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name #. placeholder {0}: key === "oidc" ? oidcProviderName : provider.name
#: src/components/AuthForm.tsx:297 #: src/components/AuthForm.tsx:301
msgid "Continue with {0}" msgid "Continue with {0}"
msgstr "Doorgaan met {0}" msgstr "Doorgaan met {0}"
@@ -444,6 +482,10 @@ msgstr "Bepaal wie je borden kan bekijken en bewerken."
msgid "Create another" msgid "Create another"
msgstr "Maak nog een" msgstr "Maak nog een"
#: src/views/settings/components/NewApiKeyModal.tsx:175
msgid "Create API key"
msgstr "API-sleutel aanmaken"
#: src/views/boards/components/NewBoardForm.tsx:128 #: src/views/boards/components/NewBoardForm.tsx:128
msgid "Create board" msgid "Create board"
msgstr "Maak bord" msgstr "Maak bord"
@@ -468,12 +510,12 @@ msgstr "Lijst maken"
msgid "Create new board" msgid "Create new board"
msgstr "Nieuw bord maken" msgstr "Nieuw bord maken"
#: src/views/settings/components/CreateAPIKeyForm.tsx:54 #: src/views/settings/ApiSettings.tsx:30
msgid "Create new key" msgid "Create new key"
msgstr "Nieuwe sleutel aanmaken" msgstr "Nieuwe sleutel aanmaken"
#: src/views/board/components/NewCardForm.tsx:394 #: src/views/board/components/NewCardForm.tsx:394
#: src/views/card/components/LabelSelector.tsx:98 #: src/views/card/components/LabelSelector.tsx:97
msgid "Create new label" msgid "Create new label"
msgstr "Maak nieuw label" msgstr "Maak nieuw label"
@@ -494,6 +536,10 @@ msgstr "heeft de kaart aangemaakt"
msgid "Critical" msgid "Critical"
msgstr "Kritiek" msgstr "Kritiek"
#: src/views/settings/components/Avatar.tsx:272
msgid "Crop your avatar"
msgstr "Snijd je avatar bij"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Huidig wachtwoord is vereist" msgstr "Huidig wachtwoord is vereist"
@@ -527,9 +573,9 @@ msgstr "Donker"
msgid "Delete" msgid "Delete"
msgstr "Verwijderen" msgstr "Verwijderen"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96 #: src/views/settings/components/DeleteAccountConfirmation.tsx:96
#: src/views/settings/index.tsx:346
#: src/views/settings/index.tsx:356
msgid "Delete account" msgid "Delete account"
msgstr "Account verwijderen" msgstr "Account verwijderen"
@@ -550,8 +596,8 @@ msgid "Delete list"
msgstr "Lijst verwijderen" msgstr "Lijst verwijderen"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/index.tsx:309 #: src/views/settings/WorkspaceSettings.tsx:96
#: src/views/settings/index.tsx:320 #: src/views/settings/WorkspaceSettings.tsx:107
msgid "Delete workspace" msgid "Delete workspace"
msgstr "Werkruimte verwijderen" msgstr "Werkruimte verwijderen"
@@ -577,7 +623,7 @@ msgstr "heeft checklistitem <0>{0}</0> verwijderd"
msgid "Design" msgid "Design"
msgstr "Ontwerp" msgstr "Ontwerp"
#: src/views/settings/index.tsx:287 #: src/views/settings/IntegrationsSettings.tsx:108
msgid "Disconnect Trello" msgid "Disconnect Trello"
msgstr "Trello ontkoppelen" msgstr "Trello ontkoppelen"
@@ -585,7 +631,7 @@ msgstr "Trello ontkoppelen"
msgid "Discuss and collaborate on cards." msgid "Discuss and collaborate on cards."
msgstr "Bespreek en werk samen aan kaarten." msgstr "Bespreek en werk samen aan kaarten."
#: src/views/settings/index.tsx:176 #: src/views/settings/AccountSettings.tsx:35
msgid "Display name" msgid "Display name"
msgstr "Weergavenaam" msgstr "Weergavenaam"
@@ -619,7 +665,7 @@ msgstr "Docs"
msgid "Documentation" msgid "Documentation"
msgstr "Documentatie" msgstr "Documentatie"
#: src/views/auth/login/index.tsx:61 #: src/views/auth/login/index.tsx:63
msgid "Don't have an account? <0><1>Sign up</1></0>" msgid "Don't have an account? <0><1>Sign up</1></0>"
msgstr "Heb je geen account? <0><1>Registreer je</1></0>" msgstr "Heb je geen account? <0><1>Registreer je</1></0>"
@@ -651,11 +697,11 @@ msgstr "Werkruimte-URL bewerken"
msgid "Editing" msgid "Editing"
msgstr "Bewerken" msgstr "Bewerken"
#: src/components/AuthForm.tsx:368 #: src/components/AuthForm.tsx:372
msgid "email" msgid "email"
msgstr "e-mail" msgstr "e-mail"
#: src/views/members/components/InviteMemberForm.tsx:161 #: src/views/members/components/InviteMemberForm.tsx:252
msgid "Email" msgid "Email"
msgstr "E-mail" msgstr "E-mail"
@@ -671,11 +717,11 @@ msgstr "Voer je huidige wachtwoord in"
msgid "Enter your current password and choose a new secure password." msgid "Enter your current password and choose a new secure password."
msgstr "Voer je huidige wachtwoord in en kies een nieuw veilig wachtwoord." msgstr "Voer je huidige wachtwoord in en kies een nieuw veilig wachtwoord."
#: src/components/AuthForm.tsx:333 #: src/components/AuthForm.tsx:337
msgid "Enter your email address" msgid "Enter your email address"
msgstr "Voer je e-mailadres in" msgstr "Voer je e-mailadres in"
#: src/components/AuthForm.tsx:321 #: src/components/AuthForm.tsx:325
msgid "Enter your name" msgid "Enter your name"
msgstr "Voer je naam in" msgstr "Voer je naam in"
@@ -683,14 +729,26 @@ msgstr "Voer je naam in"
msgid "Enter your new password" msgid "Enter your new password"
msgstr "Voer je nieuwe wachtwoord in" msgstr "Voer je nieuwe wachtwoord in"
#: src/components/AuthForm.tsx:346 #: src/components/AuthForm.tsx:350
msgid "Enter your password" msgid "Enter your password"
msgstr "Voer je wachtwoord in" msgstr "Voer je wachtwoord in"
#: src/views/members/components/InviteMemberForm.tsx:196
msgid "Error"
msgstr "Fout"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89 #: src/views/settings/components/ChangePasswordConfirmation.tsx:89
msgid "Error Changing Password" msgid "Error Changing Password"
msgstr "Fout bij wijzigen wachtwoord" msgstr "Fout bij wijzigen wachtwoord"
#: src/views/members/components/InviteMemberForm.tsx:117
msgid "Error creating invite link"
msgstr "Fout bij het maken van uitnodigingslink"
#: src/views/members/components/InviteMemberForm.tsx:132
msgid "Error deactivating invite link"
msgstr "Fout bij het deactiveren van uitnodigingslink"
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39 #: src/views/settings/components/DeleteAccountConfirmation.tsx:39
msgid "Error deleting account" msgid "Error deleting account"
msgstr "Fout bij verwijderen account" msgstr "Fout bij verwijderen account"
@@ -703,12 +761,12 @@ msgstr "Fout bij het verwijderen van label"
msgid "Error deleting workspace" msgid "Error deleting workspace"
msgstr "Fout bij verwijderen werkruimte" msgstr "Fout bij verwijderen werkruimte"
#: src/views/settings/index.tsx:126 #: src/views/settings/IntegrationsSettings.tsx:60
msgid "Error disconnecting Trello" msgid "Error disconnecting Trello"
msgstr "Fout bij ontkoppelen van Trello" msgstr "Fout bij ontkoppelen van Trello"
#: src/views/members/components/InviteMemberForm.tsx:71 #: src/views/members/components/InviteMemberForm.tsx:95
#: src/views/members/components/InviteMemberForm.tsx:77 #: src/views/members/components/InviteMemberForm.tsx:101
msgid "Error inviting member" msgid "Error inviting member"
msgstr "Fout bij het uitnodigen van lid" msgstr "Fout bij het uitnodigen van lid"
@@ -716,7 +774,7 @@ msgstr "Fout bij het uitnodigen van lid"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Fout bij bijwerken weergavenaam" msgstr "Fout bij bijwerken weergavenaam"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:77
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Fout bij het bijwerken van profielafbeelding" msgstr "Fout bij het bijwerken van profielafbeelding"
@@ -732,7 +790,7 @@ msgstr "Fout bij bijwerken naam werkruimte"
msgid "Error updating workspace URL" msgid "Error updating workspace URL"
msgstr "Fout bij het bijwerken van werkruimte-URL" msgstr "Fout bij het bijwerken van werkruimte-URL"
#: src/views/members/components/InviteMemberForm.tsx:130 #: src/views/members/components/InviteMemberForm.tsx:221
#: src/views/settings/components/UpgradeToProConfirmation.tsx:41 #: src/views/settings/components/UpgradeToProConfirmation.tsx:41
msgid "Error upgrading subscription" msgid "Error upgrading subscription"
msgstr "Fout bij het upgraden van abonnement" msgstr "Fout bij het upgraden van abonnement"
@@ -741,8 +799,8 @@ msgstr "Fout bij het upgraden van abonnement"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Fout bij upgraden naar Pro" msgstr "Fout bij upgraden naar Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:91
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:218
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Fout bij het uploaden van profielafbeelding" msgstr "Fout bij het uploaden van profielafbeelding"
@@ -758,8 +816,16 @@ msgstr "Alles wat je nodig hebt, voor altijd gratis. Onbeperkte borden, onbeperk
msgid "Execution" msgid "Execution"
msgstr "Uitvoering" msgstr "Uitvoering"
#: src/views/invite/index.tsx:41
msgid "Failed to accept invitation. Please try again later, or contact customer support."
msgstr "Uitnodiging accepteren mislukt. Probeer het later opnieuw of neem contact op met de klantenservice."
#: src/views/members/components/InviteMemberForm.tsx:197
msgid "Failed to copy invite link"
msgstr "Kopiëren van uitnodigingslink mislukt"
#. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1) #. placeholder {0}: provider.at(0)?.toUpperCase() + provider.slice(1)
#: src/components/AuthForm.tsx:269 #: src/components/AuthForm.tsx:273
msgid "Failed to login with {0}. Please try again." msgid "Failed to login with {0}. Please try again."
msgstr "Inloggen met {0} is mislukt. Probeer het opnieuw." msgstr "Inloggen met {0} is mislukt. Probeer het opnieuw."
@@ -807,7 +873,7 @@ msgstr "Voor duurzaamheid op lange termijn erkennen we dat alle goede open sourc
msgid "Free" msgid "Free"
msgstr "Gratis" msgstr "Gratis"
#: src/views/members/components/InviteMemberForm.tsx:193 #: src/views/members/components/InviteMemberForm.tsx:312
#: src/views/members/index.tsx:208 #: src/views/members/index.tsx:208
msgid "Free Plan" msgid "Free Plan"
msgstr "Gratis plan" msgstr "Gratis plan"
@@ -824,7 +890,7 @@ msgstr "Fulltime"
msgid "Fun" msgid "Fun"
msgstr "Leuk" msgstr "Leuk"
#: src/views/auth/signup/index.tsx:67 #: src/views/auth/signup/index.tsx:69
#: src/views/home/components/Cta.tsx:61 #: src/views/home/components/Cta.tsx:61
#: src/views/home/components/Header.tsx:102 #: src/views/home/components/Header.tsx:102
#: src/views/home/components/Header.tsx:141 #: src/views/home/components/Header.tsx:141
@@ -864,8 +930,13 @@ msgstr "Aan de slag"
msgid "GitHub" msgid "GitHub"
msgstr "GitHub" msgstr "GitHub"
#: src/views/invite/index.tsx:113
msgid "Go Home"
msgstr "Naar startpagina"
#: src/views/home/components/Header.tsx:96 #: src/views/home/components/Header.tsx:96
#: src/views/home/components/Header.tsx:133 #: src/views/home/components/Header.tsx:133
#: src/views/invite/index.tsx:144
msgid "Go to app" msgid "Go to app"
msgstr "Naar de app" msgstr "Naar de app"
@@ -917,7 +988,7 @@ msgstr "Ideeën"
msgid "Ideas to improve this page..." msgid "Ideas to improve this page..."
msgstr "Ideeën om deze pagina te verbeteren..." msgstr "Ideeën om deze pagina te verbeteren..."
#: src/views/boards/index.tsx:38 #: src/views/boards/index.tsx:43
msgid "Import" msgid "Import"
msgstr "Importeren" msgstr "Importeren"
@@ -955,6 +1026,7 @@ msgstr "In behandeling"
msgid "Individuals" msgid "Individuals"
msgstr "Individuen" msgstr "Individuen"
#: src/components/SettingsLayout.tsx:57
#: src/views/home/components/Features.tsx:114 #: src/views/home/components/Features.tsx:114
msgid "Integrations" msgid "Integrations"
msgstr "Integraties" msgstr "Integraties"
@@ -963,27 +1035,44 @@ msgstr "Integraties"
msgid "Interviewing" msgid "Interviewing"
msgstr "Interviewen" msgstr "Interviewen"
#: src/views/members/components/InviteMemberForm.tsx:40 #: src/views/members/components/InviteMemberForm.tsx:49
msgid "Invalid email address" msgid "Invalid email address"
msgstr "Ongeldig e-mailadres" msgstr "Ongeldig e-mailadres"
#: src/views/invite/index.tsx:105
msgid "Invalid invitation"
msgstr "Ongeldige uitnodiging"
#: src/views/members/index.tsx:221 #: src/views/members/index.tsx:221
msgid "Invite" msgid "Invite"
msgstr "Uitnodigen" msgstr "Uitnodigen"
#: src/views/members/components/InviteMemberForm.tsx:208 #: src/views/members/components/InviteMemberForm.tsx:190
msgid "Invite another" msgid "Invite link copied"
msgstr "Nog iemand uitnodigen" msgstr "Uitnodigingslink gekopieerd"
#: src/views/card/components/MemberSelector.tsx:112 #: src/views/members/components/InviteMemberForm.tsx:191
#: src/views/members/components/InviteMemberForm.tsx:233 msgid "Invite link copied to clipboard"
msgstr "Uitnodigingslink gekopieerd naar klembord"
#: src/views/card/components/MemberSelector.tsx:111
#: src/views/members/components/InviteMemberForm.tsx:350
msgid "Invite member" msgid "Invite member"
msgstr "Lid uitnodigen" msgstr "Lid uitnodigen"
#: src/views/members/components/InviteMemberForm.tsx:196 #: src/views/members/components/InviteMemberForm.tsx:315
msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace." msgid "Inviting members requires a Team Plan. You'll be redirected to upgrade your workspace."
msgstr "Voor het uitnodigen van leden is een teamplan vereist. Je wordt doorgestuurd om je werkruimte te upgraden." msgstr "Voor het uitnodigen van leden is een teamplan vereist. Je wordt doorgestuurd om je werkruimte te upgraden."
#: src/views/invite/index.tsx:79
#: src/views/invite/index.tsx:129
msgid "Join workspace"
msgstr "Deelnemen aan werkruimte"
#: src/views/invite/index.tsx:91
msgid "Join workspace | kan.bn"
msgstr "Deelnemen aan werkruimte | kan.bn"
#: src/views/boards/components/TemplateBoards.tsx:69 #: src/views/boards/components/TemplateBoards.tsx:69
msgid "Junior" msgid "Junior"
msgstr "Junior" msgstr "Junior"
@@ -1011,7 +1100,7 @@ msgstr "Labels"
msgid "Labels & Filters" msgid "Labels & Filters"
msgstr "Labels & filters" msgstr "Labels & filters"
#: src/views/settings/index.tsx:224 #: src/views/settings/AccountSettings.tsx:42
msgid "Language" msgid "Language"
msgstr "Taal" msgstr "Taal"
@@ -1056,7 +1145,7 @@ msgstr "Lijst"
msgid "List name" msgid "List name"
msgstr "Lijstnaam" msgstr "Lijstnaam"
#: src/views/auth/login/index.tsx:31 #: src/views/auth/login/index.tsx:33
msgid "Login | kan.bn" msgid "Login | kan.bn"
msgstr "Login | kan.bn" msgstr "Login | kan.bn"
@@ -1072,7 +1161,7 @@ msgstr "Lange termijn"
msgid "Low Priority" msgid "Low Priority"
msgstr "Lage prioriteit" msgstr "Lage prioriteit"
#: src/components/AuthForm.tsx:369 #: src/components/AuthForm.tsx:373
msgid "magic link" msgid "magic link"
msgstr "magische link" msgstr "magische link"
@@ -1106,7 +1195,7 @@ msgstr "Leden | {0}"
msgid "Monthly" msgid "Monthly"
msgstr "Maandelijks" msgstr "Maandelijks"
#: src/views/members/components/InviteMemberForm.tsx:93 #: src/views/members/components/InviteMemberForm.tsx:147
msgid "monthly billing" msgid "monthly billing"
msgstr "maandelijkse facturering" msgstr "maandelijkse facturering"
@@ -1129,10 +1218,14 @@ msgstr "Naam"
msgid "Need help?" msgid "Need help?"
msgstr "Hulp nodig?" msgstr "Hulp nodig?"
#: src/views/boards/index.tsx:48 #: src/views/boards/index.tsx:53
msgid "New" msgid "New"
msgstr "Nieuw" msgstr "Nieuw"
#: src/views/settings/components/NewApiKeyModal.tsx:147
msgid "New API key"
msgstr "Nieuwe API-sleutel"
#: src/views/boards/components/NewBoardForm.tsx:85 #: src/views/boards/components/NewBoardForm.tsx:85
msgid "New board" msgid "New board"
msgstr "Nieuw bord" msgstr "Nieuw bord"
@@ -1206,15 +1299,15 @@ msgstr "Aanbod"
msgid "Onboarding" msgid "Onboarding"
msgstr "Inwerktraject" msgstr "Inwerktraject"
#: src/views/settings/index.tsx:349 #: src/views/settings/AccountSettings.tsx:55
msgid "Once you delete your account, there is no going back. This action cannot be undone." msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Zodra je je account verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt." msgstr "Zodra je je account verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt."
#: src/views/settings/index.tsx:312 #: src/views/settings/WorkspaceSettings.tsx:99
msgid "Once you delete your workspace, there is no going back. This action cannot be undone." msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Zodra je je werkruimte verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt." msgstr "Zodra je je werkruimte verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt."
#: src/components/AuthForm.tsx:311 #: src/components/AuthForm.tsx:315
msgid "or" msgid "or"
msgstr "of" msgstr "of"
@@ -1242,6 +1335,10 @@ msgstr "Wachtwoord moet minimaal 8 tekens bevatten"
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Wachtwoorden komen niet overeen" msgstr "Wachtwoorden komen niet overeen"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "Gepauzeerd"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Betalingsfrequentie" msgstr "Betalingsfrequentie"
@@ -1267,19 +1364,19 @@ msgstr "Planning"
msgid "Please confirm your new password" msgid "Please confirm your new password"
msgstr "Bevestig je nieuwe wachtwoord" msgstr "Bevestig je nieuwe wachtwoord"
#: src/components/AuthForm.tsx:337 #: src/components/AuthForm.tsx:341
msgid "Please enter a valid email address" msgid "Please enter a valid email address"
msgstr "Voer een geldig e-mailadres in" msgstr "Voer een geldig e-mailadres in"
#: src/components/AuthForm.tsx:325 #: src/components/AuthForm.tsx:329
msgid "Please enter a valid name" msgid "Please enter a valid name"
msgstr "Voer een geldige naam in" msgstr "Voer een geldige naam in"
#: src/components/AuthForm.tsx:350 #: src/components/AuthForm.tsx:354
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Voer een geldig wachtwoord in" msgstr "Voer een geldig wachtwoord in"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:92
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Selecteer een bestand om te uploaden." msgstr "Selecteer een bestand om te uploaden."
@@ -1300,18 +1397,18 @@ msgstr "Selecteer een bestand om te uploaden."
#: src/views/card/components/DeleteCardConfirmation.tsx:52 #: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37 #: src/views/card/components/DeleteChecklistConfirmation.tsx:37
#: src/views/card/components/DeleteCommentConfirmation.tsx:45 #: src/views/card/components/DeleteCommentConfirmation.tsx:45
#: src/views/card/components/LabelSelector.tsx:73 #: src/views/card/components/LabelSelector.tsx:72
#: src/views/card/components/ListSelector.tsx:53 #: src/views/card/components/ListSelector.tsx:52
#: src/views/card/components/MemberSelector.tsx:80 #: src/views/card/components/MemberSelector.tsx:79
#: src/views/card/components/NewChecklistForm.tsx:70 #: src/views/card/components/NewChecklistForm.tsx:70
#: src/views/card/components/NewChecklistItemForm.tsx:89 #: src/views/card/components/NewChecklistItemForm.tsx:89
#: src/views/card/components/NewCommentForm.tsx:31 #: src/views/card/components/NewCommentForm.tsx:31
#: src/views/card/index.tsx:173 #: src/views/card/index.tsx:173
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:102
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:222
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:78
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:219
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1322,6 +1419,11 @@ msgstr "Selecteer een bestand om te uploaden."
msgid "Please try again later, or contact customer support." msgid "Please try again later, or contact customer support."
msgstr "Probeer het later opnieuw of neem contact op met de klantenservice." msgstr "Probeer het later opnieuw of neem contact op met de klantenservice."
#: src/views/members/components/InviteMemberForm.tsx:118
#: src/views/members/components/InviteMemberForm.tsx:133
msgid "Please try again later."
msgstr "Probeer het later opnieuw."
#: src/views/home/components/Footer.tsx:50 #: src/views/home/components/Footer.tsx:50
#: src/views/home/components/Header.tsx:15 #: src/views/home/components/Header.tsx:15
#: src/views/home/components/Pricing.tsx:85 #: src/views/home/components/Pricing.tsx:85
@@ -1345,15 +1447,15 @@ msgstr "Privé"
msgid "Pro Plan" msgid "Pro Plan"
msgstr "Pro Plan" msgstr "Pro Plan"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro Plan ∞" msgstr "Pro Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:64
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profielafbeelding bijgewerkt" msgstr "Profielafbeelding bijgewerkt"
#: src/views/settings/index.tsx:171 #: src/views/settings/AccountSettings.tsx:29
msgid "Profile picture" msgid "Profile picture"
msgstr "Profielfoto" msgstr "Profielfoto"
@@ -1436,10 +1538,6 @@ msgstr "Bronnen"
msgid "Review" msgid "Review"
msgstr "Beoordeling" msgstr "Beoordeling"
#: src/views/settings/components/CreateAPIKeyForm.tsx:49
msgid "Revoke"
msgstr "Intrekken"
#: src/views/home/components/Footer.tsx:36 #: src/views/home/components/Footer.tsx:36
#: src/views/home/components/Header.tsx:13 #: src/views/home/components/Header.tsx:13
msgid "Roadmap" msgid "Roadmap"
@@ -1454,6 +1552,7 @@ msgid "Run on your own infrastructure"
msgstr "Draai op je eigen infrastructuur" msgstr "Draai op je eigen infrastructuur"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:309
msgid "Save" msgid "Save"
msgstr "Opslaan" msgstr "Opslaan"
@@ -1493,35 +1592,62 @@ msgstr "Feedback versturen"
msgid "Senior" msgid "Senior"
msgstr "Senior" msgstr "Senior"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:78 #: src/components/SideNavigation.tsx:78
#: src/views/settings/index.tsx:165
msgid "Settings" msgid "Settings"
msgstr "Instellingen" msgstr "Instellingen"
#. placeholder {0}: workspace.name ?? "Workspace" #: src/views/settings/AccountSettings.tsx:25
#: src/views/settings/index.tsx:161 msgid "Settings | Account"
msgid "Settings | {0}" msgstr "Instellingen | Account"
msgstr "Instellingen | {0}"
#: src/views/settings/ApiSettings.tsx:18
msgid "Settings | API"
msgstr "Instellingen | API"
#: src/views/settings/BillingSettings.tsx:35
msgid "Settings | Billing"
msgstr "Instellingen | Facturering"
#: src/views/settings/IntegrationsSettings.tsx:69
msgid "Settings | Integrations"
msgstr "Instellingen | Integraties"
#: src/views/settings/WorkspaceSettings.tsx:54
msgid "Settings | Workspace"
msgstr "Instellingen | Werkruimte"
#: src/views/members/components/InviteMemberForm.tsx:327
msgid "Share invite link"
msgstr "Uitnodigingslink delen"
#: src/views/home/components/Header.tsx:100 #: src/views/home/components/Header.tsx:100
#: src/views/home/components/Header.tsx:138 #: src/views/home/components/Header.tsx:138
msgid "Sign in" msgid "Sign in"
msgstr "Inloggen" msgstr "Inloggen"
#: src/views/auth/signup/index.tsx:32 #: src/views/invite/index.tsx:154
#: src/views/auth/signup/index.tsx:57 msgid "Sign In"
msgstr "Inloggen"
#: src/views/invite/index.tsx:162
msgid "Sign Up"
msgstr "Registreren"
#: src/views/auth/signup/index.tsx:34
#: src/views/auth/signup/index.tsx:59
msgid "Sign up | kan.bn" msgid "Sign up | kan.bn"
msgstr "Registreren | kan.bn" msgstr "Registreren | kan.bn"
#: src/views/auth/signup/index.tsx:42 #: src/views/auth/signup/index.tsx:44
msgid "Sign up disabled" msgid "Sign up disabled"
msgstr "Registreren uitgeschakeld" msgstr "Registreren uitgeschakeld"
#: src/views/auth/signup/index.tsx:45 #: src/views/auth/signup/index.tsx:47
msgid "Sign up is currently disabled. Please try again later." msgid "Sign up is currently disabled. Please try again later."
msgstr "Registreren is momenteel uitgeschakeld. Probeer het later opnieuw." msgstr "Registreren is momenteel uitgeschakeld. Probeer het later opnieuw."
#: src/components/AuthForm.tsx:366 #: src/components/AuthForm.tsx:370
msgid "Sign up with " msgid "Sign up with "
msgstr "Registreren met " msgstr "Registreren met "
@@ -1545,8 +1671,8 @@ msgstr "Softwareontwikkeling"
msgid "Star on Github" msgid "Star on Github"
msgstr "Star op Github" msgstr "Star op Github"
#: src/components/AuthForm.tsx:203 #: src/components/AuthForm.tsx:207
#: src/components/AuthForm.tsx:220 #: src/components/AuthForm.tsx:224
msgid "Success" msgid "Success"
msgstr "Geslaagd" msgstr "Geslaagd"
@@ -1566,7 +1692,7 @@ msgstr "Ondersteun de ontwikkeling van het project"
msgid "System" msgid "System"
msgstr "Systeem" msgstr "Systeem"
#: src/views/members/components/InviteMemberForm.tsx:182 #: src/views/members/components/InviteMemberForm.tsx:301
#: src/views/members/index.tsx:207 #: src/views/members/index.tsx:207
msgid "Team Plan" msgid "Team Plan"
msgstr "Teamplan" msgstr "Teamplan"
@@ -1619,6 +1745,10 @@ msgstr "Ze zullen geen toegang meer hebben tot deze werkruimte."
msgid "This action can't be undone." msgid "This action can't be undone."
msgstr "Deze actie kan niet ongedaan worden gemaakt." msgstr "Deze actie kan niet ongedaan worden gemaakt."
#: src/views/settings/components/NewApiKeyModal.tsx:129
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:151 #: src/views/public/board/index.tsx:151
msgid "This board is private or does not exist" msgid "This board is private or does not exist"
msgstr "Dit bord is privé of bestaat niet" msgstr "Dit bord is privé of bestaat niet"
@@ -1627,6 +1757,10 @@ msgstr "Dit bord is privé of bestaat niet"
msgid "This board URL has already been taken" msgid "This board URL has already been taken"
msgstr "Deze board URL is al in gebruik" msgstr "Deze board URL is al in gebruik"
#: src/views/invite/index.tsx:108
msgid "This invitation link is invalid or has expired."
msgstr "Deze uitnodigingslink is ongeldig of verlopen."
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:70
msgid "This will result in the permanent deletion of all data associated with this workspace." msgid "This will result in the permanent deletion of all data associated with this workspace."
msgstr "Dit zal resulteren in het permanent verwijderen van alle gegevens die aan deze werkruimte zijn gekoppeld." msgstr "Dit zal resulteren in het permanent verwijderen van alle gegevens die aan deze werkruimte zijn gekoppeld."
@@ -1660,7 +1794,11 @@ msgstr "Menu in-/uitschakelen"
msgid "Track all card changes with detailed activity history." msgid "Track all card changes with detailed activity history."
msgstr "Volg alle kaartwijzigingen met gedetailleerde activiteitengeschiedenis." msgstr "Volg alle kaartwijzigingen met gedetailleerde activiteitengeschiedenis."
#: src/views/settings/index.tsx:119 #: src/views/settings/IntegrationsSettings.tsx:73
msgid "Trello"
msgstr "Trello"
#: src/views/settings/IntegrationsSettings.tsx:53
msgid "Trello disconnected" msgid "Trello disconnected"
msgstr "Trello ontkoppeld" msgstr "Trello ontkoppeld"
@@ -1745,16 +1883,16 @@ msgstr "Kan checklistitem niet bijwerken"
msgid "Unable to update comment" msgid "Unable to update comment"
msgstr "Kan reactie niet bijwerken" msgstr "Kan reactie niet bijwerken"
#: src/views/card/components/LabelSelector.tsx:72 #: src/views/card/components/LabelSelector.tsx:71
msgid "Unable to update labels" msgid "Unable to update labels"
msgstr "Kan labels niet bijwerken" msgstr "Kan labels niet bijwerken"
#: src/views/board/index.tsx:133 #: src/views/board/index.tsx:133
#: src/views/card/components/ListSelector.tsx:52 #: src/views/card/components/ListSelector.tsx:51
msgid "Unable to update list" msgid "Unable to update list"
msgstr "Kan lijst niet bijwerken" msgstr "Kan lijst niet bijwerken"
#: src/views/card/components/MemberSelector.tsx:79 #: src/views/card/components/MemberSelector.tsx:78
msgid "Unable to update members" msgid "Unable to update members"
msgstr "Kan leden niet bijwerken" msgstr "Kan leden niet bijwerken"
@@ -1797,9 +1935,9 @@ msgid "Unlimited members"
msgstr "Onbeperkt aantal leden" msgstr "Onbeperkt aantal leden"
#: src/views/board/components/UpdateBoardSlugForm.tsx:174 #: src/views/board/components/UpdateBoardSlugForm.tsx:174
#: src/views/settings/components/UpdateDisplayNameForm.tsx:79 #: src/views/settings/components/UpdateDisplayNameForm.tsx:80
#: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:90 #: src/views/settings/components/UpdateWorkspaceDescriptionForm.tsx:91
#: src/views/settings/components/UpdateWorkspaceNameForm.tsx:82 #: src/views/settings/components/UpdateWorkspaceNameForm.tsx:83
#: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154 #: src/views/settings/components/UpdateWorkspaceUrlForm.tsx:154
msgid "Update" msgid "Update"
msgstr "Bijwerken" msgstr "Bijwerken"
@@ -1830,7 +1968,7 @@ msgid "Upgrade"
msgstr "Upgraden" msgstr "Upgraden"
#: src/views/settings/components/UpgradeToProConfirmation.tsx:52 #: src/views/settings/components/UpgradeToProConfirmation.tsx:52
#: src/views/settings/index.tsx:216 #: src/views/settings/WorkspaceSettings.tsx:89
msgid "Upgrade to Pro" msgid "Upgrade to Pro"
msgstr "Upgraden naar Pro" msgstr "Upgraden naar Pro"
@@ -1838,7 +1976,7 @@ msgstr "Upgraden naar Pro"
msgid "Upgrade to Pro ($29/month)" msgid "Upgrade to Pro ($29/month)"
msgstr "Upgrade naar Pro ($29/maand)" msgstr "Upgrade naar Pro ($29/maand)"
#: src/views/members/components/InviteMemberForm.tsx:224 #: src/views/members/components/InviteMemberForm.tsx:341
msgid "Upgrade to Team Plan" msgid "Upgrade to Team Plan"
msgstr "Upgraden naar teamplan" msgstr "Upgraden naar teamplan"
@@ -1870,7 +2008,7 @@ msgstr "Sjabloon gebruiken"
msgid "User" msgid "User"
msgstr "Gebruiker" msgstr "Gebruiker"
#: src/views/members/components/InviteMemberForm.tsx:72 #: src/views/members/components/InviteMemberForm.tsx:96
msgid "User is already a member of this workspace" msgid "User is already a member of this workspace"
msgstr "Gebruiker is al lid van deze werkruimte" msgstr "Gebruiker is al lid van deze werkruimte"
@@ -1878,11 +2016,11 @@ msgstr "Gebruiker is al lid van deze werkruimte"
msgid "Video" msgid "Video"
msgstr "Video" msgstr "Video"
#: src/views/settings/index.tsx:299 #: src/views/settings/ApiSettings.tsx:25
msgid "View and manage your API keys." msgid "View and manage your API keys."
msgstr "Bekijk en beheer je API-sleutels." msgstr "Bekijk en beheer je API-sleutels."
#: src/views/settings/index.tsx:238 #: src/views/settings/BillingSettings.tsx:42
msgid "View and manage your billing and subscription." msgid "View and manage your billing and subscription."
msgstr "Bekijk en beheer je facturering en abonnement." msgstr "Bekijk en beheer je facturering en abonnement."
@@ -1914,7 +2052,7 @@ msgstr "We gebruiken de <0>AGPL-3.0 licentie</0>."
msgid "We're just getting started. " msgid "We're just getting started. "
msgstr "We zijn nog maar net begonnen. " msgstr "We zijn nog maar net begonnen. "
#: src/views/auth/login/index.tsx:41 #: src/views/auth/login/index.tsx:43
msgid "Welcome back" msgid "Welcome back"
msgstr "Welkom terug" msgstr "Welkom terug"
@@ -1934,6 +2072,7 @@ msgstr "Toen Trello in 2011 werd gelanceerd, blies het iedereen omver met zijn z
msgid "Why make an open source Trello?" msgid "Why make an open source Trello?"
msgstr "Waarom een open source Trello maken?" msgstr "Waarom een open source Trello maken?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:331 #: src/views/board/index.tsx:331
msgid "Workspace" msgid "Workspace"
msgstr "Werkruimte" msgstr "Werkruimte"
@@ -1946,7 +2085,7 @@ msgstr "Werkruimte succesvol aangemaakt. Je kunt later upgraden in de instelling
msgid "Workspace deleted" msgid "Workspace deleted"
msgstr "Werkruimte verwijderd" msgstr "Werkruimte verwijderd"
#: src/views/settings/index.tsx:202 #: src/views/settings/WorkspaceSettings.tsx:75
msgid "Workspace description" msgid "Workspace description"
msgstr "Werkruimte beschrijving" msgstr "Werkruimte beschrijving"
@@ -1968,7 +2107,7 @@ msgid "Workspace members"
msgstr "Werkruimteleden" msgstr "Werkruimteleden"
#: src/components/NewWorkspaceForm.tsx:259 #: src/components/NewWorkspaceForm.tsx:259
#: src/views/settings/index.tsx:183 #: src/views/settings/WorkspaceSettings.tsx:58
msgid "Workspace name" msgid "Workspace name"
msgstr "Naam werkruimte" msgstr "Naam werkruimte"
@@ -1992,7 +2131,7 @@ msgstr "Werkruimtenaam bijgewerkt"
msgid "Workspace slug updated" msgid "Workspace slug updated"
msgstr "Werkruimte-slug bijgewerkt" msgstr "Werkruimte-slug bijgewerkt"
#: src/views/settings/index.tsx:192 #: src/views/settings/WorkspaceSettings.tsx:66
msgid "Workspace URL" msgid "Workspace URL"
msgstr "Werkruimte URL" msgstr "Werkruimte URL"
@@ -2012,7 +2151,7 @@ msgstr "Jaarlijks"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits." msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Ja, we bieden een voor altijd gratis plan voor individueel gebruik. Geen beperkingen, geen betaalmuren, geen limieten." msgstr "Ja, we bieden een voor altijd gratis plan voor individueel gebruik. Geen beperkingen, geen betaalmuren, geen limieten."
#: src/views/settings/index.tsx:331 #: src/views/settings/AccountSettings.tsx:73
msgid "You are about to change your password." msgid "You are about to change your password."
msgstr "Je staat op het punt je wachtwoord te wijzigen." msgstr "Je staat op het punt je wachtwoord te wijzigen."
@@ -2028,18 +2167,26 @@ msgstr "Je kunt teamleden uitnodigen door op de knop \"Uitnodigen\" in de rechte
msgid "You can self-host by following the instructions in our <0>repo</0>." msgid "You can self-host by following the instructions in our <0>repo</0>."
msgstr "Je kunt zelf hosten door de instructies in onze <0>repo</0> te volgen." msgstr "Je kunt zelf hosten door de instructies in onze <0>repo</0> te volgen."
#: src/components/AuthForm.tsx:221 #: src/components/AuthForm.tsx:225
msgid "You have been logged in successfully." msgid "You have been logged in successfully."
msgstr "Je bent succesvol ingelogd." msgstr "Je bent succesvol ingelogd."
#: src/components/AuthForm.tsx:204 #: src/components/AuthForm.tsx:208
msgid "You have been signed up successfully." msgid "You have been signed up successfully."
msgstr "Je bent succesvol geregistreerd." msgstr "Je bent succesvol geregistreerd."
#: src/views/members/components/InviteMemberForm.tsx:186 #: src/views/members/components/InviteMemberForm.tsx:305
msgid "You have unlimited seats with your Pro Plan. There is no additional charge for new members!" 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!" msgstr "Je hebt onbeperkte plaatsen met je Pro Plan. Er zijn geen extra kosten voor nieuwe leden!"
#: src/views/invite/index.tsx:134
msgid "You've been invited to join a workspace on kan.bn."
msgstr "Je bent uitgenodigd om deel te nemen aan een werkruimte op kan.bn."
#: src/views/invite/index.tsx:135
msgid "You've been invited to join a workspace."
msgstr "Je bent uitgenodigd om deel te nemen aan een werkruimte."
#: src/views/settings/components/DeleteAccountConfirmation.tsx:28 #: src/views/settings/components/DeleteAccountConfirmation.tsx:28
msgid "Your account has been deleted." msgid "Your account has been deleted."
msgstr "Je account is verwijderd." msgstr "Je account is verwijderd."
@@ -2056,15 +2203,15 @@ msgstr "Je weergavenaam is bijgewerkt."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Je wachtwoord is gewijzigd." msgstr "Je wachtwoord is gewijzigd."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:65
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Je profielafbeelding is bijgewerkt." msgstr "Je profielafbeelding is bijgewerkt."
#: src/views/settings/index.tsx:120 #: src/views/settings/IntegrationsSettings.tsx:54
msgid "Your Trello account has been disconnected." msgid "Your Trello account has been disconnected."
msgstr "Je Trello-account is ontkoppeld." msgstr "Je Trello-account is ontkoppeld."
#: src/views/settings/index.tsx:281 #: src/views/settings/IntegrationsSettings.tsx:102
msgid "Your Trello account is connected." msgid "Your Trello account is connected."
msgstr "Je Trello-account is verbonden." msgstr "Je Trello-account is verbonden."

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,7 @@ import type { ReactElement, ReactNode } from "react";
import { Plus_Jakarta_Sans } from "next/font/google"; import { Plus_Jakarta_Sans } from "next/font/google";
import Script from "next/script"; import Script from "next/script";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import { ThemeProvider } from "next-themes";
import posthog from "posthog-js"; import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react"; import { PostHogProvider } from "posthog-js/react";
import { useEffect } from "react"; import { useEffect } from "react";
@@ -14,7 +15,6 @@ import { useEffect } from "react";
import { LinguiProviderWrapper } from "~/providers/lingui"; import { LinguiProviderWrapper } from "~/providers/lingui";
import { ModalProvider } from "~/providers/modal"; import { ModalProvider } from "~/providers/modal";
import { PopupProvider } from "~/providers/popup"; import { PopupProvider } from "~/providers/popup";
import { ThemeProvider } from "next-themes";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const jakarta = Plus_Jakarta_Sans({ const jakarta = Plus_Jakarta_Sans({
@@ -82,8 +82,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
<main className="font-sans"> <main className="font-sans">
<LinguiProviderWrapper> <LinguiProviderWrapper>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem> <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<ModalProvider> <ModalProvider>
<PopupProvider> <PopupProvider>
{posthogKey ? ( {posthogKey ? (
<PostHogProvider client={posthog}> <PostHogProvider client={posthog}>
{getLayout(<Component {...pageProps} />)} {getLayout(<Component {...pageProps} />)}
@@ -91,8 +91,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
) : ( ) : (
getLayout(<Component {...pageProps} />) getLayout(<Component {...pageProps} />)
)} )}
</PopupProvider> </PopupProvider>
</ModalProvider> </ModalProvider>
</ThemeProvider> </ThemeProvider>
</LinguiProviderWrapper> </LinguiProviderWrapper>
</main> </main>

View File

@@ -0,0 +1,5 @@
import InviteView from "~/views/invite";
export default function InvitePage() {
return <InviteView />;
}

View File

@@ -0,0 +1,16 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import { SettingsLayout } from "~/components/SettingsLayout";
import AccountSettings from "~/views/settings/AccountSettings";
const AccountSettingsPage: NextPageWithLayout = () => {
return (
<SettingsLayout currentTab="account">
<AccountSettings />
</SettingsLayout>
);
};
AccountSettingsPage.getLayout = (page) => getDashboardLayout(page);
export default AccountSettingsPage;

View File

@@ -0,0 +1,16 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import { SettingsLayout } from "~/components/SettingsLayout";
import ApiSettings from "~/views/settings/ApiSettings";
const ApiSettingsPage: NextPageWithLayout = () => {
return (
<SettingsLayout currentTab="api">
<ApiSettings />
</SettingsLayout>
);
};
ApiSettingsPage.getLayout = (page) => getDashboardLayout(page);
export default ApiSettingsPage;

View File

@@ -0,0 +1,16 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import { SettingsLayout } from "~/components/SettingsLayout";
import BillingSettings from "~/views/settings/BillingSettings";
const BillingSettingsPage: NextPageWithLayout = () => {
return (
<SettingsLayout currentTab="billing">
<BillingSettings />
</SettingsLayout>
);
};
BillingSettingsPage.getLayout = (page) => getDashboardLayout(page);
export default BillingSettingsPage;

View File

@@ -1,17 +0,0 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import Popup from "~/components/Popup";
import SettingsView from "~/views/settings";
const SettingsPage: NextPageWithLayout = () => {
return (
<>
<SettingsView />
<Popup />
</>
);
};
SettingsPage.getLayout = (page) => getDashboardLayout(page);
export default SettingsPage;

View File

@@ -0,0 +1,16 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import { SettingsLayout } from "~/components/SettingsLayout";
import IntegrationsSettings from "~/views/settings/IntegrationsSettings";
const IntegrationsSettingsPage: NextPageWithLayout = () => {
return (
<SettingsLayout currentTab="integrations">
<IntegrationsSettings />
</SettingsLayout>
);
};
IntegrationsSettingsPage.getLayout = (page) => getDashboardLayout(page);
export default IntegrationsSettingsPage;

View File

@@ -0,0 +1,16 @@
import type { NextPageWithLayout } from "~/pages/_app";
import { getDashboardLayout } from "~/components/Dashboard";
import { SettingsLayout } from "~/components/SettingsLayout";
import WorkspaceSettings from "~/views/settings/WorkspaceSettings";
const WorkspaceSettingsPage: NextPageWithLayout = () => {
return (
<SettingsLayout currentTab="workspace">
<WorkspaceSettings />
</SettingsLayout>
);
};
WorkspaceSettingsPage.getLayout = (page) => getDashboardLayout(page);
export default WorkspaceSettingsPage;

View File

@@ -1,5 +1,5 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { useRouter } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import React, { createContext, useContext, useEffect, useState } from "react"; import React, { createContext, useContext, useEffect, useState } from "react";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
@@ -46,6 +46,8 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
); );
const [hasLoaded, setHasLoaded] = useState(false); const [hasLoaded, setHasLoaded] = useState(false);
const workspacePublicId = useSearchParams().get("workspacePublicId");
const { data, isLoading } = api.workspace.all.useQuery(); const { data, isLoading } = api.workspace.all.useQuery();
const utils = api.useUtils(); const utils = api.useUtils();
@@ -67,7 +69,7 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
} }
const storedWorkspaceId: string | null = const storedWorkspaceId: string | null =
localStorage.getItem("workspacePublicId"); workspacePublicId ?? localStorage.getItem("workspacePublicId");
if (data.length) { if (data.length) {
const workspaces = data.map(({ workspace, role }) => ({ const workspaces = data.map(({ workspace, role }) => ({
@@ -99,6 +101,11 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
description: selectedWorkspace.workspace.description, description: selectedWorkspace.workspace.description,
role: selectedWorkspace.role, role: selectedWorkspace.role,
}); });
if (workspacePublicId) {
router.push(`/boards`);
localStorage.setItem("workspacePublicId", workspacePublicId);
}
} else { } else {
const primaryWorkspace = data[0]?.workspace; const primaryWorkspace = data[0]?.workspace;
const primaryWorkspaceRole = data[0]?.role; const primaryWorkspaceRole = data[0]?.role;
@@ -114,7 +121,7 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
role: primaryWorkspaceRole, role: primaryWorkspaceRole,
}); });
} }
}, [data, isLoading]); }, [data, isLoading, workspacePublicId, router]);
return ( return (
<WorkspaceContext.Provider <WorkspaceContext.Provider

View File

@@ -18,6 +18,8 @@ const loadMessages = async (locale: Locale) => {
return (await import("~/locales/it/messages")).messages; return (await import("~/locales/it/messages")).messages;
case "nl": case "nl":
return (await import("~/locales/nl/messages")).messages; return (await import("~/locales/nl/messages")).messages;
case "ru":
return (await import("~/locales/ru/messages")).messages;
default: default:
return enMessages; return enMessages;
} }

View File

@@ -1,5 +1,5 @@
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro"; import { Trans } from "@lingui/react/macro";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
@@ -17,6 +17,8 @@ export default function LoginPage() {
const [isMagicLinkSent, setIsMagicLinkSent] = useState<boolean>(false); const [isMagicLinkSent, setIsMagicLinkSent] = useState<boolean>(false);
const [magicLinkRecipient, setMagicLinkRecipient] = useState<string>(""); const [magicLinkRecipient, setMagicLinkRecipient] = useState<string>("");
const redirect = useSearchParams().get("next");
const handleMagicLinkSent = (value: boolean, recipient: string) => { const handleMagicLinkSent = (value: boolean, recipient: string) => {
setIsMagicLinkSent(value); setIsMagicLinkSent(value);
setMagicLinkRecipient(recipient); setMagicLinkRecipient(recipient);
@@ -61,7 +63,11 @@ export default function LoginPage() {
<Trans> <Trans>
Don't have an account?{" "} Don't have an account?{" "}
<span className="underline"> <span className="underline">
<Link href="/signup">Sign up</Link> <Link
href={redirect ? `/signup?next=${redirect}` : "/signup"}
>
Sign up
</Link>
</span> </span>
</Trans> </Trans>
</p> </p>

View File

@@ -1,5 +1,5 @@
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro"; import { Trans } from "@lingui/react/macro";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
@@ -17,6 +17,8 @@ export default function SignUpPage() {
const [isMagicLinkSent, setIsMagicLinkSent] = useState<boolean>(false); const [isMagicLinkSent, setIsMagicLinkSent] = useState<boolean>(false);
const [magicLinkRecipient, setMagicLinkRecipient] = useState<string>(""); const [magicLinkRecipient, setMagicLinkRecipient] = useState<string>("");
const redirect = useSearchParams().get("next");
const { data } = authClient.useSession(); const { data } = authClient.useSession();
if (data?.user.id) router.push("/boards"); if (data?.user.id) router.push("/boards");
@@ -86,7 +88,9 @@ export default function SignUpPage() {
<Trans> <Trans>
Already have an account?{" "} Already have an account?{" "}
<span className="underline"> <span className="underline">
<Link href="/login">Sign in</Link> <Link href={redirect ? `/login?next=${redirect}` : "/login"}>
Sign in
</Link>
</span> </span>
</Trans> </Trans>
</p> </p>

View File

@@ -155,7 +155,7 @@ export function UpdateBoardSlugForm({
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
variant="secondary" variant="secondary"
href="/settings?edit=workspace_url" href="/settings?tab=workspace"
onClick={closeModal} onClick={closeModal}
> >
{t`Edit workspace URL`} {t`Edit workspace URL`}

View File

@@ -19,7 +19,7 @@ export function BoardsList() {
if (isLoading) if (isLoading)
return ( return (
<div className="grid h-fit w-full grid-cols-1 gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-7"> <div className="3xl:grid-cols-4 grid h-fit w-full grid-cols-1 gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-3">
<div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" /> <div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
<div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" /> <div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
<div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" /> <div className="mr-5 flex h-[150px] w-full animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
@@ -45,7 +45,7 @@ export function BoardsList() {
); );
return ( return (
<div className="grid h-fit w-full grid-cols-1 gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-7"> <div className="3xl:grid-cols-4 grid h-fit w-full grid-cols-1 gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-3">
{data?.map((board) => ( {data?.map((board) => (
<Link key={board.publicId} href={`boards/${board.publicId}`}> <Link key={board.publicId} href={`boards/${board.publicId}`}>
<div className="align-center relative mr-5 flex h-[150px] w-full items-center justify-center rounded-md border border-dashed border-light-400 bg-light-50 shadow-sm hover:bg-light-200 dark:border-dark-600 dark:bg-dark-50 dark:hover:bg-dark-100"> <div className="align-center relative mr-5 flex h-[150px] w-full items-center justify-center rounded-md border border-dashed border-light-400 bg-light-50 shadow-sm hover:bg-light-200 dark:border-dark-600 dark:bg-dark-50 dark:hover:bg-dark-100">

View File

@@ -0,0 +1,171 @@
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import { useEffect, useState } from "react";
import { authClient } from "@kan/auth/client";
import Button from "~/components/Button";
import LoadingSpinner from "~/components/LoadingSpinner";
import { PageHead } from "~/components/PageHead";
import PatternedBackground from "~/components/PatternedBackground";
import { api } from "~/utils/api";
export default function InvitePage() {
const router = useRouter();
const { code } = router.query;
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const { data: session, isPending: isSessionLoading } =
authClient.useSession();
const isCloudEnv = env("NEXT_PUBLIC_KAN_ENV") === "cloud";
const inviteCode = Array.isArray(code) ? code[0] : code;
const acceptInviteMutation = api.member.acceptInviteLink.useMutation({
onSuccess: (result) => {
if (result.success) {
return router.push(
`/boards?workspacePublicId=${result.workspacePublicId}`,
);
}
},
onError: (error) => {
if (error.data?.code === "CONFLICT") {
return router.push(`/boards`);
}
setError(
error.message ||
t`Failed to accept invitation. Please try again later, or contact customer support.`,
);
setIsProcessing(false);
},
});
const {
data: inviteInfo,
isLoading: isInviteInfoLoading,
isError: isInviteInfoError,
} = api.member.getInviteByCode.useQuery(
{ inviteCode: inviteCode ?? "" },
{
enabled: !!inviteCode,
retry: false,
},
);
// Auto accept invite if user is logged in
useEffect(() => {
if (session?.user.id && inviteCode && inviteInfo && !error) {
setIsProcessing(true);
setError(null);
acceptInviteMutation.mutate({
inviteCode,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [session?.user.id, inviteCode, inviteInfo, error]);
if (
!isInviteInfoError &&
!error &&
(session?.user.id || isInviteInfoLoading || isSessionLoading)
) {
return (
<>
<PageHead title={t`Join workspace`} />
<PatternedBackground />
<div className="flex min-h-screen items-center justify-center">
<LoadingSpinner size="lg" />
</div>
</>
);
}
const PageWrapper = ({ children }: { children: React.ReactNode }) => {
return (
<>
<PageHead title={t`Join workspace | kan.bn`} />
{children}
</>
);
};
if (isInviteInfoError || (!isInviteInfoLoading && !inviteInfo)) {
return (
<PageWrapper>
<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-8">
<div>
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-light-1000 dark:text-dark-1000">
{t`Invalid invitation`}
</h2>
<p className="mt-4 text-center text-sm text-light-900 dark:text-dark-800">
{t`This invitation link is invalid or has expired.`}
</p>
</div>
<div className="text-center">
<Button href="/" variant="primary">
{t`Go Home`}
</Button>
</div>
</div>
</div>
</PageWrapper>
);
}
return (
<PageWrapper>
<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-[400px] space-y-8">
<div>
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-light-1000 dark:text-dark-1000">
{t`Join workspace`}
</h2>
{!error ? (
<p className="mt-4 text-center text-sm text-light-900 dark:text-dark-800">
{isCloudEnv
? t`You've been invited to join a workspace on kan.bn.`
: t`You've been invited to join a workspace.`}
</p>
) : (
<p className="mt-4 text-center text-sm text-red-500">{error}</p>
)}
</div>
<div className="flex justify-center gap-2">
{session?.user.id ? (
<Button href={`/boards`} variant="primary" size="md">
{t`Go to app`}
</Button>
) : (
<>
<Button
href={`/login?next=/invite/${inviteCode}`}
disabled={isProcessing}
variant="primary"
size="md"
>
{t`Sign In`}
</Button>
<Button
href={`/signup?next=/invite/${inviteCode}`}
disabled={isProcessing}
variant="primary"
size="md"
>
{t`Sign Up`}
</Button>
</>
)}
</div>
</div>
</div>
</PageWrapper>
);
}

View File

@@ -3,7 +3,12 @@ import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { HiXMark } from "react-icons/hi2"; import {
HiInformationCircle,
HiMiniCheck,
HiOutlineDocumentDuplicate,
HiXMark,
} from "react-icons/hi2";
import { z } from "zod"; import { z } from "zod";
import type { InviteMemberInput } from "@kan/api/types"; import type { InviteMemberInput } from "@kan/api/types";
@@ -31,7 +36,11 @@ export function InviteMemberForm({
userId: string | undefined; userId: string | undefined;
}) { }) {
const utils = api.useUtils(); const utils = api.useUtils();
const [isCreateAnotherEnabled, setIsCreateAnotherEnabled] = useState(false); const [isShareInviteLinkEnabled, setIsShareInviteLinkEnabled] =
useState(false);
const [inviteLink, setInviteLink] = useState<string>("");
const [isLoadingInviteLink, setIsLoadingInviteLink] = useState(false);
const [copied, setCopied] = useState(false);
const { closeModal } = useModal(); const { closeModal } = useModal();
const { workspace } = useWorkspace(); const { workspace } = useWorkspace();
const { showPopup } = usePopup(); const { showPopup } = usePopup();
@@ -56,6 +65,21 @@ export function InviteMemberForm({
const refetchBoards = () => utils.board.all.refetch(); const refetchBoards = () => utils.board.all.refetch();
// Fetch active invite link on component mount
const { data: activeInviteLink, refetch: refetchInviteLink } =
api.member.getActiveInviteLink.useQuery(
{ workspacePublicId: workspace.publicId || "" },
{ enabled: !!workspace.publicId },
);
// Set initial state based on active invite link
useEffect(() => {
if (activeInviteLink) {
setIsShareInviteLinkEnabled(activeInviteLink.isActive);
setInviteLink(activeInviteLink.inviteLink || "");
}
}, [activeInviteLink]);
const inviteMember = api.member.invite.useMutation({ const inviteMember = api.member.invite.useMutation({
onSuccess: async () => { onSuccess: async () => {
closeModal(); closeModal();
@@ -64,7 +88,7 @@ export function InviteMemberForm({
}, },
onError: (error) => { onError: (error) => {
reset(); reset();
if (!isCreateAnotherEnabled) closeModal(); if (!isShareInviteLinkEnabled) closeModal();
if (error.data?.code === "CONFLICT") { if (error.data?.code === "CONFLICT") {
showPopup({ showPopup({
@@ -82,6 +106,36 @@ export function InviteMemberForm({
}, },
}); });
const createInviteLink = api.member.createInviteLink.useMutation({
onSuccess: (data) => {
setInviteLink(data.inviteLink);
setIsLoadingInviteLink(false);
},
onError: () => {
setIsLoadingInviteLink(false);
showPopup({
header: t`Error creating invite link`,
message: t`Please try again later.`,
icon: "error",
});
},
});
const deactivateInviteLink = api.member.deactivateInviteLink.useMutation({
onSuccess: () => {
setInviteLink("");
setIsLoadingInviteLink(false);
},
onError: () => {
setIsLoadingInviteLink(false);
showPopup({
header: t`Error deactivating invite link`,
message: t`Please try again later.`,
icon: "error",
});
},
});
const teamSubscription = getSubscriptionByPlan(subscriptions, "team"); const teamSubscription = getSubscriptionByPlan(subscriptions, "team");
const proSubscription = getSubscriptionByPlan(subscriptions, "pro"); const proSubscription = getSubscriptionByPlan(subscriptions, "pro");
@@ -109,6 +163,43 @@ export function InviteMemberForm({
inviteMember.mutate(member); inviteMember.mutate(member);
}; };
const handleInviteLinkToggle = async () => {
setIsLoadingInviteLink(true);
if (isShareInviteLinkEnabled && workspace.publicId) {
// Deactivate invite link
await deactivateInviteLink.mutateAsync({
workspacePublicId: workspace.publicId,
});
setIsShareInviteLinkEnabled(false);
} else {
// Create new invite link
await createInviteLink.mutateAsync({
workspacePublicId: workspace.publicId,
});
setIsShareInviteLinkEnabled(true);
}
};
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(inviteLink);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
showPopup({
header: t`Invite link copied`,
message: t`Invite link copied to clipboard`,
icon: "success",
});
} catch (error) {
showPopup({
header: t`Error`,
message: t`Failed to copy invite link`,
icon: "error",
});
}
};
const handleUpgrade = async () => { const handleUpgrade = async () => {
const { data, error } = await authClient.subscription.upgrade({ const { data, error } = await authClient.subscription.upgrade({
plan: "team", plan: "team",
@@ -173,6 +264,34 @@ export function InviteMemberForm({
}} }}
errorMessage={errors.email?.message} errorMessage={errors.email?.message}
/> />
{isShareInviteLinkEnabled && inviteLink && (
<div className="my-4">
<div className="relative">
<Input
value={inviteLink}
className="pr-10 text-sm text-light-900 dark:text-dark-900"
readOnly
/>
<button
type="button"
className="absolute inset-y-0 right-0 flex items-center pr-3 text-light-900 hover:text-light-950 dark:text-dark-900 dark:hover:text-dark-950"
onClick={copyToClipboard}
>
{copied ? (
<HiMiniCheck className="h-5 w-5 text-green-600" />
) : (
<HiOutlineDocumentDuplicate className="h-5 w-5" />
)}
</button>
</div>
<div className="mt-2 flex items-start gap-1">
<HiInformationCircle className="mt-0.5 h-4 w-4 text-dark-900" />
<p className="text-xs text-gray-500 dark:text-dark-900">
{t`Anyone with this link can join your workspace`}
</p>
</div>
</div>
)}
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" && ( {env("NEXT_PUBLIC_KAN_ENV") === "cloud" && (
<div className="mt-3 rounded-md bg-light-100 p-3 text-xs text-light-900 dark:bg-dark-200 dark:text-dark-900"> <div className="mt-3 rounded-md bg-light-100 p-3 text-xs text-light-900 dark:bg-dark-200 dark:text-dark-900">
@@ -205,11 +324,9 @@ export function InviteMemberForm({
{(hasTeamSubscription || hasProSubscription) && {(hasTeamSubscription || hasProSubscription) &&
env("NEXT_PUBLIC_KAN_ENV") === "cloud" && ( env("NEXT_PUBLIC_KAN_ENV") === "cloud" && (
<Toggle <Toggle
label={t`Invite another`} label={t`Share invite link`}
isChecked={isCreateAnotherEnabled} isChecked={isShareInviteLinkEnabled}
onChange={() => onChange={handleInviteLinkToggle}
setIsCreateAnotherEnabled(!isCreateAnotherEnabled)
}
/> />
)} )}
<div> <div>
@@ -226,7 +343,7 @@ export function InviteMemberForm({
) : ( ) : (
<Button <Button
type="submit" type="submit"
disabled={inviteMember.isPending} disabled={inviteMember.isPending || isShareInviteLinkEnabled}
isLoading={inviteMember.isPending} isLoading={inviteMember.isPending}
className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50" className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
> >

View File

@@ -129,9 +129,9 @@ export default function MembersPage() {
{memberRole && {memberRole &&
memberRole.charAt(0).toUpperCase() + memberRole.slice(1)} memberRole.charAt(0).toUpperCase() + memberRole.slice(1)}
</span> </span>
{memberStatus === "invited" && ( {(memberStatus === "invited" || memberStatus === "paused") && (
<span className="mt-1 inline-flex items-center rounded-md bg-gray-500/10 px-1.5 py-0.5 text-[10px] font-medium text-gray-400 ring-1 ring-inset ring-gray-500/20 sm:ml-2 sm:mt-0 sm:text-[11px]"> <span className="mt-1 inline-flex items-center rounded-md bg-gray-500/10 px-1.5 py-0.5 text-[10px] font-medium text-gray-400 ring-1 ring-inset ring-gray-500/20 sm:ml-2 sm:mt-0 sm:text-[11px]">
{t`Pending`} {memberStatus === "invited" ? t`Pending` : t`Paused`}
</span> </span>
)} )}
</div> </div>
@@ -183,7 +183,7 @@ export default function MembersPage() {
<> <>
{!proSubscription && ( {!proSubscription && (
<Link <Link
href="/settings?upgrade=pro" href="/settings/workspace?upgrade=pro"
className="hidden items-center rounded-full border border-emerald-300 bg-emerald-50 px-3 py-1 text-center text-xs text-emerald-400 dark:border-emerald-700 dark:bg-emerald-950 dark:text-emerald-400 lg:flex" className="hidden items-center rounded-full border border-emerald-300 bg-emerald-50 px-3 py-1 text-center text-xs text-emerald-400 dark:border-emerald-700 dark:bg-emerald-950 dark:text-emerald-400 lg:flex"
> >
<HiBolt /> <HiBolt />

View File

@@ -0,0 +1,116 @@
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import { LanguageSelector } from "~/components/LanguageSelector";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import { api } from "~/utils/api";
import Avatar from "./components/Avatar";
import { ChangePasswordFormConfirmation } from "./components/ChangePasswordConfirmation";
import { DeleteAccountConfirmation } from "./components/DeleteAccountConfirmation";
import UpdateDisplayNameForm from "./components/UpdateDisplayNameForm";
export default function AccountSettings() {
const { modalContentType, openModal, isOpen } = useModal();
const isCredentialsEnabled =
env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true";
const { data } = api.user.getUser.useQuery();
return (
<>
<PageHead title={t`Settings | Account`} />
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Profile picture`}
</h2>
<Avatar userId={data?.id} userImage={data?.image} />
<div className="mb-4">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Display name`}
</h2>
<UpdateDisplayNameForm displayName={data?.name ?? ""} />
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Language`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Change your language preferences.`}
</p>
<LanguageSelector />
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Delete account`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Once you delete your account, there is no going back. This action cannot be undone.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("DELETE_ACCOUNT")}
>
{t`Delete account`}
</Button>
</div>
</div>
{isCredentialsEnabled && (
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Change Password`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`You are about to change your password.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("CHANGE_PASSWORD")}
>
{t`Change Password`}
</Button>
</div>
</div>
)}
</div>
{/* Account-specific modals */}
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "DELETE_ACCOUNT"}
>
<DeleteAccountConfirmation />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "CHANGE_PASSWORD"}
>
<ChangePasswordFormConfirmation />
</Modal>
{/* Global modals */}
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
</>
);
}

View File

@@ -0,0 +1,66 @@
import { t } from "@lingui/core/macro";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import ApiKeyList from "./components/ApiKeyList";
import NewApiKeyModal from "./components/NewApiKeyModal";
import { RevokeApiKeyConfirmation } from "./components/RevokeApiKeyConfirmation";
export default function ApiSettings() {
const { modalContentType, openModal, isOpen } = useModal();
return (
<>
<PageHead title={t`Settings | API`} />
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`API keys`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`View and manage your API keys.`}
</p>
<div className="mb-4 flex items-center justify-between">
<Button variant="primary" onClick={() => openModal("NEW_API_KEY")}>
{t`Create new key`}
</Button>
</div>
<ApiKeyList />
</div>
{/* API-specific modals */}
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_API_KEY"}
>
<NewApiKeyModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "REVOKE_API_KEY"}
>
<RevokeApiKeyConfirmation />
</Modal>
{/* Global modals */}
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
</>
);
}

View File

@@ -0,0 +1,68 @@
import { t } from "@lingui/core/macro";
import { HiMiniArrowTopRightOnSquare } from "react-icons/hi2";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
export default function BillingSettings() {
const { modalContentType, isOpen } = useModal();
const handleOpenBillingPortal = async () => {
try {
const response = await fetch("/api/stripe/create_billing_session", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const { url } = (await response.json()) as { url: string };
if (url) {
window.location.href = url;
}
} catch (error) {
console.error("Error creating billing session:", error);
}
};
return (
<>
<PageHead title={t`Settings | Billing`} />
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Billing`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`View and manage your billing and subscription.`}
</p>
<Button
variant="primary"
iconRight={<HiMiniArrowTopRightOnSquare />}
onClick={handleOpenBillingPortal}
>
{t`Billing portal`}
</Button>
</div>
{/* Global modals */}
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
</>
);
}

View File

@@ -0,0 +1,130 @@
import { t } from "@lingui/core/macro";
import { useEffect } from "react";
import { HiMiniArrowTopRightOnSquare } from "react-icons/hi2";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api";
export default function IntegrationsSettings() {
const { modalContentType, isOpen } = useModal();
const { showPopup } = usePopup();
const {
data: integrations,
refetch: refetchIntegrations,
isLoading: integrationsLoading,
} = api.integration.providers.useQuery();
const { data: trelloUrl, refetch: refetchTrelloUrl } =
api.integration.getAuthorizationUrl.useQuery(
{ provider: "trello" },
{
enabled:
!integrationsLoading &&
!integrations?.some(
(integration) => integration.provider === "trello",
),
refetchOnWindowFocus: true,
},
);
useEffect(() => {
const handleFocus = () => {
refetchIntegrations();
};
window.addEventListener("focus", handleFocus);
return () => {
window.removeEventListener("focus", handleFocus);
};
}, [refetchIntegrations]);
const { mutateAsync: disconnectTrello } =
api.integration.disconnect.useMutation({
onSuccess: () => {
refetchIntegrations();
refetchTrelloUrl();
showPopup({
header: t`Trello disconnected`,
message: t`Your Trello account has been disconnected.`,
icon: "success",
});
},
onError: () => {
showPopup({
header: t`Error disconnecting Trello`,
message: t`An error occurred while disconnecting your Trello account.`,
icon: "error",
});
},
});
return (
<>
<PageHead title={t`Settings | Integrations`} />
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Trello`}
</h2>
{!integrations?.some(
(integration) => integration.provider === "trello",
) && trelloUrl ? (
<>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Connect your Trello account to import boards.`}
</p>
<Button
variant="primary"
iconRight={<HiMiniArrowTopRightOnSquare />}
onClick={() =>
window.open(
trelloUrl.url,
"trello_auth",
"height=800,width=600",
)
}
>
{t`Connect Trello`}
</Button>
</>
) : (
integrations?.some(
(integration) => integration.provider === "trello",
) && (
<>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Your Trello account is connected.`}
</p>
<Button
variant="secondary"
onClick={() => disconnectTrello({ provider: "trello" })}
>
{t`Disconnect Trello`}
</Button>
</>
)
)}
</div>
{/* Global modals */}
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
</>
);
}

View File

@@ -0,0 +1,145 @@
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import { useEffect, useState } from "react";
import { HiBolt } from "react-icons/hi2";
import type { Subscription } from "@kan/shared/utils";
import { hasActiveSubscription } from "@kan/shared/utils";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
import { DeleteWorkspaceConfirmation } from "./components/DeleteWorkspaceConfirmation";
import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescriptionForm";
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
export default function WorkspaceSettings() {
const { modalContentType, openModal, isOpen } = useModal();
const { workspace } = useWorkspace();
const router = useRouter();
const { data } = api.user.getUser.useQuery();
const [hasOpenedUpgradeModal, setHasOpenedUpgradeModal] = useState(false);
const { data: workspaceData } = api.workspace.byId.useQuery({
workspacePublicId: workspace.publicId,
});
const subscriptions = workspaceData?.subscriptions as
| Subscription[]
| undefined;
// Open upgrade modal if upgrade=pro is in URL params
useEffect(() => {
if (
router.query.upgrade === "pro" &&
env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!hasActiveSubscription(subscriptions, "pro") &&
!hasOpenedUpgradeModal
) {
openModal("UPGRADE_TO_PRO");
setHasOpenedUpgradeModal(true);
}
}, [router.query.upgrade, subscriptions, openModal, hasOpenedUpgradeModal]);
return (
<>
<PageHead title={t`Settings | Workspace`} />
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Workspace name`}
</h2>
<UpdateWorkspaceNameForm
workspacePublicId={workspace.publicId}
workspaceName={workspace.name}
/>
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Workspace URL`}
</h2>
<UpdateWorkspaceUrlForm
workspacePublicId={workspace.publicId}
workspaceUrl={workspace.slug ?? ""}
workspacePlan={workspace.plan ?? "free"}
/>
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Workspace description`}
</h2>
<UpdateWorkspaceDescriptionForm
workspacePublicId={workspace.publicId}
workspaceDescription={workspace.description ?? ""}
/>
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!hasActiveSubscription(subscriptions, "pro") && (
<div className="my-8">
<Button
onClick={() => openModal("UPGRADE_TO_PRO")}
iconRight={<HiBolt />}
>
{t`Upgrade to Pro`}
</Button>
</div>
)}
<div className="border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Delete workspace`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Once you delete your workspace, there is no going back. This action cannot be undone.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("DELETE_WORKSPACE")}
disabled={workspace.role !== "admin"}
>
{t`Delete workspace`}
</Button>
</div>
</div>
</div>
{/* Workspace-specific modals */}
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "DELETE_WORKSPACE"}
>
<DeleteWorkspaceConfirmation />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "UPGRADE_TO_PRO"}
>
<UpgradeToProConfirmation
userId={data?.id ?? ""}
workspacePublicId={workspace.publicId}
/>
</Modal>
{/* Global modals */}
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
</>
);
}

View File

@@ -0,0 +1,202 @@
import { useQuery } from "@tanstack/react-query";
import { HiEllipsisHorizontal } from "react-icons/hi2";
import { twMerge } from "tailwind-merge";
import { authClient } from "@kan/auth/client";
import Dropdown from "~/components/Dropdown";
import { useModal } from "~/providers/modal";
export default function ApiKeyList() {
const { openModal } = useModal();
const { data, isLoading } = useQuery({
queryKey: ["apiKeys"],
queryFn: () => authClient.apiKey.list(),
});
const TableRow = ({
keyId,
keyName,
keyStart,
createdAt,
lastRequest,
isLastRow,
showSkeleton,
}: {
keyId?: string;
keyName?: string | null | undefined;
keyStart?: string | null | undefined;
createdAt?: Date | null;
lastRequest?: Date | null;
isLastRow?: boolean | undefined;
showSkeleton?: boolean | undefined;
}) => {
const formatDate = (date?: Date | string | null) => {
if (!date) return "Never";
const dateObj = date instanceof Date ? date : new Date(date);
return dateObj.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
};
return (
<tr className="rounded-b-lg">
<td className={twMerge("w-[30%]", isLastRow ? "rounded-bl-lg" : "")}>
<div className="flex items-center p-4">
<div className="ml-2 min-w-0 flex-1">
<div>
<div className="flex items-center">
<p
className={twMerge(
"mr-2 text-sm font-medium text-light-900 dark:text-dark-900",
showSkeleton &&
"md mb-2 h-3 w-[125px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
)}
>
{keyName}
</p>
</div>
</div>
</div>
</div>
</td>
<td className="w-[20%] px-3 py-4">
<p
className={twMerge(
"text-sm text-light-900 dark:text-dark-900",
showSkeleton &&
"h-3 w-[80px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
)}
>
{formatDate(createdAt)}
</p>
</td>
<td className="w-[20%] px-3 py-4">
<p
className={twMerge(
"text-sm text-light-900 dark:text-dark-900",
showSkeleton &&
"h-3 w-[80px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
)}
>
{formatDate(lastRequest)}
</p>
</td>
<td className="w-[25%] px-3 py-4">
<div>
<span
className={twMerge(
"inline-flex items-center rounded-md bg-emerald-500/10 px-1.5 py-0.5 text-[11px] font-medium text-emerald-400 ring-1 ring-inset ring-emerald-500/20",
showSkeleton &&
"h-5 w-[50px] animate-pulse bg-light-200 ring-0 dark:bg-dark-200",
)}
>
{keyStart}...
</span>
</div>
</td>
<td
className={twMerge(
"w-[5%] min-w-[50px]",
isLastRow && "rounded-br-lg",
)}
>
<div className="flex w-full items-center justify-center px-3">
<div className="relative z-50">
<Dropdown
items={[
{
label: "Revoke",
action: () =>
openModal("REVOKE_API_KEY", keyId, keyName ?? ""),
},
]}
>
<HiEllipsisHorizontal
size={25}
className="text-light-900 dark:text-dark-900"
/>
</Dropdown>
</div>
</div>
</td>
</tr>
);
};
if (!isLoading && (!data?.data || data.data.length === 0)) {
return null;
}
return (
<div className="mt-8 flow-root">
<div className="overflow-x-auto overflow-y-visible">
<div className="inline-block min-w-full py-2 pb-12 align-middle">
<div className="relative h-full shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
<table className="min-w-[600px] divide-y divide-light-600 dark:divide-dark-600">
<thead className="rounded-t-lg bg-light-300 dark:bg-dark-200">
<tr>
<th
scope="col"
className="w-[30%] rounded-tl-lg py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-light-900 dark:text-dark-900 sm:pl-6"
>
Name
</th>
<th
scope="col"
className="w-[20%] px-3 py-3.5 text-left text-sm font-semibold text-light-900 dark:text-dark-900"
>
Created
</th>
<th
scope="col"
className="w-[20%] px-3 py-3.5 text-left text-sm font-semibold text-light-900 dark:text-dark-900"
>
Last Used
</th>
<th
scope="col"
className="w-[25%] px-3 py-3.5 text-left text-sm font-semibold text-light-900 dark:text-dark-900"
>
Key
</th>
<th
scope="col"
className="w-[5%] rounded-tr-lg px-3 py-3.5 text-center text-sm font-semibold text-light-900 dark:text-dark-900"
>
{/* Actions column */}
</th>
</tr>
</thead>
<tbody className="divide-y divide-light-600 bg-light-50 dark:divide-dark-600 dark:bg-dark-100">
{!isLoading &&
data?.data?.map((apiKey, index) => (
<TableRow
key={apiKey.id}
keyId={apiKey.id}
keyName={apiKey.name}
keyStart={apiKey.start}
createdAt={apiKey.createdAt}
lastRequest={apiKey.lastRequest}
isLastRow={index === data.data.length - 1}
/>
))}
{isLoading && (
<>
<TableRow showSkeleton />
<TableRow showSkeleton />
<TableRow showSkeleton isLastRow />
</>
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,14 +1,45 @@
import Image from "next/image"; import Image from "next/image";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import { useState } from "react"; import { useCallback, useRef, useState } from "react";
import ReactCrop from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { generateUID } from "@kan/shared/utils"; import { generateUID } from "@kan/shared/utils";
import Button from "~/components/Button";
import Modal from "~/components/modal";
import { usePopup } from "~/providers/popup"; import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { getAvatarUrl } from "~/utils/helpers"; import { getAvatarUrl } from "~/utils/helpers";
interface PercentCrop {
unit: "%";
x: number;
y: number;
width: number;
height: number;
}
interface LocalPixelCrop {
x: number;
y: number;
width: number;
height: number;
}
interface ReactCropProps {
crop: PercentCrop | undefined;
onChange: (crop: LocalPixelCrop, percentCrop: PercentCrop) => void;
aspect?: number;
className?: string;
circularCrop?: boolean;
children: React.ReactNode;
}
const AnyReactCrop = ReactCrop as unknown as React.FC<ReactCropProps>;
export default function Avatar({ export default function Avatar({
userId, userId,
userImage, userImage,
@@ -19,6 +50,13 @@ export default function Avatar({
const utils = api.useUtils(); const utils = api.useUtils();
const { showPopup } = usePopup(); const { showPopup } = usePopup();
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [cropDialogOpen, setCropDialogOpen] = useState(false);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [selectedPreviewUrl, setSelectedPreviewUrl] = useState<string | null>(
null,
);
const [crop, setCrop] = useState<PercentCrop>();
const imgRef = useRef<HTMLImageElement | null>(null);
const updateUser = api.user.update.useMutation({ const updateUser = api.user.update.useMutation({
onSuccess: async () => { onSuccess: async () => {
@@ -45,24 +83,109 @@ export default function Avatar({
const avatarUrl = userImage ? getAvatarUrl(userImage) : undefined; const avatarUrl = userImage ? getAvatarUrl(userImage) : undefined;
const uploadAvatar = async (event: React.ChangeEvent<HTMLInputElement>) => { const onFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
try { event.preventDefault();
event.preventDefault(); const file = event.target.files?.[0] ?? null;
if (!file || !userId) {
return showPopup({
header: t`Error uploading profile image`,
message: t`Please select a file to upload.`,
icon: "error",
});
}
// Open crop dialog with preview
setSelectedFile(file);
const objUrl = URL.createObjectURL(file);
setSelectedPreviewUrl(objUrl);
setCropDialogOpen(true);
};
const file = event.target.files?.[0]; const onImageLoad = useCallback(
(e: React.SyntheticEvent<HTMLImageElement>) => {
if (!file || !userId) { const { naturalWidth, naturalHeight } = e.currentTarget;
return showPopup({ // Create a centered square crop at ~90% of the smaller dimension
header: t`Error uploading profile image`, // Compute width% so that the square fits within the image
message: t`Please select a file to upload.`, let widthPercent: number;
icon: "error", let heightPercent: number;
}); if (naturalWidth >= naturalHeight) {
// landscape: height is limiting
heightPercent = 90;
widthPercent = (naturalHeight / naturalWidth) * heightPercent;
} else {
// portrait: width is limiting
widthPercent = 90;
heightPercent = (naturalWidth / naturalHeight) * widthPercent;
} }
const x = (100 - widthPercent) / 2;
const y = (100 - heightPercent) / 2;
setCrop({ unit: "%", x, y, width: widthPercent, height: heightPercent });
},
[],
);
const fileExt = file.name.split(".").pop(); const getCroppedBlob = useCallback(async (): Promise<Blob> => {
const fileName = `${userId}/avatar-${generateUID()}.${fileExt}`; if (!imgRef.current || !crop) throw new Error("No crop to save");
const image = imgRef.current;
const canvas = document.createElement("canvas");
const cropXpx = (crop.x / 100) * image.naturalWidth;
const cropYpx = (crop.y / 100) * image.naturalHeight;
const cropWpx = (crop.width / 100) * image.naturalWidth;
const cropHpx = (crop.height / 100) * image.naturalHeight;
canvas.width = Math.max(1, Math.floor(cropWpx));
canvas.height = Math.max(1, Math.floor(cropHpx));
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Canvas not supported");
// For better quality on HiDPI screens
const pixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.width * pixelRatio;
canvas.height = canvas.height * pixelRatio;
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = "high";
ctx.drawImage(
image,
cropXpx,
cropYpx,
cropWpx,
cropHpx,
0,
0,
canvas.width / pixelRatio,
canvas.height / pixelRatio,
);
const mime = selectedFile?.type ?? "image/jpeg";
const blob: Blob = await new Promise((resolve, reject) => {
canvas.toBlob(
(b) => (b ? resolve(b) : reject(new Error("toBlob failed"))),
mime,
);
});
return blob;
}, [crop, selectedFile]);
const resetCropState = useCallback(() => {
setCrop(undefined);
setSelectedFile(null);
if (selectedPreviewUrl) URL.revokeObjectURL(selectedPreviewUrl);
setSelectedPreviewUrl(null);
}, [selectedPreviewUrl]);
const handleCancelCrop = useCallback(() => {
setCropDialogOpen(false);
resetCropState();
}, [resetCropState]);
const handleSaveCrop = useCallback(async () => {
try {
if (!userId || !selectedFile) return;
setUploading(true); setUploading(true);
const blob = await getCroppedBlob();
const originalExt = selectedFile.name.split(".").pop() ?? "jpg";
const fileName = `${userId}/avatar-${generateUID()}.${originalExt}`;
const response = await fetch( const response = await fetch(
env("NEXT_PUBLIC_BASE_URL") + "/api/upload/image", env("NEXT_PUBLIC_BASE_URL") + "/api/upload/image",
@@ -71,26 +194,24 @@ export default function Avatar({
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ filename: fileName, contentType: file.type }), body: JSON.stringify({ filename: fileName, contentType: blob.type }),
}, },
); );
if (!response.ok) throw new Error("Failed to get pre-signed URL"); if (!response.ok) throw new Error("Failed to get pre-signed URL");
const { url } = (await response.json()) as { const { url } = (await response.json()) as { url: string };
url: string;
};
const uploadResponse = await fetch(url, { const uploadResponse = await fetch(url, {
method: "PUT", method: "PUT",
body: file, body: blob,
}); });
if (!uploadResponse.ok) throw new Error("Failed to upload profile image"); if (!uploadResponse.ok) throw new Error("Failed to upload profile image");
updateUser.mutate({ updateUser.mutate({ image: fileName });
image: fileName, setCropDialogOpen(false);
}); resetCropState();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
showPopup({ showPopup({
@@ -101,7 +222,14 @@ export default function Avatar({
} finally { } finally {
setUploading(false); setUploading(false);
} }
}; }, [
getCroppedBlob,
resetCropState,
selectedFile,
showPopup,
updateUser,
userId,
]);
return ( return (
<div> <div>
@@ -111,7 +239,7 @@ export default function Avatar({
type="file" type="file"
id="single" id="single"
accept="image/*" accept="image/*"
onChange={uploadAvatar} onChange={onFileChange}
disabled={uploading} disabled={uploading}
/> />
{avatarUrl ? ( {avatarUrl ? (
@@ -134,6 +262,56 @@ export default function Avatar({
</span> </span>
)} )}
</div> </div>
{/* Crop Dialog */}
{cropDialogOpen && (
<Modal modalSize="md" positionFromTop="sm" isVisible>
<div className="p-4 sm:p-6">
<div className="mb-4">
<h3 className="text-base font-semibold text-light-1000 dark:text-dark-1000">
{t`Crop your avatar`}
</h3>
<p className="mt-1 text-sm text-light-800 dark:text-dark-800">
{t`Adjust the square crop to fit your avatar.`}
</p>
</div>
<div className="max-h-[80vh]">
<div className="rounded-md border border-light-600 p-2 dark:border-dark-600">
<AnyReactCrop
crop={crop}
onChange={(_crop: LocalPixelCrop, percentCrop: PercentCrop) =>
setCrop(percentCrop)
}
aspect={1}
circularCrop
className="w-full"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
ref={imgRef}
src={selectedPreviewUrl ?? undefined}
alt="Avatar to crop"
onLoad={onImageLoad}
className="h-auto max-h-[50vh] w-full object-contain"
/>
</AnyReactCrop>
</div>
</div>
<div className="mt-6 flex items-center justify-end gap-2">
<Button
variant="ghost"
onClick={handleCancelCrop}
disabled={uploading}
>
{t`Cancel`}
</Button>
<Button onClick={handleSaveCrop} isLoading={uploading}>
{t`Save`}
</Button>
</div>
</div>
</Modal>
)}
</div> </div>
); );
} }

View File

@@ -1,60 +0,0 @@
import { t } from "@lingui/core/macro";
import { authClient } from "@kan/auth/client";
import Button from "~/components/Button";
import Input from "~/components/Input";
const CreateAPIKeyForm = ({
apiKey,
refetchUser,
}: {
apiKey:
| {
id: number;
prefix: string | null;
key: string;
}
| null
| undefined;
refetchUser: () => void;
}) => {
const handleCreateAPIKey = async () => {
await authClient.apiKey.create({
name: "Kan API Key",
prefix: "kan_",
});
refetchUser();
};
const handleRevokeAPIKey = async () => {
if (!apiKey) return;
await authClient.apiKey.delete({
keyId: apiKey.id.toString(),
});
refetchUser();
};
return (
<div>
{apiKey ? (
<div className="flex gap-2">
<div className="mb-4 flex w-full max-w-[325px] items-center gap-2">
<Input value={apiKey.key} readOnly type="password" />
</div>
<div>
<Button variant="danger" onClick={handleRevokeAPIKey}>
{t`Revoke`}
</Button>
</div>
</div>
) : (
<Button onClick={handleCreateAPIKey}>{t`Create new key`}</Button>
)}
</div>
);
};
export default CreateAPIKeyForm;

View File

@@ -0,0 +1,69 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { authClient } from "@kan/auth/client";
import Button from "~/components/Button";
import Input from "~/components/Input";
import { useModal } from "~/providers/modal";
const newApiKeySchema = z.object({
name: z.string().min(1),
});
export default function NewApiKeyForm() {
const { openModal } = useModal();
const form = useForm({
resolver: zodResolver(newApiKeySchema),
defaultValues: {
name: "",
},
});
const qc = useQueryClient();
const createApiKeyMutation = useMutation({
mutationFn: ({ name }: { name: string }) =>
authClient.apiKey.create({ name, prefix: "kan_" }),
onSuccess: ({ data: apiKey }) => {
qc.invalidateQueries({
queryKey: ["apiKeys"],
});
openModal("API_KEY_CREATED", apiKey?.key, apiKey?.name ?? "");
},
onError: () => {
form.setError("name", {
type: "manual",
message: "Failed to create API key",
});
},
});
const handleSubmit = (data: z.infer<typeof newApiKeySchema>) => {
createApiKeyMutation.mutate({ name: data.name });
};
return (
<div className="px-2 py-2">
<form
onSubmit={form.handleSubmit(handleSubmit)}
className="flex flex-col gap-2"
>
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
New API key
</h2>
<Input
{...form.register("name")}
placeholder="Name"
className="w-full"
errorMessage={form.formState.errors.name?.message}
/>
<Button type="submit" isLoading={createApiKeyMutation.isPending}>
Create
</Button>
</form>
</div>
);
}

View File

@@ -0,0 +1,181 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/core/macro";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import {
HiInformationCircle,
HiMiniCheck,
HiOutlineDocumentDuplicate,
HiXMark,
} from "react-icons/hi2";
import { z } from "zod";
import { authClient } from "@kan/auth/client";
import Button from "~/components/Button";
import Input from "~/components/Input";
import { useClipboard } from "~/hooks/useClipboard";
import { useModal } from "~/providers/modal";
const newApiKeySchema = z.object({
name: z
.string()
.min(1, { message: t`API key name is required` })
.max(30, { message: t`API key name cannot exceed 30 characters` }),
});
export default function NewApiKeyModal() {
const { closeModal } = useModal();
const { copied, copy } = useClipboard({ timeout: 2000 });
const [createdApiKey, setCreatedApiKey] = useState<{
key: string;
name: string;
} | null>(null);
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<z.infer<typeof newApiKeySchema>>({
resolver: zodResolver(newApiKeySchema),
defaultValues: {
name: "",
},
});
const qc = useQueryClient();
const createApiKeyMutation = useMutation({
mutationFn: ({ name }: { name: string }) =>
authClient.apiKey.create({ name, prefix: "kan_" }),
onSuccess: ({ data: apiKey }) => {
void qc.invalidateQueries({
queryKey: ["apiKeys"],
});
if (apiKey && apiKey.key && apiKey.name) {
setCreatedApiKey({
key: apiKey.key,
name: apiKey.name,
});
}
},
onError: () => {
// Handle error if needed
},
});
const onSubmit = (data: z.infer<typeof newApiKeySchema>) => {
createApiKeyMutation.mutate({ name: data.name });
};
useEffect(() => {
// Reset state and form when modal opens
setCreatedApiKey(null);
reset();
}, [reset]);
useEffect(() => {
if (!createdApiKey) {
const nameElement = document.querySelector<HTMLElement>("#name");
if (nameElement) nameElement.focus();
}
}, [createdApiKey]);
if (createdApiKey) {
return (
<div>
<div className="px-5 pt-5">
<div className="flex w-full items-center justify-between pb-4 text-neutral-900 dark:text-dark-1000">
<h2 className="text-sm font-bold">{t`API key created`}</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-300 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
closeModal();
}}
>
<HiXMark
size={18}
className="text-light-900 dark:text-dark-900"
/>
</button>
</div>
<div className="mb-4">
<div className="relative">
<Input
value={createdApiKey.key}
className="pr-10 text-sm text-light-900 dark:text-dark-900"
readOnly
/>
<button
type="button"
className="absolute inset-y-0 right-0 flex items-center pr-3 text-light-900 hover:text-light-950 dark:text-dark-900 dark:hover:text-dark-950"
onClick={() => copy(createdApiKey.key)}
>
{copied ? (
<HiMiniCheck className="h-5 w-5 text-green-600" />
) : (
<HiOutlineDocumentDuplicate className="h-5 w-5" />
)}
</button>
</div>
<div className="mt-2 flex items-start gap-1">
<HiInformationCircle className="mt-0.5 h-4 w-4 text-dark-900" />
<p className="text-xs text-gray-500 dark:text-dark-900">
{t`This API key will only be shown once. Please save it in a secure location.`}
</p>
</div>
</div>
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
<div>
<Button onClick={() => closeModal()}>{t`Close`}</Button>
</div>
</div>
</div>
);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="px-5 pt-5">
<div className="flex w-full items-center justify-between pb-4 text-neutral-900 dark:text-dark-1000">
<h2 className="text-sm font-bold">{t`New API key`}</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-300 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
closeModal();
}}
>
<HiXMark size={18} className="text-light-900 dark:text-dark-900" />
</button>
</div>
<Input
id="name"
placeholder={t`API key name`}
{...register("name", { required: true })}
errorMessage={errors.name?.message}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
<div>
<Button type="submit" isLoading={createApiKeyMutation.isPending}>
{t`Create API key`}
</Button>
</div>
</div>
</form>
);
}

View File

@@ -0,0 +1,96 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { authClient } from "@kan/auth/client";
import Button from "~/components/Button";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
export function RevokeApiKeyConfirmation() {
const { closeModal, entityId, entityLabel } = useModal();
const { showPopup } = usePopup();
const qc = useQueryClient();
const [isAcknowledgmentChecked, setIsAcknowledgmentChecked] = useState(false);
const deleteApiKeyMutation = useMutation({
mutationFn: () => authClient.apiKey.delete({ keyId: entityId }),
onSuccess: async () => {
closeModal();
showPopup({
header: "API key revoked",
message: `Your API key: ${entityLabel} has been revoked.`,
icon: "success",
});
qc.invalidateQueries({
queryKey: ["apiKeys"],
});
},
onError: () => {
closeModal();
showPopup({
header: "Error revoking API key",
message: "Please try again later, or contact customer support.",
icon: "error",
});
},
});
const handleRevokeApiKey = () => {
deleteApiKeyMutation.mutate();
};
return (
<div className="p-5">
<div className="flex w-full flex-col justify-between pb-4">
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
{`Are you sure you want to revoke this API key: ${entityLabel}?`}
</h2>
<p className="mb-4 text-sm text-light-900 dark:text-dark-900">
Keep in mind that this action is irreversible.
</p>
<p className="text-sm text-light-900 dark:text-dark-900">
This will result in the permanent revocation of this API key.
</p>
</div>
<div className="relative flex items-start">
<div className="flex h-6 items-center">
<input
id="acknowledgment"
name="acknowledgment"
type="checkbox"
aria-describedby="acknowledgment-description"
className="mt-2 h-[14px] w-[14px] rounded border-gray-300 bg-transparent text-indigo-600 focus:shadow-none focus:ring-0 focus:ring-offset-0"
checked={isAcknowledgmentChecked}
onChange={() =>
setIsAcknowledgmentChecked(!isAcknowledgmentChecked)
}
/>
</div>
<div className="ml-3 text-sm leading-6">
<p
id="comments-description"
className="text-light-900 dark:text-dark-1000"
>
I acknowledge that this API key will be permanently revoked and want
to proceed.
</p>
</div>
</div>
<div className="mt-5 flex justify-end space-x-2 sm:mt-6">
<Button variant="secondary" onClick={() => closeModal()}>
Cancel
</Button>
<Button
variant="danger"
onClick={handleRevokeApiKey}
disabled={!isAcknowledgmentChecked}
isLoading={deleteApiKeyMutation.isPending}
>
Revoke API key
</Button>
</div>
</div>
);
}

View File

@@ -69,16 +69,18 @@ const UpdateDisplayNameForm = ({ displayName }: { displayName: string }) => {
<div className="mb-4 flex w-full max-w-[325px] items-center gap-2"> <div className="mb-4 flex w-full max-w-[325px] items-center gap-2">
<Input {...register("name")} errorMessage={errors.name?.message} /> <Input {...register("name")} errorMessage={errors.name?.message} />
</div> </div>
<div> {isDirty && (
<Button <div>
onClick={handleSubmit(onSubmit)} <Button
variant="primary" onClick={handleSubmit(onSubmit)}
disabled={!isDirty || updateDisplayName.isPending} variant="primary"
isLoading={updateDisplayName.isPending} disabled={updateDisplayName.isPending}
> isLoading={updateDisplayName.isPending}
{t`Update`} >
</Button> {t`Update`}
</div> </Button>
</div>
)}
</div> </div>
); );
}; };

View File

@@ -80,16 +80,18 @@ const UpdateWorkspaceDescriptionForm = ({
errorMessage={errors.description?.message} errorMessage={errors.description?.message}
/> />
</div> </div>
<div> {isDirty && (
<Button <div>
onClick={handleSubmit(onSubmit)} <Button
variant="primary" onClick={handleSubmit(onSubmit)}
disabled={!isDirty || updateWorkspaceDescription.isPending} variant="primary"
isLoading={updateWorkspaceDescription.isPending} disabled={updateWorkspaceDescription.isPending}
> isLoading={updateWorkspaceDescription.isPending}
{t`Update`} >
</Button> {t`Update`}
</div> </Button>
</div>
)}
</div> </div>
); );
}; };

View File

@@ -72,16 +72,18 @@ const UpdateWorkspaceNameForm = ({
<div className="mb-4 flex w-full max-w-[325px] items-center gap-2"> <div className="mb-4 flex w-full max-w-[325px] items-center gap-2">
<Input {...register("name")} errorMessage={errors.name?.message} /> <Input {...register("name")} errorMessage={errors.name?.message} />
</div> </div>
<div> {isDirty && (
<Button <div>
onClick={handleSubmit(onSubmit)} <Button
variant="primary" onClick={handleSubmit(onSubmit)}
disabled={!isDirty || updateWorkspaceName.isPending} variant="primary"
isLoading={updateWorkspaceName.isPending} disabled={updateWorkspaceName.isPending}
> isLoading={updateWorkspaceName.isPending}
{t`Update`} >
</Button> {t`Update`}
</div> </Button>
</div>
)}
</div> </div>
); );
}; };

View File

@@ -138,22 +138,23 @@ const UpdateWorkspaceUrlForm = ({
} }
/> />
</div> </div>
<div> {isDirty && (
<Button <div>
onClick={handleSubmit(onSubmit)} <Button
variant="primary" onClick={handleSubmit(onSubmit)}
disabled={ variant="primary"
!isDirty || disabled={
updateWorkspaceSlug.isPending || updateWorkspaceSlug.isPending ||
checkWorkspaceSlugAvailability.isPending || checkWorkspaceSlugAvailability.isPending ||
isWorkspaceSlugAvailable?.isAvailable === false || isWorkspaceSlugAvailable?.isAvailable === false ||
isTyping isTyping
} }
isLoading={updateWorkspaceSlug.isPending} isLoading={updateWorkspaceSlug.isPending}
> >
{t`Update`} {t`Update`}
</Button> </Button>
</div> </div>
)}
</div> </div>
); );
}; };

View File

@@ -1,412 +0,0 @@
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import { useEffect, useRef, useState } from "react";
import { HiBolt, HiMiniArrowTopRightOnSquare } from "react-icons/hi2";
import type { Subscription } from "@kan/shared/utils";
import { hasActiveSubscription } from "@kan/shared/utils";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import { LanguageSelector } from "~/components/LanguageSelector";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
import Avatar from "./components/Avatar";
import { ChangePasswordFormConfirmation } from "./components/ChangePasswordConfirmation";
import CreateAPIKeyForm from "./components/CreateAPIKeyForm";
import { DeleteAccountConfirmation } from "./components/DeleteAccountConfirmation";
import { DeleteWorkspaceConfirmation } from "./components/DeleteWorkspaceConfirmation";
import UpdateDisplayNameForm from "./components/UpdateDisplayNameForm";
import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescriptionForm";
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
export default function SettingsPage() {
const { modalContentType, openModal, isOpen } = useModal();
const { workspace } = useWorkspace();
const utils = api.useUtils();
const { showPopup } = usePopup();
const router = useRouter();
const workspaceUrlSectionRef = useRef<HTMLDivElement>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const [hasOpenedUpgradeModal, setHasOpenedUpgradeModal] = useState(false);
const isCredentialsEnabled =
env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true";
const { data } = api.user.getUser.useQuery();
const { data: workspaceData } = api.workspace.byId.useQuery({
workspacePublicId: workspace.publicId,
});
const subscriptions = workspaceData?.subscriptions as
| Subscription[]
| undefined;
const {
data: integrations,
refetch: refetchIntegrations,
isLoading: integrationsLoading,
} = api.integration.providers.useQuery();
const { data: trelloUrl, refetch: refetchTrelloUrl } =
api.integration.getAuthorizationUrl.useQuery(
{ provider: "trello" },
{
enabled:
!integrationsLoading &&
!integrations?.some(
(integration) => integration.provider === "trello",
),
refetchOnWindowFocus: true,
},
);
useEffect(() => {
const handleFocus = () => {
refetchIntegrations();
};
window.addEventListener("focus", handleFocus);
return () => {
window.removeEventListener("focus", handleFocus);
};
}, [refetchIntegrations]);
useEffect(() => {
if (
router.query.edit === "workspace_url" &&
workspaceUrlSectionRef.current &&
scrollContainerRef.current
) {
const element = workspaceUrlSectionRef.current;
const container = scrollContainerRef.current;
container.scrollTop = element.offsetTop - 40;
const input = element.querySelector('input[type="text"]');
if (input instanceof HTMLInputElement) {
input.focus();
}
}
}, [router.query.edit]);
// Open upgrade modal if upgrade=pro is in URL params
useEffect(() => {
if (
router.query.upgrade === "pro" &&
env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!hasActiveSubscription(subscriptions, "pro") &&
!hasOpenedUpgradeModal
) {
openModal("UPGRADE_TO_PRO");
setHasOpenedUpgradeModal(true);
}
}, [router.query.upgrade, subscriptions, openModal, hasOpenedUpgradeModal]);
const { mutateAsync: disconnectTrello } =
api.integration.disconnect.useMutation({
onSuccess: () => {
refetchUser();
refetchIntegrations();
refetchTrelloUrl();
showPopup({
header: t`Trello disconnected`,
message: t`Your Trello account has been disconnected.`,
icon: "success",
});
},
onError: () => {
showPopup({
header: t`Error disconnecting Trello`,
message: t`An error occurred while disconnecting your Trello account.`,
icon: "error",
});
},
});
const refetchUser = () => utils.user.getUser.refetch();
const handleOpenBillingPortal = async () => {
try {
const response = await fetch("/api/stripe/create_billing_session", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const { url } = (await response.json()) as { url: string };
if (url) {
window.location.href = url;
}
} catch (error) {
console.error("Error creating billing session:", error);
}
};
return (
<>
<div className="flex h-full w-full flex-col overflow-hidden">
<div
ref={scrollContainerRef}
className="h-full max-h-[calc(100vdh-3rem)] overflow-y-auto md:max-h-[calc(100vdh-4rem)]"
>
<PageHead title={t`Settings | ${workspace.name ?? "Workspace"}`} />
<div className="m-auto max-w-[1100px] px-5 py-6 md:px-28 md:py-12">
<div className="mb-8 flex w-full justify-between">
<h1 className="font-bold tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
{t`Settings`}
</h1>
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Profile picture`}
</h2>
<Avatar userId={data?.id} userImage={data?.image} />
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Display name`}
</h2>
<UpdateDisplayNameForm displayName={data?.name ?? ""} />
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Workspace name`}
</h2>
<UpdateWorkspaceNameForm
workspacePublicId={workspace.publicId}
workspaceName={workspace.name}
/>
<div ref={workspaceUrlSectionRef}>
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Workspace URL`}
</h2>
<UpdateWorkspaceUrlForm
workspacePublicId={workspace.publicId}
workspaceUrl={workspace.slug ?? ""}
workspacePlan={workspace.plan ?? "free"}
/>
</div>
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Workspace description`}
</h2>
<UpdateWorkspaceDescriptionForm
workspacePublicId={workspace.publicId}
workspaceDescription={workspace.description ?? ""}
/>
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!hasActiveSubscription(subscriptions, "pro") && (
<div className="mt-8">
<Button
onClick={() => openModal("UPGRADE_TO_PRO")}
iconRight={<HiBolt />}
>
{t`Upgrade to Pro`}
</Button>
</div>
)}
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Language`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Change the language of the app.`}
</p>
<LanguageSelector />
</div>
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" && (
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Billing`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`View and manage your billing and subscription.`}
</p>
<Button
variant="primary"
iconRight={<HiMiniArrowTopRightOnSquare />}
onClick={handleOpenBillingPortal}
>
{t`Billing portal`}
</Button>
</div>
)}
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
Trello
</h2>
{!integrations?.some(
(integration) => integration.provider === "trello",
) && trelloUrl ? (
<>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Connect your Trello account to import boards.`}
</p>
<Button
variant="primary"
iconRight={<HiMiniArrowTopRightOnSquare />}
onClick={() =>
window.open(
trelloUrl.url,
"trello_auth",
"height=800,width=600",
)
}
>
{t`Connect Trello`}
</Button>
</>
) : (
integrations?.some(
(integration) => integration.provider === "trello",
) && (
<>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Your Trello account is connected.`}
</p>
<Button
variant="secondary"
onClick={() => disconnectTrello({ provider: "trello" })}
>
{t`Disconnect Trello`}
</Button>
</>
)
)}
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`API keys`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`View and manage your API keys.`}
</p>
<CreateAPIKeyForm
apiKey={data?.apiKey}
refetchUser={refetchUser}
/>
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Delete workspace`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Once you delete your workspace, there is no going back. This action cannot be undone.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("DELETE_WORKSPACE")}
disabled={workspace.role !== "admin"}
>
{t`Delete workspace`}
</Button>
</div>
</div>
{isCredentialsEnabled && (
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Change Password`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`You are about to change your password.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("CHANGE_PASSWORD")}
>
{t`Change Password`}
</Button>
</div>
</div>
)}
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
{t`Delete account`}
</h2>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Once you delete your account, there is no going back. This action cannot be undone.`}
</p>
<div className="mt-4">
<Button
variant="secondary"
onClick={() => openModal("DELETE_ACCOUNT")}
>
{t`Delete account`}
</Button>
</div>
</div>
</div>
<>
<Modal
modalSize="md"
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
>
<FeedbackModal />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
>
<NewWorkspaceForm />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "DELETE_WORKSPACE"}
>
<DeleteWorkspaceConfirmation />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "UPGRADE_TO_PRO"}
>
<UpgradeToProConfirmation
userId={data?.id ?? ""}
workspacePublicId={workspace.publicId}
/>
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "DELETE_ACCOUNT"}
>
<DeleteAccountConfirmation />
</Modal>
<Modal
modalSize="sm"
isVisible={isOpen && modalContentType === "CHANGE_PASSWORD"}
>
<ChangePasswordFormConfirmation />
</Modal>
</>
</div>
</div>
</>
);
}

View File

@@ -1,14 +1,19 @@
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { z } from "zod"; import { z } from "zod";
import * as inviteLinkRepo from "@kan/db/repository/inviteLink.repo";
import * as memberRepo from "@kan/db/repository/member.repo"; import * as memberRepo from "@kan/db/repository/member.repo";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo"; import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as userRepo from "@kan/db/repository/user.repo"; import * as userRepo from "@kan/db/repository/user.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo"; import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { getSubscriptionByPlan, hasUnlimitedSeats } from "@kan/shared/utils"; import {
generateUID,
getSubscriptionByPlan,
hasUnlimitedSeats,
} from "@kan/shared/utils";
import { updateSubscriptionSeats } from "@kan/stripe"; import { updateSubscriptionSeats } from "@kan/stripe";
import { createTRPCRouter, protectedProcedure } from "../trpc"; import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import { assertUserInWorkspace } from "../utils/auth"; import { assertUserInWorkspace } from "../utils/auth";
export const memberRouter = createTRPCRouter({ export const memberRouter = createTRPCRouter({
@@ -241,4 +246,379 @@ export const memberRouter = createTRPCRouter({
return { success: true }; return { success: true };
}), }),
getActiveInviteLink: protectedProcedure
.meta({
openapi: {
summary: "Get active invite link for workspace",
method: "GET",
path: "/workspaces/{workspacePublicId}/invite",
description: "Gets the active invite link for a workspace",
tags: ["Invites"],
protect: true,
},
})
.input(
z.object({
workspacePublicId: z.string().min(12),
}),
)
.output(
z.object({
id: z.number().optional(),
inviteCode: z.string().optional(),
inviteLink: z.string().optional(),
isActive: z.boolean(),
expiresAt: z.date().optional(),
}),
)
.query(async ({ ctx, input }) => {
const userId = ctx.user?.id;
if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const workspace = await workspaceRepo.getByPublicId(
ctx.db,
input.workspacePublicId,
);
if (!workspace)
throw new TRPCError({
message: `Workspace not found`,
code: "NOT_FOUND",
});
// Check if user is in workspace
await assertUserInWorkspace(ctx.db, userId, workspace.id);
// Get active invite link for this workspace
const activeInviteLink = await inviteLinkRepo.getActiveForWorkspace(
ctx.db,
workspace.id,
);
if (
activeInviteLink &&
(!activeInviteLink.expiresAt || new Date() < activeInviteLink.expiresAt)
) {
return {
id: activeInviteLink.id,
inviteCode: activeInviteLink.code,
inviteLink: `${process.env.NEXT_PUBLIC_BASE_URL}/invite/${activeInviteLink.code}`,
isActive: true,
expiresAt: activeInviteLink.expiresAt ?? undefined,
};
}
return { isActive: false };
}),
createInviteLink: protectedProcedure
.meta({
openapi: {
summary: "Create invite link for workspace",
method: "POST",
path: "/workspaces/{workspacePublicId}/invites",
description: "Create invite link for a workspace",
tags: ["Invites"],
protect: true,
},
})
.input(
z.object({
workspacePublicId: z.string().min(12),
}),
)
.output(
z.object({
publicId: z.string().min(12),
inviteCode: z.string(),
inviteLink: z.string(),
expiresAt: z.date().nullable(),
}),
)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const workspace = await workspaceRepo.getByPublicId(
ctx.db,
input.workspacePublicId,
);
if (!workspace)
throw new TRPCError({
message: `Workspace not found`,
code: "NOT_FOUND",
});
// Check if user is in workspace
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
// Deactivate any existing active invite links
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
workspaceId: workspace.id,
updatedBy: userId,
});
// Generate new invite code
const inviteCode = generateUID();
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + 7);
// Create new invite link
const inviteLink = await inviteLinkRepo.createInviteLink(ctx.db, {
workspaceId: workspace.id,
code: inviteCode,
expiresAt,
createdBy: userId,
});
if (!inviteLink) {
throw new TRPCError({
message: `Failed to create invite link`,
code: "INTERNAL_SERVER_ERROR",
});
}
return {
publicId: inviteLink.publicId,
inviteCode: inviteLink.code,
inviteLink: `${process.env.NEXT_PUBLIC_BASE_URL}/invite/${inviteLink.code}`,
expiresAt: inviteLink.expiresAt,
};
}),
deactivateInviteLink: protectedProcedure
.meta({
openapi: {
summary: "Deactivate invite link for workspace",
method: "DELETE",
path: "/workspaces/{workspacePublicId}/invites",
description: "Deactivates the invite link for a workspace",
tags: ["Invites"],
protect: true,
},
})
.input(
z.object({
workspacePublicId: 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 workspace = await workspaceRepo.getByPublicId(
ctx.db,
input.workspacePublicId,
);
if (!workspace)
throw new TRPCError({
message: `Workspace not found`,
code: "NOT_FOUND",
});
// Check if user is in workspace
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
// Deactivate all active invite links
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
workspaceId: workspace.id,
updatedBy: userId,
});
return { success: true };
}),
getInviteByCode: publicProcedure
.meta({
openapi: {
summary: "Get invite information by code",
method: "GET",
path: "/workspaces/{workspacePublicId}/invites/{inviteCode}",
description: "Get invite information by invite code",
tags: ["Invites"],
protect: false,
},
})
.input(
z.object({
inviteCode: z.string().min(12),
}),
)
.output(
z
.object({
publicId: z.string().min(12),
status: z.string(),
expiresAt: z.date().nullable(),
})
.optional(),
)
.query(async ({ ctx, input }) => {
const invite = await inviteLinkRepo.getByCode(ctx.db, input.inviteCode);
if (
!invite ||
invite.status !== "active" ||
(invite.expiresAt && new Date() > invite.expiresAt)
) {
throw new TRPCError({
message: `Invalid or expired invite link`,
code: "BAD_REQUEST",
});
}
return {
publicId: invite.publicId,
status: invite.status,
expiresAt: invite.expiresAt ?? null,
};
}),
acceptInviteLink: publicProcedure
.meta({
openapi: {
summary: "Accept an invite link",
method: "POST",
path: "/workspaces/{workspacePublicId}/invites/accept",
description: "Accepts an invitation via invite link",
tags: ["Invites"],
protect: false,
},
})
.input(
z.object({
inviteCode: z.string().min(12),
}),
)
.output(
z.object({
success: z.boolean(),
workspacePublicId: z.string().optional(),
workspaceSlug: z.string().optional(),
}),
)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const invite = await inviteLinkRepo.getByCode(ctx.db, input.inviteCode);
if (
!invite ||
invite.status !== "active" ||
(invite.expiresAt && new Date() > invite.expiresAt)
)
throw new TRPCError({
message: `Invalid or expired invite link`,
code: "BAD_REQUEST",
});
const workspace = await workspaceRepo.getById(ctx.db, invite.workspaceId);
if (!workspace)
throw new TRPCError({
message: `Workspace not found`,
code: "NOT_FOUND",
});
const isMember = await workspaceRepo.isUserInWorkspace(
ctx.db,
userId,
invite.workspaceId,
);
if (isMember) {
throw new TRPCError({
message: `User is already a member of this workspace`,
code: "CONFLICT",
});
}
const user = await userRepo.getById(ctx.db, userId);
if (!user)
throw new TRPCError({
message: `User not found`,
code: "NOT_FOUND",
});
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
const subscriptions = await subscriptionRepo.getByReferenceId(
ctx.db,
workspace.publicId,
);
// get the active subscriptions
const activeTeamSubscription = getSubscriptionByPlan(
subscriptions,
"team",
);
const activeProSubscription = getSubscriptionByPlan(
subscriptions,
"pro",
);
const unlimitedSeats = hasUnlimitedSeats(subscriptions);
if (!activeTeamSubscription && !activeProSubscription) {
throw new TRPCError({
message: `Workspace with public ID ${workspace.publicId} does not have an active subscription`,
code: "NOT_FOUND",
});
}
// Update the Stripe subscription
if (activeTeamSubscription?.stripeSubscriptionId && !unlimitedSeats) {
try {
await updateSubscriptionSeats(
activeTeamSubscription.stripeSubscriptionId,
1,
);
} catch (error) {
console.error("Failed to update Stripe subscription seats:", error);
throw new TRPCError({
message: `Failed to update subscription for the new member.`,
code: "INTERNAL_SERVER_ERROR",
});
}
}
}
await memberRepo.create(ctx.db, {
workspaceId: invite.workspaceId,
email: user.email,
userId: user.id,
createdBy: user.id,
role: "member",
status: "active",
});
return {
success: true,
workspacePublicId: workspace.publicId,
workspaceSlug: workspace.slug,
};
}),
}); });

View File

@@ -220,6 +220,19 @@ export const initAuth = (db: dbClient) => {
console.log( console.log(
`Pro subscription ${stripeSubscription.id} activated with unlimited seats`, `Pro subscription ${stripeSubscription.id} activated with unlimited seats`,
); );
const workspace = await workspaceRepo.getByPublicId(
db,
subscription.referenceId,
);
if (workspace?.id) {
await memberRepo.unpauseAllMembers(db, workspace.id);
console.log(
`Unpausing all members for workspace ${workspace.id}`,
);
}
} }
}, },
}, },

View File

@@ -0,0 +1 @@
ALTER TYPE "public"."member_status" ADD VALUE 'paused';

View File

@@ -0,0 +1,34 @@
CREATE TYPE "public"."invite_link_status" AS ENUM('active', 'inactive');--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "workspace_invite_links" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"workspaceId" bigint NOT NULL,
"code" varchar(12) NOT NULL,
"status" "invite_link_status" DEFAULT 'active' NOT NULL,
"expiresAt" timestamp,
"createdAt" timestamp DEFAULT now() NOT NULL,
"createdBy" uuid,
"updatedAt" timestamp,
"updatedBy" uuid,
CONSTRAINT "workspace_invite_links_publicId_unique" UNIQUE("publicId"),
CONSTRAINT "workspace_invite_links_code_unique" UNIQUE("code")
);
--> statement-breakpoint
ALTER TABLE "workspace_invite_links" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_invite_links" ADD CONSTRAINT "workspace_invite_links_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_invite_links" ADD CONSTRAINT "workspace_invite_links_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_invite_links" ADD CONSTRAINT "workspace_invite_links_updatedBy_user_id_fk" FOREIGN KEY ("updatedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -99,6 +99,20 @@
"when": 1757535838766, "when": 1757535838766,
"tag": "20250910202358_AddCascadeSetNullToReferenceIdOnSubsriptions", "tag": "20250910202358_AddCascadeSetNullToReferenceIdOnSubsriptions",
"breakpoints": true "breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1758226671081,
"tag": "20250918201751_AddPausedMemberStatus",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1758662398166,
"tag": "20250923211958_AddWorkspaceInviteLinks",
"breakpoints": true
} }
] ]
} }

View File

@@ -0,0 +1,71 @@
import { and, eq, gt } from "drizzle-orm";
import type { dbClient } from "@kan/db/client";
import { workspaceInviteLinks } from "@kan/db/schema";
import { generateUID } from "@kan/shared/utils";
export const createInviteLink = async (
db: dbClient,
args: {
workspaceId: number;
code: string;
expiresAt: Date | null;
createdBy: string;
},
) => {
const [result] = await db
.insert(workspaceInviteLinks)
.values({
publicId: generateUID(),
workspaceId: args.workspaceId,
code: args.code,
expiresAt: args.expiresAt ?? null,
status: "active",
createdBy: args.createdBy,
})
.returning({
publicId: workspaceInviteLinks.publicId,
code: workspaceInviteLinks.code,
status: workspaceInviteLinks.status,
expiresAt: workspaceInviteLinks.expiresAt,
});
return result;
};
export const deactivateAllActiveForWorkspace = async (
db: dbClient,
args: { workspaceId: number; updatedBy: string },
) => {
await db
.update(workspaceInviteLinks)
.set({
status: "inactive",
updatedBy: args.updatedBy,
updatedAt: new Date(),
})
.where(
and(
eq(workspaceInviteLinks.workspaceId, args.workspaceId),
eq(workspaceInviteLinks.status, "active"),
),
);
};
export const getActiveForWorkspace = async (
db: dbClient,
workspaceId: number,
) => {
return db.query.workspaceInviteLinks.findFirst({
where: and(
eq(workspaceInviteLinks.workspaceId, workspaceId),
eq(workspaceInviteLinks.status, "active"),
),
orderBy: (links, { desc }) => [desc(links.createdAt)],
});
};
export const getByCode = async (db: dbClient, code: string) => {
return db.query.workspaceInviteLinks.findFirst({
where: eq(workspaceInviteLinks.code, code),
});
};

View File

@@ -59,9 +59,32 @@ export const create = async (
.having(gt(countExpr, 1)); .having(gt(countExpr, 1));
if (duplicateIndices.length > 0) { if (duplicateIndices.length > 0) {
throw new Error( // Compact indices to sequential values (0..n-1) to resolve duplicates while preserving order
`Duplicate indices found after reordering in board ${result.boardId}`, await tx.execute(sql`
); WITH ordered AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY "index", id) - 1 AS new_index
FROM "list"
WHERE "boardId" = ${result.boardId} AND "deletedAt" IS NULL
)
UPDATE "list" l
SET "index" = o.new_index
FROM ordered o
WHERE l.id = o.id;
`);
// Last resort: verify fix; if duplicates persist (e.g., due to race conditions), rollback
const postFixDupes = await tx
.select({ index: lists.index, count: countExpr })
.from(lists)
.where(and(eq(lists.boardId, result.boardId), isNull(lists.deletedAt)))
.groupBy(lists.index)
.having(gt(countExpr, 1));
if (postFixDupes.length > 0) {
throw new Error(
`Invariant violation: duplicate indices remain after compaction in board ${result.boardId}`,
);
}
} }
return result; return result;
@@ -79,7 +102,98 @@ export const bulkCreate = async (
importId?: number; importId?: number;
}[], }[],
) => { ) => {
return db.insert(lists).values(listInput).returning(); if (listInput.length === 0) return [];
return db.transaction(async (tx) => {
// Group incoming rows by board to compute safe, sequential indices per board
const byBoard = new Map<number, typeof listInput>();
for (const item of listInput) {
const arr = byBoard.get(item.boardId) ?? [];
arr.push(item);
byBoard.set(item.boardId, arr);
}
const allValuesToInsert: {
publicId: string;
name: string;
createdBy: string;
boardId: number;
index: number;
importId?: number;
}[] = [];
// For each board, append incoming lists after the current max index, preserving their relative order
for (const [boardId, items] of byBoard.entries()) {
// Find current max index for non-deleted lists in this board
const last = await tx.query.lists.findFirst({
columns: { index: true },
where: and(eq(lists.boardId, boardId), isNull(lists.deletedAt)),
orderBy: [desc(lists.index)],
});
let nextIndex = last ? last.index + 1 : 0;
// Sort incoming by their provided index to preserve Trello order, then reassign sequential indices
const sorted = [...items].sort((a, b) => a.index - b.index);
for (const it of sorted) {
allValuesToInsert.push({
publicId: it.publicId,
name: it.name,
createdBy: it.createdBy,
boardId: it.boardId,
index: nextIndex++,
importId: it.importId,
});
}
}
// Insert all rows in one go
const inserted = await tx
.insert(lists)
.values(allValuesToInsert)
.returning();
// Post-insert check: if duplicates exist, compact indices per board instead of failing
const countExpr = sql<number>`COUNT(*)`.mapWith(Number);
for (const boardId of byBoard.keys()) {
const duplicateIndices = await tx
.select({ index: lists.index, count: countExpr })
.from(lists)
.where(and(eq(lists.boardId, boardId), isNull(lists.deletedAt)))
.groupBy(lists.index)
.having(gt(countExpr, 1));
if (duplicateIndices.length > 0) {
await tx.execute(sql`
WITH ordered AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY "index", id) - 1 AS new_index
FROM "list"
WHERE "boardId" = ${boardId} AND "deletedAt" IS NULL
)
UPDATE "list" l
SET "index" = o.new_index
FROM ordered o
WHERE l.id = o.id;
`);
// Last resort: verify fix; if duplicates persist (e.g., due to race conditions), rollback
const postFixDupes = await tx
.select({ index: lists.index, count: countExpr })
.from(lists)
.where(and(eq(lists.boardId, boardId), isNull(lists.deletedAt)))
.groupBy(lists.index)
.having(gt(countExpr, 1));
if (postFixDupes.length > 0) {
throw new Error(
`Invariant violation: duplicate indices remain after compaction in board ${boardId}`,
);
}
}
}
return inserted;
});
}; };
export const getByPublicId = async (db: dbClient, listPublicId: string) => { export const getByPublicId = async (db: dbClient, listPublicId: string) => {
@@ -180,9 +294,32 @@ export const reorder = async (
.having(gt(countExpr, 1)); .having(gt(countExpr, 1));
if (duplicateIndices.length > 0) { if (duplicateIndices.length > 0) {
throw new Error( // Attempt to auto-heal by compacting indices to sequential values (0..n-1) while preserving order
`Duplicate indices found after reordering in board ${list.boardId}`, await tx.execute(sql`
); WITH ordered AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY "index", id) - 1 AS new_index
FROM "list"
WHERE "boardId" = ${list.boardId} AND "deletedAt" IS NULL
)
UPDATE "list" l
SET "index" = o.new_index
FROM ordered o
WHERE l.id = o.id;
`);
// Last resort verification: if duplicates persist, rollback
const postFixDupes = await tx
.select({ index: lists.index, count: countExpr })
.from(lists)
.where(and(eq(lists.boardId, list.boardId), isNull(lists.deletedAt)))
.groupBy(lists.index)
.having(gt(countExpr, 1));
if (postFixDupes.length > 0) {
throw new Error(
`Invariant violation: duplicate indices remain after compaction in board ${list.boardId}`,
);
}
} }
const updatedList = await tx.query.lists.findFirst({ const updatedList = await tx.query.lists.findFirst({

View File

@@ -95,3 +95,15 @@ export const softDelete = async (
return result; return result;
}; };
export const unpauseAllMembers = async (db: dbClient, workspaceId: number) => {
await db
.update(workspaceMembers)
.set({ status: "active" })
.where(
and(
eq(workspaceMembers.workspaceId, workspaceId),
eq(workspaceMembers.status, "paused"),
),
);
};

View File

@@ -87,11 +87,25 @@ export const getByPublicId = (db: dbClient, workspacePublicId: string) => {
publicId: true, publicId: true,
name: true, name: true,
plan: true, plan: true,
slug: true,
}, },
where: eq(workspaces.publicId, workspacePublicId), where: eq(workspaces.publicId, workspacePublicId),
}); });
}; };
export const getById = (db: dbClient, workspaceId: number) => {
return db.query.workspaces.findFirst({
columns: {
id: true,
publicId: true,
name: true,
plan: true,
slug: true,
},
where: eq(workspaces.id, workspaceId),
});
};
export const getByPublicIdWithMembers = ( export const getByPublicIdWithMembers = (
db: dbClient, db: dbClient,
workspacePublicId: string, workspacePublicId: string,

View File

@@ -11,3 +11,4 @@ export * from "./users";
export * from "./integrations"; export * from "./integrations";
export * from "./workspaces"; export * from "./workspaces";
export * from "./subscriptions"; export * from "./subscriptions";
export * from "./workspaceInviteLinks";

View File

@@ -0,0 +1,38 @@
import {
bigint,
bigserial,
pgEnum,
pgTable,
timestamp,
uuid,
varchar,
} from "drizzle-orm/pg-core";
import { users } from "./users";
import { workspaces } from "./workspaces";
export const inviteLinkStatuses = ["active", "inactive"] as const;
export type InviteLinkStatus = (typeof inviteLinkStatuses)[number];
export const inviteLinkStatusEnum = pgEnum(
"invite_link_status",
inviteLinkStatuses,
);
export const workspaceInviteLinks = pgTable("workspace_invite_links", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
workspaceId: bigint("workspaceId", { mode: "number" })
.notNull()
.references(() => workspaces.id, { onDelete: "cascade" }),
code: varchar("code", { length: 12 }).notNull().unique(),
status: inviteLinkStatusEnum("status").notNull().default("active"),
expiresAt: timestamp("expiresAt"),
createdAt: timestamp("createdAt").defaultNow().notNull(),
createdBy: uuid("createdBy").references(() => users.id, {
onDelete: "set null",
}),
updatedAt: timestamp("updatedAt"),
updatedBy: uuid("updatedBy").references(() => users.id, {
onDelete: "set null",
}),
}).enableRLS();

View File

@@ -19,7 +19,12 @@ export const memberRoles = ["admin", "member", "guest"] as const;
export type MemberRole = (typeof memberRoles)[number]; export type MemberRole = (typeof memberRoles)[number];
export const memberRoleEnum = pgEnum("role", memberRoles); export const memberRoleEnum = pgEnum("role", memberRoles);
export const memberStatuses = ["invited", "active", "removed"] as const; export const memberStatuses = [
"invited",
"active",
"removed",
"paused",
] as const;
export type MemberStatus = (typeof memberStatuses)[number]; export type MemberStatus = (typeof memberStatuses)[number];
export const memberStatusEnum = pgEnum("member_status", memberStatuses); export const memberStatusEnum = pgEnum("member_status", memberStatuses);

12
pnpm-lock.yaml generated
View File

@@ -205,6 +205,9 @@ importers:
react-icons: react-icons:
specifier: ^5.5.0 specifier: ^5.5.0
version: 5.5.0(react@18.3.1) version: 5.5.0(react@18.3.1)
react-image-crop:
specifier: ^11.0.10
version: 11.0.10(react@18.3.1)
react-lottie-player: react-lottie-player:
specifier: ^1.5.5 specifier: ^1.5.5
version: 1.5.6(react@18.3.1) version: 1.5.6(react@18.3.1)
@@ -6116,6 +6119,11 @@ packages:
peerDependencies: peerDependencies:
react: '*' react: '*'
react-image-crop@11.0.10:
resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==}
peerDependencies:
react: '>=16.13.1'
react-is@16.13.1: react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -13696,6 +13704,10 @@ snapshots:
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
react-image-crop@11.0.10(react@18.3.1):
dependencies:
react: 18.3.1
react-is@16.13.1: {} react-is@16.13.1: {}
react-is@17.0.2: {} react-is@17.0.2: {}