Compare commits

..

18 Commits

Author SHA1 Message Date
Henry
575526a341 feat: add env var to use virtual hosted urls 2026-01-25 22:51:29 +00:00
Henry
befe7ab7f4 feat: setup AGENTS.md file (#337) 2026-01-25 22:40:33 +00:00
Henry
53a33c68fc feat: rate limit api routes (#336)
* feat: install rate-limiter-flexible and ioredis

* feat: setup redis client

* feat: add withRateLimit wrapper

* feat: wrap trpc endpoint in withRateLimit

* feat: wrap withRateLimit on remaining routes

* feat: exclude webhook route from rate limiting

* chore: update compose files and readme

* refactor: move into api/db packages
2026-01-25 22:28:41 +00:00
Henry
3bae03613d feat(cloud): reset workspace slug on subscription cancelled (#335) 2026-01-25 21:20:04 +00:00
Sachin Divekar
c42ee7cf2c fix: disable tooltips on touch devices (#333) 2026-01-25 13:41:59 +00:00
Henry
07f997c3ad fix: update localization for brazilian portuguese (#332)
* fix: update localization for brazilian portuguese

* compile
2026-01-24 22:51:32 +00:00
Sachin Divekar
d084d323bc feat: show user avatar on comments and activity (#331)
Display user profile pictures instead of initials on card comments
and activity items. Fetches the user image field from the database
and passes imageUrl to the Avatar component.

Co-authored-by: Sachin Divekar <sachin.divekar@remiges.tech>
2026-01-24 22:04:46 +00:00
Sachin Divekar
6729c2e228 fix: support virtual-hosted S3 URLs for avatar storage (#330)
Avatar images failed to load with 403 on Tigris and newer AWS S3 buckets
because getAvatarUrl only constructed path-style URLs. Modern S3-compatible
providers require virtual-hosted URLs (bucket.domain/key).

Add NEXT_PUBLIC_STORAGE_DOMAIN env var to signal URL style:
- If set: virtual-hosted URL (Tigris, AWS S3)
- If not set: path-style URL (MinIO, LocalStack) - backward compatible

Add vitest and tests for getAvatarUrl behavior.

Co-authored-by: Sachin Divekar <sachin.divekar@remiges.tech>
2026-01-24 22:02:41 +00:00
Charity
b18ef10313 refactor: simplify drag-to-scroll logic to enable dragging on any non-interactive element within the container (fixes my oopsie) (#328) 2026-01-24 21:43:12 +00:00
Charity
03bd2d771b Hide member emails from non-admins (#327)
* feat(workspace): sanitize member emails for non-admin users in workspace router

* feat(workspace): add email visibility setting and update member display logic

* fix(workspace): update default value for showEmailsToMembers column to true

* - Removed unnecessary type assertions
- Added anonymous name handling (anonymous_[publicId]) in the API
- Removed placeholder logic
- Reverted null check
- Avoided as unknown cast
2026-01-24 21:41:59 +00:00
Redox
ff7944a4a2 Show display name instead of email (#323)
* Show display name instead of email

* Properly pass displayName

* Show email on settings page too

* Show email on missing username
2026-01-24 21:34:38 +00:00
Redox
0ca9c1d0e6 Add NEXT_API_BODY_SIZE_LIMIT config (#325)
* Add `NEXT_API_BODY_SIZE_LIMIT` config

* Add NEXT_API_BODY_SIZE_LIMIT env var to more files
2026-01-24 21:22:32 +00:00
Charity
927bf2fe69 feat: implement horizontal drag-to-scroll functionality in board views (#326) 2026-01-22 19:49:25 +00:00
Redox
ccd84385a2 Add Discord CDN avatars to allowed image sources (#322) 2026-01-22 14:23:25 +00:00
Henry
58c5e92155 feat(cloud): handle cancelled subscriptions (#313)
* feat(cloud): handle cancelled subscriptions

* chore: refactor auth
2026-01-16 20:20:22 +00:00
Henry
885f119404 chore: unshallow git clone 2026-01-15 20:15:19 +00:00
Henry
b17a24455a chore: generate app version during build 2026-01-14 21:21:04 +00:00
Henry
0c9561467d feat: display app version in user menu (#310)
* feat: display app version

* feat: add fetch depth
2026-01-13 12:48:07 +00:00
80 changed files with 4020 additions and 2169 deletions

View File

@@ -15,4 +15,4 @@ pnpm-debug.log
README.md
.next
.git
# .git

View File

@@ -32,15 +32,23 @@ NEXT_PUBLIC_STORAGE_URL=
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=
NEXT_PUBLIC_STORAGE_DOMAIN=
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=
# Auth config (optional)
NEXT_PUBLIC_ALLOW_CREDENTIALS=
NEXT_PUBLIC_DISABLE_SIGN_UP=
# API configuration (optional)
NEXT_API_BODY_SIZE_LIMIT= # e.g. 50mb (defaults to 1mb)
# Integration providers (optional)
TRELLO_APP_API_KEY=
TRELLO_APP_SECRET=
# Redis (optional - for rate limiting)
# If not provided, rate limiting will use in-memory storage
REDIS_URL= # e.g. redis://default:your_password@your_host:6379
# OAuth providers (optional)
BETTER_AUTH_TRUSTED_ORIGINS=
# Optional: Restrict OIDC/Social sign-ins to specific email domains (comma-separated)

315
AGENTS.md Normal file
View File

@@ -0,0 +1,315 @@
# AGENTS.md
## Project Overview
Kan is an open-source project management tool (Trello alternative) built with:
- **Frontend**: Next.js, React, TypeScript, Tailwind CSS
- **Backend**: tRPC, Node.js
- **Database**: PostgreSQL with Drizzle ORM
- **Monorepo**: pnpm workspaces with Turbo
- **Auth**: Better Auth
- **Internationalization**: Lingui
## Setup Commands
- Install deps: `pnpm install`
- Start dev server: `pnpm dev`
- Create migrations: `cd packages/db && pnpm drizzle-kit generate --name "AddFieldToTable"`
- Run database migrations: `pnpm db:migrate`
- Run linter: `pnpm lint`
- Run type check: `pnpm typecheck`
- Format code: `pnpm format:fix`
- Extract i18n strings: `pnpm lingui:extract`
## Project Structure
- `apps/web/` - Next.js web application
- `packages/api/` - tRPC API routers
- `packages/db/` - Database schema, migrations, and repositories
- `packages/auth/` - Authentication package
- `packages/shared/` - Shared utilities
- `packages/email/` - Email templates and sending
- `packages/stripe/` - Stripe integration
- `tooling/` - Shared tooling configs (ESLint, Prettier, TypeScript)
## Code Style
### TypeScript
- Use TypeScript strictly - avoid `any` types
- Prefer explicit types over inference when it improves clarity
- Use `as const` for literal types when appropriate
- Follow existing patterns for type definitions
### Naming Conventions
- **Files**: kebab-case for files (e.g., `card-repo.ts`)
- **Components**: PascalCase for React components
- **Functions**: camelCase for functions
- **Constants**: UPPER_SNAKE_CASE for constants
- **Types/Interfaces**: PascalCase
### Database Layer (`packages/db/`)
- **Schema**: Define schemas in `src/schema/` using Drizzle ORM
- **Migrations**: Create migrations with `cd packages/db && pnpm drizzle-kit generate --name "MigrationName"`, then run with `pnpm db:migrate`
- **Repositories**: Put database queries in `src/repository/` files
- **Soft Deletes**: Use `deletedAt` timestamp for soft deletion (not hard deletes)
- **Index Management**: Cards have `index` fields that must be maintained sequentially per list
- **Activity Logging**: Use `card_activity` table to track all card changes
### API Layer (`packages/api/`)
- **Routers**: Create tRPC routers in `src/routers/`
- **Procedures**: Use `protectedProcedure` for authenticated endpoints, `publicProcedure` for public
- **Validation**: Use Zod schemas for input validation
- **Error Handling**: Use `TRPCError` with appropriate error codes
- **OpenAPI**: Add OpenAPI metadata for all endpoints
- **Authorization**: Always check workspace membership with `assertUserInWorkspace`
### Frontend (`apps/web/`)
- **Components**: React components in `src/components/`
- **Views**: Page-level components in `src/views/`
- **Hooks**: Custom hooks in `src/hooks/`
- **i18n**: Use `t` template literal for translations (Lingui)
- **Styling**: Use Tailwind CSS classes
- **State Management**: Use tRPC React Query hooks for server state
- **Modals**: Use `useModal` hook for modal management
- **Popups**: Use `usePopup` hook for toast notifications
## Key Concepts
### Cards
- Cards are the main entity in Kan
- Cards belong to Lists, which belong to Boards
- Cards have: title, description, labels, members, checklists, comments, attachments, due dates
- Cards use soft deletion (`deletedAt` field)
- Cards have an `index` field that must be maintained sequentially per list
- All card changes are tracked in `card_activity` table
### Activity Tracking
- Every significant card change creates an activity record
- Activity types include: created, updated (various fields), etc.
- Activities are displayed in card activity feeds
### Workspaces & Boards
- Users belong to Workspaces
- Boards belong to Workspaces
- Workspace members have different permission levels
- Boards can be public or private
### Soft Deletion Pattern
- Entities use `deletedAt` timestamp for soft deletion
- Queries filter with `isNull(table.deletedAt)` to exclude deleted items
## File Locations Reference
### Database
- Schema: `packages/db/src/schema/*.ts`
- Repositories: `packages/db/src/repository/*.repo.ts`
- Migrations: `packages/db/migrations/`
### API
- Routers: `packages/api/src/routers/*.ts`
- Utils: `packages/api/src/utils/`
- Types: `packages/api/src/types/`
### Frontend
- Components: `apps/web/src/components/`
- Views: `apps/web/src/views/`
- Pages: `apps/web/src/pages/`
- Hooks: `apps/web/src/hooks/`
- Utils: `apps/web/src/utils/`
- Locales: `apps/web/src/locales/`
## Database Patterns
- **Soft Deletes**: Always filter with `isNull(table.deletedAt)` in queries
- **Public IDs**: Use 12-character public IDs (`publicId`) for all user-facing entities
- **Internal IDs**: Never expose internal database IDs (e.g., `id`, `cardId`, `listId`) in API responses or URLs - always use `publicId` externally
- **Transactions**: Use database transactions for multi-step operations
- **Index Management**: When deleting/moving cards, maintain sequential indices
- **Activity Tracking**: Create activity records for all significant changes
## API Patterns
- **Input Validation**: Always validate inputs with Zod
- **Error Messages**: Provide clear, user-friendly error messages
- **Optimistic Updates**: Use tRPC's `onMutate` for optimistic UI updates
- **Cache Invalidation**: Properly invalidate queries after mutations
- **ID Exposure**: Never expose internal database IDs (`id`, `cardId`, `listId`, etc.) in API responses, URLs, or frontend code - always use `publicId` for external communication
## Important Patterns
### Card Index Management
When cards are created, moved, or deleted, their indices must be maintained:
- New cards: Append to end (max index + 1) or insert at position
- Moving cards: Adjust indices of affected cards
- Deleting cards: Decrement indices of cards after deleted one
- Always use transactions for index updates
### Activity Logging
Create activity records for:
- Card creation
- Card updates (title, description, list, etc.)
- Label/member additions/removals
- Comments
- Checklists and items
- Attachments
- Due dates
### Authorization
Always check:
1. User is authenticated
2. User has access to workspace
3. User has permission for the operation
Use `assertUserInWorkspace` helper for workspace checks.
### Error Handling
- Use TRPCError with appropriate codes (UNAUTHORIZED, NOT_FOUND, etc.)
- Provide user-friendly error messages
- Log errors appropriately
- Show popup notifications for user-facing errors
## Common Patterns
### Creating a Card
1. Create card in repository with proper index management
2. Create `card.created` activity
3. Handle label/member relationships if provided
4. Return the created card
### Updating a Card
1. Validate user has workspace access
2. Update card fields
3. Create appropriate activity records
4. Invalidate relevant queries
### Querying Cards
- Always filter by `isNull(cards.deletedAt)` in queries
- Include related data (labels, members, checklists) via Drizzle relations
- Order by `index` for proper card ordering
## Adding a New Feature
1. **Database**: Update schema in `packages/db/src/schema/`
2. **Migration**: Create migration with `cd packages/db && pnpm drizzle-kit generate --name "MigrationName"`, then run with `pnpm db:migrate`
3. **Repository**: Add repository functions in `packages/db/src/repository/`
4. **API**: Add tRPC router procedures in `packages/api/src/routers/`
5. **Frontend**: Add UI components in `apps/web/src/`
6. **i18n**: Add translations for new strings
## Database Changes
- Always create migrations (never modify existing migrations)
- Create migrations with: `cd packages/db && pnpm drizzle-kit generate --name "MigrationName"`
- Run migrations with: `pnpm db:migrate`
- Update schema files in `packages/db/src/schema/`
- Test migrations on development database first
- Update TypeScript types after schema changes
- Consider index management for card operations
## API Endpoints
- Use tRPC procedures (not REST)
- Add OpenAPI metadata for documentation
- Validate inputs with Zod
- Check workspace permissions
- Create activity records for significant changes
## Frontend Components
- Use Tailwind for styling
- Follow existing component patterns
- Use tRPC hooks for data fetching
- Implement optimistic updates where appropriate
- Add proper loading and error states
## Testing Instructions
- Test database operations in transactions that rollback
- Test authorization checks
- Test index management when moving/deleting cards
- Test activity logging
- Test UI interactions
- Run `pnpm lint` and `pnpm typecheck` before committing
## Performance Considerations
- Use database indexes appropriately
- Batch operations when possible
- Avoid N+1 queries
- Use transactions for related operations
- Implement optimistic updates in UI
## Security
- Always check workspace membership before operations
- Validate all inputs
- Never expose internal database IDs (`id`, `cardId`, `listId`, etc.) in API responses, URLs, or frontend code - always use `publicId` externally
- Sanitize user input
## Internationalization
- All user-facing strings must use `t` template literal
- Add translations to locale files in `apps/web/src/locales/`
- Run `pnpm lingui:extract` to update translation files
- Update locale files for all languages
## Dependencies
- Use workspace dependencies (`workspace:*`) for internal packages
- Keep dependencies up to date
- Use catalog for shared dependency versions
## When Implementing Features
### Adding New Card Fields
1. Update schema in `packages/db/src/schema/cards.ts`
2. Create migration
3. Update repository functions
4. Add API endpoints
5. Update frontend components
6. Add activity tracking if needed
### Adding New Activity Types
1. Add to `activityTypes` array in schema
2. Create migration to update enum
3. Use in activity creation code
4. Update activity display components if needed
## Git & Commits
- Use conventional commits: `feat:`, `fix:`, `refactor:`, `docs:`, etc.
- Keep commits focused on single changes
- Reference issue numbers when applicable
## PR Instructions
- Title format: `feat: description` or `fix: description`
- Always run `pnpm lint` and `pnpm typecheck` before committing
- Provide clear description of changes
- Include screenshots for UI changes
- Keep PRs focused on a single feature/fix

View File

@@ -141,6 +141,7 @@ pnpm dev
| Variable | Description | Required | Example |
| ----------------------------------------- | --------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------- |
| `POSTGRES_URL` | PostgreSQL connection URL | To use external database | `postgres://user:pass@localhost:5432/db` |
| `REDIS_URL` | Redis connection URL | For rate limiting (optional) | `redis://localhost:6379` or `redis://redis:6379` (Docker) |
| `EMAIL_FROM` | Sender email address | For Email | `"Kan <hello@mail.kan.bn>"` |
| `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` |
| `SMTP_PORT` | SMTP server port | For Email | `465` |
@@ -150,6 +151,7 @@ pnpm dev
| `SMTP_REJECT_UNAUTHORIZED` | Reject invalid certificates (defaults to true if not set) | For Email | `false` |
| `NEXT_PUBLIC_DISABLE_EMAIL` | To disable all email features | For Email | `true` |
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
| `NEXT_API_BODY_SIZE_LIMIT` | Maximum API request body size (defaults to 1mb) | No | `50mb` |
| `BETTER_AUTH_ALLOWED_DOMAINS` | Comma-separated list of allowed domains for OIDC logins | For OIDC/Social login | `example.com,subsidiary.com` |
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
@@ -171,6 +173,7 @@ pnpm dev
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
| `NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS` | Use virtual-hosted style URLs (bucket.domain.com) | For file uploads (optional) | `true` |
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
| `NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME` | S3 bucket name for attachments | For file uploads | `attachments` |
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |

View File

@@ -19,19 +19,22 @@ RUN pnpm config set store-dir ~/.pnpm-store
# 2. Prune projects
FROM base AS pruner
# https://stackoverflow.com/questions/49681984/how-to-get-version-value-of-package-json-inside-of-dockerfile
# RUN export VERSION=$(npm run version)
ARG PROJECT
# Set working directory
WORKDIR /app
RUN apk add --no-cache git
# It might be the path to <ROOT> turborepo
WORKDIR /app
COPY . .
# Generate a partial monorepo with a pruned lockfile for a target workspace.
# Assuming "@acme/nextjs" is the name entered in the project's package.json: { name: "@acme/nextjs" }
# Generate version from git (fallback if APP_VERSION not provided)
RUN git fetch --tags --unshallow 2>/dev/null || git fetch --tags 2>/dev/null || true && \
AUTO_VERSION=$(git describe --tags --always --long 2>/dev/null | \
sed -E 's/^v?([0-9]+\.[0-9]+\.[0-9]+)-[0-9]+-g([a-f0-9]{7}).*/\1+\2/' | \
sed 's/^v//' || \
git rev-parse --short HEAD 2>/dev/null | head -c 7 || \
echo "unknown") && \
echo "$AUTO_VERSION" > /app/AUTO_VERSION
RUN turbo prune --scope=${PROJECT} --scope=@kan/db --docker
# 3. Build the project
@@ -39,25 +42,22 @@ FROM base AS builder
ARG PROJECT
ARG APP_VERSION
# Environment to skip .env validation on build
ENV CI=true
ENV NEXT_PUBLIC_APP_VERSION=${APP_VERSION}
WORKDIR /app
# Copy lockfile and package.json's of isolated subworkspace
COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/AUTO_VERSION /tmp/AUTO_VERSION
ENV CI=true
# First install the dependencies (as they change less often)
RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm install --frozen-lockfile
# Copy source code of isolated subworkspace
COPY --from=pruner /app/out/full/ .
RUN pnpm build --filter=${PROJECT}
# Use provided APP_VERSION or auto-generated from pruner stage
RUN VERSION="${APP_VERSION:-$(cat /tmp/AUTO_VERSION 2>/dev/null | tr -d '\n\r' || echo 'unknown')}" && \
NEXT_PUBLIC_APP_VERSION="$VERSION" pnpm build --filter=${PROJECT}
# # Copy static files to standalone directory
# RUN mkdir -p apps/web/.next/standalone/.next && \

View File

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

View File

@@ -39,6 +39,7 @@ checksums:
Adjust%20the%20square%20crop%20to%20fit%20your%20avatar./singular: a4df26bbce6f14c6962fac1324db00a8
Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df
All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc
Allow%20workspace%20members%20to%20see%20each%20other's%20email%20addresses/singular: 0077436d9f37bfd64f3ae076a5a05040
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%20unexpected%20error%20occurred.%20Please%20try%20again%20later./singular: 1b5749b0cca6a62d75a577bee6804074
@@ -193,6 +194,7 @@ checksums:
Editing/singular: 3449a7988cd69207b7c6929af1f4abf1
email/singular: f31eb214738e037d58e26149797739df
Email/singular: e7f34943a0c2fb849db1839ff6ef5cb5
Email%20visibility/singular: 81d41cf573a7109c376d30d905beb596
Enhancement/singular: 785fe23c0eef0a5b60b5b2a88151de31
Enter%20a%20custom%20title/singular: f002074db0bd51d4f28d2736e140370a
Enter%20your%20current%20password/singular: bfceabde4c0b6f2cb439015b76549651

View File

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

View File

@@ -50,6 +50,11 @@ const config = {
protocol: "https",
hostname: "*.googleusercontent.com",
},
{
protocol: 'https',
hostname: 'cdn.discordapp.com',
pathname: '/avatars/**',
},
];
// Extract root domain from S3_ENDPOINT and add wildcard pattern
@@ -90,6 +95,12 @@ const config = {
swcPlugins: [["@lingui/swc-plugin", {}]],
},
api: {
bodyParser: {
sizeLimit: env("NEXT_API_BODY_SIZE_LIMIT") || '1mb',
},
},
async rewrites() {
return [
{

View File

@@ -10,6 +10,8 @@
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"start": "pnpm with-env next start",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"with-env": "dotenv -e ../../.env --",
"lingui:extract": "lingui extract",
@@ -86,7 +88,8 @@
"jiti": "^1.21.6",
"prettier": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vitest": "^3.0.0"
},
"prettier": "@kan/prettier-config"
}

View File

@@ -155,7 +155,7 @@ export default function Dashboard({
className={`fixed top-12 z-40 h-[calc(100dvh-3rem)] w-[calc(100vw-1.5rem)] transform transition-transform duration-300 ease-in-out md:relative md:top-0 md:h-full md:w-auto md:translate-x-0 ${isSideNavOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0"} `}
>
<SideNavigation
user={{ email: session?.user.email, image: session?.user.image }}
user={{ displayName: session?.user.name, email: session?.user.email, image: session?.user.image }}
isLoading={sessionLoading}
onCloseSideNav={closeSideNav}
/>

View File

@@ -39,6 +39,7 @@ interface SideNavigationProps {
}
interface UserType {
displayName?: string | null | undefined;
email?: string | null | undefined;
image?: string | null | undefined;
}
@@ -206,7 +207,8 @@ export default function SideNavigation({
<div className="space-y-2">
<UserMenu
email={user.email ?? ""}
displayName={user.displayName ?? undefined}
email={user.email ?? "Email not provided?"}
imageUrl={user.image ?? undefined}
isLoading={isLoading}
isCollapsed={isCollapsed}

View File

@@ -35,6 +35,7 @@ export function Tooltip({
delay,
interactive: false,
theme: "tooltip",
touch: false,
});
return () => {

View File

@@ -17,6 +17,7 @@ import { getAvatarUrl } from "~/utils/helpers";
interface UserMenuProps {
imageUrl: string | undefined;
displayName: string | undefined;
email: string;
isLoading: boolean;
isCollapsed?: boolean;
@@ -26,6 +27,7 @@ interface UserMenuProps {
export default function UserMenu({
imageUrl,
email,
displayName,
isLoading,
isCollapsed = false,
onCloseSideNav,
@@ -75,7 +77,7 @@ export default function UserMenu({
) : (
<Menu.Button
className="flex w-full items-center rounded-md p-1.5 text-neutral-900 hover:bg-light-200 dark:text-dark-900 dark:hover:bg-dark-200 dark:hover:text-dark-1000"
title={isCollapsed ? email : undefined}
title={isCollapsed ? displayName ?? email : undefined}
>
{avatarUrl ? (
<Image
@@ -102,7 +104,7 @@ export default function UserMenu({
isCollapsed && "md:hidden",
)}
>
{email}
{displayName ?? email}
</span>
</Menu.Button>
)}

View File

@@ -78,6 +78,7 @@ export const env = createEnv({
S3_ENDPOINT: z.string().optional(),
S3_FORCE_PATH_STYLE: z.string().optional(),
EMAIL_FROM: z.string().optional(),
REDIS_URL: z.string().url().optional(),
},
/**
@@ -95,6 +96,13 @@ export const env = createEnv({
NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(),
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME: z.string().optional(),
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: z
.string()
.transform((s) => (s === "" ? undefined : s))
.refine(
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
)
.optional(),
NEXT_PUBLIC_APP_VERSION: z.string().optional(),
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
.string()
@@ -133,6 +141,8 @@ export const env = createEnv({
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME:
process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME,
NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN,
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS:
process.env.NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS,
NEXT_PUBLIC_APP_VERSION: process.env.NEXT_PUBLIC_APP_VERSION,
NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS,
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,

View File

@@ -0,0 +1,101 @@
import { useEffect, useRef, useState } from "react";
interface UseDragToScrollOptions {
/**
* Whether drag-to-scroll is enabled
*/
enabled?: boolean;
/**
* The direction to scroll
*/
direction?: "horizontal" | "vertical" | "both";
}
/**
* Hook to enable drag-to-scroll functionality on a scrollable element
* @param options Configuration options
* @returns Ref to attach to the scrollable element and mouse event handlers
*/
export function useDragToScroll({
enabled = true,
direction = "horizontal",
}: UseDragToScrollOptions = {}) {
const scrollRef = useRef<HTMLDivElement>(null);
const [isDragging, setIsDragging] = useState(false);
const startPosRef = useRef({ x: 0, y: 0 });
const scrollStartRef = useRef({ x: 0, y: 0 });
useEffect(() => {
if (!enabled || !isDragging) return;
const handleMouseMove = (e: MouseEvent) => {
if (!scrollRef.current) return;
const deltaX = e.clientX - startPosRef.current.x;
const deltaY = e.clientY - startPosRef.current.y;
if (direction === "horizontal" || direction === "both") {
scrollRef.current.scrollLeft = scrollStartRef.current.x - deltaX;
}
if (direction === "vertical" || direction === "both") {
scrollRef.current.scrollTop = scrollStartRef.current.y - deltaY;
}
};
const handleMouseUp = () => {
setIsDragging(false);
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
document.body.style.cursor = "grabbing";
document.body.style.userSelect = "none";
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
document.body.style.cursor = "";
document.body.style.userSelect = "";
};
}, [enabled, isDragging, direction]);
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
if (!scrollRef.current) return;
const target = e.target as HTMLElement;
const container = scrollRef.current;
// Check if the click is on an interactive or draggable element
// We need to be careful not to interfere with react-beautiful-dnd dragging
const isInteractiveElement =
target.closest("a") ||
target.closest("button") ||
target.closest("input") ||
target.closest("textarea") ||
target.closest("[role='button']") ||
target.closest("[draggable='true']") ||
target.closest(".react-beautiful-dnd-drag-handle") ||
target.closest("[data-rbd-drag-handle-draggable-id]") ||
target.closest("[data-rbd-draggable-id]");
// Don't start dragging if clicking on interactive elements
if (isInteractiveElement) return;
// Enable drag-to-scroll for any non-interactive element within the container
if (container.contains(target)) {
e.preventDefault();
setIsDragging(true);
startPosRef.current = { x: e.clientX, y: e.clientY };
scrollStartRef.current = {
x: container.scrollLeft,
y: container.scrollTop,
};
}
};
return {
ref: scrollRef,
onMouseDown: handleMouseDown,
isDragging,
};
}

View File

@@ -19,7 +19,7 @@ export function useLocalisation() {
nl,
ru,
pl,
ptbr: ptBR,
"pt-BR": ptBR,
};
const currentDateLocale = dateLocaleMap[locale] ?? enGB;

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (bearbeitet)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} Labels"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} nicht gefunden"
@@ -100,7 +100,7 @@ msgstr "Aktivitätsprotokolle"
msgid "Add a card"
msgstr "Karte hinzufügen"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Kommentar hinzufügen..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Mitglied hinzufügen"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "{0} Labels hinzugefügt: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "hat eine Checkliste hinzugefügt"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "hat ein Checklistenelement hinzugefügt"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "hat ein Label zur Karte hinzugefügt"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "hat ein Mitglied zur Karte hinzugefügt"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "hat Checkliste <0>{0}</0> hinzugefügt"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "hat Checklistenelement <0>{0}</0> hinzugefügt"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "hat Label <0>{0}</0> hinzugefügt"
@@ -184,6 +184,10 @@ msgstr "Administratorrollen"
msgid "All systems operational"
msgstr "Alle Systeme funktionieren"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Workspace-Mitgliedern erlauben, die E-Mail-Adressen der anderen zu sehen"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Du hast bereits ein Konto? <0><1>Anmelden</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Bist du sicher, dass du dein Konto löschen möchtest?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "hat <0>{0}</0> der Karte zugewiesen"
@@ -317,9 +321,9 @@ msgstr "Abrechnungsportal"
msgid "Blog Post"
msgstr "Blogbeitrag"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Board"
@@ -336,7 +340,7 @@ msgstr "Der Name des Boards darf 100 Zeichen nicht überschreiten"
msgid "Board name is required"
msgstr "Boardname ist erforderlich"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Board nicht gefunden"
@@ -352,7 +356,7 @@ msgstr "Board-URL darf nur Buchstaben, Zahlen und Bindestriche enthalten"
msgid "Board URL cannot exceed 60 characters"
msgstr "Board-URL darf 60 Zeichen nicht überschreiten"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "Board-URL in die Zwischenablage kopiert"
@@ -369,7 +373,7 @@ msgstr "Board-Sichtbarkeit"
msgid "Board visibility updated"
msgstr "Board-Sichtbarkeit aktualisiert"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Boards"
@@ -388,7 +392,7 @@ msgstr "Fehlerbericht"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Karte nicht gefunden"
msgid "Card title"
msgstr "Kartentitel"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Passwort ändern"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Ändern Sie Ihre Spracheinstellungen."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "hat den Fälligkeitstermin auf <0>{formattedDate}</0> geändert"
@@ -500,12 +504,12 @@ msgstr "Abgeschlossen"
msgid "Complete control and ownership:"
msgstr "Vollständige Kontrolle und Eigentum:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "hat ein Checklistenelement abgeschlossen"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "hat Checklistenelement <0>{0}</0> abgeschlossen"
@@ -614,8 +618,8 @@ msgstr "Neuen Schlüssel erstellen"
msgid "Create new label"
msgstr "Neues Label erstellen"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Neue Liste erstellen"
@@ -628,7 +632,7 @@ msgstr "Vorlage erstellen"
msgid "Create workspace"
msgstr "Arbeitsbereich erstellen"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "hat die Karte erstellt"
@@ -674,7 +678,7 @@ msgstr "Benutzerdefinierte Workspace-URL"
msgid "Customer Support"
msgstr "Kundensupport"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Dunkel"
@@ -692,8 +696,8 @@ msgstr "Einladungslink deaktivieren"
msgid "Delete"
msgstr "Löschen"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Konto löschen"
@@ -706,7 +710,7 @@ msgstr "Board löschen"
msgid "Delete card"
msgstr "Karte löschen"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Kommentar löschen"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Vorlage löschen"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Workspace löschen"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "hat eine Checkliste gelöscht"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "hat ein Checklistenelement gelöscht"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "hat Checkliste <0>{0}</0> gelöscht"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "hat Checklistenelement <0>{0}</0> gelöscht"
@@ -786,7 +790,7 @@ msgstr "Dokumente"
msgid "Docs"
msgstr "Dokumente"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Bearbeiten"
msgid "Edit board URL"
msgstr "Board-URL bearbeiten"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Kommentar bearbeiten"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "E-Mail"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "E-Mail"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "E-Mail-Sichtbarkeit"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Verbesserung"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Features"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Feedback"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Für langfristige Nachhaltigkeit erkennen wir an, dass alle guten Open-Source-Projekte eine Einnahmequelle benötigen. Unsere stammt aus dem kostenpflichtigen Cloud-Angebot für Workspaces mit mehreren Benutzern und für benutzerdefinierte Workspace-Slugs. Es besteht keine Verpflichtung, es zu nutzen, und Sie können die Software kostenlos auf Ihrer eigenen Infrastruktur selbst hosten."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Kostenlos"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Kostenloser Plan"
@@ -1116,7 +1123,7 @@ msgstr "Loslegen"
msgid "Get started by creating a new {0}"
msgstr "Beginnen Sie, indem Sie eine(n) neue(n) {0} erstellen"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Beginne mit dem Erstellen einer neuen Liste"
@@ -1150,19 +1157,19 @@ msgstr "Zur Startseite"
msgid "Go to app"
msgstr "Zur App"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Zu Boards gehen"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Zu Mitgliedern gehen"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Zu Einstellungen gehen"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Zu Vorlagen gehen"
@@ -1287,7 +1294,7 @@ msgstr "Ungültige E-Mail-Adresse"
msgid "Invalid invitation"
msgstr "Ungültige Einladung"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Einladen"
@@ -1368,7 +1375,7 @@ msgstr "Labels & Filter"
msgid "Labels & Filters"
msgstr "Labels & Filter"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Sprache"
@@ -1377,7 +1384,7 @@ msgstr "Sprache"
msgid "Launch offer"
msgstr "Einführungsangebot"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Einführungsangebot: Erhalten Sie unbegrenzte Mitglieder mit Pro"
@@ -1402,11 +1409,11 @@ msgstr "Rechtliches"
msgid "License"
msgstr "Lizenz"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Hell"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Link kopiert"
@@ -1422,11 +1429,11 @@ msgstr "Listenname"
msgid "Lists"
msgstr "Listen"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Weitere Aktivitäten laden"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Wird geladen..."
@@ -1434,7 +1441,7 @@ msgstr "Wird geladen..."
msgid "Login | kan.bn"
msgstr "Login | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Abmelden"
@@ -1458,12 +1465,12 @@ msgstr "Magic Link"
msgid "Make template"
msgstr "Als Vorlage speichern"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "hat ein Checklistenelement als unvollständig markiert"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "hat Checklistenelement <0>{0}</0> als unvollständig markiert"
@@ -1471,16 +1478,16 @@ msgstr "hat Checklistenelement <0>{0}</0> als unvollständig markiert"
msgid "Medium Priority"
msgstr "Mittlere Priorität"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Mitglieder"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Mitglieder | {0}"
@@ -1495,11 +1502,11 @@ msgstr "monatliche Abrechnung"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "hat die Karte von <0>{0}</0> nach <1>{1}</1> verschoben"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "hat die Karte in eine andere Liste verschoben"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Neues Label"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Neue Liste"
@@ -1609,7 +1616,7 @@ msgstr "Für diesen Anhang ist keine Download-URL verfügbar."
msgid "No keyboard shortcuts registered."
msgstr "Keine Tastaturkürzel registriert."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Keine Listen"
@@ -1625,11 +1632,11 @@ msgstr "Angebot"
msgid "Onboarding"
msgstr "Einarbeitung"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1699,7 +1706,7 @@ msgstr "Passwort muss mindestens 8 Zeichen lang sein"
msgid "Passwords do not match"
msgstr "Passwörter stimmen nicht überein"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Pausiert"
@@ -1708,7 +1715,7 @@ msgstr "Pausiert"
msgid "Payment frequency"
msgstr "Zahlungshäufigkeit"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "Ausstehend"
@@ -1765,15 +1772,15 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Datenschutzrichtlinie"
msgid "Private"
msgstr "Privat"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Pro-Plan"
@@ -1881,44 +1888,44 @@ msgstr "Remote"
msgid "Remove"
msgstr "Entfernen"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Mitglied entfernen"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "{0} Labels entfernt: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "hat ein Label von der Karte entfernt"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "hat ein Mitglied von der Karte entfernt"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "hat Label <0>{0}</0> entfernt"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "hat den Fälligkeitstermin entfernt"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "hat eine Checkliste umbenannt"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "hat Checkliste <0>{0}</0> umbenannt"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "hat Checklistenelement in <0>{0}</0> umbenannt"
@@ -1948,7 +1955,7 @@ msgstr "Überprüfung"
msgid "Roadmap"
msgstr "Roadmap"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Rolle"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Auf eigener Infrastruktur betreiben"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Speichern"
@@ -1996,7 +2003,7 @@ msgstr "Selbst hosten"
msgid "Self host with Github"
msgstr "Selbst hosten mit Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "hat sich selbst die Karte zugewiesen"
@@ -2016,12 +2023,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Fälligkeitsdatum festlegen"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "hat den Fälligkeitstermin festgelegt"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Einstellungen"
@@ -2041,11 +2048,11 @@ msgstr "Einstellungen | Abrechnung"
msgid "Settings | Integrations"
msgstr "Einstellungen | Integrationen"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Einstellungen | Arbeitsbereich"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Kürzel"
@@ -2117,7 +2124,7 @@ msgstr "Erfolg"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Optimiere deinen Workspace für nur $29/Monat. Das bekommst du dafür:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Support"
@@ -2126,12 +2133,12 @@ msgstr "Support"
msgid "Support the development of the project"
msgstr "Unterstütze die Entwicklung des Projekts"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "System"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Team-Plan"
@@ -2141,8 +2148,8 @@ msgstr "Team-Plan"
msgid "Teams"
msgstr "Teams"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Vorlage"
@@ -2162,7 +2169,7 @@ msgstr "Vorlagenname darf 100 Zeichen nicht überschreiten"
msgid "Template name is required"
msgstr "Vorlagenname ist erforderlich"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Vorlagen"
@@ -2196,7 +2203,7 @@ msgstr "Die open source <0/> alternative zu Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "Die Sichtbarkeit deines Boards wurde auf {0} gesetzt."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Design"
@@ -2216,7 +2223,7 @@ msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Dieser API-Schlüssel wird nur einmal angezeigt. Bitte speichern Sie ihn an einem sicheren Ort."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Dieses Board ist privat oder existiert nicht"
@@ -2359,7 +2366,7 @@ msgstr "Board-URL kann nicht aktualisiert werden"
msgid "Unable to update board visibility"
msgstr "Board-Sichtbarkeit konnte nicht aktualisiert werden"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Karte konnte nicht aktualisiert werden"
@@ -2372,7 +2379,7 @@ msgstr "Checkliste kann nicht aktualisiert werden"
msgid "Unable to update checklist item"
msgstr "Checklistenelement kann nicht aktualisiert werden"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Kommentar konnte nicht aktualisiert werden"
@@ -2384,7 +2391,7 @@ msgstr "Fälligkeitsdatum konnte nicht aktualisiert werden"
msgid "Unable to update labels"
msgstr "Labels konnten nicht aktualisiert werden"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Liste konnte nicht aktualisiert werden"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "Mitglieder konnten nicht aktualisiert werden"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "hat <0>{0}</0> von der Karte entfernt"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "hat sich selbst von der Karte entfernt"
@@ -2457,30 +2464,30 @@ msgstr "Aktualisieren"
msgid "Update label"
msgstr "Label aktualisieren"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "hat ein Checklistenelement aktualisiert"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "hat die Beschreibung aktualisiert"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "hat den Fälligkeitstermin aktualisiert"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "hat den Titel aktualisiert"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "hat den Titel in <0>{0}</0> geändert"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Upgrade auf Pro"
@@ -2517,7 +2524,7 @@ msgstr "URL muss mindestens 3 Zeichen lang sein"
msgid "Use template"
msgstr "Vorlage verwenden"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Benutzer"
@@ -2542,7 +2549,7 @@ msgstr "Verwalte deine Abrechnung und dein Abonnement."
msgid "View docs"
msgstr "Dokumentation ansehen"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Nur ansehen"
@@ -2550,7 +2557,7 @@ msgstr "Nur ansehen"
msgid "View our roadmap."
msgstr "Sieh dir unsere roadmap an."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Workspace anzeigen"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "Warum ein open source Trello entwickeln?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Arbeitsbereich"
@@ -2611,7 +2618,7 @@ msgstr "Workspace erfolgreich erstellt. Du kannst später in den Einstellungen u
msgid "Workspace deleted"
msgstr "Workspace gelöscht"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Workspace-Beschreibung"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Workspace-mitglieder"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Name des Workspaces"
@@ -2659,7 +2666,7 @@ msgstr "Workspace-Name aktualisiert"
msgid "Workspace slug updated"
msgstr "Workspace-Slug aktualisiert"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "Workspace-URL"
@@ -2680,7 +2687,7 @@ msgstr "Jährlich"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Sie sind dabei, Ihr Passwort zu ändern."

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (edited)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} labels"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} not found"
@@ -112,7 +112,7 @@ msgstr "Activity logs"
msgid "Add a card"
msgstr "Add a card"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Add a comment..."
@@ -148,38 +148,38 @@ msgid "Add member"
msgstr "Add member"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "added {0} labels: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "added a checklist"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "added a checklist item"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "added a label to the card"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "added a member to the card"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "added checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "added checklist item <0>{0}</0>"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "added label <0>{0}</0>"
@@ -208,6 +208,10 @@ msgstr "Admin roles"
msgid "All systems operational"
msgstr "All systems operational"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Allow workspace members to see each other's email addresses"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Already have an account? <0><1>Sign in</1></0>"
@@ -303,7 +307,7 @@ msgstr "Are you sure you want to delete your account?"
#~ msgstr "around the world"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "assigned <0>{0}</0> to the card"
@@ -357,9 +361,9 @@ msgstr "Billing portal"
msgid "Blog Post"
msgstr "Blog Post"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Board"
@@ -385,7 +389,7 @@ msgstr "Board name cannot exceed 100 characters"
msgid "Board name is required"
msgstr "Board name is required"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Board not found"
@@ -401,7 +405,7 @@ msgstr "Board URL can only contain letters, numbers, and hyphens"
msgid "Board URL cannot exceed 60 characters"
msgstr "Board URL cannot exceed 60 characters"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "Board URL copied to clipboard"
@@ -418,7 +422,7 @@ msgstr "Board visibility"
msgid "Board visibility updated"
msgstr "Board visibility updated"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Boards"
@@ -445,7 +449,7 @@ msgstr "Bug Report"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -471,8 +475,8 @@ msgstr "Card not found"
msgid "Card title"
msgstr "Card title"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
@@ -482,12 +486,12 @@ msgstr "Change Password"
#~ msgid "Change the language of the app."
#~ msgstr "Change the language of the app."
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Change your language preferences."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "changed the due date to <0>{formattedDate}</0>"
@@ -561,12 +565,12 @@ msgstr "Complete"
msgid "Complete control and ownership:"
msgstr "Complete control and ownership:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "completed a checklist item"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "completed checklist item <0>{0}</0>"
@@ -691,8 +695,8 @@ msgstr "Create new key"
msgid "Create new label"
msgstr "Create new label"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Create new list"
@@ -709,7 +713,7 @@ msgstr "Create template"
msgid "Create workspace"
msgstr "Create workspace"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "created the card"
@@ -763,7 +767,7 @@ msgstr "Custom workspace URL"
msgid "Customer Support"
msgstr "Customer Support"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Dark"
@@ -781,8 +785,8 @@ msgstr "Deactivate invite link"
msgid "Delete"
msgstr "Delete"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Delete account"
@@ -795,7 +799,7 @@ msgstr "Delete board"
msgid "Delete card"
msgstr "Delete card"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Delete comment"
@@ -808,26 +812,26 @@ msgid "Delete template"
msgstr "Delete template"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Delete workspace"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "deleted a checklist"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "deleted a checklist item"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "deleted checklist <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "deleted checklist item <0>{0}</0>"
@@ -875,7 +879,7 @@ msgstr "docs"
msgid "Docs"
msgstr "Docs"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -928,7 +932,7 @@ msgstr "Edit"
msgid "Edit board URL"
msgstr "Edit board URL"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Edit comment"
@@ -953,9 +957,14 @@ msgid "email"
msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "Email"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Email visibility"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Enhancement"
@@ -1137,7 +1146,7 @@ msgid "Features"
msgstr "Features"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Feedback"
@@ -1173,7 +1182,7 @@ msgid "Free"
msgstr "Free"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Free Plan"
@@ -1217,7 +1226,7 @@ msgstr "Get started by creating a new {0}"
#~ msgid "Get started by creating a new board"
#~ msgstr "Get started by creating a new board"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Get started by creating a new list"
@@ -1251,19 +1260,19 @@ msgstr "Go Home"
msgid "Go to app"
msgstr "Go to app"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Go to boards"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Go to members"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Go to settings"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Go to templates"
@@ -1392,7 +1401,7 @@ msgstr "Invalid email address"
msgid "Invalid invitation"
msgstr "Invalid invitation"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Invite"
@@ -1477,7 +1486,7 @@ msgstr "Labels & filters"
msgid "Labels & Filters"
msgstr "Labels & Filters"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Language"
@@ -1486,7 +1495,7 @@ msgstr "Language"
msgid "Launch offer"
msgstr "Launch offer"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Launch offer: Get unlimited members with Pro"
@@ -1511,11 +1520,11 @@ msgstr "Legal"
msgid "License"
msgstr "License"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Light"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Link copied"
@@ -1531,11 +1540,11 @@ msgstr "List name"
msgid "Lists"
msgstr "Lists"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Load more activities"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Loading..."
@@ -1543,7 +1552,7 @@ msgstr "Loading..."
msgid "Login | kan.bn"
msgstr "Login | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Logout"
@@ -1567,12 +1576,12 @@ msgstr "magic link"
msgid "Make template"
msgstr "Make template"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "marked a checklist item as incomplete"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "marked checklist item <0>{0}</0> as incomplete"
@@ -1580,16 +1589,16 @@ msgstr "marked checklist item <0>{0}</0> as incomplete"
msgid "Medium Priority"
msgstr "Medium Priority"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Members"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Members | {0}"
@@ -1604,7 +1613,7 @@ msgstr "monthly billing"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "moved the card from <0>{0}</0> to<1>{1}</1>"
@@ -1612,7 +1621,7 @@ msgstr "moved the card from <0>{0}</0> to<1>{1}</1>"
#~ msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
#~ msgstr "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "moved the card to another list"
@@ -1669,7 +1678,7 @@ msgid "New label"
msgstr "New label"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "New list"
@@ -1738,7 +1747,7 @@ msgstr "No download URL available for this attachment."
msgid "No keyboard shortcuts registered."
msgstr "No keyboard shortcuts registered."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "No lists"
@@ -1754,11 +1763,11 @@ msgstr "Offer"
msgid "Onboarding"
msgstr "Onboarding"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1828,7 +1837,7 @@ msgstr "Password must be at least 8 characters"
msgid "Passwords do not match"
msgstr "Passwords do not match"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Paused"
@@ -1837,7 +1846,7 @@ msgstr "Paused"
msgid "Payment frequency"
msgstr "Payment frequency"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "Pending"
@@ -1894,15 +1903,15 @@ msgstr "Please select a file to upload."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1962,7 +1971,7 @@ msgstr "Privacy policy"
msgid "Private"
msgstr "Private"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Pro Plan"
@@ -2010,25 +2019,25 @@ msgstr "Remote"
msgid "Remove"
msgstr "Remove"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Remove member"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "removed {0} labels: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "removed a label from the card"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "removed a member from the card"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "removed label <0>{0}</0>"
@@ -2036,22 +2045,22 @@ msgstr "removed label <0>{0}</0>"
#~ msgid "removed label <0>{label}</0>"
#~ msgstr "removed label <0>{label}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "removed the due date"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "renamed a checklist"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "renamed checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "renamed checklist item to <0>{0}</0>"
@@ -2085,7 +2094,7 @@ msgstr "Review"
msgid "Roadmap"
msgstr "Roadmap"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Role"
@@ -2095,7 +2104,7 @@ msgid "Run on your own infrastructure"
msgstr "Run on your own infrastructure"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Save"
@@ -2133,7 +2142,7 @@ msgstr "Self Host"
msgid "Self host with Github"
msgstr "Self host with Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "self-assigned the card"
@@ -2157,12 +2166,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Set due date"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "set the due date"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Settings"
@@ -2186,7 +2195,7 @@ msgstr "Settings | Billing"
msgid "Settings | Integrations"
msgstr "Settings | Integrations"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Settings | Workspace"
@@ -2194,7 +2203,7 @@ msgstr "Settings | Workspace"
#~ msgid "Share invite link"
#~ msgstr "Share invite link"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Shortcuts"
@@ -2266,7 +2275,7 @@ msgstr "Success"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Supercharge your workspace for just $29/month. Here's what you'll get:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Support"
@@ -2275,12 +2284,12 @@ msgstr "Support"
msgid "Support the development of the project"
msgstr "Support the development of the project"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "System"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Team Plan"
@@ -2290,8 +2299,8 @@ msgstr "Team Plan"
msgid "Teams"
msgstr "Teams"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Template"
@@ -2311,7 +2320,7 @@ msgstr "Template name cannot exceed 100 characters"
msgid "Template name is required"
msgstr "Template name is required"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Templates"
@@ -2345,7 +2354,7 @@ msgstr "The open source <0/> alternative to Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "The visibility of your board has been set to {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Theme"
@@ -2365,7 +2374,7 @@ msgstr "This action can't be undone."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "This API key will only be shown once. Please save it in a secure location."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "This board is private or does not exist"
@@ -2516,7 +2525,7 @@ msgstr "Unable to update board URL"
msgid "Unable to update board visibility"
msgstr "Unable to update board visibility"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Unable to update card"
@@ -2529,7 +2538,7 @@ msgstr "Unable to update checklist"
msgid "Unable to update checklist item"
msgstr "Unable to update checklist item"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Unable to update comment"
@@ -2541,7 +2550,7 @@ msgstr "Unable to update due date"
msgid "Unable to update labels"
msgstr "Unable to update labels"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Unable to update list"
@@ -2551,7 +2560,7 @@ msgid "Unable to update members"
msgstr "Unable to update members"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "unassigned <0>{0}</0> from the card"
@@ -2559,7 +2568,7 @@ msgstr "unassigned <0>{0}</0> from the card"
#~ msgid "unassigned <0>{memberName}</0> from the card"
#~ msgstr "unassigned <0>{memberName}</0> from the card"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "unassigned themselves from the card"
@@ -2618,24 +2627,24 @@ msgstr "Update"
msgid "Update label"
msgstr "Update label"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "updated a checklist item"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "updated the description"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "updated the due date"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "updated the title"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "updated the title to <0>{0}</0>"
@@ -2647,9 +2656,9 @@ msgstr "updated the title to <0>{0}</0>"
#~ msgid "Upgrade"
#~ msgstr "Upgrade"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Upgrade to Pro"
@@ -2690,7 +2699,7 @@ msgstr "URL must be at least 3 characters long"
msgid "Use template"
msgstr "Use template"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "User"
@@ -2715,7 +2724,7 @@ msgstr "View and manage your billing and subscription."
msgid "View docs"
msgstr "View docs"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "View only"
@@ -2723,7 +2732,7 @@ msgstr "View only"
msgid "View our roadmap."
msgstr "View our roadmap."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "View workspace"
@@ -2776,10 +2785,10 @@ msgid "Why make an open source Trello?"
msgstr "Why make an open source Trello?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Workspace"
@@ -2792,7 +2801,7 @@ msgstr "Workspace created successfully. You can upgrade later in settings."
msgid "Workspace deleted"
msgstr "Workspace deleted"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Workspace description"
@@ -2815,7 +2824,7 @@ msgid "Workspace members"
msgstr "Workspace members"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Workspace name"
@@ -2844,7 +2853,7 @@ msgstr "Workspace name updated"
msgid "Workspace slug updated"
msgstr "Workspace slug updated"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "Workspace URL"
@@ -2865,7 +2874,7 @@ msgstr "Yearly"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "You are about to change your password."

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (editado)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} etiquetas"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} no encontrado"
@@ -100,7 +100,7 @@ msgstr "Registros de actividad"
msgid "Add a card"
msgstr "Añadir una tarjeta"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Añadir un comentario..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Añadir miembro"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "añadió {0} etiquetas: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "añadió una lista de verificación"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "añadió un elemento a la lista de verificación"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "añadió una etiqueta a la tarjeta"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "añadió un miembro a la tarjeta"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "añadió la lista de verificación <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "añadió el elemento <0>{0}</0> a la lista de verificación"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "añadió la etiqueta <0>{0}</0>"
@@ -184,6 +184,10 @@ msgstr "Roles de administrador"
msgid "All systems operational"
msgstr "Todos los sistemas operativos"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Permitir que los miembros del espacio de trabajo vean las direcciones de correo electrónico de los demás"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "¿Ya tienes una cuenta? <0><1>Iniciar sesión</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "¿Estás seguro de que quieres eliminar tu cuenta?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "asignó <0>{0}</0> a la tarjeta"
@@ -317,9 +321,9 @@ msgstr "Portal de facturación"
msgid "Blog Post"
msgstr "Entrada de blog"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Tablero"
@@ -336,7 +340,7 @@ msgstr "El nombre del tablero no puede exceder los 100 caracteres"
msgid "Board name is required"
msgstr "El nombre del tablero es obligatorio"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Tablero no encontrado"
@@ -352,7 +356,7 @@ msgstr "La URL del tablero solo puede contener letras, números y guiones"
msgid "Board URL cannot exceed 60 characters"
msgstr "La URL del tablero no puede exceder los 60 caracteres"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "URL del tablero copiada al portapapeles"
@@ -369,7 +373,7 @@ msgstr "Visibilidad del tablero"
msgid "Board visibility updated"
msgstr "Visibilidad del tablero actualizada"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Tableros"
@@ -388,7 +392,7 @@ msgstr "Informe de error"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Tarjeta no encontrada"
msgid "Card title"
msgstr "Título de la tarjeta"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Cambiar contraseña"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Cambia tus preferencias de idioma."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "cambió la fecha de vencimiento a <0>{formattedDate}</0>"
@@ -500,12 +504,12 @@ msgstr "Completado"
msgid "Complete control and ownership:"
msgstr "Control y propiedad completos:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "completó un elemento de la lista de verificación"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "completó el elemento <0>{0}</0> de la lista de verificación"
@@ -614,8 +618,8 @@ msgstr "Crear nueva clave"
msgid "Create new label"
msgstr "Crear nueva etiqueta"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Crear nueva lista"
@@ -628,7 +632,7 @@ msgstr "Crear plantilla"
msgid "Create workspace"
msgstr "Crear espacio de trabajo"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "creó la tarjeta"
@@ -674,7 +678,7 @@ msgstr "URL personalizada del espacio de trabajo"
msgid "Customer Support"
msgstr "Atención al cliente"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Oscuro"
@@ -692,8 +696,8 @@ msgstr "Desactivar enlace de invitación"
msgid "Delete"
msgstr "Eliminar"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Eliminar cuenta"
@@ -706,7 +710,7 @@ msgstr "Eliminar tablero"
msgid "Delete card"
msgstr "Eliminar tarjeta"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Eliminar comentario"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Eliminar plantilla"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Eliminar espacio de trabajo"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "eliminó una lista de verificación"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "eliminó un elemento de la lista de verificación"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "eliminó la lista de verificación <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "eliminó el elemento <0>{0}</0> de la lista de verificación"
@@ -786,7 +790,7 @@ msgstr "documentos"
msgid "Docs"
msgstr "Documentos"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Editar"
msgid "Edit board URL"
msgstr "Editar URL del tablero"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Editar comentario"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "correo electrónico"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "Correo electrónico"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Visibilidad del correo electrónico"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Mejora"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Características"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Comentarios"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Para la sostenibilidad a largo plazo, reconocemos que todos los buenos proyectos de código abierto necesitan una fuente de ingresos. La nuestra proviene de la oferta de nube de pago para espacios de trabajo con múltiples usuarios y para slugs de espacio de trabajo personalizados. No hay obligación de usarla, y puedes alojar el software en tu propia infraestructura sin costo alguno."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Gratis"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Plan gratuito"
@@ -1116,7 +1123,7 @@ msgstr "Comenzar"
msgid "Get started by creating a new {0}"
msgstr "Comienza creando un nuevo {0}"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Comienza creando una nueva lista"
@@ -1150,19 +1157,19 @@ msgstr "Ir a inicio"
msgid "Go to app"
msgstr "Ir a la aplicación"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Ir a tableros"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Ir a miembros"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Ir a configuración"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Ir a plantillas"
@@ -1287,7 +1294,7 @@ msgstr "Dirección de correo electrónico no válida"
msgid "Invalid invitation"
msgstr "Invitación inválida"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Invitar"
@@ -1368,7 +1375,7 @@ msgstr "Etiquetas y filtros"
msgid "Labels & Filters"
msgstr "Etiquetas y filtros"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Idioma"
@@ -1377,7 +1384,7 @@ msgstr "Idioma"
msgid "Launch offer"
msgstr "Oferta de lanzamiento"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Oferta de lanzamiento: Obtén miembros ilimitados con Pro"
@@ -1402,11 +1409,11 @@ msgstr "Legal"
msgid "License"
msgstr "Licencia"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Claro"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Enlace copiado"
@@ -1422,11 +1429,11 @@ msgstr "Nombre de la lista"
msgid "Lists"
msgstr "Listas"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Cargar más actividades"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Cargando..."
@@ -1434,7 +1441,7 @@ msgstr "Cargando..."
msgid "Login | kan.bn"
msgstr "Iniciar sesión | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Cerrar sesión"
@@ -1458,12 +1465,12 @@ msgstr "enlace mágico"
msgid "Make template"
msgstr "Crear plantilla"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "marcó un elemento de la lista de verificación como incompleto"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "marcó el elemento <0>{0}</0> de la lista de verificación como incompleto"
@@ -1471,16 +1478,16 @@ msgstr "marcó el elemento <0>{0}</0> de la lista de verificación como incomple
msgid "Medium Priority"
msgstr "Prioridad media"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Miembros"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Miembros | {0}"
@@ -1495,11 +1502,11 @@ msgstr "facturación mensual"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "movió la tarjeta de <0>{0}</0> a<1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "movió la tarjeta a otra lista"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Nueva etiqueta"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Nueva lista"
@@ -1609,7 +1616,7 @@ msgstr "No hay URL de descarga disponible para este archivo adjunto."
msgid "No keyboard shortcuts registered."
msgstr "No hay atajos de teclado registrados."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Sin listas"
@@ -1625,11 +1632,11 @@ msgstr "Oferta"
msgid "Onboarding"
msgstr "Incorporación"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1699,7 +1706,7 @@ msgstr "La contraseña debe tener al menos 8 caracteres"
msgid "Passwords do not match"
msgstr "Las contraseñas no coinciden"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Pausado"
@@ -1708,7 +1715,7 @@ msgstr "Pausado"
msgid "Payment frequency"
msgstr "Frecuencia de pago"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "Pendiente"
@@ -1765,15 +1772,15 @@ msgstr "Por favor selecciona un archivo para subir."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Política de privacidad"
msgid "Private"
msgstr "Privado"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Plan Pro"
@@ -1881,44 +1888,44 @@ msgstr "Remoto"
msgid "Remove"
msgstr "Eliminar"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Eliminar miembro"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "eliminó {0} etiquetas: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "eliminó una etiqueta de la tarjeta"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "eliminó un miembro de la tarjeta"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "eliminó la etiqueta <0>{0}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "eliminó la fecha de vencimiento"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "renombró una lista de verificación"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "renombró la lista de verificación <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "renombró el elemento de la lista de verificación a <0>{0}</0>"
@@ -1948,7 +1955,7 @@ msgstr "Revisión"
msgid "Roadmap"
msgstr "Hoja de ruta"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Rol"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Ejecuta en tu propia infraestructura"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Guardar"
@@ -1996,7 +2003,7 @@ msgstr "Autoalojamiento"
msgid "Self host with Github"
msgstr "Autoalojamiento con Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "se autoasignó la tarjeta"
@@ -2016,12 +2023,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Establecer fecha de vencimiento"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "estableció la fecha de vencimiento"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Configuración"
@@ -2041,11 +2048,11 @@ msgstr "Configuración | Facturación"
msgid "Settings | Integrations"
msgstr "Configuración | Integraciones"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Configuración | Espacio de trabajo"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Atajos"
@@ -2117,7 +2124,7 @@ msgstr "Éxito"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Potencia tu espacio de trabajo por solo $29/mes. Esto es lo que obtendrás:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Soporte"
@@ -2126,12 +2133,12 @@ msgstr "Soporte"
msgid "Support the development of the project"
msgstr "Apoya el desarrollo del proyecto"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "Sistema"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Plan de Equipo"
@@ -2141,8 +2148,8 @@ msgstr "Plan de Equipo"
msgid "Teams"
msgstr "Equipos"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Plantilla"
@@ -2162,7 +2169,7 @@ msgstr "El nombre de la plantilla no puede exceder los 100 caracteres"
msgid "Template name is required"
msgstr "El nombre de la plantilla es obligatorio"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Plantillas"
@@ -2196,7 +2203,7 @@ msgstr "La alternativa de código abierto <0/> a Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "La visibilidad de tu tablero ha sido establecida a {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Tema"
@@ -2216,7 +2223,7 @@ msgstr "Esta acción no se puede deshacer."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Esta clave API solo se mostrará una vez. Por favor, guárdala en un lugar seguro."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Este tablero es privado o no existe"
@@ -2359,7 +2366,7 @@ msgstr "No se puede actualizar la URL del tablero"
msgid "Unable to update board visibility"
msgstr "No se puede actualizar la visibilidad del tablero"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "No se puede actualizar la tarjeta"
@@ -2372,7 +2379,7 @@ msgstr "No se puede actualizar la lista de verificación"
msgid "Unable to update checklist item"
msgstr "No se puede actualizar el elemento de la lista de verificación"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "No se puede actualizar el comentario"
@@ -2384,7 +2391,7 @@ msgstr "No se puede actualizar la fecha de vencimiento"
msgid "Unable to update labels"
msgstr "No se pueden actualizar las etiquetas"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "No se puede actualizar la lista"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "No se pueden actualizar los miembros"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "desasignó <0>{0}</0> de la tarjeta"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "se desasignó de la tarjeta"
@@ -2457,30 +2464,30 @@ msgstr "Actualizar"
msgid "Update label"
msgstr "Actualizar etiqueta"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "actualizó un elemento de la lista de verificación"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "actualizó la descripción"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "actualizó la fecha de vencimiento"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "actualizó el título"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "actualizó el título a <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Actualizar a Pro"
@@ -2517,7 +2524,7 @@ msgstr "La URL debe tener al menos 3 caracteres"
msgid "Use template"
msgstr "Usar plantilla"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Usuario"
@@ -2542,7 +2549,7 @@ msgstr "Ver y gestionar tu facturación y suscripción."
msgid "View docs"
msgstr "Ver documentación"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Solo visualización"
@@ -2550,7 +2557,7 @@ msgstr "Solo visualización"
msgid "View our roadmap."
msgstr "Ver nuestra hoja de ruta."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Ver espacio de trabajo"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "¿Por qué crear un Trello de código abierto?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Espacio de trabajo"
@@ -2611,7 +2618,7 @@ msgstr "Espacio de trabajo creado con éxito. Puedes actualizar más tarde en co
msgid "Workspace deleted"
msgstr "Espacio de trabajo eliminado"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Descripción del espacio de trabajo"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Miembros del espacio de trabajo"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Nombre del espacio de trabajo"
@@ -2659,7 +2666,7 @@ msgstr "Nombre del espacio de trabajo actualizado"
msgid "Workspace slug updated"
msgstr "Slug del espacio de trabajo actualizado"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "URL del espacio de trabajo"
@@ -2680,7 +2687,7 @@ msgstr "Anual"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Estás a punto de cambiar tu contraseña."

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (modifié)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} étiquettes"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} introuvable"
@@ -100,7 +100,7 @@ msgstr "Journaux d'activité"
msgid "Add a card"
msgstr "Ajouter une carte"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Ajouter un commentaire..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Ajouter un membre"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "a ajouté {0} étiquettes : <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "a ajouté une checklist"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "a ajouté un élément à la checklist"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "a ajouté une étiquette à la carte"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "a ajouté un membre à la carte"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "a ajouté la checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "a ajouté l'élément <0>{0}</0> à la checklist"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "a ajouté l'étiquette <0>{0}</0>"
@@ -184,6 +184,10 @@ msgstr "Rôles d'administrateur"
msgid "All systems operational"
msgstr "Tous les systèmes opérationnels"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Permettre aux membres de l'espace de travail de voir les adresses e-mail des autres"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Vous avez déjà un compte ? <0><1>Connectez-vous</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Êtes-vous sûr de vouloir supprimer votre compte ?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "a assigné <0>{0}</0> à la carte"
@@ -317,9 +321,9 @@ msgstr "Portail de facturation"
msgid "Blog Post"
msgstr "Article de blog"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Tableau"
@@ -336,7 +340,7 @@ msgstr "Le nom du tableau ne peut pas dépasser 100 caractères"
msgid "Board name is required"
msgstr "Le nom du tableau est requis"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Tableau introuvable"
@@ -352,7 +356,7 @@ msgstr "L'URL du tableau ne peut contenir que des lettres, des chiffres et des t
msgid "Board URL cannot exceed 60 characters"
msgstr "L'URL du tableau ne peut pas dépasser 60 caractères"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "URL du tableau copiée dans le presse-papiers"
@@ -369,7 +373,7 @@ msgstr "Visibilité du tableau"
msgid "Board visibility updated"
msgstr "Visibilité du tableau mise à jour"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Tableaux"
@@ -388,7 +392,7 @@ msgstr "Rapport de bug"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Carte introuvable"
msgid "Card title"
msgstr "Titre de la carte"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Modifier le mot de passe"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Modifiez vos préférences linguistiques."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "a modifié la date d'échéance pour <0>{formattedDate}</0>"
@@ -500,12 +504,12 @@ msgstr "Terminé"
msgid "Complete control and ownership:"
msgstr "Contrôle et propriété complets :"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "a terminé un élément de la checklist"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "a terminé l'élément <0>{0}</0> de la checklist"
@@ -614,8 +618,8 @@ msgstr "Créer une nouvelle clé"
msgid "Create new label"
msgstr "Créer une nouvelle étiquette"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Créer une nouvelle liste"
@@ -628,7 +632,7 @@ msgstr "Créer un modèle"
msgid "Create workspace"
msgstr "Créer un espace de travail"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "a créé la carte"
@@ -674,7 +678,7 @@ msgstr "URL d'espace de travail personnalisée"
msgid "Customer Support"
msgstr "Support client"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Sombre"
@@ -692,8 +696,8 @@ msgstr "Désactiver le lien d'invitation"
msgid "Delete"
msgstr "Supprimer"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Supprimer le compte"
@@ -706,7 +710,7 @@ msgstr "Supprimer le tableau"
msgid "Delete card"
msgstr "Supprimer la carte"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Supprimer le commentaire"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Supprimer le modèle"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Supprimer l'espace de travail"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "a supprimé une checklist"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "a supprimé un élément de la checklist"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "a supprimé la checklist <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "a supprimé l'élément <0>{0}</0> de la checklist"
@@ -786,7 +790,7 @@ msgstr "documentation"
msgid "Docs"
msgstr "Documentation"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Modifier"
msgid "Edit board URL"
msgstr "Modifier l'URL du tableau"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Modifier le commentaire"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "e-mail"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "E-mail"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Visibilité des e-mails"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Amélioration"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Fonctionnalités"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Commentaires"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Pour une durabilité à long terme, nous reconnaissons que tous les bons projets open source ont besoin d'une source de revenus. La nôtre provient de l'offre cloud payante pour les espaces de travail avec plusieurs utilisateurs et pour les slugs d'espace de travail personnalisés. Il n'y a aucune obligation de l'utiliser, et vous pouvez auto-héberger le logiciel sur votre propre infrastructure gratuitement."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Gratuit"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Forfait gratuit"
@@ -1116,7 +1123,7 @@ msgstr "Commencer"
msgid "Get started by creating a new {0}"
msgstr "Commencez par créer un nouveau {0}"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Commencez par créer une nouvelle liste"
@@ -1150,19 +1157,19 @@ msgstr "Aller à l'accueil"
msgid "Go to app"
msgstr "Accéder à l'application"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Aller aux tableaux"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Aller aux membres"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Aller aux paramètres"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Aller aux modèles"
@@ -1287,7 +1294,7 @@ msgstr "Adresse e-mail invalide"
msgid "Invalid invitation"
msgstr "Invitation invalide"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Inviter"
@@ -1368,7 +1375,7 @@ msgstr "Étiquettes & filtres"
msgid "Labels & Filters"
msgstr "Étiquettes & filtres"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Langue"
@@ -1377,7 +1384,7 @@ msgstr "Langue"
msgid "Launch offer"
msgstr "Offre de lancement"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Offre de lancement : obtenez des membres illimités avec Pro"
@@ -1402,11 +1409,11 @@ msgstr "Mentions légales"
msgid "License"
msgstr "Licence"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Clair"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Lien copié"
@@ -1422,11 +1429,11 @@ msgstr "Nom de la liste"
msgid "Lists"
msgstr "Listes"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Charger plus d'activités"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Chargement..."
@@ -1434,7 +1441,7 @@ msgstr "Chargement..."
msgid "Login | kan.bn"
msgstr "Connexion | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Déconnexion"
@@ -1458,12 +1465,12 @@ msgstr "lien magique"
msgid "Make template"
msgstr "Créer un modèle"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "a marqué un élément de la checklist comme incomplet"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "a marqué l'élément <0>{0}</0> de la checklist comme incomplet"
@@ -1471,16 +1478,16 @@ msgstr "a marqué l'élément <0>{0}</0> de la checklist comme incomplet"
msgid "Medium Priority"
msgstr "Priorité moyenne"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Membres"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Membres | {0}"
@@ -1495,11 +1502,11 @@ msgstr "facturation mensuelle"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "a déplacé la carte de <0>{0}</0> vers <1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "a déplacé la carte vers une autre liste"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Nouvelle étiquette"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Nouvelle liste"
@@ -1609,7 +1616,7 @@ msgstr "Aucune URL de téléchargement disponible pour cette pièce jointe."
msgid "No keyboard shortcuts registered."
msgstr "Aucun raccourci clavier enregistré."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Aucune liste"
@@ -1625,11 +1632,11 @@ msgstr "Offre"
msgid "Onboarding"
msgstr "Intégration"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1699,7 +1706,7 @@ msgstr "Le mot de passe doit comporter au moins 8 caractères"
msgid "Passwords do not match"
msgstr "Les mots de passe ne correspondent pas"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "En pause"
@@ -1708,7 +1715,7 @@ msgstr "En pause"
msgid "Payment frequency"
msgstr "Fréquence de paiement"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "En attente"
@@ -1765,15 +1772,15 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Politique de confidentialité"
msgid "Private"
msgstr "Privé"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Plan Pro"
@@ -1881,44 +1888,44 @@ msgstr "À distance"
msgid "Remove"
msgstr "Supprimer"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Supprimer le membre"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "a supprimé {0} étiquettes : <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "a supprimé une étiquette de la carte"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "a retiré un membre de la carte"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "a supprimé l'étiquette <0>{0}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "a supprimé la date d'échéance"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "a renommé une checklist"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "a renommé la checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "a renommé l'élément de la liste de contrôle en <0>{0}</0>"
@@ -1948,7 +1955,7 @@ msgstr "Révision"
msgid "Roadmap"
msgstr "Feuille de route"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Rôle"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Exécutez sur votre propre infrastructure"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Enregistrer"
@@ -1996,7 +2003,7 @@ msgstr "Auto-hébergement"
msgid "Self host with Github"
msgstr "Auto-hébergement avec Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "s'est auto-assigné la carte"
@@ -2016,12 +2023,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Définir la date d'échéance"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "a défini la date d'échéance"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Paramètres"
@@ -2041,11 +2048,11 @@ msgstr "Paramètres | Facturation"
msgid "Settings | Integrations"
msgstr "Paramètres | Intégrations"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Paramètres | Espace de travail"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Raccourcis"
@@ -2117,7 +2124,7 @@ msgstr "Succès"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Optimisez votre espace de travail pour seulement 29 $/mois. Voici ce que vous obtiendrez :"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Assistance"
@@ -2126,12 +2133,12 @@ msgstr "Assistance"
msgid "Support the development of the project"
msgstr "Soutenir le développement du projet"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "Système"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Forfait d'équipe"
@@ -2141,8 +2148,8 @@ msgstr "Forfait d'équipe"
msgid "Teams"
msgstr "Équipes"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Modèle"
@@ -2162,7 +2169,7 @@ msgstr "Le nom du modèle ne peut pas dépasser 100 caractères"
msgid "Template name is required"
msgstr "Le nom du modèle est requis"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Modèles"
@@ -2196,7 +2203,7 @@ msgstr "L'alternative open source <0/> à Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "La visibilité de votre tableau a été définie sur {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Thème"
@@ -2216,7 +2223,7 @@ msgstr "Cette action ne peut pas être annulée."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Cette clé API ne sera affichée qu'une seule fois. Veuillez la sauvegarder dans un emplacement sécurisé."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Ce tableau est privé ou n'existe pas"
@@ -2359,7 +2366,7 @@ msgstr "Impossible de mettre à jour l'URL du tableau"
msgid "Unable to update board visibility"
msgstr "Impossible de mettre à jour la visibilité du tableau"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Impossible de mettre à jour la carte"
@@ -2372,7 +2379,7 @@ msgstr "Impossible de mettre à jour la liste de contrôle"
msgid "Unable to update checklist item"
msgstr "Impossible de mettre à jour l'élément de la liste de contrôle"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Impossible de mettre à jour le commentaire"
@@ -2384,7 +2391,7 @@ msgstr "Impossible de mettre à jour la date d'échéance"
msgid "Unable to update labels"
msgstr "Impossible de mettre à jour les étiquettes"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Impossible de mettre à jour la liste"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "Impossible de mettre à jour les membres"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "a désassigné <0>{0}</0> de la carte"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "s'est retiré de la carte"
@@ -2457,30 +2464,30 @@ msgstr "Mettre à jour"
msgid "Update label"
msgstr "Mettre à jour l'étiquette"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "a mis à jour un élément de la liste de contrôle"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "a mis à jour la description"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "a mis à jour la date d'échéance"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "a mis à jour le titre"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "a mis à jour le titre en <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Passer à Pro"
@@ -2517,7 +2524,7 @@ msgstr "L'URL doit comporter au moins 3 caractères"
msgid "Use template"
msgstr "Utiliser le modèle"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Utilisateur"
@@ -2542,7 +2549,7 @@ msgstr "Consultez et gérez votre facturation et votre abonnement."
msgid "View docs"
msgstr "Voir la documentation"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Affichage uniquement"
@@ -2550,7 +2557,7 @@ msgstr "Affichage uniquement"
msgid "View our roadmap."
msgstr "Consultez notre feuille de route."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Voir l'espace de travail"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "Pourquoi créer un Trello open source ?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Espace de travail"
@@ -2611,7 +2618,7 @@ msgstr "Espace de travail créé avec succès. Vous pourrez effectuer la mise à
msgid "Workspace deleted"
msgstr "Espace de travail supprimé"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Description de l'espace de travail"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Membres de l'espace de travail"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Nom de l'espace de travail"
@@ -2659,7 +2666,7 @@ msgstr "Nom de l'espace de travail mis à jour"
msgid "Workspace slug updated"
msgstr "Slug de l'espace de travail mis à jour"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "URL de l'espace de travail"
@@ -2680,7 +2687,7 @@ msgstr "Annuel"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Vous êtes sur le point de modifier votre mot de passe."

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@ export const locales = [
"nl",
"ru",
"pl",
"ptbr"
"pt-BR"
] as const;
export type Locale = (typeof locales)[number];
@@ -23,5 +23,5 @@ export const localeNames: Record<Locale, string> = {
nl: "Nederlands",
ru: "Русский",
pl: "Polski",
ptbr: "Português",
"pt-BR": "Português",
};

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (modificato)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} etichette"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} non trovato"
@@ -100,7 +100,7 @@ msgstr "Registri attività"
msgid "Add a card"
msgstr "Aggiungi una carta"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Aggiungi un commento..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Aggiungi membro"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "ha aggiunto {0} etichette: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "ha aggiunto una checklist"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "ha aggiunto un elemento alla checklist"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "ha aggiunto un'etichetta alla carta"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "ha aggiunto un membro alla carta"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "ha aggiunto la checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "ha aggiunto l'elemento <0>{0}</0> alla checklist"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "ha aggiunto l'etichetta <0>{0}</0>"
@@ -184,6 +184,10 @@ msgstr "Ruoli amministratore"
msgid "All systems operational"
msgstr "Tutti i sistemi operativi"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Consenti ai membri dello spazio di lavoro di vedere gli indirizzi email degli altri"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Hai già un account? <0><1>Accedi</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Sei sicuro di voler eliminare il tuo account?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "ha assegnato <0>{0}</0> alla scheda"
@@ -317,9 +321,9 @@ msgstr "Portale di fatturazione"
msgid "Blog Post"
msgstr "Post del blog"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Bacheca"
@@ -336,7 +340,7 @@ msgstr "Il nome della bacheca non può superare i 100 caratteri"
msgid "Board name is required"
msgstr "Il nome della bacheca è obbligatorio"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Bacheca non trovata"
@@ -352,7 +356,7 @@ msgstr "L'URL della bacheca può contenere solo lettere, numeri e trattini"
msgid "Board URL cannot exceed 60 characters"
msgstr "L'URL della bacheca non può superare i 60 caratteri"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "URL della bacheca copiato negli appunti"
@@ -369,7 +373,7 @@ msgstr "Visibilità bacheca"
msgid "Board visibility updated"
msgstr "Visibilità della bacheca aggiornata"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Bacheche"
@@ -388,7 +392,7 @@ msgstr "Segnalazione bug"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Carta non trovata"
msgid "Card title"
msgstr "Titolo della carta"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Cambia password"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Modifica le tue preferenze di lingua."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "ha cambiato la data di scadenza a <0>{formattedDate}</0>"
@@ -500,12 +504,12 @@ msgstr "Completato"
msgid "Complete control and ownership:"
msgstr "Controllo e proprietà completi:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "ha completato un elemento della checklist"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "ha completato l'elemento <0>{0}</0> della checklist"
@@ -614,8 +618,8 @@ msgstr "Crea nuova chiave"
msgid "Create new label"
msgstr "Crea nuova etichetta"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Crea nuova lista"
@@ -628,7 +632,7 @@ msgstr "Crea template"
msgid "Create workspace"
msgstr "Crea spazio di lavoro"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "ha creato la carta"
@@ -674,7 +678,7 @@ msgstr "URL personalizzato dell'area di lavoro"
msgid "Customer Support"
msgstr "Assistenza clienti"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Scuro"
@@ -692,8 +696,8 @@ msgstr "Disattiva link di invito"
msgid "Delete"
msgstr "Elimina"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Elimina account"
@@ -706,7 +710,7 @@ msgstr "Elimina bacheca"
msgid "Delete card"
msgstr "Elimina carta"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Elimina commento"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Elimina template"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Elimina spazio di lavoro"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "ha eliminato una checklist"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "ha eliminato un elemento della checklist"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "ha eliminato la checklist <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "ha eliminato l'elemento <0>{0}</0> della checklist"
@@ -786,7 +790,7 @@ msgstr "documenti"
msgid "Docs"
msgstr "Documenti"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Modifica"
msgid "Edit board URL"
msgstr "Modifica URL della bacheca"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Modifica commento"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "Email"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Visibilità email"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Miglioramento"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Funzionalità"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Feedback"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Per la sostenibilità a lungo termine, riconosciamo che tutti i buoni progetti open source necessitano di una fonte di entrate. La nostra proviene dall'offerta cloud a pagamento per gli spazi di lavoro con più utenti e per gli slug personalizzati degli spazi di lavoro. Non c'è alcun obbligo di utilizzarla, e puoi ospitare autonomamente il software sulla tua infrastruttura gratuitamente."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Gratuito"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Piano gratuito"
@@ -1116,7 +1123,7 @@ msgstr "Inizia ora"
msgid "Get started by creating a new {0}"
msgstr "Inizia creando un nuovo {0}"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Inizia creando una nuova lista"
@@ -1150,19 +1157,19 @@ msgstr "Vai alla home"
msgid "Go to app"
msgstr "Vai all'app"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Vai alle bacheche"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Vai ai membri"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Vai alle impostazioni"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Vai ai modelli"
@@ -1287,7 +1294,7 @@ msgstr "Indirizzo email non valido"
msgid "Invalid invitation"
msgstr "Invito non valido"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Invita"
@@ -1368,7 +1375,7 @@ msgstr "Etichette & filtri"
msgid "Labels & Filters"
msgstr "Etichette & Filtri"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Lingua"
@@ -1377,7 +1384,7 @@ msgstr "Lingua"
msgid "Launch offer"
msgstr "Offerta di lancio"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Offerta di lancio: ottieni membri illimitati con Pro"
@@ -1402,11 +1409,11 @@ msgstr "Legale"
msgid "License"
msgstr "Licenza"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Chiaro"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Link copiato"
@@ -1422,11 +1429,11 @@ msgstr "Nome lista"
msgid "Lists"
msgstr "Liste"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Carica altre attività"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Caricamento in corso..."
@@ -1434,7 +1441,7 @@ msgstr "Caricamento in corso..."
msgid "Login | kan.bn"
msgstr "Login | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Esci"
@@ -1458,12 +1465,12 @@ msgstr "link magico"
msgid "Make template"
msgstr "Crea template"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "ha segnato un elemento della checklist come incompleto"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "ha segnato l'elemento <0>{0}</0> della checklist come incompleto"
@@ -1471,16 +1478,16 @@ msgstr "ha segnato l'elemento <0>{0}</0> della checklist come incompleto"
msgid "Medium Priority"
msgstr "Media priorità"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Membri"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Membri | {0}"
@@ -1495,11 +1502,11 @@ msgstr "fatturazione mensile"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "ha spostato la scheda da <0>{0}</0> a<1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "ha spostato la scheda in un'altra lista"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Nuova etichetta"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Nuova lista"
@@ -1609,7 +1616,7 @@ msgstr "Nessun URL di download disponibile per questo allegato."
msgid "No keyboard shortcuts registered."
msgstr "Nessuna scorciatoia da tastiera registrata."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Nessuna lista"
@@ -1625,11 +1632,11 @@ msgstr "Offerta"
msgid "Onboarding"
msgstr "Inserimento"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1699,7 +1706,7 @@ msgstr "La password deve contenere almeno 8 caratteri"
msgid "Passwords do not match"
msgstr "Le password non corrispondono"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "In pausa"
@@ -1708,7 +1715,7 @@ msgstr "In pausa"
msgid "Payment frequency"
msgstr "Frequenza di pagamento"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "In attesa"
@@ -1765,15 +1772,15 @@ msgstr "Seleziona un file da caricare."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Informativa sulla privacy"
msgid "Private"
msgstr "Privato"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Piano Pro"
@@ -1881,44 +1888,44 @@ msgstr "Remoto"
msgid "Remove"
msgstr "Rimuovi"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Rimuovi membro"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "ha rimosso {0} etichette: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "ha rimosso un'etichetta dalla scheda"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "ha rimosso un membro dalla scheda"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "ha rimosso l'etichetta <0>{0}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "ha rimosso la data di scadenza"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "ha rinominato una checklist"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "ha rinominato la checklist <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "ha rinominato l'elemento della checklist in <0>{0}</0>"
@@ -1948,7 +1955,7 @@ msgstr "Revisione"
msgid "Roadmap"
msgstr "Roadmap"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Ruolo"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Esegui sulla tua infrastruttura"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Salva"
@@ -1996,7 +2003,7 @@ msgstr "Self Host"
msgid "Self host with Github"
msgstr "Self host con Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "si è auto-assegnato la scheda"
@@ -2016,12 +2023,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Imposta data di scadenza"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "ha impostato la data di scadenza"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Impostazioni"
@@ -2041,11 +2048,11 @@ msgstr "Impostazioni | Fatturazione"
msgid "Settings | Integrations"
msgstr "Impostazioni | Integrazioni"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Impostazioni | Area di lavoro"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Scorciatoie"
@@ -2117,7 +2124,7 @@ msgstr "Operazione riuscita"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Potenzia la tua area di lavoro per soli $29/mese. Ecco cosa otterrai:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Supporto"
@@ -2126,12 +2133,12 @@ msgstr "Supporto"
msgid "Support the development of the project"
msgstr "Sostieni lo sviluppo del progetto"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "Sistema"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Piano Team"
@@ -2141,8 +2148,8 @@ msgstr "Piano Team"
msgid "Teams"
msgstr "Team"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Template"
@@ -2162,7 +2169,7 @@ msgstr "Il nome del template non può superare i 100 caratteri"
msgid "Template name is required"
msgstr "Il nome del template è obbligatorio"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Template"
@@ -2196,7 +2203,7 @@ msgstr "L'alternativa open source <0/> a Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "La visibilità della tua bacheca è stata impostata su {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Tema"
@@ -2216,7 +2223,7 @@ msgstr "Questa azione non può essere annullata."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Questa chiave API verrà mostrata una sola volta. Salvala in un luogo sicuro."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Questa bacheca è privata o non esiste"
@@ -2359,7 +2366,7 @@ msgstr "Impossibile aggiornare l'URL della bacheca"
msgid "Unable to update board visibility"
msgstr "Impossibile aggiornare la visibilità della bacheca"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Impossibile aggiornare la scheda"
@@ -2372,7 +2379,7 @@ msgstr "Impossibile aggiornare la checklist"
msgid "Unable to update checklist item"
msgstr "Impossibile aggiornare l'elemento della checklist"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Impossibile aggiornare il commento"
@@ -2384,7 +2391,7 @@ msgstr "Impossibile aggiornare la data di scadenza"
msgid "Unable to update labels"
msgstr "Impossibile aggiornare le etichette"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Impossibile aggiornare la lista"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "Impossibile aggiornare i membri"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "ha rimosso l'assegnazione di <0>{0}</0> dalla scheda"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "si è rimosso dall'assegnazione della scheda"
@@ -2457,30 +2464,30 @@ msgstr "Aggiorna"
msgid "Update label"
msgstr "Aggiorna etichetta"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "ha aggiornato un elemento della checklist"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "ha aggiornato la descrizione"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "ha aggiornato la data di scadenza"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "ha aggiornato il titolo"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "ha aggiornato il titolo in <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Passa a Pro"
@@ -2517,7 +2524,7 @@ msgstr "L'URL deve contenere almeno 3 caratteri"
msgid "Use template"
msgstr "Usa template"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Utente"
@@ -2542,7 +2549,7 @@ msgstr "Visualizza e gestisci la tua fatturazione e abbonamento."
msgid "View docs"
msgstr "Visualizza documenti"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Solo visualizzazione"
@@ -2550,7 +2557,7 @@ msgstr "Solo visualizzazione"
msgid "View our roadmap."
msgstr "Visualizza la nostra roadmap."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Visualizza spazio di lavoro"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "Perché creare un Trello open source?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Spazio di lavoro"
@@ -2611,7 +2618,7 @@ msgstr "Spazio di lavoro creato con successo. Puoi effettuare l'aggiornamento pi
msgid "Workspace deleted"
msgstr "Spazio di lavoro eliminato"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Descrizione dello spazio di lavoro"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Membri del workspace"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Nome dello spazio di lavoro"
@@ -2659,7 +2666,7 @@ msgstr "Nome dello spazio di lavoro aggiornato"
msgid "Workspace slug updated"
msgstr "Slug dell'area di lavoro aggiornato"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "URL dello spazio di lavoro"
@@ -2680,7 +2687,7 @@ msgstr "Annuale"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Stai per cambiare la tua password."

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (bewerkt)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} labels"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} niet gevonden"
@@ -100,7 +100,7 @@ msgstr "Activiteitenlogboeken"
msgid "Add a card"
msgstr "Voeg een kaart toe"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Voeg een reactie toe..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Lid toevoegen"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "{0} labels toegevoegd: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "heeft een checklist toegevoegd"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "heeft een checklistitem toegevoegd"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "heeft een label aan de kaart toegevoegd"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "heeft een lid aan de kaart toegevoegd"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "heeft checklist <0>{0}</0> toegevoegd"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "heeft checklistitem <0>{0}</0> toegevoegd"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "heeft label <0>{0}</0> toegevoegd"
@@ -184,6 +184,10 @@ msgstr "Beheerdersrollen"
msgid "All systems operational"
msgstr "Alle systemen operationeel"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Sta werkruimteleden toe elkaars e-mailadressen te zien"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Heb je al een account? <0><1>Log in</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Weet je zeker dat je je account wilt verwijderen?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "heeft <0>{0}</0> aan de kaart toegewezen"
@@ -317,9 +321,9 @@ msgstr "Factureringsportaal"
msgid "Blog Post"
msgstr "Blogbericht"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Bord"
@@ -336,7 +340,7 @@ msgstr "Bordnaam mag niet langer zijn dan 100 tekens"
msgid "Board name is required"
msgstr "Bordnaam is verplicht"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Bord niet gevonden"
@@ -352,7 +356,7 @@ msgstr "Board URL kan alleen letters, cijfers en koppeltekens bevatten"
msgid "Board URL cannot exceed 60 characters"
msgstr "Board URL mag niet langer zijn dan 60 tekens"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "Board URL gekopieerd naar klembord"
@@ -369,7 +373,7 @@ msgstr "Bordzichtbaarheid"
msgid "Board visibility updated"
msgstr "Zichtbaarheid van bord bijgewerkt"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Borden"
@@ -388,7 +392,7 @@ msgstr "Bugrapport"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Kaart niet gevonden"
msgid "Card title"
msgstr "Kaarttitel"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Wachtwoord wijzigen"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Wijzig je taalvoorkeuren."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "heeft de vervaldatum gewijzigd naar <0>{formattedDate}</0>"
@@ -500,12 +504,12 @@ msgstr "Voltooid"
msgid "Complete control and ownership:"
msgstr "Volledige controle en eigendom:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "heeft een checklistitem voltooid"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "heeft checklistitem <0>{0}</0> voltooid"
@@ -614,8 +618,8 @@ msgstr "Nieuwe sleutel aanmaken"
msgid "Create new label"
msgstr "Maak nieuw label"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Maak nieuwe lijst"
@@ -628,7 +632,7 @@ msgstr "Sjabloon maken"
msgid "Create workspace"
msgstr "Werkruimte maken"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "heeft de kaart aangemaakt"
@@ -674,7 +678,7 @@ msgstr "Aangepaste werkruimte-URL"
msgid "Customer Support"
msgstr "Klantenservice"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Donker"
@@ -692,8 +696,8 @@ msgstr "Uitnodigingslink deactiveren"
msgid "Delete"
msgstr "Verwijderen"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Account verwijderen"
@@ -706,7 +710,7 @@ msgstr "Board verwijderen"
msgid "Delete card"
msgstr "Kaart verwijderen"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Reactie verwijderen"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Sjabloon verwijderen"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Werkruimte verwijderen"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "heeft een checklist verwijderd"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "heeft een checklistitem verwijderd"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "heeft checklist <0>{0}</0> verwijderd"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "heeft checklistitem <0>{0}</0> verwijderd"
@@ -786,7 +790,7 @@ msgstr "docs"
msgid "Docs"
msgstr "Docs"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Bewerken"
msgid "Edit board URL"
msgstr "Board URL bewerken"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Reactie bewerken"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "e-mail"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "E-mail"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "E-mailzichtbaarheid"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Verbetering"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Functies"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Feedback"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Voor duurzaamheid op lange termijn erkennen we dat alle goede open source projecten een inkomstenbron nodig hebben. De onze komt van de betaalde cloudoplossing voor werkruimtes met meerdere gebruikers en voor aangepaste werkruimte-slugs. Er is geen verplichting om het te gebruiken, en je kunt de software gratis op je eigen infrastructuur hosten."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Gratis"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Gratis plan"
@@ -1116,7 +1123,7 @@ msgstr "Aan de slag"
msgid "Get started by creating a new {0}"
msgstr "Begin door een nieuwe {0} te maken"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Begin door een nieuwe lijst te maken"
@@ -1150,19 +1157,19 @@ msgstr "Naar startpagina"
msgid "Go to app"
msgstr "Naar de app"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Ga naar borden"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Ga naar leden"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Ga naar instellingen"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Ga naar sjablonen"
@@ -1287,7 +1294,7 @@ msgstr "Ongeldig e-mailadres"
msgid "Invalid invitation"
msgstr "Ongeldige uitnodiging"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Uitnodigen"
@@ -1368,7 +1375,7 @@ msgstr "Labels & filters"
msgid "Labels & Filters"
msgstr "Labels & filters"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Taal"
@@ -1377,7 +1384,7 @@ msgstr "Taal"
msgid "Launch offer"
msgstr "Introductieaanbieding"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Lanceringsaanbieding: krijg onbeperkt aantal leden met Pro"
@@ -1402,11 +1409,11 @@ msgstr "Juridisch"
msgid "License"
msgstr "Licentie"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Licht"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Link gekopieerd"
@@ -1422,11 +1429,11 @@ msgstr "Lijstnaam"
msgid "Lists"
msgstr "Lijsten"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Meer activiteiten laden"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Laden..."
@@ -1434,7 +1441,7 @@ msgstr "Laden..."
msgid "Login | kan.bn"
msgstr "Login | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Uitloggen"
@@ -1458,12 +1465,12 @@ msgstr "magische link"
msgid "Make template"
msgstr "Sjabloon maken"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "heeft een checklistitem als onvoltooid gemarkeerd"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "heeft checklistitem <0>{0}</0> als onvoltooid gemarkeerd"
@@ -1471,16 +1478,16 @@ msgstr "heeft checklistitem <0>{0}</0> als onvoltooid gemarkeerd"
msgid "Medium Priority"
msgstr "Gemiddelde prioriteit"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Leden"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Leden | {0}"
@@ -1495,11 +1502,11 @@ msgstr "maandelijkse facturering"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "heeft de kaart verplaatst van <0>{0}</0> naar<1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "heeft de kaart naar een andere lijst verplaatst"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Nieuw label"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Nieuwe lijst"
@@ -1609,7 +1616,7 @@ msgstr "Geen download-URL beschikbaar voor deze bijlage."
msgid "No keyboard shortcuts registered."
msgstr "Geen sneltoetsen geregistreerd."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Geen lijsten"
@@ -1625,11 +1632,11 @@ msgstr "Aanbod"
msgid "Onboarding"
msgstr "Inwerktraject"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
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."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
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."
@@ -1699,7 +1706,7 @@ msgstr "Wachtwoord moet minimaal 8 tekens bevatten"
msgid "Passwords do not match"
msgstr "Wachtwoorden komen niet overeen"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Gepauzeerd"
@@ -1708,7 +1715,7 @@ msgstr "Gepauzeerd"
msgid "Payment frequency"
msgstr "Betalingsfrequentie"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "In behandeling"
@@ -1765,15 +1772,15 @@ msgstr "Selecteer een bestand om te uploaden."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Privacybeleid"
msgid "Private"
msgstr "Privé"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Pro Plan"
@@ -1881,44 +1888,44 @@ msgstr "Op afstand"
msgid "Remove"
msgstr "Verwijderen"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Lid verwijderen"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "{0} labels verwijderd: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "heeft een label van de kaart verwijderd"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "heeft een lid van de kaart verwijderd"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "heeft label <0>{0}</0> verwijderd"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "heeft de vervaldatum verwijderd"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "heeft een checklist hernoemd"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "heeft checklist <0>{0}</0> hernoemd"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "checklistitem hernoemd naar <0>{0}</0>"
@@ -1948,7 +1955,7 @@ msgstr "Beoordeling"
msgid "Roadmap"
msgstr "Roadmap"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Rol"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Draai op je eigen infrastructuur"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Opslaan"
@@ -1996,7 +2003,7 @@ msgstr "Zelf hosten"
msgid "Self host with Github"
msgstr "Zelf hosten met Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "heeft de kaart aan zichzelf toegewezen"
@@ -2016,12 +2023,12 @@ msgstr "Senior"
msgid "Set due date"
msgstr "Vervaldatum instellen"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "heeft de vervaldatum ingesteld"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Instellingen"
@@ -2041,11 +2048,11 @@ msgstr "Instellingen | Facturering"
msgid "Settings | Integrations"
msgstr "Instellingen | Integraties"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Instellingen | Werkruimte"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Snelkoppelingen"
@@ -2117,7 +2124,7 @@ msgstr "Geslaagd"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Geef je werkruimte een boost voor slechts $29/maand. Dit krijg je:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Ondersteuning"
@@ -2126,12 +2133,12 @@ msgstr "Ondersteuning"
msgid "Support the development of the project"
msgstr "Ondersteun de ontwikkeling van het project"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "Systeem"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Teamplan"
@@ -2141,8 +2148,8 @@ msgstr "Teamplan"
msgid "Teams"
msgstr "Teams"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Sjabloon"
@@ -2162,7 +2169,7 @@ msgstr "Sjabloonnaam mag niet langer zijn dan 100 tekens"
msgid "Template name is required"
msgstr "Sjabloonnaam is verplicht"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Sjablonen"
@@ -2196,7 +2203,7 @@ msgstr "Het open source <0/> alternatief voor Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "De zichtbaarheid van je bord is ingesteld op {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Thema"
@@ -2216,7 +2223,7 @@ msgstr "Deze actie kan niet ongedaan worden gemaakt."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Deze API-sleutel wordt slechts één keer getoond. Bewaar deze op een veilige plaats."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Dit bord is privé of bestaat niet"
@@ -2359,7 +2366,7 @@ msgstr "Kan board URL niet bijwerken"
msgid "Unable to update board visibility"
msgstr "Kan bordzichtbaarheid niet bijwerken"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Kan kaart niet bijwerken"
@@ -2372,7 +2379,7 @@ msgstr "Kan checklist niet bijwerken"
msgid "Unable to update checklist item"
msgstr "Kan checklistitem niet bijwerken"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Kan reactie niet bijwerken"
@@ -2384,7 +2391,7 @@ msgstr "Kan vervaldatum niet bijwerken"
msgid "Unable to update labels"
msgstr "Kan labels niet bijwerken"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Kan lijst niet bijwerken"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "Kan leden niet bijwerken"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "<0>{0}</0> van de kaart verwijderd"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "zichzelf van de kaart verwijderd"
@@ -2457,30 +2464,30 @@ msgstr "Bijwerken"
msgid "Update label"
msgstr "Label bijwerken"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "een checklistitem bijgewerkt"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "beschrijving bijgewerkt"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "heeft de vervaldatum bijgewerkt"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "titel bijgewerkt"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "titel bijgewerkt naar <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Upgraden naar Pro"
@@ -2517,7 +2524,7 @@ msgstr "URL moet minimaal 3 tekens lang zijn"
msgid "Use template"
msgstr "Sjabloon gebruiken"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Gebruiker"
@@ -2542,7 +2549,7 @@ msgstr "Bekijk en beheer je facturering en abonnement."
msgid "View docs"
msgstr "Bekijk documentatie"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Alleen bekijken"
@@ -2550,7 +2557,7 @@ msgstr "Alleen bekijken"
msgid "View our roadmap."
msgstr "Bekijk onze roadmap."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Werkruimte bekijken"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "Waarom een open source Trello maken?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Werkruimte"
@@ -2611,7 +2618,7 @@ msgstr "Werkruimte succesvol aangemaakt. Je kunt later upgraden in de instelling
msgid "Workspace deleted"
msgstr "Werkruimte verwijderd"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Werkruimte beschrijving"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Werkruimteleden"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Naam werkruimte"
@@ -2659,7 +2666,7 @@ msgstr "Werkruimtenaam bijgewerkt"
msgid "Workspace slug updated"
msgstr "Werkruimte-slug bijgewerkt"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "Werkruimte URL"
@@ -2680,7 +2687,7 @@ msgstr "Jaarlijks"
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."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Je staat op het punt je wachtwoord te wijzigen."

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (edytowano)"
@@ -46,7 +46,7 @@ msgid "{0} labels"
msgstr "{0} etykiety"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} nie znaleziono"
@@ -105,7 +105,7 @@ msgstr "Dzienniki aktywności"
msgid "Add a card"
msgstr "Dodaj kartę"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Dodaj komentarz..."
@@ -137,38 +137,38 @@ msgid "Add member"
msgstr "Dodaj członka"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "dodano {0} etykiety: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "dodał listę kontrolną"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "dodał(a) element listy kontrolnej"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "dodał(a) etykietę do karty"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "dodał(a) członka do karty"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "dodał(a) listę kontrolną <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "dodał(a) element listy kontrolnej <0>{0}</0>"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "dodał(a) etykietę <0>{0}</0>"
@@ -189,6 +189,10 @@ msgstr "Role administratora"
msgid "All systems operational"
msgstr "Wszystkie systemy działają poprawnie"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Zezwól członkom workspace'u na widoczność swoich adresów e-mail"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Masz już konto? <0><1>Zaloguj się</1></0>"
@@ -276,7 +280,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Czy na pewno chcesz usunąć swoje konto?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "przypisano <0>{0}</0> do karty"
@@ -322,9 +326,9 @@ msgstr "Portal rozliczeniowy"
msgid "Blog Post"
msgstr "Post na blogu"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Tablica"
@@ -341,7 +345,7 @@ msgstr "Nazwa tablicy nie może przekraczać 100 znaków"
msgid "Board name is required"
msgstr "Nazwa tablicy jest wymagana"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Tablica nie została znaleziona"
@@ -357,7 +361,7 @@ msgstr "Adres URL tablicy może zawierać tylko litery, cyfry i myślniki"
msgid "Board URL cannot exceed 60 characters"
msgstr "Adres URL tablicy nie może przekraczać 60 znaków"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "Adres URL tablicy został skopiowany do schowka"
@@ -374,7 +378,7 @@ msgstr "Widoczność tablicy"
msgid "Board visibility updated"
msgstr "Widoczność tablicy została zaktualizowana"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Tablice"
@@ -393,7 +397,7 @@ msgstr "Zgłoszenie błędu"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -419,19 +423,19 @@ msgstr "Nie można było znaleźć karty"
msgid "Card title"
msgstr "Tytuł karty"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Zmień hasło"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Zmień swoje preferencje językowe."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "zmieniono termin na <0>{formattedDate}</0>"
@@ -505,12 +509,12 @@ msgstr "Zakończ"
msgid "Complete control and ownership:"
msgstr "Pełna kontrola i własność:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "ukończono element listy kontrolnej"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "ukończono element listy kontrolnej <0>{0}</0>"
@@ -619,8 +623,8 @@ msgstr "Utwórz nowy klucz"
msgid "Create new label"
msgstr "Utwórz nową etykietę"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Utwórz nową listę"
@@ -633,7 +637,7 @@ msgstr "Utwórz szablon"
msgid "Create workspace"
msgstr "Utwórz przestrzeń roboczą"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "utworzył(a) kartę"
@@ -679,7 +683,7 @@ msgstr "Niestandardowy adres URL przestrzeni roboczej"
msgid "Customer Support"
msgstr "Obsługa klienta"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Ciemny"
@@ -697,8 +701,8 @@ msgstr "Dezaktywuj link zaproszenia"
msgid "Delete"
msgstr "Usuń"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Usuń konto"
@@ -711,7 +715,7 @@ msgstr "Usuń tablicę"
msgid "Delete card"
msgstr "Usuń kartę"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Usuń komentarz"
@@ -724,26 +728,26 @@ msgid "Delete template"
msgstr "Usuń szablon"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Usuń przestrzeń roboczą"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "usunięto listę kontrolną"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "usunięto element listy kontrolnej"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "usunięto listę kontrolną <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "usunięto element listy kontrolnej <0>{0}</0>"
@@ -791,7 +795,7 @@ msgstr "dokumentacja"
msgid "Docs"
msgstr "Dokumentacja"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -844,7 +848,7 @@ msgstr "Edytuj"
msgid "Edit board URL"
msgstr "Edytuj URL tablicy"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Edytuj komentarz"
@@ -869,9 +873,14 @@ msgid "email"
msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "Email"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Widoczność adresu e-mail"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Ulepszenie"
@@ -1053,7 +1062,7 @@ msgid "Features"
msgstr "Funkcje"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Opinie"
@@ -1074,14 +1083,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Dla długoterminowej trwałości uznajemy, że wszystkie dobre projekty open source potrzebują źródła dochodu. Nasze pochodzi z płatnej oferty w chmurze dla przestrzeni roboczych z wieloma użytkownikami oraz dla niestandardowych nazw przestrzeni roboczych. Nie ma obowiązku korzystania z niej, a oprogramowanie można hostować samodzielnie na własnej infrastrukturze bezpłatnie."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Darmowy"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Darmowy plan"
@@ -1121,7 +1128,7 @@ msgstr "Rozpocznij"
msgid "Get started by creating a new {0}"
msgstr "Rozpocznij, tworząc nowy {0}"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Rozpocznij, tworząc nową listę"
@@ -1155,19 +1162,19 @@ msgstr "Wróć do strony głównej"
msgid "Go to app"
msgstr "Przejdź do aplikacji"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Przejdź do tablic"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Przejdź do członków"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Przejdź do ustawień"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Przejdź do szablonów"
@@ -1292,7 +1299,7 @@ msgstr "Nieprawidłowy adres e-mail"
msgid "Invalid invitation"
msgstr "Nieprawidłowe zaproszenie"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Zaproś"
@@ -1373,7 +1380,7 @@ msgstr "Etykiety i filtry"
msgid "Labels & Filters"
msgstr "Etykiety i Filtry"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Język"
@@ -1382,7 +1389,7 @@ msgstr "Język"
msgid "Launch offer"
msgstr "Oferta startowa"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Oferta startowa: Nieograniczona liczba członków z Pro"
@@ -1407,11 +1414,11 @@ msgstr "Prawne"
msgid "License"
msgstr "Licencja"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Jasny"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Link skopiowany"
@@ -1427,11 +1434,11 @@ msgstr "Nazwa listy"
msgid "Lists"
msgstr "Listy"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Załaduj więcej aktywności"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Ładowanie..."
@@ -1439,7 +1446,7 @@ msgstr "Ładowanie..."
msgid "Login | kan.bn"
msgstr "Zaloguj się | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Wyloguj się"
@@ -1463,12 +1470,12 @@ msgstr "magiczny link"
msgid "Make template"
msgstr "Utwórz szablon"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "oznaczył element listy kontrolnej jako nieukończony"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "oznaczył element listy kontrolnej <0>{0}</0> jako nieukończony"
@@ -1476,16 +1483,16 @@ msgstr "oznaczył element listy kontrolnej <0>{0}</0> jako nieukończony"
msgid "Medium Priority"
msgstr "Średni priorytet"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Członkowie"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Członkowie | {0}"
@@ -1500,11 +1507,11 @@ msgstr "rozliczenie miesięczne"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "przeniesiono kartę z <0>{0}</0> do<1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "przeniesiono kartę do innej listy"
@@ -1553,7 +1560,7 @@ msgid "New label"
msgstr "Nowa etykieta"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Nowa lista"
@@ -1614,7 +1621,7 @@ msgstr "Brak dostępnego URL do pobrania tego załącznika."
msgid "No keyboard shortcuts registered."
msgstr "Brak zarejestrowanych skrótów klawiaturowych."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Brak list"
@@ -1630,11 +1637,11 @@ msgstr "Oferta"
msgid "Onboarding"
msgstr "Wprowadzenie"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "Po usunięciu konta nie będzie możliwości jego przywrócenia. Tej operacji nie można cofnąć."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "Po usunięciu przestrzeni roboczej nie będzie możliwości jej przywrócenia. Tej operacji nie można cofnąć."
@@ -1704,7 +1711,7 @@ msgstr "Hasło musi mieć co najmniej 8 znaków"
msgid "Passwords do not match"
msgstr "Hasła nie pasują do siebie"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Wstrzymane"
@@ -1713,7 +1720,7 @@ msgstr "Wstrzymane"
msgid "Payment frequency"
msgstr "Częstotliwość płatności"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "Oczekujące"
@@ -1770,15 +1777,15 @@ msgstr "Proszę wybrać plik do przesłania."
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1838,7 +1845,7 @@ msgstr "Polityka prywatności"
msgid "Private"
msgstr "Prywatne"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Plan Pro"
@@ -1886,44 +1893,44 @@ msgstr "Zdalne"
msgid "Remove"
msgstr "Usuń"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Usuń członka"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "usunięto {0} etykiety: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "usunął etykietę z karty"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "usunął członka z karty"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "usunięto etykietę <0>{0}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "usunięto termin"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "zmieniono nazwę listy kontrolnej"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "zmieniono nazwę listy kontrolnej <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "zmieniono nazwę elementu listy kontrolnej na <0>{0}</0>"
@@ -1953,7 +1960,7 @@ msgstr "Przegląd"
msgid "Roadmap"
msgstr "Plan ulepszeń"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Rola"
@@ -1963,7 +1970,7 @@ msgid "Run on your own infrastructure"
msgstr "Uruchom na własnej infrastrukturze"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Zapisz"
@@ -2001,7 +2008,7 @@ msgstr "Hostuj samodzielnie"
msgid "Self host with Github"
msgstr "Hostuj samodzielnie z Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "przypisał(a) sobie kartę"
@@ -2021,12 +2028,12 @@ msgstr "Starszy"
msgid "Set due date"
msgstr "Ustaw termin"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "ustawiono termin"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Ustawienia"
@@ -2046,11 +2053,11 @@ msgstr "Ustawienia | Rozliczenia"
msgid "Settings | Integrations"
msgstr "Ustawienia | Integracje"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Ustawienia | Obszar roboczy"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Skróty"
@@ -2122,7 +2129,7 @@ msgstr "Sukces"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Zwiększ możliwości swojego obszaru roboczego za jedyne 29 USD/miesiąc. Oto, co otrzymasz:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Wsparcie"
@@ -2131,12 +2138,12 @@ msgstr "Wsparcie"
msgid "Support the development of the project"
msgstr "Wspieraj rozwój projektu"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "System"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Plan zespołowy"
@@ -2146,8 +2153,8 @@ msgstr "Plan zespołowy"
msgid "Teams"
msgstr "Zespoły"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Szablon"
@@ -2167,7 +2174,7 @@ msgstr "Nazwa szablonu nie może przekraczać 100 znaków"
msgid "Template name is required"
msgstr "Nazwa szablonu jest wymagana"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Szablony"
@@ -2201,7 +2208,7 @@ msgstr "Otwarta alternatywa <0/> dla Trello"
msgid "The visibility of your board has been set to {0}."
msgstr "Widoczność Twojej tablicy została ustawiona na {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Motyw"
@@ -2221,7 +2228,7 @@ msgstr "Tej akcji nie można cofnąć."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Ten klucz API zostanie wyświetlony tylko raz. Proszę zapisać go w bezpiecznym miejscu."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Ta tablica jest prywatna lub nie istnieje"
@@ -2364,7 +2371,7 @@ msgstr "Nie można zaktualizować adresu URL tablicy"
msgid "Unable to update board visibility"
msgstr "Nie można zaktualizować widoczności tablicy"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Nie można zaktualizować karty"
@@ -2377,7 +2384,7 @@ msgstr "Nie można zaktualizować listy kontrolnej"
msgid "Unable to update checklist item"
msgstr "Nie można zaktualizować elementu listy kontrolnej"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Nie można zaktualizować komentarza"
@@ -2389,7 +2396,7 @@ msgstr "Nie można zaktualizować terminu"
msgid "Unable to update labels"
msgstr "Nie można zaktualizować etykiet"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Nie można zaktualizować listy"
@@ -2399,11 +2406,11 @@ msgid "Unable to update members"
msgstr "Nie można zaktualizować członków"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "usunięto przypisanie <0>{0}</0> z karty"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "usunęli swoje przypisanie z karty"
@@ -2462,30 +2469,30 @@ msgstr "Aktualizuj"
msgid "Update label"
msgstr "Zaktualizuj etykietę"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "zaktualizowano element listy kontrolnej"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "zaktualizowano opis"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "zaktualizowano termin"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "zaktualizowano tytuł"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "zaktualizowano tytuł na <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Ulepsz do planu Pro"
@@ -2522,7 +2529,7 @@ msgstr "Adres URL musi mieć co najmniej 3 znaki"
msgid "Use template"
msgstr "Użyj szablonu"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Użytkownik"
@@ -2547,7 +2554,7 @@ msgstr "Zobacz i zarządzaj swoimi płatnościami i subskrypcją."
msgid "View docs"
msgstr "Zobacz dokumentację"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Tylko podgląd"
@@ -2555,7 +2562,7 @@ msgstr "Tylko podgląd"
msgid "View our roadmap."
msgstr "Zobacz nasz plan ulepszeń."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Zobacz obszar roboczy"
@@ -2600,10 +2607,10 @@ msgid "Why make an open source Trello?"
msgstr "Dlaczego próbujecie stworzyć Trello w wersji otwartoźródłowej?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Obszar roboczy"
@@ -2616,7 +2623,7 @@ msgstr "Obszar roboczy został pomyślnie utworzony. Możesz go ulepszyć późn
msgid "Workspace deleted"
msgstr "Obszar roboczy został usunięty"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Opis obszaru roboczego"
@@ -2639,7 +2646,7 @@ msgid "Workspace members"
msgstr "Członkowie przestrzeni roboczej"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Nazwa przestrzeni roboczej"
@@ -2664,7 +2671,7 @@ msgstr "Nazwa przestrzeni roboczej została zaktualizowana"
msgid "Workspace slug updated"
msgstr "Slug przestrzeni roboczej został zaktualizowany"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "URL przestrzeni roboczej"
@@ -2685,7 +2692,7 @@ msgstr "Rocznie"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Tak, oferujemy wiecznie darmowy plan dla użytkowników indywidualnych. Bez ograniczeń, bez płatnych ścian, bez limitów."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Zaraz zmienisz swoje hasło."

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ msgstr ""
"Language-Team: \n"
"Plural-Forms: \n"
#: src/views/card/components/Comment.tsx:124
#: src/views/card/components/Comment.tsx:128
msgid " (edited)"
msgstr " (отредактировано)"
@@ -41,7 +41,7 @@ msgid "{0} labels"
msgstr "{0} метки"
#. placeholder {0}: isTemplate ? "Template" : "Board"
#: src/views/board/index.tsx:416
#: src/views/board/index.tsx:422
msgid "{0} not found"
msgstr "{0} не найден"
@@ -100,7 +100,7 @@ msgstr "Журналы активности"
msgid "Add a card"
msgstr "Добавить карточку"
#: src/views/card/components/Comment.tsx:147
#: src/views/card/components/Comment.tsx:151
#: src/views/card/components/NewCommentForm.tsx:55
msgid "Add a comment..."
msgstr "Добавить комментарий..."
@@ -132,38 +132,38 @@ msgid "Add member"
msgstr "Добавить участника"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:77
#: src/views/card/components/ActivityList.tsx:78
msgid "added {0} labels: <0>{labelList}</0>"
msgstr "добавил {0} метки: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:107
#: src/views/card/components/ActivityList.tsx:108
msgid "added a checklist"
msgstr "добавил(а) чек-лист"
#: src/views/card/components/ActivityList.tsx:110
#: src/views/card/components/ActivityList.tsx:111
msgid "added a checklist item"
msgstr "добавил(а) элемент чек-листа"
#: src/views/card/components/ActivityList.tsx:103
#: src/views/card/components/ActivityList.tsx:104
msgid "added a label to the card"
msgstr "добавил(а) метку к карточке"
#: src/views/card/components/ActivityList.tsx:105
#: src/views/card/components/ActivityList.tsx:106
msgid "added a member to the card"
msgstr "добавил(а) участника к карточке"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:181
#: src/views/card/components/ActivityList.tsx:182
msgid "added checklist <0>{0}</0>"
msgstr "добавлен контрольный список <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:205
#: src/views/card/components/ActivityList.tsx:206
msgid "added checklist item <0>{0}</0>"
msgstr "добавлен элемент контрольного списка <0>{0}</0>"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:165
#: src/views/card/components/ActivityList.tsx:166
msgid "added label <0>{0}</0>"
msgstr "добавлена метка <0>{0}</0>"
@@ -184,6 +184,10 @@ msgstr "Роли администратора"
msgid "All systems operational"
msgstr "Все системы работают нормально"
#: src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx:42
msgid "Allow workspace members to see each other's email addresses"
msgstr "Разрешить участникам рабочего пространства видеть электронные адреса друг друга"
#: src/views/auth/signup/index.tsx:88
msgid "Already have an account? <0><1>Sign in</1></0>"
msgstr "Уже есть аккаунт? <0><1>Войти</1></0>"
@@ -271,7 +275,7 @@ msgid "Are you sure you want to delete your account?"
msgstr "Вы уверены, что хотите удалить свой аккаунт?"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:145
#: src/views/card/components/ActivityList.tsx:146
msgid "assigned <0>{0}</0> to the card"
msgstr "назначено <0>{0}</0> к карточке"
@@ -317,9 +321,9 @@ msgstr "Портал выставления счетов"
msgid "Blog Post"
msgstr "Пост в блоге"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/card/index.tsx:273
#: src/views/public/board/index.tsx:114
#: src/views/public/board/index.tsx:120
msgid "Board"
msgstr "Доска"
@@ -336,7 +340,7 @@ msgstr "Название доски не может превышать 100 си
msgid "Board name is required"
msgstr "Название доски обязательно"
#: src/views/public/board/index.tsx:166
#: src/views/public/board/index.tsx:176
msgid "Board not found"
msgstr "Доска не найдена"
@@ -352,7 +356,7 @@ msgstr "URL доски может содержать только буквы, ц
msgid "Board URL cannot exceed 60 characters"
msgstr "URL доски не может превышать 60 символов"
#: src/views/public/board/index.tsx:80
#: src/views/public/board/index.tsx:86
msgid "Board URL copied to clipboard"
msgstr "URL доски скопирован в буфер обмена"
@@ -369,7 +373,7 @@ msgstr "Видимость доски"
msgid "Board visibility updated"
msgstr "Видимость доски обновлена"
#: src/components/SideNavigation.tsx:97
#: src/components/SideNavigation.tsx:98
msgid "Boards"
msgstr "Доски"
@@ -388,7 +392,7 @@ msgstr "Отчет об ошибке"
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:176
#: src/views/board/components/DeleteBoardConfirmation.tsx:44
#: src/views/card/components/Comment.tsx:159
#: src/views/card/components/Comment.tsx:163
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/DeleteChecklistConfirmation.tsx:64
#: src/views/card/components/DeleteCommentConfirmation.tsx:77
@@ -414,19 +418,19 @@ msgstr "Карточка не найдена"
msgid "Card title"
msgstr "Название карточки"
#: src/views/settings/AccountSettings.tsx:70
#: src/views/settings/AccountSettings.tsx:80
#: src/views/settings/AccountSettings.tsx:77
#: src/views/settings/AccountSettings.tsx:87
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
msgid "Change Password"
msgstr "Изменить пароль"
#: src/views/settings/AccountSettings.tsx:45
#: src/views/settings/AccountSettings.tsx:52
msgid "Change your language preferences."
msgstr "Измените настройки языка."
#: src/views/card/components/ActivityList.tsx:255
#: src/views/card/components/ActivityList.tsx:269
#: src/views/card/components/ActivityList.tsx:256
#: src/views/card/components/ActivityList.tsx:270
msgid "changed the due date to <0>{formattedDate}</0>"
msgstr "изменил(а) дату выполнения на <0>{formattedDate}</0>"
@@ -500,12 +504,12 @@ msgstr "Завершить"
msgid "Complete control and ownership:"
msgstr "Полный контроль и владение:"
#: src/views/card/components/ActivityList.tsx:112
#: src/views/card/components/ActivityList.tsx:113
msgid "completed a checklist item"
msgstr "завершил элемент контрольного списка"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:222
#: src/views/card/components/ActivityList.tsx:223
msgid "completed checklist item <0>{0}</0>"
msgstr "завершил элемент контрольного списка <0>{0}</0>"
@@ -614,8 +618,8 @@ msgstr "Создать новый ключ"
msgid "Create new label"
msgstr "Создать новую метку"
#: src/views/board/index.tsx:65
#: src/views/board/index.tsx:507
#: src/views/board/index.tsx:71
#: src/views/board/index.tsx:517
msgid "Create new list"
msgstr "Создать новый список"
@@ -628,7 +632,7 @@ msgstr "Создать шаблон"
msgid "Create workspace"
msgstr "Создать рабочее пространство"
#: src/views/card/components/ActivityList.tsx:99
#: src/views/card/components/ActivityList.tsx:100
msgid "created the card"
msgstr "создал(а) карточку"
@@ -674,7 +678,7 @@ msgstr "Пользовательский URL рабочего пространс
msgid "Customer Support"
msgstr "Служба поддержки"
#: src/components/UserMenu.tsx:155
#: src/components/UserMenu.tsx:158
msgid "Dark"
msgstr "Тёмный"
@@ -692,8 +696,8 @@ msgstr "Деактивировать ссылку-приглашение"
msgid "Delete"
msgstr "Удалить"
#: src/views/settings/AccountSettings.tsx:52
#: src/views/settings/AccountSettings.tsx:62
#: src/views/settings/AccountSettings.tsx:59
#: src/views/settings/AccountSettings.tsx:69
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
msgid "Delete account"
msgstr "Удалить аккаунт"
@@ -706,7 +710,7 @@ msgstr "Удалить доску"
msgid "Delete card"
msgstr "Удалить карточку"
#: src/views/card/components/Comment.tsx:92
#: src/views/card/components/Comment.tsx:95
msgid "Delete comment"
msgstr "Удалить комментарий"
@@ -719,26 +723,26 @@ msgid "Delete template"
msgstr "Удалить шаблон"
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:97
#: src/views/settings/WorkspaceSettings.tsx:108
#: src/views/settings/WorkspaceSettings.tsx:106
#: src/views/settings/WorkspaceSettings.tsx:117
msgid "Delete workspace"
msgstr "Удалить рабочее пространство"
#: src/views/card/components/ActivityList.tsx:109
#: src/views/card/components/ActivityList.tsx:110
msgid "deleted a checklist"
msgstr "удалил контрольный список"
#: src/views/card/components/ActivityList.tsx:114
#: src/views/card/components/ActivityList.tsx:115
msgid "deleted a checklist item"
msgstr "удалил элемент контрольного списка"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:197
#: src/views/card/components/ActivityList.tsx:198
msgid "deleted checklist <0>{0}</0>"
msgstr "удалил контрольный список <0>{0}</0>"
#. placeholder {0}: truncate(fromTitle)
#: src/views/card/components/ActivityList.tsx:240
#: src/views/card/components/ActivityList.tsx:241
msgid "deleted checklist item <0>{0}</0>"
msgstr "удалил элемент контрольного списка <0>{0}</0>"
@@ -786,7 +790,7 @@ msgstr "документы"
msgid "Docs"
msgstr "Документы"
#: src/components/UserMenu.tsx:206
#: src/components/UserMenu.tsx:209
#: src/views/boards/components/TemplateBoards.tsx:24
#: src/views/home/components/Footer.tsx:78
#: src/views/home/components/Header.tsx:36
@@ -839,7 +843,7 @@ msgstr "Редактировать"
msgid "Edit board URL"
msgstr "Изменить URL доски"
#: src/views/card/components/Comment.tsx:83
#: src/views/card/components/Comment.tsx:86
msgid "Edit comment"
msgstr "Редактировать комментарий"
@@ -864,9 +868,14 @@ msgid "email"
msgstr "email"
#: src/views/members/components/InviteMemberForm.tsx:272
#: src/views/settings/AccountSettings.tsx:42
msgid "Email"
msgstr "Email"
#: src/views/settings/WorkspaceSettings.tsx:84
msgid "Email visibility"
msgstr "Видимость электронной почты"
#: src/views/boards/components/TemplateBoards.tsx:24
msgid "Enhancement"
msgstr "Улучшение"
@@ -1048,7 +1057,7 @@ msgid "Features"
msgstr "Функции"
#: src/components/FeedbackModal.tsx:59
#: src/components/UserMenu.tsx:214
#: src/components/UserMenu.tsx:217
msgid "Feedback"
msgstr "Обратная связь"
@@ -1069,14 +1078,12 @@ msgid "For long-term sustainability, we recognise all good open source projects
msgstr "Для долгосрочной устойчивости мы признаем, что всем хорошим проектам с открытым исходным кодом необходим источник дохода. Наш доход поступает от платного облачного предложения для рабочих пространств с несколькими пользователями и для пользовательских идентификаторов рабочих пространств. Нет обязательства использовать его, и вы можете самостоятельно разместить программное обеспечение на своей инфраструктуре бесплатно."
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/Pricing.tsx:32
#: src/views/pricing/components/PricingTiers.tsx:30
#: src/views/pricing/components/PricingTiers.tsx:30
msgid "Free"
msgstr "Бесплатно"
#: src/views/members/components/InviteMemberForm.tsx:333
#: src/views/members/index.tsx:208
#: src/views/members/index.tsx:217
msgid "Free Plan"
msgstr "Бесплатный план"
@@ -1116,7 +1123,7 @@ msgstr "Начать"
msgid "Get started by creating a new {0}"
msgstr "Начните с создания нового {0}"
#: src/views/board/index.tsx:499
#: src/views/board/index.tsx:509
msgid "Get started by creating a new list"
msgstr "Начните с создания нового списка"
@@ -1150,19 +1157,19 @@ msgstr "На главную"
msgid "Go to app"
msgstr "Перейти в приложение"
#: src/components/SideNavigation.tsx:105
#: src/components/SideNavigation.tsx:106
msgid "Go to boards"
msgstr "Перейти к доскам"
#: src/components/SideNavigation.tsx:129
#: src/components/SideNavigation.tsx:130
msgid "Go to members"
msgstr "Перейти к участникам"
#: src/components/SideNavigation.tsx:141
#: src/components/SideNavigation.tsx:142
msgid "Go to settings"
msgstr "Перейти к настройкам"
#: src/components/SideNavigation.tsx:117
#: src/components/SideNavigation.tsx:118
msgid "Go to templates"
msgstr "Перейти к шаблонам"
@@ -1287,7 +1294,7 @@ msgstr "Недействительный адрес электронной по
msgid "Invalid invitation"
msgstr "Недействительное приглашение"
#: src/views/members/index.tsx:221
#: src/views/members/index.tsx:230
msgid "Invite"
msgstr "Пригласить"
@@ -1368,7 +1375,7 @@ msgstr "Метки и фильтры"
msgid "Labels & Filters"
msgstr "Метки и фильтры"
#: src/views/settings/AccountSettings.tsx:42
#: src/views/settings/AccountSettings.tsx:49
msgid "Language"
msgstr "Язык"
@@ -1377,7 +1384,7 @@ msgstr "Язык"
msgid "Launch offer"
msgstr "Стартовое предложение"
#: src/views/members/index.tsx:191
#: src/views/members/index.tsx:200
msgid "Launch offer: Get unlimited members with Pro"
msgstr "Стартовое предложение: получите неограниченное количество участников с Pro"
@@ -1402,11 +1409,11 @@ msgstr "Юридическое"
msgid "License"
msgstr "Лицензия"
#: src/components/UserMenu.tsx:169
#: src/components/UserMenu.tsx:172
msgid "Light"
msgstr "Светлый"
#: src/views/public/board/index.tsx:78
#: src/views/public/board/index.tsx:84
msgid "Link copied"
msgstr "Ссылка скопирована"
@@ -1422,11 +1429,11 @@ msgstr "Название списка"
msgid "Lists"
msgstr "Списки"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Load more activities"
msgstr "Загрузить больше действий"
#: src/views/card/components/ActivityList.tsx:530
#: src/views/card/components/ActivityList.tsx:533
msgid "Loading..."
msgstr "Загрузка..."
@@ -1434,7 +1441,7 @@ msgstr "Загрузка..."
msgid "Login | kan.bn"
msgstr "Вход | kan.bn"
#: src/components/UserMenu.tsx:224
#: src/components/UserMenu.tsx:227
msgid "Logout"
msgstr "Выход"
@@ -1458,12 +1465,12 @@ msgstr "магическая ссылка"
msgid "Make template"
msgstr "Создать шаблон"
#: src/views/card/components/ActivityList.tsx:113
#: src/views/card/components/ActivityList.tsx:114
msgid "marked a checklist item as incomplete"
msgstr "отметил элемент контрольного списка как незавершённый"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:231
#: src/views/card/components/ActivityList.tsx:232
msgid "marked checklist item <0>{0}</0> as incomplete"
msgstr "отметил элемент контрольного списка <0>{0}</0> как незавершённый"
@@ -1471,16 +1478,16 @@ msgstr "отметил элемент контрольного списка <0>{
msgid "Medium Priority"
msgstr "Средний приоритет"
#: src/components/SideNavigation.tsx:121
#: src/components/SideNavigation.tsx:122
#: src/views/board/components/Filters.tsx:147
#: src/views/board/components/NewCardForm.tsx:377
#: src/views/card/index.tsx:131
#: src/views/members/index.tsx:178
#: src/views/members/index.tsx:187
msgid "Members"
msgstr "Участники"
#. placeholder {0}: workspace.name ?? t`Workspace`
#: src/views/members/index.tsx:173
#: src/views/members/index.tsx:182
msgid "Members | {0}"
msgstr "Участники | {0}"
@@ -1495,11 +1502,11 @@ msgstr "ежемесячная оплата"
#. placeholder {0}: truncate(fromList)
#. placeholder {1}: truncate(toList)
#: src/views/card/components/ActivityList.tsx:133
#: src/views/card/components/ActivityList.tsx:134
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
msgstr "переместил карточку из <0>{0}</0> в <1>{1}</1>"
#: src/views/card/components/ActivityList.tsx:102
#: src/views/card/components/ActivityList.tsx:103
msgid "moved the card to another list"
msgstr "переместил карточку в другой список"
@@ -1548,7 +1555,7 @@ msgid "New label"
msgstr "Новая метка"
#: src/views/board/components/NewListForm.tsx:113
#: src/views/board/index.tsx:470
#: src/views/board/index.tsx:476
msgid "New list"
msgstr "Новый список"
@@ -1609,7 +1616,7 @@ msgstr "URL для загрузки этого вложения недоступ
msgid "No keyboard shortcuts registered."
msgstr "Горячие клавиши не зарегистрированы."
#: src/views/board/index.tsx:496
#: src/views/board/index.tsx:506
msgid "No lists"
msgstr "Нет списков"
@@ -1625,11 +1632,11 @@ msgstr "Предложение"
msgid "Onboarding"
msgstr "Введение"
#: src/views/settings/AccountSettings.tsx:55
#: src/views/settings/AccountSettings.tsx:62
msgid "Once you delete your account, there is no going back. This action cannot be undone."
msgstr "После удаления аккаунта возврат будет невозможен. Это действие необратимо."
#: src/views/settings/WorkspaceSettings.tsx:100
#: src/views/settings/WorkspaceSettings.tsx:109
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
msgstr "После удаления рабочего пространства возврат будет невозможен. Это действие необратимо."
@@ -1699,7 +1706,7 @@ msgstr "Пароль должен содержать не менее 8 симв
msgid "Passwords do not match"
msgstr "Пароли не совпадают"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Paused"
msgstr "Приостановлено"
@@ -1708,7 +1715,7 @@ msgstr "Приостановлено"
msgid "Payment frequency"
msgstr "Частота платежей"
#: src/views/members/index.tsx:134
#: src/views/members/index.tsx:143
msgid "Pending"
msgstr "В ожидании"
@@ -1765,15 +1772,15 @@ msgstr "Пожалуйста, выберите файл для загрузки.
#: src/views/board/components/NewTemplateForm.tsx:77
#: src/views/board/components/UpdateBoardSlugForm.tsx:73
#: src/views/board/components/VisibilityButton.tsx:54
#: src/views/board/index.tsx:171
#: src/views/board/index.tsx:227
#: src/views/board/index.tsx:177
#: src/views/board/index.tsx:233
#: src/views/boards/components/ImportBoardsForm.tsx:205
#: src/views/card/components/AttachmentThumbnails.tsx:74
#: src/views/card/components/ChecklistItemRow.tsx:69
#: src/views/card/components/ChecklistItemRow.tsx:97
#: src/views/card/components/ChecklistNameInput.tsx:47
#: src/views/card/components/Checklists.tsx:81
#: src/views/card/components/Comment.tsx:65
#: src/views/card/components/Comment.tsx:68
#: src/views/card/components/DeleteCardConfirmation.tsx:52
#: src/views/card/components/DeleteChecklistConfirmation.tsx:38
#: src/views/card/components/DeleteCommentConfirmation.tsx:46
@@ -1833,7 +1840,7 @@ msgstr "Политика конфиденциальности"
msgid "Private"
msgstr "Личное"
#: src/views/members/index.tsx:205
#: src/views/members/index.tsx:214
msgid "Pro Plan"
msgstr "Профессиональный план"
@@ -1881,44 +1888,44 @@ msgstr "Удалённый"
msgid "Remove"
msgstr "Удалить"
#: src/views/members/index.tsx:148
#: src/views/members/index.tsx:157
msgid "Remove member"
msgstr "Удалить участника"
#. placeholder {0}: mergedLabels.length
#: src/views/card/components/ActivityList.tsx:91
#: src/views/card/components/ActivityList.tsx:92
msgid "removed {0} labels: <0>{labelList}</0>"
msgstr "удалил {0} метки: <0>{labelList}</0>"
#: src/views/card/components/ActivityList.tsx:104
#: src/views/card/components/ActivityList.tsx:105
msgid "removed a label from the card"
msgstr "удалил метку с карточки"
#: src/views/card/components/ActivityList.tsx:106
#: src/views/card/components/ActivityList.tsx:107
msgid "removed a member from the card"
msgstr "удалил участника из карточки"
#. placeholder {0}: truncate(label)
#: src/views/card/components/ActivityList.tsx:173
#: src/views/card/components/ActivityList.tsx:174
msgid "removed label <0>{0}</0>"
msgstr "удалил метку <0>{0}</0>"
#: src/views/card/components/ActivityList.tsx:117
#: src/views/card/components/ActivityList.tsx:276
#: src/views/card/components/ActivityList.tsx:118
#: src/views/card/components/ActivityList.tsx:277
msgid "removed the due date"
msgstr "удалил(а) дату выполнения"
#: src/views/card/components/ActivityList.tsx:108
#: src/views/card/components/ActivityList.tsx:109
msgid "renamed a checklist"
msgstr "переименовал контрольный список"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:189
#: src/views/card/components/ActivityList.tsx:190
msgid "renamed checklist <0>{0}</0>"
msgstr "переименовал контрольный список <0>{0}</0>"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:213
#: src/views/card/components/ActivityList.tsx:214
msgid "renamed checklist item to <0>{0}</0>"
msgstr "переименовал элемент контрольного списка в <0>{0}</0>"
@@ -1948,7 +1955,7 @@ msgstr "Обзор"
msgid "Roadmap"
msgstr "Дорожная карта"
#: src/views/members/index.tsx:243
#: src/views/members/index.tsx:252
msgid "Role"
msgstr "Роль"
@@ -1958,7 +1965,7 @@ msgid "Run on your own infrastructure"
msgstr "Запустите на своей инфраструктуре"
#: src/components/YouTubeEmbed/EditYouTubeModal.tsx:183
#: src/views/card/components/Comment.tsx:166
#: src/views/card/components/Comment.tsx:170
#: src/views/settings/components/Avatar.tsx:309
msgid "Save"
msgstr "Сохранить"
@@ -1996,7 +2003,7 @@ msgstr "Самостоятельный хостинг"
msgid "Self host with Github"
msgstr "Самостоятельный хостинг с Github"
#: src/views/card/components/ActivityList.tsx:142
#: src/views/card/components/ActivityList.tsx:143
msgid "self-assigned the card"
msgstr "самостоятельно назначил карточку"
@@ -2016,12 +2023,12 @@ msgstr "Старший"
msgid "Set due date"
msgstr "Установить дату выполнения"
#: src/views/card/components/ActivityList.tsx:115
#: src/views/card/components/ActivityList.tsx:116
msgid "set the due date"
msgstr "установил(а) дату выполнения"
#: src/components/SettingsLayout.tsx:82
#: src/components/SideNavigation.tsx:133
#: src/components/SideNavigation.tsx:134
msgid "Settings"
msgstr "Настройки"
@@ -2041,11 +2048,11 @@ msgstr "Настройки | Оплата"
msgid "Settings | Integrations"
msgstr "Настройки | Интеграции"
#: src/views/settings/WorkspaceSettings.tsx:54
#: src/views/settings/WorkspaceSettings.tsx:55
msgid "Settings | Workspace"
msgstr "Настройки | Рабочая область"
#: src/components/UserMenu.tsx:184
#: src/components/UserMenu.tsx:187
msgid "Shortcuts"
msgstr "Сочетания клавиш"
@@ -2117,7 +2124,7 @@ msgstr "Успех"
msgid "Supercharge your workspace for just $29/month. Here's what you'll get:"
msgstr "Улучшите свою рабочую область всего за $29/месяц. Вот что вы получите:"
#: src/components/UserMenu.tsx:195
#: src/components/UserMenu.tsx:198
msgid "Support"
msgstr "Поддержка"
@@ -2126,12 +2133,12 @@ msgstr "Поддержка"
msgid "Support the development of the project"
msgstr "Поддержите развитие проекта"
#: src/components/UserMenu.tsx:141
#: src/components/UserMenu.tsx:144
msgid "System"
msgstr "Система"
#: src/views/members/components/InviteMemberForm.tsx:322
#: src/views/members/index.tsx:207
#: src/views/members/index.tsx:216
msgid "Team Plan"
msgstr "Командный план"
@@ -2141,8 +2148,8 @@ msgstr "Командный план"
msgid "Teams"
msgstr "Команды"
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:425
#: src/views/board/index.tsx:396
#: src/views/board/index.tsx:431
msgid "Template"
msgstr "Шаблон"
@@ -2162,7 +2169,7 @@ msgstr "Имя шаблона не может превышать 100 симво
msgid "Template name is required"
msgstr "Имя шаблона обязательно"
#: src/components/SideNavigation.tsx:109
#: src/components/SideNavigation.tsx:110
#: src/views/home/components/Features.tsx:115
msgid "Templates"
msgstr "Шаблоны"
@@ -2196,7 +2203,7 @@ msgstr "Альтернатива Trello с открытым исходным к
msgid "The visibility of your board has been set to {0}."
msgstr "Видимость вашей доски установлена на {0}."
#: src/components/UserMenu.tsx:128
#: src/components/UserMenu.tsx:131
msgid "Theme"
msgstr "Тема"
@@ -2216,7 +2223,7 @@ msgstr "Это действие нельзя будет отменить."
msgid "This API key will only be shown once. Please save it in a secure location."
msgstr "Этот API-ключ будет показан только один раз. Пожалуйста, сохраните его в безопасном месте."
#: src/views/public/board/index.tsx:169
#: src/views/public/board/index.tsx:179
msgid "This board is private or does not exist"
msgstr "Эта доска является приватной или не существует."
@@ -2359,7 +2366,7 @@ msgstr "Не удалось обновить URL доски"
msgid "Unable to update board visibility"
msgstr "Не удалось обновить видимость доски"
#: src/views/board/index.tsx:226
#: src/views/board/index.tsx:232
#: src/views/card/index.tsx:187
msgid "Unable to update card"
msgstr "Не удалось обновить карточку"
@@ -2372,7 +2379,7 @@ msgstr "Не удалось обновить контрольный список
msgid "Unable to update checklist item"
msgstr "Не удалось обновить элемент контрольного списка"
#: src/views/card/components/Comment.tsx:64
#: src/views/card/components/Comment.tsx:67
msgid "Unable to update comment"
msgstr "Не удалось обновить комментарий"
@@ -2384,7 +2391,7 @@ msgstr "Не удалось обновить дату выполнения"
msgid "Unable to update labels"
msgstr "Не удалось обновить метки"
#: src/views/board/index.tsx:170
#: src/views/board/index.tsx:176
#: src/views/card/components/ListSelector.tsx:52
msgid "Unable to update list"
msgstr "Не удалось обновить список"
@@ -2394,11 +2401,11 @@ msgid "Unable to update members"
msgstr "Не удалось обновить участников"
#. placeholder {0}: truncate(memberName)
#: src/views/card/components/ActivityList.tsx:156
#: src/views/card/components/ActivityList.tsx:157
msgid "unassigned <0>{0}</0> from the card"
msgstr "удалил(а) <0>{0}</0> из карточки"
#: src/views/card/components/ActivityList.tsx:153
#: src/views/card/components/ActivityList.tsx:154
msgid "unassigned themselves from the card"
msgstr "удалил(а) себя из карточки"
@@ -2457,30 +2464,30 @@ msgstr "Обновить"
msgid "Update label"
msgstr "Обновить метку"
#: src/views/card/components/ActivityList.tsx:111
#: src/views/card/components/ActivityList.tsx:112
msgid "updated a checklist item"
msgstr "обновлен элемент контрольного списка"
#: src/views/card/components/ActivityList.tsx:101
#: src/views/card/components/ActivityList.tsx:102
msgid "updated the description"
msgstr "обновлено описание"
#: src/views/card/components/ActivityList.tsx:116
#: src/views/card/components/ActivityList.tsx:117
msgid "updated the due date"
msgstr "обновил(а) дату выполнения"
#: src/views/card/components/ActivityList.tsx:100
#: src/views/card/components/ActivityList.tsx:101
msgid "updated the title"
msgstr "обновлен заголовок"
#. placeholder {0}: truncate(toTitle)
#: src/views/card/components/ActivityList.tsx:125
#: src/views/card/components/ActivityList.tsx:126
msgid "updated the title to <0>{0}</0>"
msgstr "обновлен заголовок на <0>{0}</0>"
#: src/components/SideNavigation.tsx:237
#: src/components/SideNavigation.tsx:239
#: src/views/settings/components/UpgradeToProConfirmation.tsx:53
#: src/views/settings/WorkspaceSettings.tsx:90
#: src/views/settings/WorkspaceSettings.tsx:99
msgid "Upgrade to Pro"
msgstr "Обновить до Pro"
@@ -2517,7 +2524,7 @@ msgstr "URL должен содержать не менее 3 символов"
msgid "Use template"
msgstr "Использовать шаблон"
#: src/views/members/index.tsx:237
#: src/views/members/index.tsx:246
msgid "User"
msgstr "Пользователь"
@@ -2542,7 +2549,7 @@ msgstr "Просмотр и управление вашими счетами и
msgid "View docs"
msgstr "Просмотреть документацию"
#: src/views/public/board/index.tsx:142
#: src/views/public/board/index.tsx:148
msgid "View only"
msgstr "Только просмотр"
@@ -2550,7 +2557,7 @@ msgstr "Только просмотр"
msgid "View our roadmap."
msgstr "Просмотреть нашу дорожную карту."
#: src/views/public/board/index.tsx:172
#: src/views/public/board/index.tsx:182
msgid "View workspace"
msgstr "Просмотреть рабочее пространство"
@@ -2595,10 +2602,10 @@ msgid "Why make an open source Trello?"
msgstr "Зачем создавать Trello с открытым исходным кодом?"
#: src/components/SettingsLayout.tsx:39
#: src/views/board/index.tsx:390
#: src/views/board/index.tsx:396
#: src/views/boards/index.tsx:33
#: src/views/members/index.tsx:173
#: src/views/public/board/index.tsx:114
#: src/views/members/index.tsx:182
#: src/views/public/board/index.tsx:120
#: src/views/public/boards/index.tsx:66
msgid "Workspace"
msgstr "Рабочее пространство"
@@ -2611,7 +2618,7 @@ msgstr "Рабочее пространство успешно создано.
msgid "Workspace deleted"
msgstr "Рабочее пространство удалено"
#: src/views/settings/WorkspaceSettings.tsx:75
#: src/views/settings/WorkspaceSettings.tsx:76
msgid "Workspace description"
msgstr "Описание рабочего пространства"
@@ -2634,7 +2641,7 @@ msgid "Workspace members"
msgstr "Участники рабочего пространства"
#: src/components/NewWorkspaceForm.tsx:262
#: src/views/settings/WorkspaceSettings.tsx:58
#: src/views/settings/WorkspaceSettings.tsx:59
msgid "Workspace name"
msgstr "Название рабочего пространства"
@@ -2659,7 +2666,7 @@ msgstr "Название рабочего пространства обновл
msgid "Workspace slug updated"
msgstr "Slug рабочего пространства обновлен"
#: src/views/settings/WorkspaceSettings.tsx:66
#: src/views/settings/WorkspaceSettings.tsx:67
msgid "Workspace URL"
msgstr "URL рабочего пространства"
@@ -2680,7 +2687,7 @@ msgstr "Ежегодно"
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
msgstr "Да, мы предлагаем навсегда бесплатный план для индивидуального использования. Никаких ограничений, платных стен или лимитов."
#: src/views/settings/AccountSettings.tsx:73
#: src/views/settings/AccountSettings.tsx:80
msgid "You are about to change your password."
msgstr "Вы собираетесь изменить свой пароль."

File diff suppressed because one or more lines are too long

View File

@@ -2,9 +2,17 @@ import { toNodeHandler } from "better-auth/node";
import { initAuth } from "@kan/auth/server";
import { createDrizzleClient } from "@kan/db/client";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export const config = { api: { bodyParser: false } };
export const auth = initAuth(createDrizzleClient());
export default toNodeHandler(auth.handler);
const authHandler = toNodeHandler(auth.handler);
export default withRateLimit(
{ points: 100, duration: 60 },
async (req, res) => {
return await authHandler(req, res);
},
);

View File

@@ -1,9 +1,10 @@
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "GET") {
return res.status(405).json({ message: "Method not allowed" });
}
@@ -44,4 +45,5 @@ export default async function handler(
console.error("Error downloading attachment:", error);
return res.status(500).json({ message: "Failed to download attachment" });
}
}
},
);

View File

@@ -1,9 +1,10 @@
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "GET") {
return res.status(405).json({ message: "Method not allowed" });
}
@@ -20,4 +21,5 @@ export default async function handler(
console.error("Error fetching OSS friends:", error);
return res.status(500).json({ message: "Failed to fetch OSS friends" });
}
}
},
);

View File

@@ -3,11 +3,11 @@ import { env } from "next-runtime-env";
import { createNextApiContext } from "@kan/api/trpc";
import { createStripeClient } from "@kan/stripe";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
const stripe = createStripeClient();
if (req.method !== "POST") {
@@ -31,4 +31,5 @@ export default async function handler(
console.error("Error:", error);
return res.status(500).json({ error: "Error creating portal session" });
}
}
},
);

View File

@@ -6,6 +6,7 @@ import { createNextApiContext } from "@kan/api/trpc";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { createStripeClient } from "@kan/stripe";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const workspaceSlugSchema = z
.string()
@@ -21,10 +22,9 @@ interface CheckoutSessionRequest {
stripeCustomerId: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
const stripe = createStripeClient();
if (req.method !== "POST") {
@@ -115,4 +115,5 @@ export default async function handler(
console.error("Error:", error);
return res.status(500).json({ error: "Error creating checkout session" });
}
}
},
);

View File

@@ -3,11 +3,11 @@ import type { NextApiRequest, NextApiResponse } from "next";
import { createNextApiContext } from "@kan/api/trpc";
import { integrations } from "@kan/db/schema";
import { addYears } from "date-fns";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}
@@ -48,4 +48,5 @@ export default async function handler(
console.error("Trello authentication error:", err);
return res.status(400).json({ message: "Trello authentication failed" });
}
}
},
);

View File

@@ -3,12 +3,14 @@ import { createNextApiHandler } from "@trpc/server/adapters/next";
import { appRouter } from "@kan/api/root";
import { createTRPCContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const nextApiHandler = createNextApiHandler({
router: appRouter,
createContext: createTRPCContext,
onError:
process.env.NODE_ENV === "development"
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
@@ -17,11 +19,16 @@ const nextApiHandler = createNextApiHandler({
: undefined,
});
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "OPTIONS") {
res.writeHead(200);
return res.end();
}
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "OPTIONS") {
res.writeHead(200);
res.end();
return;
}
return nextApiHandler(req, res);
}
const result = await nextApiHandler(req, res);
return result;
},
);

View File

@@ -4,6 +4,7 @@ import { jwtVerify } from "jose";
import { z } from "zod";
import { env } from "~/env";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const requestSchema = z.object({
token: z.string().min(1),
@@ -19,10 +20,9 @@ type ResponseData =
const textEncoder = new TextEncoder();
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) {
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse<ResponseData>) => {
if (process.env.NEXT_PUBLIC_KAN_ENV !== "cloud") {
return res.status(404).json({
success: false,
@@ -101,4 +101,5 @@ export default async function handler(
}
return res.status(200).json({ success: true });
}
},
);

View File

@@ -6,13 +6,13 @@ import { env as nextRuntimeEnv } from "next-runtime-env";
import { createNextApiContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const allowedContentTypes = ["image/jpeg", "image/png"];
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
@@ -71,4 +71,5 @@ export default async function handler(
} catch (error) {
return res.status(500).json({ error: (error as Error).message });
}
}
},
);

View File

@@ -6,25 +6,26 @@ import { appRouter } from "@kan/api";
import { createRESTContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
await cors(req, res);
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
await cors(req, res);
const openApiHandler = createOpenApiNextHandler({
router: appRouter,
createContext: createRESTContext,
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(
`❌ REST failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,
});
const openApiHandler = createOpenApiNextHandler({
router: appRouter,
createContext: createRESTContext,
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(
`❌ REST failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,
});
return await openApiHandler(req, res);
}
return await openApiHandler(req, res);
},
);

View File

@@ -1,9 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { openApiDocument } from "@kan/api/openapi";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).send(openApiDocument);
};
export default handler;
export default withRateLimit(
{ points: 100, duration: 60 },
(req: NextApiRequest, res: NextApiResponse) => {
res.status(200).send(openApiDocument);
},
);

View File

@@ -0,0 +1,101 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("next-runtime-env", () => ({
env: vi.fn(),
}));
import { env } from "next-runtime-env";
import { getAvatarUrl } from "./helpers";
const mockEnv = env as ReturnType<typeof vi.fn>;
describe("getAvatarUrl", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("returns empty string for null input", () => {
expect(getAvatarUrl(null)).toBe("");
});
it("returns empty string for empty string input", () => {
expect(getAvatarUrl("")).toBe("");
});
it("returns URL unchanged if already absolute http", () => {
expect(getAvatarUrl("http://example.com/avatar.jpg")).toBe(
"http://example.com/avatar.jpg",
);
});
it("returns URL unchanged if already absolute https", () => {
expect(getAvatarUrl("https://example.com/avatar.jpg")).toBe(
"https://example.com/avatar.jpg",
);
});
describe("path-style URLs (MinIO/LocalStack)", () => {
it("constructs path-style URL when STORAGE_DOMAIN is not set", () => {
mockEnv.mockImplementation((key: string) => {
const vars: Record<string, string> = {
NEXT_PUBLIC_STORAGE_URL: "http://s3.localtest.me:9000",
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan",
};
return vars[key];
});
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
"http://s3.localtest.me:9000/kan/user123/avatar.jpg",
);
});
});
describe("virtual-hosted URLs (Tigris/AWS S3)", () => {
it("constructs virtual-hosted URL when USE_VIRTUAL_HOSTED_URLS is true and STORAGE_DOMAIN is set", () => {
mockEnv.mockImplementation((key: string) => {
const vars: Record<string, string> = {
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: "true",
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
};
return vars[key];
});
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
"https://kan-avatars.fly.storage.tigris.dev/user123/avatar.jpg",
);
});
it("uses path-style URL when USE_VIRTUAL_HOSTED_URLS is false even if STORAGE_DOMAIN is set", () => {
mockEnv.mockImplementation((key: string) => {
const vars: Record<string, string> = {
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: "false",
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
};
return vars[key];
});
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
"https://fly.storage.tigris.dev/kan-avatars/user123/avatar.jpg",
);
});
it("uses path-style URL when USE_VIRTUAL_HOSTED_URLS is not set even if STORAGE_DOMAIN is set", () => {
mockEnv.mockImplementation((key: string) => {
const vars: Record<string, string> = {
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
};
return vars[key];
});
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
"https://fly.storage.tigris.dev/kan-avatars/user123/avatar.jpg",
);
});
});
});

View File

@@ -52,5 +52,14 @@ export const getAvatarUrl = (imageOrKey: string | null) => {
return imageOrKey;
}
return `${env("NEXT_PUBLIC_STORAGE_URL")}/${env("NEXT_PUBLIC_AVATAR_BUCKET_NAME")}/${imageOrKey}`;
const bucket = env("NEXT_PUBLIC_AVATAR_BUCKET_NAME");
const useVirtualHostedUrls = env("NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS");
const storageDomain = env("NEXT_PUBLIC_STORAGE_DOMAIN");
if (useVirtualHostedUrls === "true" && storageDomain) {
return `https://${bucket}.${storageDomain}/${imageOrKey}`;
}
const storageUrl = env("NEXT_PUBLIC_STORAGE_URL");
return `${storageUrl}/${bucket}/${imageOrKey}`;
};

View File

@@ -22,8 +22,8 @@ const loadMessages = async (locale: Locale) => {
return (await import("~/locales/ru/messages")).messages;
case "pl":
return (await import("~/locales/pl/messages")).messages;
case "ptbr":
return (await import("~/locales/ptbr/messages")).messages;
case "pt-BR":
return (await import("~/locales/pt-BR/messages")).messages;
default:
return enMessages;
}

View File

@@ -25,6 +25,7 @@ import PatternedBackground from "~/components/PatternedBackground";
import { StrictModeDroppable as Droppable } from "~/components/StrictModeDroppable";
import { Tooltip } from "~/components/Tooltip";
import { EditYouTubeModal } from "~/components/YouTubeEmbed/EditYouTubeModal";
import { useDragToScroll } from "~/hooks/useDragToScroll";
import { useKeyboardShortcut } from "~/providers/keyboard-shortcuts";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
@@ -56,6 +57,11 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
const [selectedPublicListId, setSelectedPublicListId] =
useState<PublicListId>("");
const [isInitialLoading, setIsInitialLoading] = useState(true);
const { ref: scrollRef, onMouseDown } = useDragToScroll({
enabled: true,
direction: "horizontal",
});
const { tooltipContent: createListShortcutTooltipContent } =
useKeyboardShortcut({
@@ -479,7 +485,11 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
</div>
</div>
<div className="scrollbar-w-none scrollbar-track-rounded-[4px] scrollbar-thumb-rounded-[4px] scrollbar-h-[8px] z-0 flex-1 overflow-y-hidden overflow-x-scroll overscroll-contain scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300">
<div
ref={scrollRef}
onMouseDown={onMouseDown}
className={`scrollbar-w-none scrollbar-track-rounded-[4px] scrollbar-thumb-rounded-[4px] scrollbar-h-[8px] z-0 flex-1 overflow-y-hidden overflow-x-scroll overscroll-contain scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300`}
>
{isLoading ? (
<div className="ml-[2rem] flex">
<div className="0 mr-5 h-[500px] w-[18rem] animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />

View File

@@ -25,6 +25,7 @@ import { authClient } from "@kan/auth/client";
import Avatar from "~/components/Avatar";
import { useLocalisation } from "~/hooks/useLocalisation";
import { api } from "~/utils/api";
import { getAvatarUrl } from "~/utils/helpers";
import Comment from "./Comment";
type ActivityType =
@@ -471,6 +472,7 @@ const ActivityList = ({
cardPublicId={cardPublicId}
name={activity.user?.name ?? ""}
email={activity.user?.email ?? ""}
image={activity.user?.image ?? null}
isLoading={isLoading}
createdAt={activity.createdAt.toISOString()}
comment={activity.comment?.comment}
@@ -493,6 +495,7 @@ const ActivityList = ({
size="sm"
name={activity.user?.name ?? ""}
email={activity.user?.email ?? ""}
imageUrl={getAvatarUrl(activity.user?.image ?? null) || undefined}
icon={getActivityIcon(
activity.type,
activity.fromList?.index,

View File

@@ -12,6 +12,7 @@ import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api";
import { invalidateCard } from "~/utils/cardInvalidation";
import { getAvatarUrl } from "~/utils/helpers";
interface FormValues {
comment: string;
@@ -22,6 +23,7 @@ const Comment = ({
cardPublicId,
name,
email,
image,
isLoading,
createdAt,
comment,
@@ -34,6 +36,7 @@ const Comment = ({
cardPublicId: string;
name: string;
email: string;
image: string | null;
isLoading: boolean;
createdAt: string;
comment: string | undefined;
@@ -108,6 +111,7 @@ const Comment = ({
size="sm"
name={name ?? ""}
email={email ?? ""}
imageUrl={getAvatarUrl(image) || undefined}
isLoading={isLoading}
/>

View File

@@ -54,6 +54,7 @@ export default function MembersPage() {
memberStatus,
isLastRow,
showSkeleton,
showPendingIcon,
}: {
memberPublicId?: string;
memberId?: string | null | undefined;
@@ -64,6 +65,7 @@ export default function MembersPage() {
memberStatus?: string;
isLastRow?: boolean;
showSkeleton?: boolean;
showPendingIcon?: boolean;
}) => {
return (
<tr className="rounded-b-lg">
@@ -82,6 +84,7 @@ export default function MembersPage() {
name={memberName ?? ""}
email={memberEmail ?? ""}
imageUrl={memberImage ? getAvatarUrl(memberImage) : undefined}
icon={showPendingIcon ? "?" : undefined}
/>
)}
</div>
@@ -93,20 +96,26 @@ export default function MembersPage() {
"mr-2 truncate text-xs font-medium text-neutral-900 dark:text-dark-1000 sm:text-sm",
showSkeleton &&
"md mb-2 h-3 w-[125px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
showPendingIcon &&
"italic text-neutral-500 dark:text-dark-900",
)}
>
{memberName}
</p>
</div>
<p
className={twMerge(
"truncate text-xs text-dark-900 sm:text-sm",
showSkeleton &&
"h-3 w-[175px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
)}
>
{memberEmail}
</p>
{((workspace.role === "admin" ||
data?.showEmailsToMembers === true) ||
showSkeleton) && (
<p
className={twMerge(
"truncate text-xs text-dark-900 sm:text-sm",
showSkeleton &&
"h-3 w-[175px] animate-pulse rounded-sm bg-light-200 dark:bg-dark-200",
)}
>
{memberEmail}
</p>
)}
</div>
</div>
</div>
@@ -246,19 +255,24 @@ export default function MembersPage() {
</thead>
<tbody className="divide-y divide-light-600 overflow-visible bg-light-50 dark:divide-dark-600 dark:bg-dark-100">
{!isLoading &&
data?.members.map((member, index) => (
<TableRow
key={member.publicId}
memberPublicId={member.publicId}
memberId={member.user?.id}
memberName={member.user?.name}
memberEmail={member.user?.email ?? member.email}
memberImage={member.user?.image}
memberRole={member.role}
memberStatus={member.status}
isLastRow={index === data.members.length - 1}
/>
))}
data?.members.map((member, index) => {
const isPendingInvite = member.status === "invited";
return (
<TableRow
key={member.publicId}
memberPublicId={member.publicId}
memberId={member.user?.id}
memberName={member.user?.name}
memberEmail={member.user?.email ?? member.email}
memberImage={member.user?.image}
memberRole={member.role}
memberStatus={member.status}
isLastRow={index === data.members.length - 1}
showPendingIcon={isPendingInvite}
/>
);
})}
{isLoading && (
<>

View File

@@ -12,6 +12,7 @@ import { PageHead } from "~/components/PageHead";
import PatternedBackground from "~/components/PatternedBackground";
import Popup from "~/components/Popup";
import ThemeToggle from "~/components/ThemeToggle";
import { useDragToScroll } from "~/hooks/useDragToScroll";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api";
@@ -29,6 +30,11 @@ export default function PublicBoardView() {
const { showPopup } = usePopup();
const [isRouteLoaded, setIsRouteLoaded] = useState(false);
const { openModal } = useModal();
const { ref: scrollRef, onMouseDown } = useDragToScroll({
enabled: true,
direction: "horizontal",
});
const boardSlug = Array.isArray(router.query.boardSlug)
? router.query.boardSlug[0]
@@ -151,7 +157,11 @@ export default function PublicBoardView() {
)}
</div>
<div className="scrollbar-w-none scrollbar-track-rounded-[4px] scrollbar-thumb-rounded-[4px] scrollbar-h-[8px] relative h-full flex-1 overflow-y-hidden overflow-x-scroll overscroll-contain scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300">
<div
ref={scrollRef}
onMouseDown={onMouseDown}
className="scrollbar-w-none scrollbar-track-rounded-[4px] scrollbar-thumb-rounded-[4px] scrollbar-h-[8px] relative h-full flex-1 overflow-y-hidden overflow-x-scroll overscroll-contain scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300"
>
{isLoading || !router.isReady ? (
<div className="ml-[2rem] flex">
<div className="0 mr-5 h-[500px] w-[18rem] animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />

View File

@@ -37,6 +37,13 @@ export default function AccountSettings() {
<UpdateDisplayNameForm displayName={data?.name ?? ""} />
</div>
<div className="mb-4">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Email`}
</h2>
<p className="text-sm text-neutral-700 dark:text-dark-900">{data?.email}</p>
</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`}

View File

@@ -17,6 +17,7 @@ import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
import { DeleteWorkspaceConfirmation } from "./components/DeleteWorkspaceConfirmation";
import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescriptionForm";
import UpdateWorkspaceEmailVisibilityForm from "./components/UpdateWorkspaceEmailVisibilityForm";
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
@@ -79,6 +80,14 @@ export default function WorkspaceSettings() {
workspaceDescription={workspace.description ?? ""}
/>
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`Email visibility`}
</h2>
<UpdateWorkspaceEmailVisibilityForm
workspacePublicId={workspace.publicId}
showEmailsToMembers={workspaceData?.showEmailsToMembers ?? false}
/>
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!hasActiveSubscription(subscriptions, "pro") &&
!hasActiveSubscription(subscriptions, "team") && (

View File

@@ -0,0 +1,53 @@
import { t } from "@lingui/core/macro";
import { useEffect, useState } from "react";
import Toggle from "~/components/Toggle";
import { api } from "~/utils/api";
export default function UpdateWorkspaceEmailVisibilityForm({
workspacePublicId,
showEmailsToMembers,
}: {
workspacePublicId: string;
showEmailsToMembers: boolean;
}) {
const utils = api.useUtils();
const [isChecked, setIsChecked] = useState(showEmailsToMembers);
useEffect(() => {
setIsChecked(showEmailsToMembers);
}, [showEmailsToMembers]);
const updateWorkspace = api.workspace.update.useMutation({
onSuccess: () => {
void utils.workspace.byId.invalidate({
workspacePublicId,
});
},
});
const handleToggle = () => {
const newValue = !isChecked;
setIsChecked(newValue);
updateWorkspace.mutate({
workspacePublicId,
showEmailsToMembers: newValue,
});
};
return (
<div className="mb-8 flex items-center justify-between">
<div className="flex-1">
<p className="text-sm text-neutral-500 dark:text-dark-900">
{t`Allow workspace members to see each other's email addresses`}
</p>
</div>
<Toggle
isChecked={isChecked}
onChange={handleToggle}
label=""
disabled={updateWorkspace.isPending}
/>
</div>
);
}

View File

@@ -9,6 +9,8 @@ services:
build:
context: ..
dockerfile: apps/web/Dockerfile
args:
APP_VERSION: ${APP_VERSION:-}
env_file:
- .env
restart: unless-stopped
@@ -19,6 +21,7 @@ services:
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- POSTGRES_URL=${POSTGRES_URL}
- NEXT_PUBLIC_USE_STANDALONE_OUTPUT=${NEXT_PUBLIC_USE_STANDALONE_OUTPUT}
- REDIS_URL=${REDIS_URL}
# Stripe
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
@@ -53,11 +56,15 @@ services:
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
- NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=${NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS}
# Auth config
# Auth config (optional)
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
# API configuration (optional)
- NEXT_API_BODY_SIZE_LIMIT=${NEXT_API_BODY_SIZE_LIMIT}
# Integration providers
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}

View File

@@ -18,6 +18,9 @@ services:
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- POSTGRES_URL=${POSTGRES_URL}
# Redis (optional - for rate limiting)
- REDIS_URL=${REDIS_URL}
# Admin API key (optional)
- KAN_ADMIN_API_KEY=${KAN_ADMIN_API_KEY}
@@ -42,6 +45,7 @@ services:
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
- NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=${NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS}
# White label
- NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY=${NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY}
@@ -50,6 +54,9 @@ services:
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
# API configuration (optional)
- NEXT_API_BODY_SIZE_LIMIT=${NEXT_API_BODY_SIZE_LIMIT}
# Integration providers (optional)
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}

View File

@@ -23,6 +23,10 @@
"./openapi": {
"types": "./dist/openapi.d.ts",
"default": "./src/openapi.ts"
},
"./utils/rateLimit": {
"types": "./dist/utils/rateLimit.d.ts",
"default": "./src/utils/rateLimit.ts"
}
},
"license": "GPL-3.0",
@@ -43,6 +47,7 @@
"@kan/shared": "workspace:^",
"@kan/stripe": "workspace:^",
"@trpc/server": "catalog:",
"rate-limiter-flexible": "^9.0.1",
"superjson": "2.2.1",
"trpc-to-openapi": "^2.3.2",
"zod": "catalog:"

View File

@@ -77,6 +77,49 @@ export const workspaceRouter = createTRPCRouter({
await assertUserInWorkspace(ctx.db, userId, result.id);
// Check if user is an admin
const userMember = result.members.find(
(member) => member.user?.id === userId,
);
const isAdmin = userMember?.role === "admin";
// Show emails if user is admin OR workspace setting allows it
const shouldShowEmails = isAdmin || result.showEmailsToMembers === true;
// If emails should be hidden, filter them out
if (!shouldShowEmails) {
const sanitizedMembers = result.members.map((member) => {
// If user doesn't have a display name, use anonymous identifier
const displayName =
member.user?.name?.trim() ?? `anonymous_${member.publicId}`;
const { email: _memberEmail, ...memberWithoutEmail } = member;
const sanitizedUser = member.user
? (() => {
const { email: _userEmail, ...userWithoutEmail } = member.user;
return {
...userWithoutEmail,
name: displayName,
};
})()
: {
id: null,
name: displayName,
image: null,
};
return {
...memberWithoutEmail,
user: sanitizedUser,
};
});
return {
...result,
members: sanitizedMembers,
} as Awaited<ReturnType<typeof workspaceRepo.getByPublicIdWithMembers>>;
}
return result;
}),
bySlug: publicProcedure
@@ -230,6 +273,7 @@ export const workspaceRouter = createTRPCRouter({
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/)
.optional(),
description: z.string().min(3).max(280).optional(),
showEmailsToMembers: z.boolean().optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.update>>>())
@@ -291,9 +335,16 @@ export const workspaceRouter = createTRPCRouter({
name: input.name,
slug: input.slug,
description: input.description,
showEmailsToMembers: input.showEmailsToMembers,
},
);
if (!result)
throw new TRPCError({
message: `Unable to delete workspace`,
code: "INTERNAL_SERVER_ERROR",
});
return result;
}),
delete: protectedProcedure
@@ -336,12 +387,6 @@ export const workspaceRouter = createTRPCRouter({
input.workspacePublicId,
);
if (!result)
throw new TRPCError({
message: `Unable to delete workspace`,
code: "INTERNAL_SERVER_ERROR",
});
return result;
}),
checkSlugAvailability: publicProcedure

View File

@@ -0,0 +1,99 @@
import type { NextApiRequest, NextApiResponse } from "next";
import {
RateLimiterRedis,
RateLimiterMemory,
} from "rate-limiter-flexible";
import { getRedisClient } from "@kan/db/redis";
export interface RateLimitOptions {
points?: number;
duration?: number;
identifier?: (req: NextApiRequest) => string | Promise<string>;
errorMessage?: string;
}
const defaultIdentifier = (req: NextApiRequest): string => {
// Try to identify the IP address of the request
const forwardedFor = req.headers["x-forwarded-for"];
const realIp = req.headers["x-real-ip"];
const cfConnectingIp = req.headers["cf-connecting-ip"];
const ip =
(typeof forwardedFor === "string"
? forwardedFor.split(",")[0]?.trim()
: null) ??
(typeof realIp === "string" ? realIp : null) ??
(typeof cfConnectingIp === "string" ? cfConnectingIp : null) ??
req.socket.remoteAddress ??
"unknown";
return ip;
};
const DEFAULT_OPTIONS = {
points: 100,
duration: 60,
errorMessage: "Too many requests, please try again later.",
identifier: defaultIdentifier,
} as const;
function createRateLimiter(options: RateLimitOptions = {}) {
const redis = getRedisClient();
const points = options.points ?? DEFAULT_OPTIONS.points;
const duration = options.duration ?? DEFAULT_OPTIONS.duration;
// Use Redis if available, otherwise fall back to in-memory storage
if (redis) {
console.log("Using Redis for rate limiting");
return new RateLimiterRedis({
storeClient: redis,
points,
duration,
});
}
console.log("Using in-memory for rate limiting");
return new RateLimiterMemory({
points,
duration,
});
}
export function withRateLimit(
options: RateLimitOptions,
handler: (
req: NextApiRequest,
res: NextApiResponse,
) => Promise<unknown> | unknown,
) {
const rateLimiter = createRateLimiter(options);
const identifier = options.identifier ?? DEFAULT_OPTIONS.identifier;
const errorMessage = options.errorMessage ?? DEFAULT_OPTIONS.errorMessage;
return async (req: NextApiRequest, res: NextApiResponse) => {
try {
const id = await identifier(req);
const key = `ratelimit_${id}`;
await rateLimiter.consume(key);
return await handler(req, res);
} catch (error) {
// rate-limiter-flexible throws an error with msBeforeNext or remainingPoints
// when limit is exceeded. Check for these properties directly.
if (
error &&
typeof error === "object" &&
("msBeforeNext" in error || "remainingPoints" in error)
) {
return res.status(429).json({
message: errorMessage,
});
}
return await handler(req, res);
}
};
}

View File

@@ -1,147 +1,23 @@
import type { Subscription } from "@better-auth/stripe";
import type Stripe from "stripe";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { stripe } from "@better-auth/stripe";
import { ChatOrPushProviderEnum } from "@novu/api/models/components";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
import { apiKey, genericOAuth } from "better-auth/plugins";
import { magicLink } from "better-auth/plugins/magic-link";
import { socialProviderList } from "better-auth/social-providers";
import { env } from "next-runtime-env";
import type { dbClient } from "@kan/db/client";
import * as memberRepo from "@kan/db/repository/member.repo";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as userRepo from "@kan/db/repository/user.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import * as schema from "@kan/db/schema";
import { notificationClient, sendEmail } from "@kan/email";
import { createEmailUnsubscribeLink } from "@kan/shared";
import { createStripeClient } from "@kan/stripe";
import { sendEmail } from "@kan/email";
export const configuredProviders = socialProviderList.reduce<
Record<
string,
{
clientId: string;
clientSecret: string;
appBundleIdentifier?: string;
tenantId?: string;
requireSelectAccount?: boolean;
clientKey?: string;
issuer?: string;
// Google-specific optional hints
hostedDomain?: string;
hd?: string;
}
>
>((acc, provider) => {
const id = process.env[`${provider.toUpperCase()}_CLIENT_ID`];
const secret = process.env[`${provider.toUpperCase()}_CLIENT_SECRET`];
if (id && id.length > 0 && secret && secret.length > 0) {
acc[provider] = { clientId: id, clientSecret: secret };
}
if (
provider === "apple" &&
Object.keys(acc).includes("apple") &&
acc[provider]
) {
const bundleId =
process.env[`${provider.toUpperCase()}_APP_BUNDLE_IDENTIFIER`];
if (bundleId && bundleId.length > 0) {
acc[provider].appBundleIdentifier = bundleId;
}
}
if (
provider === "gitlab" &&
Object.keys(acc).includes("gitlab") &&
acc[provider]
) {
const issuer = process.env[`${provider.toUpperCase()}_ISSUER`];
if (issuer && issuer.length > 0) {
acc[provider].issuer = issuer;
}
}
if (
provider === "microsoft" &&
Object.keys(acc).includes("microsoft") &&
acc[provider]
) {
acc[provider].tenantId = "common";
acc[provider].requireSelectAccount = true;
}
// Add Google domain hint if allowed domains is configured
if (
provider === "google" &&
Object.keys(acc).includes("google") &&
acc[provider]
) {
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS?.split(",")
.map((d) => d.trim().toLowerCase())
.filter(Boolean);
if (allowed && allowed.length > 0) {
// Use the first domain as an authorization hint
acc[provider].hostedDomain = allowed[0];
acc[provider].hd = allowed[0];
}
}
if (
provider === "tiktok" &&
Object.keys(acc).includes("tiktok") &&
acc[provider]
) {
const key = process.env[`${provider.toUpperCase()}_CLIENT_KEY`];
if (key && key.length > 0) {
acc[provider].clientKey = key;
}
}
return acc;
}, {});
export const socialProvidersPlugin = () => ({
id: "social-providers-plugin",
endpoints: {
getSocialProviders: createAuthEndpoint(
"/social-providers",
{
method: "GET",
},
async (ctx) => {
const providers = ctx.context.socialProviders.map((p) =>
p.id.toLowerCase(),
);
// Add OIDC provider if configured
if (
process.env.OIDC_CLIENT_ID &&
process.env.OIDC_CLIENT_SECRET &&
process.env.OIDC_DISCOVERY_URL
) {
providers.push("oidc");
}
return ctx.json(providers);
},
),
},
});
async function downloadImage(url: string): Promise<Buffer> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to download image: ${response.statusText}`);
}
return Buffer.from(await response.arrayBuffer());
}
import { createDatabaseHooks, createMiddlewareHooks } from "./hooks";
import { createPlugins } from "./plugins";
import { configuredProviders } from "./providers";
export const initAuth = (db: dbClient) => {
return betterAuth({
secret: process.env.BETTER_AUTH_SECRET!,
secret: env("BETTER_AUTH_SECRET"),
baseURL: env("NEXT_PUBLIC_BASE_URL"),
trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS
trustedOrigins: env("BETTER_AUTH_TRUSTED_ORIGINS")
? [
env("NEXT_PUBLIC_BASE_URL") ?? "",
...process.env.BETTER_AUTH_TRUSTED_ORIGINS.split(","),
...(env("BETTER_AUTH_TRUSTED_ORIGINS")?.split(",") ?? []),
]
: [env("NEXT_PUBLIC_BASE_URL") ?? ""],
database: drizzleAdapter(db, {
@@ -181,360 +57,9 @@ export const initAuth = (db: dbClient) => {
},
},
},
plugins: [
socialProvidersPlugin(),
...(process.env.NEXT_PUBLIC_KAN_ENV === "cloud"
? [
stripe({
stripeClient: createStripeClient(),
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
createCustomerOnSignUp: true,
subscription: {
enabled: true,
plans: [
{
name: "team",
priceId: process.env.STRIPE_TEAM_PLAN_MONTHLY_PRICE_ID!,
annualDiscountPriceId:
process.env.STRIPE_TEAM_PLAN_YEARLY_PRICE_ID!,
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
await triggerWorkflow(
db,
"trial-expired",
subscription,
);
},
},
},
{
name: "pro",
priceId: process.env.STRIPE_PRO_PLAN_MONTHLY_PRICE_ID!,
annualDiscountPriceId:
process.env.STRIPE_PRO_PLAN_YEARLY_PRICE_ID!,
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
await triggerWorkflow(
db,
"trial-expired",
subscription,
);
},
},
},
],
authorizeReference: async (data) => {
const workspace = await workspaceRepo.getByPublicId(
db,
data.referenceId,
);
if (!workspace) {
return Promise.resolve(false);
}
const isUserInWorkspace =
await workspaceRepo.isUserInWorkspace(
db,
data.user.id,
workspace.id,
);
return isUserInWorkspace;
},
getCheckoutSessionParams: () => {
return {
params: {
allow_promotion_codes: true,
},
};
},
onSubscriptionComplete: async ({
subscription,
stripeSubscription,
}) => {
// Set unlimited seats to true for pro plans
if (subscription.plan === "pro") {
await subscriptionRepo.updateByStripeSubscriptionId(
db,
stripeSubscription.id,
{
unlimitedSeats: true,
},
);
console.log(
`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}`,
);
}
}
},
},
}),
]
: []),
apiKey({
enableSessionForAPIKeys: true,
rateLimit: {
enabled: true,
timeWindow: 1000 * 60, // 1 minute
maxRequests: 100, // 100 requests per minute
},
}),
magicLink({
expiresIn: 60 * 60 * 24 * 7, // 7 days
sendMagicLink: async ({ email, url }) => {
if (url.includes("type=invite")) {
await sendEmail(
email,
"Invitation to join workspace",
"JOIN_WORKSPACE",
{
magicLoginUrl: url,
},
);
} else {
await sendEmail(email, "Sign in to kan.bn", "MAGIC_LINK", {
magicLoginUrl: url,
});
}
},
}),
// Generic OIDC provider
...(process.env.OIDC_CLIENT_ID &&
process.env.OIDC_CLIENT_SECRET &&
process.env.OIDC_DISCOVERY_URL
? [
genericOAuth({
config: [
{
providerId: "oidc",
clientId: process.env.OIDC_CLIENT_ID,
clientSecret: process.env.OIDC_CLIENT_SECRET,
discoveryUrl: process.env.OIDC_DISCOVERY_URL,
scopes: ["openid", "email", "profile"],
pkce: true,
mapProfileToUser: (profile: {
name?: string;
display_name?: string;
preferred_username?: string;
given_name?: string;
family_name?: string;
email?: string;
email_verified?: boolean;
sub?: string;
picture?: string;
avatar?: string;
}) => {
console.log("OIDC profile:", profile);
const name =
profile.name ??
profile.display_name ??
profile.preferred_username ??
(profile.given_name && profile.family_name
? `${profile.given_name} ${profile.family_name}`.trim()
: (profile.given_name ?? profile.family_name)) ??
profile.sub ??
"";
return {
email: profile.email,
name: name,
emailVerified: profile.email_verified ?? false,
image: profile.picture ?? profile.avatar ?? null,
};
},
},
],
}),
]
: []),
],
databaseHooks: {
user: {
create: {
async before(user) {
if (env("NEXT_PUBLIC_DISABLE_SIGN_UP")?.toLowerCase() === "true") {
const pendingInvitation = await memberRepo.getByEmailAndStatus(
db,
user.email,
"invited",
);
if (!pendingInvitation) {
return Promise.resolve(false);
}
// Fall through to any additional checks below
}
// Enforce allowed domains (OIDC/social) if configured
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS?.split(",")
.map((d) => d.trim().toLowerCase())
.filter(Boolean);
if (allowed && allowed.length > 0) {
const domain = user.email.split("@")[1]?.toLowerCase();
if (!domain || !allowed.includes(domain)) {
return Promise.resolve(false);
}
}
return Promise.resolve(true);
},
async after(user) {
let avatarKey = user.image;
if (
user.image &&
!user.image.includes(process.env.NEXT_PUBLIC_STORAGE_DOMAIN!)
) {
try {
const credentials =
env("S3_ACCESS_KEY_ID") && env("S3_SECRET_ACCESS_KEY")
? {
accessKeyId: env("S3_ACCESS_KEY_ID")!,
secretAccessKey: env("S3_SECRET_ACCESS_KEY")!,
}
: undefined;
const client = new S3Client({
region: env("S3_REGION") ?? "",
endpoint: env("S3_ENDPOINT") ?? "",
forcePathStyle: env("S3_FORCE_PATH_STYLE") === "true",
credentials,
});
const allowedFileExtensions = ["jpg", "jpeg", "png", "webp"];
const fileExtension =
user.image.split(".").pop()?.split("?")[0] || "jpg";
const key = `${user.id}/avatar.${!allowedFileExtensions.includes(fileExtension) ? "jpg" : fileExtension}`;
const imageBuffer = await downloadImage(user.image);
await client.send(
new PutObjectCommand({
Bucket: env("NEXT_PUBLIC_AVATAR_BUCKET_NAME") ?? "",
Key: key,
Body: imageBuffer,
ContentType: `image/${!allowedFileExtensions.includes(fileExtension) ? "jpeg" : fileExtension}`,
ACL: "public-read",
}),
);
avatarKey = key;
await userRepo.update(db, user.id, {
image: key,
});
} catch (error) {
console.error(error);
}
}
if (notificationClient) {
try {
const [firstName, ...rest] = user.name
.split(" ")
.filter(Boolean);
const lastName = rest.length ? rest.join(" ") : undefined;
const avatarUrl = avatarKey
? `${env("NEXT_PUBLIC_STORAGE_URL")}/${env("NEXT_PUBLIC_AVATAR_BUCKET_NAME")}/${avatarKey}`
: undefined;
const unsubscribeUrl = await createEmailUnsubscribeLink(
user.id,
);
await notificationClient.trigger({
to: {
subscriberId: user.id,
firstName: firstName,
lastName: lastName,
email: user.email,
avatar: avatarUrl,
data: {
emailVerified: user.emailVerified,
stripeCustomerId: user.stripeCustomerId,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
},
},
payload: {
emailUnsubscribeUrl: unsubscribeUrl,
},
workflowId: "user-signup",
});
await notificationClient.subscribers.credentials.update(
{
providerId: ChatOrPushProviderEnum.Discord,
credentials: {
webhookUrl: process.env.DISCORD_WEBHOOK_URL!,
},
integrationIdentifier: "discord",
},
user.id,
);
} catch (error) {
console.error(
"Error adding user to notification client",
error,
);
}
}
},
},
},
},
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (
ctx.path === "/magic-link/verify" &&
(ctx.query?.callbackURL as string | undefined)?.includes(
"type=invite",
)
) {
const userId = ctx.context.newSession?.session.userId;
const callbackURL = ctx.query?.callbackURL as string | undefined;
const memberPublicId = callbackURL?.split("memberPublicId=")[1];
if (userId && memberPublicId) {
const member = await memberRepo.getByPublicId(db, memberPublicId);
if (member?.id) {
await memberRepo.acceptInvite(db, {
memberId: member.id,
userId,
});
}
}
}
}),
},
plugins: createPlugins(db),
databaseHooks: createDatabaseHooks(db),
hooks: createMiddlewareHooks(db),
advanced: {
cookiePrefix: "kan",
database: {
@@ -543,37 +68,3 @@ export const initAuth = (db: dbClient) => {
},
});
};
async function triggerWorkflow(
db: dbClient,
workflowId: string,
subscription: Subscription,
cancellationDetails?: Stripe.Subscription.CancellationDetails | null,
) {
try {
if (!subscription.stripeCustomerId || !notificationClient) return;
const user = await userRepo.getByStripeCustomerId(
db,
subscription.stripeCustomerId,
);
if (!user || !notificationClient) return;
const unsubscribeUrl = await createEmailUnsubscribeLink(user.id);
await notificationClient.trigger({
to: {
subscriberId: user.id,
},
payload: {
...subscription,
cancellationDetails,
emailUnsubscribeUrl: unsubscribeUrl,
},
workflowId,
});
} catch (error) {
console.error("Error triggering workflow", error);
}
}

View File

@@ -8,7 +8,7 @@ import {
} from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/react";
import type { socialProvidersPlugin } from "./auth";
import type { socialProvidersPlugin } from "./providers";
const socialProvidersPluginClient = {
id: "social-providers-plugin",

183
packages/auth/src/hooks.ts Normal file
View File

@@ -0,0 +1,183 @@
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { ChatOrPushProviderEnum } from "@novu/api/models/components";
import { createAuthMiddleware } from "better-auth/api";
import { env } from "next-runtime-env";
import type { dbClient } from "@kan/db/client";
import * as memberRepo from "@kan/db/repository/member.repo";
import * as userRepo from "@kan/db/repository/user.repo";
import { notificationClient } from "@kan/email";
import { createEmailUnsubscribeLink } from "@kan/shared";
import { downloadImage } from "./utils";
type BetterAuthUser = {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
stripeCustomerId?: string | null | undefined;
} & Record<string, unknown>;
export function createDatabaseHooks(db: dbClient) {
return {
user: {
create: {
async before(user: BetterAuthUser, _context: unknown) {
if (env("NEXT_PUBLIC_DISABLE_SIGN_UP")?.toLowerCase() === "true") {
const pendingInvitation = await memberRepo.getByEmailAndStatus(
db,
user.email,
"invited",
);
if (!pendingInvitation) {
return Promise.resolve(false);
}
// Fall through to any additional checks below
}
// Enforce allowed domains (OIDC/social) if configured
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS?.split(",")
.map((d) => d.trim().toLowerCase())
.filter(Boolean);
if (allowed && allowed.length > 0) {
const domain = user.email.split("@")[1]?.toLowerCase();
if (!domain || !allowed.includes(domain)) {
return Promise.resolve(false);
}
}
return Promise.resolve(true);
},
async after(user: BetterAuthUser, _context: unknown) {
let avatarKey = user.image;
const storageDomain = process.env.NEXT_PUBLIC_STORAGE_DOMAIN;
if (
user.image &&
storageDomain &&
!user.image.includes(storageDomain)
) {
try {
const credentials =
env("S3_ACCESS_KEY_ID") && env("S3_SECRET_ACCESS_KEY")
? {
accessKeyId: env("S3_ACCESS_KEY_ID")!,
secretAccessKey: env("S3_SECRET_ACCESS_KEY")!,
}
: undefined;
const client = new S3Client({
region: env("S3_REGION") ?? "",
endpoint: env("S3_ENDPOINT") ?? "",
forcePathStyle: env("S3_FORCE_PATH_STYLE") === "true",
credentials,
});
const allowedFileExtensions = ["jpg", "jpeg", "png", "webp"];
const fileExtension =
user.image.split(".").pop()?.split("?")[0] ?? "jpg";
const key = `${user.id}/avatar.${!allowedFileExtensions.includes(fileExtension) ? "jpg" : fileExtension}`;
const imageBuffer = await downloadImage(user.image);
await client.send(
new PutObjectCommand({
Bucket: env("NEXT_PUBLIC_AVATAR_BUCKET_NAME") ?? "",
Key: key,
Body: imageBuffer,
ContentType: `image/${!allowedFileExtensions.includes(fileExtension) ? "jpeg" : fileExtension}`,
ACL: "public-read",
}),
);
avatarKey = key;
await userRepo.update(db, user.id, {
image: key,
});
} catch (error) {
console.error(error);
}
}
if (notificationClient) {
try {
const [firstName, ...rest] = (user.name || "")
.split(" ")
.filter(Boolean);
const lastName = rest.length ? rest.join(" ") : undefined;
const avatarUrl = avatarKey
? `${env("NEXT_PUBLIC_STORAGE_URL")}/${env("NEXT_PUBLIC_AVATAR_BUCKET_NAME")}/${avatarKey}`
: undefined;
const unsubscribeUrl = await createEmailUnsubscribeLink(user.id);
await notificationClient.trigger({
to: {
subscriberId: user.id,
firstName: firstName,
lastName: lastName,
email: user.email,
avatar: avatarUrl,
data: {
emailVerified: user.emailVerified,
stripeCustomerId: user.stripeCustomerId,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
},
},
payload: {
emailUnsubscribeUrl: unsubscribeUrl,
},
workflowId: "user-signup",
});
await notificationClient.subscribers.credentials.update(
{
providerId: ChatOrPushProviderEnum.Discord,
credentials: {
webhookUrl: env("DISCORD_WEBHOOK_URL"),
},
integrationIdentifier: "discord",
},
user.id,
);
} catch (error) {
console.error("Error adding user to notification client", error);
}
}
},
},
},
};
}
export function createMiddlewareHooks(db: dbClient) {
return {
after: createAuthMiddleware(async (ctx) => {
if (
ctx.path === "/magic-link/verify" &&
(ctx.query?.callbackURL as string | undefined)?.includes("type=invite")
) {
const userId = ctx.context.newSession?.session.userId;
const callbackURL = ctx.query?.callbackURL as string | undefined;
const memberPublicId = callbackURL?.split("memberPublicId=")[1];
if (userId && memberPublicId) {
const member = await memberRepo.getByPublicId(db, memberPublicId);
if (member?.id) {
await memberRepo.acceptInvite(db, {
memberId: member.id,
userId,
});
}
}
}
}),
};
}

View File

@@ -0,0 +1,241 @@
import { stripe } from "@better-auth/stripe";
import { apiKey, genericOAuth } from "better-auth/plugins";
import { magicLink } from "better-auth/plugins/magic-link";
import type { dbClient } from "@kan/db/client";
import * as memberRepo from "@kan/db/repository/member.repo";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { generateUID } from "@kan/shared/utils";
import { sendEmail } from "@kan/email";
import { createStripeClient } from "@kan/stripe";
import { socialProvidersPlugin } from "./providers";
import { triggerWorkflow } from "./utils";
export function createPlugins(db: dbClient) {
return [
socialProvidersPlugin(),
...(process.env.NEXT_PUBLIC_KAN_ENV === "cloud"
? [
stripe({
stripeClient: createStripeClient(),
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
createCustomerOnSignUp: true,
subscription: {
enabled: true,
plans: [
{
name: "team",
priceId: process.env.STRIPE_TEAM_PLAN_MONTHLY_PRICE_ID!,
annualDiscountPriceId:
process.env.STRIPE_TEAM_PLAN_YEARLY_PRICE_ID!,
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
await triggerWorkflow(db, "trial-expired", subscription);
},
},
},
{
name: "pro",
priceId: process.env.STRIPE_PRO_PLAN_MONTHLY_PRICE_ID!,
annualDiscountPriceId:
process.env.STRIPE_PRO_PLAN_YEARLY_PRICE_ID!,
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
await triggerWorkflow(db, "trial-expired", subscription);
},
},
},
],
authorizeReference: async (data) => {
const workspace = await workspaceRepo.getByPublicId(
db,
data.referenceId,
);
if (!workspace) {
return Promise.resolve(false);
}
const isUserInWorkspace = await workspaceRepo.isUserInWorkspace(
db,
data.user.id,
workspace.id,
);
return isUserInWorkspace;
},
getCheckoutSessionParams: () => {
return {
params: {
allow_promotion_codes: true,
},
};
},
onSubscriptionComplete: async ({
subscription,
stripeSubscription,
}) => {
// Set unlimited seats to true for pro plans
if (subscription.plan === "pro") {
await subscriptionRepo.updateByStripeSubscriptionId(
db,
stripeSubscription.id,
{
unlimitedSeats: true,
},
);
console.log(
`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);
}
}
},
onSubscriptionCancel: async ({
subscription,
cancellationDetails,
}) => {
await triggerWorkflow(
db,
"subscription-canceled",
subscription,
cancellationDetails,
);
// for cancelled subscriptions, we need to pause all members and set their workspace plan to free
const workspace = await workspaceRepo.getByPublicId(
db,
subscription.referenceId,
);
if (workspace?.id) {
await memberRepo.pauseAllMembers(db, workspace.id);
// Reset slug to publicId, or generate a UID if publicId is taken
let newSlug = workspace.publicId;
if (workspace.slug !== workspace.publicId) {
const isPublicIdAvailable = await workspaceRepo.isWorkspaceSlugAvailable(
db,
workspace.publicId,
);
if (!isPublicIdAvailable) {
newSlug = generateUID();
}
}
await workspaceRepo.update(db, subscription.referenceId, {
plan: "free",
slug: newSlug,
});
}
},
onSubscriptionUpdate: async ({ subscription }) => {
await triggerWorkflow(db, "subscription-updated", subscription);
},
},
}),
]
: []),
apiKey({
enableSessionForAPIKeys: true,
rateLimit: {
enabled: true,
timeWindow: 1000 * 60, // 1 minute
maxRequests: 100, // 100 requests per minute
},
}),
magicLink({
expiresIn: 60 * 60 * 24 * 7, // 7 days
sendMagicLink: async ({ email, url }) => {
if (url.includes("type=invite")) {
await sendEmail(
email,
"Invitation to join workspace",
"JOIN_WORKSPACE",
{
magicLoginUrl: url,
},
);
} else {
await sendEmail(email, "Sign in to kan.bn", "MAGIC_LINK", {
magicLoginUrl: url,
});
}
},
}),
// Generic OIDC provider
...(process.env.OIDC_CLIENT_ID &&
process.env.OIDC_CLIENT_SECRET &&
process.env.OIDC_DISCOVERY_URL
? [
genericOAuth({
config: [
{
providerId: "oidc",
clientId: process.env.OIDC_CLIENT_ID,
clientSecret: process.env.OIDC_CLIENT_SECRET,
discoveryUrl: process.env.OIDC_DISCOVERY_URL,
scopes: ["openid", "email", "profile"],
pkce: true,
mapProfileToUser: (profile: {
name?: string;
display_name?: string;
preferred_username?: string;
given_name?: string;
family_name?: string;
email?: string;
email_verified?: boolean;
sub?: string;
picture?: string;
avatar?: string;
}) => {
console.log("OIDC profile:", profile);
const name =
profile.name ??
profile.display_name ??
profile.preferred_username ??
(profile.given_name && profile.family_name
? `${profile.given_name} ${profile.family_name}`.trim()
: (profile.given_name ?? profile.family_name)) ??
profile.sub ??
"";
return {
email: profile.email,
name: name,
emailVerified: profile.email_verified ?? false,
image: profile.picture ?? profile.avatar ?? null,
};
},
},
],
}),
]
: []),
];
}

View File

@@ -0,0 +1,107 @@
import { createAuthEndpoint } from "better-auth/api";
import { socialProviderList } from "better-auth/social-providers";
export const configuredProviders = socialProviderList.reduce<
Record<
string,
{
clientId: string;
clientSecret: string;
appBundleIdentifier?: string;
tenantId?: string;
requireSelectAccount?: boolean;
clientKey?: string;
issuer?: string;
// Google-specific optional hints
hostedDomain?: string;
hd?: string;
}
>
>((acc, provider) => {
const id = process.env[`${provider.toUpperCase()}_CLIENT_ID`];
const secret = process.env[`${provider.toUpperCase()}_CLIENT_SECRET`];
if (id && id.length > 0 && secret && secret.length > 0) {
acc[provider] = { clientId: id, clientSecret: secret };
}
if (
provider === "apple" &&
Object.keys(acc).includes("apple") &&
acc[provider]
) {
const bundleId =
process.env[`${provider.toUpperCase()}_APP_BUNDLE_IDENTIFIER`];
if (bundleId && bundleId.length > 0) {
acc[provider].appBundleIdentifier = bundleId;
}
}
if (
provider === "gitlab" &&
Object.keys(acc).includes("gitlab") &&
acc[provider]
) {
const issuer = process.env[`${provider.toUpperCase()}_ISSUER`];
if (issuer && issuer.length > 0) {
acc[provider].issuer = issuer;
}
}
if (
provider === "microsoft" &&
Object.keys(acc).includes("microsoft") &&
acc[provider]
) {
acc[provider].tenantId = "common";
acc[provider].requireSelectAccount = true;
}
// Add Google domain hint if allowed domains is configured
if (
provider === "google" &&
Object.keys(acc).includes("google") &&
acc[provider]
) {
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS?.split(",")
.map((d) => d.trim().toLowerCase())
.filter(Boolean);
if (allowed && allowed.length > 0) {
// Use the first domain as an authorization hint
acc[provider].hostedDomain = allowed[0];
acc[provider].hd = allowed[0];
}
}
if (
provider === "tiktok" &&
Object.keys(acc).includes("tiktok") &&
acc[provider]
) {
const key = process.env[`${provider.toUpperCase()}_CLIENT_KEY`];
if (key && key.length > 0) {
acc[provider].clientKey = key;
}
}
return acc;
}, {});
export const socialProvidersPlugin = () => ({
id: "social-providers-plugin",
endpoints: {
getSocialProviders: createAuthEndpoint(
"/social-providers",
{
method: "GET",
},
async (ctx) => {
const providers = ctx.context.socialProviders.map((p) =>
p.id.toLowerCase(),
);
// Add OIDC provider if configured
if (
process.env.OIDC_CLIENT_ID &&
process.env.OIDC_CLIENT_SECRET &&
process.env.OIDC_DISCOVERY_URL
) {
providers.push("oidc");
}
return ctx.json(providers);
},
),
},
});

View File

@@ -0,0 +1,49 @@
import type { Subscription } from "@better-auth/stripe";
import type Stripe from "stripe";
import type { dbClient } from "@kan/db/client";
import * as userRepo from "@kan/db/repository/user.repo";
import { notificationClient } from "@kan/email";
import { createEmailUnsubscribeLink } from "@kan/shared";
export async function downloadImage(url: string): Promise<Buffer> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to download image: ${response.statusText}`);
}
return Buffer.from(await response.arrayBuffer());
}
export async function triggerWorkflow(
db: dbClient,
workflowId: string,
subscription: Subscription,
cancellationDetails?: Stripe.Subscription.CancellationDetails | null,
) {
try {
if (!subscription.stripeCustomerId || !notificationClient) return;
const user = await userRepo.getByStripeCustomerId(
db,
subscription.stripeCustomerId,
);
if (!user || !notificationClient) return;
const unsubscribeUrl = await createEmailUnsubscribeLink(user.id);
await notificationClient.trigger({
to: {
subscriberId: user.id,
},
payload: {
...subscription,
cancellationDetails,
emailUnsubscribeUrl: unsubscribeUrl,
},
workflowId,
});
} catch (error) {
console.error("Error triggering workflow", error);
}
}

View File

@@ -0,0 +1 @@
ALTER TABLE "workspace" ADD COLUMN "showEmailsToMembers" boolean NOT NULL DEFAULT true;

View File

@@ -155,6 +155,13 @@
"when": 1767045713686,
"tag": "20251229220153_UpdateCardTitleFromVarcharToText",
"breakpoints": true
},
{
"idx": 22,
"version": "7",
"when": 1768858977000,
"tag": "20260119164257_AddShowEmailsToMembersToWorkspace",
"breakpoints": true
}
]
}

View File

@@ -23,6 +23,10 @@
"./repository/*": {
"types": "./dist/repository/*.d.ts",
"default": "./src/repository/*.ts"
},
"./redis": {
"types": "./dist/redis.d.ts",
"default": "./src/redis.ts"
}
},
"license": "GPL-3.0",
@@ -43,6 +47,7 @@
"@kan/shared": "workspace:^",
"drizzle-orm": "^0.42.0",
"drizzle-zod": "^0.5.1",
"ioredis": "^5.9.2",
"pg": "^8.11.3",
"uuid": "^11.1.0",
"zod": "catalog:"

31
packages/db/src/redis.ts Normal file
View File

@@ -0,0 +1,31 @@
import Redis from "ioredis";
let redisClient: Redis | null = null;
export function getRedisClient(): Redis | null {
if (redisClient) {
return redisClient;
}
const redisUrl = process.env.REDIS_URL;
if (!redisUrl) {
return null;
}
redisClient = new Redis(redisUrl, {
maxRetriesPerRequest: 3,
enableReadyCheck: true,
lazyConnect: true,
});
return redisClient;
}
export async function closeRedisClient(): Promise<void> {
if (redisClient) {
await redisClient.quit();
redisClient = null;
}
}

View File

@@ -169,6 +169,7 @@ export const getPaginatedActivities = async (
id: true,
name: true,
email: true,
image: true,
},
},
},
@@ -178,6 +179,7 @@ export const getPaginatedActivities = async (
id: true,
name: true,
email: true,
image: true,
},
},
comment: {

View File

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

View File

@@ -82,6 +82,7 @@ export const update = async (
slug?: string;
plan?: "free" | "pro" | "enterprise";
description?: string;
showEmailsToMembers?: boolean;
},
) => {
const [result] = await db
@@ -91,6 +92,7 @@ export const update = async (
slug: workspaceInput.slug,
plan: workspaceInput.plan,
description: workspaceInput.description,
showEmailsToMembers: workspaceInput.showEmailsToMembers,
})
.where(eq(workspaces.publicId, workspacePublicId))
.returning({
@@ -100,6 +102,7 @@ export const update = async (
slug: workspaces.slug,
description: workspaces.description,
plan: workspaces.plan,
showEmailsToMembers: workspaces.showEmailsToMembers,
});
return result;
@@ -139,6 +142,7 @@ export const getByPublicIdWithMembers = (
columns: {
id: true,
publicId: true,
showEmailsToMembers: true,
},
with: {
members: {

View File

@@ -43,6 +43,7 @@ export const workspaces = pgTable("workspace", {
description: text("description"),
slug: varchar("slug", { length: 255 }).notNull().unique(),
plan: workspacePlanEnum("plan").notNull().default("free"),
showEmailsToMembers: boolean("showEmailsToMembers").notNull().default(true),
createdBy: uuid("createdBy").references(() => users.id, {
onDelete: "set null",
}),

1002
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -111,9 +111,11 @@
"STRIPE_TEAM_PLAN_YEARLY_PRICE_ID",
"NEXT_PUBLIC_STORAGE_DOMAIN",
"NEXT_PUBLIC_STORAGE_URL",
"NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS",
"NEXT_PUBLIC_AVATAR_BUCKET_NAME",
"NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME",
"NEXT_PUBLIC_ALLOW_CREDENTIALS",
"NEXT_API_BODY_SIZE_LIMIT",
"NEXT_PUBLIC_DISABLE_SIGN_UP",
"NEXT_PUBLIC_USE_STANDALONE_OUTPUT",
"S3_REGION",
@@ -125,7 +127,8 @@
"BETTER_AUTH_SECRET",
"BETTER_AUTH_TRUSTED_ORIGINS",
"NOVU_API_KEY",
"EMAIL_UNSUBSCRIBE_SECRET"
"EMAIL_UNSUBSCRIBE_SECRET",
"REDIS_URL"
],
"globalPassThroughEnv": [
"NODE_ENV",