Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d147614f76 | ||
|
|
c999df15e0 | ||
|
|
908d6e298f | ||
|
|
44c4a2e269 | ||
|
|
dc060f258b | ||
|
|
3b1c9f1efb | ||
|
|
a45184995f | ||
|
|
b717663b5c | ||
|
|
0e12ba87bc | ||
|
|
ec1feadee9 | ||
|
|
2e0d8d4fed | ||
|
|
b7f0f9d3ee | ||
|
|
c303454db3 | ||
|
|
3972589f76 | ||
|
|
3c5e0ad513 | ||
|
|
384fd19203 | ||
|
|
9d1a12b0d1 | ||
|
|
24e100bd7b | ||
|
|
1da4feeb89 | ||
|
|
c0a245e11b | ||
|
|
7a15fbb465 | ||
|
|
0bfbaea49a | ||
|
|
82871ce5dc | ||
|
|
593a65dac1 | ||
|
|
92ee1ab527 | ||
|
|
e71f6cd159 | ||
|
|
0b07bfbc14 | ||
|
|
63842cd0cc | ||
|
|
9f686c6ee3 | ||
|
|
c6d8188e4e | ||
|
|
6d87e20e29 | ||
|
|
b8efb9f54b | ||
|
|
013b9886af | ||
|
|
43bff91db2 | ||
|
|
1aa3d8e5e8 | ||
|
|
4dae7e250a | ||
|
|
7e91d83f9a | ||
|
|
e11dbfe893 | ||
|
|
ea83cf3876 | ||
|
|
5ca0bffc0a | ||
|
|
64515d77cf | ||
|
|
6058dca273 | ||
|
|
d01cba4a06 | ||
|
|
98aa9f97ea | ||
|
|
9c734ec439 | ||
|
|
e663da45b1 | ||
|
|
f52dffdaac | ||
|
|
e572506d4f | ||
|
|
76df6f66d9 |
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,3 +1,64 @@
|
||||
## [0.24.1](https://github.com/stonith404/pingvin-share/compare/v0.24.0...v0.24.1) (2024-05-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* error on admin share management page if a share was created by an anonymous user ([c999df1](https://github.com/stonith404/pingvin-share/commit/c999df15e04a927f6e952db3c807b9591fb14894))
|
||||
|
||||
## [0.24.0](https://github.com/stonith404/pingvin-share/compare/v0.23.1...v0.24.0) (2024-05-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add admin-exclusive share-management page ([#461](https://github.com/stonith404/pingvin-share/issues/461)) ([3b1c9f1](https://github.com/stonith404/pingvin-share/commit/3b1c9f1efb7d02469e92537a2d1378b6cb412878))
|
||||
* add name property to share ([#462](https://github.com/stonith404/pingvin-share/issues/462)) ([b717663](https://github.com/stonith404/pingvin-share/commit/b717663b5c3a4a98e361e7e39b680f4852537c59))
|
||||
|
||||
## [0.23.1](https://github.com/stonith404/pingvin-share/compare/v0.23.0...v0.23.1) (2024-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **backend:** crash on unhandled promise rejections ([1da4fee](https://github.com/stonith404/pingvin-share/commit/1da4feeb895a13d0a0ae754bd716a84e8186d081))
|
||||
* changing the chunk size needed an app restart ([24e100b](https://github.com/stonith404/pingvin-share/commit/24e100bd7be8bf20778bdf2767aa35cae8d7e502))
|
||||
* disable js execution on raw file view ([9d1a12b](https://github.com/stonith404/pingvin-share/commit/9d1a12b0d1812214f1fe6fa56e3848091ce4945c))
|
||||
* incorrect layout on 404 page ([3c5e0ad](https://github.com/stonith404/pingvin-share/commit/3c5e0ad5134ee2d405ac420152b5825102f65bfc))
|
||||
* normal shares were added to the previous reverse share ([3972589](https://github.com/stonith404/pingvin-share/commit/3972589f76519b03074d916fb2460c795b1f0737))
|
||||
* redirect vulnerability on error, sign in and totp page ([384fd19](https://github.com/stonith404/pingvin-share/commit/384fd19203b63eeb4b952f83a9e1eaab1b19b90d))
|
||||
|
||||
## [0.23.0](https://github.com/stonith404/pingvin-share/compare/v0.22.2...v0.23.0) (2024-04-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add config variable to adjust chunk size ([0bfbaea](https://github.com/stonith404/pingvin-share/commit/0bfbaea49aad0c695fee6558c89c661687912e4f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* delete share files if user gets deleted ([e71f6cd](https://github.com/stonith404/pingvin-share/commit/e71f6cd1598ed87366074398042a6b88675587ca))
|
||||
* error in logs if "allow unauthenticated shares" is enabled ([c6d8188](https://github.com/stonith404/pingvin-share/commit/c6d8188e4e33ba682551a3ca79205ff5a6d7ead5))
|
||||
* memory leak while uploading files by disabling base64 encoding of chunks ([7a15fbb](https://github.com/stonith404/pingvin-share/commit/7a15fbb4651c2fee32fb4c1ee2c9d7f12323feb0))
|
||||
|
||||
## [0.22.2](https://github.com/stonith404/pingvin-share/compare/v0.22.1...v0.22.2) (2024-02-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* extend access token cookie expiration ([013b988](https://github.com/stonith404/pingvin-share/commit/013b9886af5629b2ead6000b962267afc761c612))
|
||||
* reduce refresh access token calls ([1aa3d8e](https://github.com/stonith404/pingvin-share/commit/1aa3d8e5e89b3696cc9554f41e9ce13806dde406))
|
||||
* replace Nginx with Caddy to fix "premature close" error while downloading larger files ([43bff91](https://github.com/stonith404/pingvin-share/commit/43bff91db2ba4ec68d76e601f7bc42cb7a506bc5))
|
||||
|
||||
## [0.22.1](https://github.com/stonith404/pingvin-share/compare/v0.22.0...v0.22.1) (2024-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* back links on error modals ([f52dffd](https://github.com/stonith404/pingvin-share/commit/f52dffdaac5a893804525913943f3f4f99b7c55a))
|
||||
* prevent zoom on input field click on mobile ([9c734ec](https://github.com/stonith404/pingvin-share/commit/9c734ec439aeaeebe172caa41bf531e6d8b3fac3))
|
||||
* replace middleware backend url with local backend url ([76df6f6](https://github.com/stonith404/pingvin-share/commit/76df6f66d965dd751146468abfafb0c6acd46310))
|
||||
* user `id` and `totpVerified` can't be changed by user ([e663da4](https://github.com/stonith404/pingvin-share/commit/e663da45b1d15f5e6e33118e6a28e1504688034c))
|
||||
* user enumaration on forgot password page ([64515d7](https://github.com/stonith404/pingvin-share/commit/64515d77cfc116a243d78610395ccc383ba62940))
|
||||
|
||||
## [0.22.0](https://github.com/stonith404/pingvin-share/compare/v0.21.5...v0.22.0) (2024-02-04)
|
||||
|
||||
|
||||
|
||||
15
Caddyfile
Normal file
15
Caddyfile
Normal file
@@ -0,0 +1,15 @@
|
||||
:3000 {
|
||||
# Reverse proxy for /api
|
||||
reverse_proxy /api/* http://localhost:8080 {
|
||||
header_up X-Forwarded-Host {host}:{server_port}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
}
|
||||
|
||||
# Reverse proxy for all other requests
|
||||
reverse_proxy http://localhost:3333 {
|
||||
header_up X-Forwarded-Host {host}:{server_port}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
}
|
||||
}
|
||||
17
Dockerfile
17
Dockerfile
@@ -30,12 +30,12 @@ RUN npm run build && npm prune --production
|
||||
FROM node:20-alpine AS runner
|
||||
ENV NODE_ENV=docker
|
||||
|
||||
# Alpine specific dependencies
|
||||
RUN apk update --no-cache
|
||||
RUN apk upgrade --no-cache
|
||||
RUN apk add --no-cache curl nginx
|
||||
# Install Caddy
|
||||
RUN apk update --no-cache \
|
||||
&& apk upgrade --no-cache \
|
||||
&& apk add --no-cache curl caddy
|
||||
|
||||
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY ./Caddyfile /etc/caddy/Caddyfile
|
||||
|
||||
WORKDIR /opt/app/frontend
|
||||
COPY --from=frontend-builder /opt/app/public ./public
|
||||
@@ -53,9 +53,8 @@ WORKDIR /opt/app
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
# Add a health check to ensure the container is healthy
|
||||
# Health check remains unchanged
|
||||
HEALTHCHECK --interval=10s --timeout=3s CMD curl -f http://localhost:3000/api/health || exit 1
|
||||
|
||||
# Application startup
|
||||
# HOSTNAME=0.0.0.0 fixes https://github.com/vercel/next.js/issues/51684. It can be removed as soon as the issue is fixed
|
||||
CMD cp -rn /tmp/img/* /opt/app/frontend/public/img && nginx && PORT=3333 HOSTNAME=0.0.0.0 node frontend/server.js & cd backend && npm run prod
|
||||
# Application startup updated for Caddy
|
||||
CMD cp -rn /tmp/img/* /opt/app/frontend/public/img && caddy run --config /etc/caddy/Caddyfile & PORT=3333 HOSTNAME=0.0.0.0 node frontend/server.js & cd backend && npm run prod
|
||||
13
README.md
13
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
|
||||
_Read this in another language: [Spanish](/docs/README.es.md), [English](/README.md), [Simplified Chinese](/docs/README.zh-cn.md), [日本語](/docs/README.ja-jp.md)_
|
||||
_Read this in another language: [Spanish](/docs/README.es.md), [English](/README.md), [简体中文](/docs/README.zh-cn.md), [日本語](/docs/README.ja-jp.md)_
|
||||
|
||||
---
|
||||
|
||||
@@ -60,10 +60,11 @@ pm2 start --name="pingvin-share-backend" npm -- run prod
|
||||
cd ../frontend
|
||||
npm install
|
||||
npm run build
|
||||
pm2 start --name="pingvin-share-frontend" npm -- run start
|
||||
API_URL=http://localhost:8080 # Set the URL of the backend, default: http://localhost:8080
|
||||
pm2 start --name="pingvin-share-frontend" .next/standalone/server.js
|
||||
```
|
||||
|
||||
**Uploading Large Files**: By default, Pingvin Share uses a built-in reverse proxy to reduce the installation steps. However, this reverse proxy is not optimized for uploading large files. If you wish to upload larger files, you can either use the Docker installation or set up your own reverse proxy. An example configuration for Nginx can be found in `/nginx/nginx.conf`.
|
||||
**Uploading Large Files**: By default, Pingvin Share uses a built-in reverse proxy to reduce the installation steps. However, this reverse proxy is not optimized for uploading large files. If you wish to upload larger files, you can either use the Docker installation or set up your own reverse proxy. An example configuration for Caddy can be found in `./Caddyfile`.
|
||||
|
||||
The website is now listening on `http://localhost:3000`, have fun with Pingvin Share 🐧!
|
||||
|
||||
@@ -86,6 +87,7 @@ View the [OAuth 2 guide](/docs/oauth2-guide.md) for more information.
|
||||
### Additional resources
|
||||
|
||||
- [Synology NAS installation](https://mariushosting.com/how-to-install-pingvin-share-on-your-synology-nas/)
|
||||
- [Zeabur installation](https://zeabur.com/templates/19G6OK)
|
||||
|
||||
### Upgrade to a new version
|
||||
|
||||
@@ -114,18 +116,21 @@ docker compose up -d
|
||||
|
||||
# Start the backend
|
||||
cd backend
|
||||
npm install
|
||||
npm run build
|
||||
pm2 restart pingvin-share-backend
|
||||
|
||||
# Start the frontend
|
||||
cd ../frontend
|
||||
npm install
|
||||
npm run build
|
||||
API_URL=http://localhost:8080 # Set the URL of the backend, default: http://localhost:8080
|
||||
pm2 restart pingvin-share-frontend
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
You can customize Pingvin Share by going to the configuration page in your admin dashboard.
|
||||
You can customize Pingvin Share like changing your domain by going to the configuration page in your admin dashboard `/admin/config`.
|
||||
|
||||
#### Environment variables
|
||||
|
||||
|
||||
4
backend/package-lock.json
generated
4
backend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pingvin-share-backend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pingvin-share-backend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"dependencies": {
|
||||
"@nestjs/cache-manager": "^2.1.0",
|
||||
"@nestjs/common": "^10.1.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pingvin-share-backend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"dev": "cross-env NODE_ENV=development nest start --watch",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Share" ADD COLUMN "name" TEXT;
|
||||
@@ -75,6 +75,7 @@ model Share {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
name String?
|
||||
uploadLocked Boolean @default(false)
|
||||
isZipReady Boolean @default(false)
|
||||
views Int @default(0)
|
||||
|
||||
@@ -51,6 +51,11 @@ const configVariables: ConfigVariables = {
|
||||
type: "number",
|
||||
defaultValue: "9",
|
||||
},
|
||||
chunkSize: {
|
||||
type: "number",
|
||||
defaultValue: "10000000",
|
||||
secret: false,
|
||||
},
|
||||
},
|
||||
email: {
|
||||
enableShareEmailRecipients: {
|
||||
|
||||
@@ -96,9 +96,9 @@ export class AuthController {
|
||||
|
||||
@Post("resetPassword/:email")
|
||||
@Throttle(5, 5 * 60)
|
||||
@HttpCode(204)
|
||||
@HttpCode(202)
|
||||
async requestResetPassword(@Param("email") email: string) {
|
||||
return await this.authService.requestResetPassword(email);
|
||||
this.authService.requestResetPassword(email);
|
||||
}
|
||||
|
||||
@Post("resetPassword")
|
||||
|
||||
@@ -99,7 +99,7 @@ export class AuthService {
|
||||
include: { resetPasswordToken: true },
|
||||
});
|
||||
|
||||
if (!user) throw new BadRequestException("User not found");
|
||||
if (!user) return;
|
||||
|
||||
// Delete old reset password token
|
||||
if (user.resetPasswordToken) {
|
||||
@@ -139,7 +139,7 @@ export class AuthService {
|
||||
|
||||
async updatePassword(user: User, newPassword: string, oldPassword?: string) {
|
||||
const isPasswordValid =
|
||||
!user.password || await argon.verify(user.password, oldPassword);
|
||||
!user.password || (await argon.verify(user.password, oldPassword));
|
||||
|
||||
if (!isPasswordValid) throw new ForbiddenException("Invalid password");
|
||||
|
||||
@@ -227,13 +227,16 @@ export class AuthService {
|
||||
accessToken?: string,
|
||||
) {
|
||||
if (accessToken)
|
||||
response.cookie("access_token", accessToken, { sameSite: "lax" });
|
||||
response.cookie("access_token", accessToken, {
|
||||
sameSite: "lax",
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30 * 3, // 3 months
|
||||
});
|
||||
if (refreshToken)
|
||||
response.cookie("refresh_token", refreshToken, {
|
||||
path: "/api/auth/token",
|
||||
httpOnly: true,
|
||||
sameSite: "strict",
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30 * 3,
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30 * 3, // 3 months
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -26,18 +26,21 @@ export class FileController {
|
||||
@SkipThrottle()
|
||||
@UseGuards(CreateShareGuard, ShareOwnerGuard)
|
||||
async create(
|
||||
@Query() query: any,
|
||||
|
||||
@Query()
|
||||
query: {
|
||||
id: string;
|
||||
name: string;
|
||||
chunkIndex: string;
|
||||
totalChunks: string;
|
||||
},
|
||||
@Body() body: string,
|
||||
@Param("shareId") shareId: string,
|
||||
) {
|
||||
const { id, name, chunkIndex, totalChunks } = query;
|
||||
|
||||
// Data can be empty if the file is empty
|
||||
const data = body.toString().split(",")[1] ?? "";
|
||||
|
||||
return await this.fileService.create(
|
||||
data,
|
||||
body,
|
||||
{ index: parseInt(chunkIndex), total: parseInt(totalChunks) },
|
||||
{ id, name },
|
||||
shareId,
|
||||
@@ -72,6 +75,7 @@ export class FileController {
|
||||
const headers = {
|
||||
"Content-Type": file.metaData.mimeType,
|
||||
"Content-Length": file.metaData.size,
|
||||
"Content-Security-Policy": "script-src 'none'",
|
||||
};
|
||||
|
||||
if (download === "true") {
|
||||
|
||||
@@ -47,7 +47,7 @@ export class FileService {
|
||||
}
|
||||
|
||||
// If the sent chunk index and the expected chunk index doesn't match throw an error
|
||||
const chunkSize = 10 * 1024 * 1024; // 10MB
|
||||
const chunkSize = this.config.get("share.chunkSize");
|
||||
const expectedChunkIndex = Math.ceil(diskFileSize / chunkSize);
|
||||
|
||||
if (expectedChunkIndex != chunk.index)
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { ClassSerializerInterceptor, ValidationPipe } from "@nestjs/common";
|
||||
import {
|
||||
ClassSerializerInterceptor,
|
||||
Logger,
|
||||
ValidationPipe,
|
||||
} from "@nestjs/common";
|
||||
import { NestFactory, Reflector } from "@nestjs/core";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
||||
import * as bodyParser from "body-parser";
|
||||
import * as cookieParser from "cookie-parser";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import * as fs from "fs";
|
||||
import { AppModule } from "./app.module";
|
||||
import { ConfigService } from "./config/config.service";
|
||||
import { DATA_DIRECTORY } from "./constants";
|
||||
|
||||
async function bootstrap() {
|
||||
@@ -13,7 +19,16 @@ async function bootstrap() {
|
||||
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
|
||||
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
||||
|
||||
app.use(bodyParser.raw({ type: "application/octet-stream", limit: "20mb" }));
|
||||
const config = app.get<ConfigService>(ConfigService);
|
||||
|
||||
app.use((req: Request, res: Response, next: NextFunction) => {
|
||||
const chunkSize = config.get("share.chunkSize");
|
||||
bodyParser.raw({
|
||||
type: "application/octet-stream",
|
||||
limit: `${chunkSize}B`,
|
||||
})(req, res, next);
|
||||
});
|
||||
|
||||
app.use(cookieParser());
|
||||
app.set("trust proxy", true);
|
||||
|
||||
@@ -34,5 +49,8 @@ async function bootstrap() {
|
||||
}
|
||||
|
||||
await app.listen(parseInt(process.env.PORT) || 8080);
|
||||
|
||||
const logger = new Logger("UnhandledAsyncError");
|
||||
process.on("unhandledRejection", (e) => logger.error(e));
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
@@ -13,7 +13,7 @@ export class ReverseShareTokenWithShares extends OmitType(ReverseShareDTO, [
|
||||
@Type(() => OmitType(MyShareDTO, ["recipients", "hasPassword"] as const))
|
||||
shares: Omit<
|
||||
MyShareDTO,
|
||||
"recipients" | "files" | "from" | "fromList" | "hasPassword"
|
||||
"recipients" | "files" | "from" | "fromList" | "hasPassword" | "size"
|
||||
>[];
|
||||
|
||||
@Expose()
|
||||
|
||||
27
backend/src/share/dto/adminShare.dto.ts
Normal file
27
backend/src/share/dto/adminShare.dto.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { OmitType } from "@nestjs/swagger";
|
||||
import { Expose, plainToClass } from "class-transformer";
|
||||
import { ShareDTO } from "./share.dto";
|
||||
|
||||
export class AdminShareDTO extends OmitType(ShareDTO, [
|
||||
"files",
|
||||
"from",
|
||||
"fromList",
|
||||
] as const) {
|
||||
@Expose()
|
||||
views: number;
|
||||
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
from(partial: Partial<AdminShareDTO>) {
|
||||
return plainToClass(AdminShareDTO, partial, {
|
||||
excludeExtraneousValues: true,
|
||||
});
|
||||
}
|
||||
|
||||
fromList(partial: Partial<AdminShareDTO>[]) {
|
||||
return partial.map((part) =>
|
||||
plainToClass(AdminShareDTO, part, { excludeExtraneousValues: true }),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,10 @@ export class CreateShareDTO {
|
||||
@Length(3, 50)
|
||||
id: string;
|
||||
|
||||
@Length(3, 30)
|
||||
@IsOptional()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
expiration: string;
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ export class ShareDTO {
|
||||
@Expose()
|
||||
id: string;
|
||||
|
||||
@Expose()
|
||||
name?: string;
|
||||
|
||||
@Expose()
|
||||
expiration: Date;
|
||||
|
||||
@@ -23,6 +26,9 @@ export class ShareDTO {
|
||||
@Expose()
|
||||
hasPassword: boolean;
|
||||
|
||||
@Expose()
|
||||
size: number;
|
||||
|
||||
from(partial: Partial<ShareDTO>) {
|
||||
return plainToClass(ShareDTO, partial, { excludeExtraneousValues: true });
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Throttle } from "@nestjs/throttler";
|
||||
import { User } from "@prisma/client";
|
||||
import { Request, Response } from "express";
|
||||
import { GetUser } from "src/auth/decorator/getUser.decorator";
|
||||
import { AdministratorGuard } from "src/auth/guard/isAdmin.guard";
|
||||
import { JwtGuard } from "src/auth/guard/jwt.guard";
|
||||
import { CreateShareDTO } from "./dto/createShare.dto";
|
||||
import { MyShareDTO } from "./dto/myShare.dto";
|
||||
@@ -25,10 +26,17 @@ import { ShareOwnerGuard } from "./guard/shareOwner.guard";
|
||||
import { ShareSecurityGuard } from "./guard/shareSecurity.guard";
|
||||
import { ShareTokenSecurity } from "./guard/shareTokenSecurity.guard";
|
||||
import { ShareService } from "./share.service";
|
||||
import { AdminShareDTO } from "./dto/adminShare.dto";
|
||||
@Controller("shares")
|
||||
export class ShareController {
|
||||
constructor(private shareService: ShareService) {}
|
||||
|
||||
@Get("all")
|
||||
@UseGuards(JwtGuard, AdministratorGuard)
|
||||
async getAllShares() {
|
||||
return new AdminShareDTO().fromList(await this.shareService.getShares());
|
||||
}
|
||||
|
||||
@Get()
|
||||
@UseGuards(JwtGuard)
|
||||
async getMyShares(@GetUser() user: User) {
|
||||
|
||||
@@ -194,6 +194,22 @@ export class ShareService {
|
||||
});
|
||||
}
|
||||
|
||||
async getShares() {
|
||||
const shares = await this.prisma.share.findMany({
|
||||
orderBy: {
|
||||
expiration: "desc",
|
||||
},
|
||||
include: { files: true, creator: true },
|
||||
});
|
||||
|
||||
return shares.map((share) => {
|
||||
return {
|
||||
...share,
|
||||
size: share.files.reduce((acc, file) => acc + parseInt(file.size), 0),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async getSharesByUser(userId: string) {
|
||||
const shares = await this.prisma.share.findMany({
|
||||
where: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OmitType, PartialType } from "@nestjs/swagger";
|
||||
import { PartialType, PickType } from "@nestjs/swagger";
|
||||
import { UserDTO } from "./user.dto";
|
||||
|
||||
export class UpdateOwnUserDTO extends PartialType(
|
||||
OmitType(UserDTO, ["isAdmin", "password"] as const),
|
||||
PickType(UserDTO, ["username", "email"] as const),
|
||||
) {}
|
||||
|
||||
@@ -27,7 +27,8 @@ export class UserController {
|
||||
// Own user operations
|
||||
@Get("me")
|
||||
@UseGuards(JwtGuard)
|
||||
async getCurrentUser(@GetUser() user: User) {
|
||||
async getCurrentUser(@GetUser() user?: User) {
|
||||
if (!user) return null;
|
||||
const userDTO = new UserDTO().from(user);
|
||||
userDTO.hasPassword = !!user.password;
|
||||
return userDTO;
|
||||
|
||||
@@ -2,9 +2,10 @@ import { Module } from "@nestjs/common";
|
||||
import { EmailModule } from "src/email/email.module";
|
||||
import { UserController } from "./user.controller";
|
||||
import { UserSevice } from "./user.service";
|
||||
import { FileModule } from "src/file/file.module";
|
||||
|
||||
@Module({
|
||||
imports: [EmailModule],
|
||||
imports: [EmailModule, FileModule],
|
||||
providers: [UserSevice],
|
||||
controllers: [UserController],
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as argon from "argon2";
|
||||
import * as crypto from "crypto";
|
||||
import { EmailService } from "src/email/email.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { FileService } from "../file/file.service";
|
||||
import { CreateUserDTO } from "./dto/createUser.dto";
|
||||
import { UpdateUserDto } from "./dto/updateUser.dto";
|
||||
|
||||
@@ -12,6 +13,7 @@ export class UserSevice {
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
private emailService: EmailService,
|
||||
private fileService: FileService,
|
||||
) {}
|
||||
|
||||
async list() {
|
||||
@@ -74,6 +76,16 @@ export class UserSevice {
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: { shares: true },
|
||||
});
|
||||
if (!user) throw new BadRequestException("User not found");
|
||||
|
||||
await Promise.all(
|
||||
user.shares.map((share) => this.fileService.deleteAllFiles(share.id)),
|
||||
);
|
||||
|
||||
return await this.prisma.user.delete({ where: { id } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@
|
||||
" const responseBody = pm.response.json();",
|
||||
" pm.expect(responseBody).to.have.property(\"id\")",
|
||||
" pm.expect(responseBody).to.have.property(\"expiration\")",
|
||||
" pm.expect(Object.keys(responseBody).length).be.equal(3)",
|
||||
" pm.expect(Object.keys(responseBody).length).be.equal(4)",
|
||||
"});",
|
||||
""
|
||||
],
|
||||
@@ -626,7 +626,7 @@
|
||||
" const responseBody = pm.response.json();",
|
||||
" pm.expect(responseBody).to.have.property(\"id\")",
|
||||
" pm.expect(responseBody).to.have.property(\"expiration\")",
|
||||
" pm.expect(Object.keys(responseBody).length).be.equal(3)",
|
||||
" pm.expect(Object.keys(responseBody).length).be.equal(4)",
|
||||
"});",
|
||||
""
|
||||
],
|
||||
|
||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pingvin-share-frontend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pingvin-share-frontend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/server": "^11.11.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pingvin-share-frontend",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
|
||||
@@ -17,13 +17,9 @@ const showShareInformationsModal = (
|
||||
const t = translateOutsideContext();
|
||||
const link = `${appUrl}/s/${share.id}`;
|
||||
|
||||
let shareSize: number = 0;
|
||||
for (let file of share.files as FileMetaData[])
|
||||
shareSize += parseInt(file.size);
|
||||
|
||||
const formattedShareSize = byteToHumanSizeString(shareSize);
|
||||
const formattedShareSize = byteToHumanSizeString(share.size);
|
||||
const formattedMaxShareSize = byteToHumanSizeString(maxShareSize);
|
||||
const shareSizeProgress = (shareSize / maxShareSize) * 100;
|
||||
const shareSizeProgress = (share.size / maxShareSize) * 100;
|
||||
|
||||
const formattedCreatedAt = moment(share.createdAt).format("LLL");
|
||||
const formattedExpiration =
|
||||
@@ -42,12 +38,18 @@ const showShareInformationsModal = (
|
||||
</b>
|
||||
{share.id}
|
||||
</Text>
|
||||
<Text size="sm">
|
||||
<b>
|
||||
<FormattedMessage id="account.shares.table.name" />:{" "}
|
||||
</b>
|
||||
{share.name || "-"}
|
||||
</Text>
|
||||
|
||||
<Text size="sm">
|
||||
<b>
|
||||
<FormattedMessage id="account.shares.table.description" />:{" "}
|
||||
</b>
|
||||
{share.description || "No description"}
|
||||
{share.description || "-"}
|
||||
</Text>
|
||||
|
||||
<Text size="sm">
|
||||
@@ -75,15 +77,15 @@ const showShareInformationsModal = (
|
||||
</Text>
|
||||
|
||||
<Flex align="center" justify="center">
|
||||
{shareSize / maxShareSize < 0.1 && (
|
||||
{share.size / maxShareSize < 0.1 && (
|
||||
<Text size="xs" style={{ marginRight: "4px" }}>
|
||||
{formattedShareSize}
|
||||
</Text>
|
||||
)}
|
||||
<Progress
|
||||
value={shareSizeProgress}
|
||||
label={shareSize / maxShareSize >= 0.1 ? formattedShareSize : ""}
|
||||
style={{ width: shareSize / maxShareSize < 0.1 ? "70%" : "80%" }}
|
||||
label={share.size / maxShareSize >= 0.1 ? formattedShareSize : ""}
|
||||
style={{ width: share.size / maxShareSize < 0.1 ? "70%" : "80%" }}
|
||||
size="xl"
|
||||
radius="xl"
|
||||
/>
|
||||
|
||||
149
frontend/src/components/admin/shares/ManageShareTable.tsx
Normal file
149
frontend/src/components/admin/shares/ManageShareTable.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
Box,
|
||||
Group,
|
||||
MediaQuery,
|
||||
Skeleton,
|
||||
Table,
|
||||
Text,
|
||||
} from "@mantine/core";
|
||||
import { useClipboard } from "@mantine/hooks";
|
||||
import { useModals } from "@mantine/modals";
|
||||
import moment from "moment";
|
||||
import { TbLink, TbTrash } from "react-icons/tb";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import useConfig from "../../../hooks/config.hook";
|
||||
import useTranslate from "../../../hooks/useTranslate.hook";
|
||||
import { MyShare } from "../../../types/share.type";
|
||||
import { byteToHumanSizeString } from "../../../utils/fileSize.util";
|
||||
import toast from "../../../utils/toast.util";
|
||||
import showShareLinkModal from "../../account/showShareLinkModal";
|
||||
|
||||
const ManageShareTable = ({
|
||||
shares,
|
||||
deleteShare,
|
||||
isLoading,
|
||||
}: {
|
||||
shares: MyShare[];
|
||||
deleteShare: (share: MyShare) => void;
|
||||
isLoading: boolean;
|
||||
}) => {
|
||||
const modals = useModals();
|
||||
const clipboard = useClipboard();
|
||||
const config = useConfig();
|
||||
const t = useTranslate();
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "block", overflowX: "auto" }}>
|
||||
<Table verticalSpacing="sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.id" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.name" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="admin.shares.table.username" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.visitors" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.size" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.expiresAt" />
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{isLoading
|
||||
? skeletonRows
|
||||
: shares.map((share) => (
|
||||
<tr key={share.id}>
|
||||
<td>{share.id}</td>
|
||||
<td>{share.name}</td>
|
||||
<td>
|
||||
{share.creator ? (
|
||||
share.creator.username
|
||||
) : (
|
||||
<Text color="dimmed">Anonymous</Text>
|
||||
)}
|
||||
</td>
|
||||
<td>{share.views}</td>
|
||||
<td>{byteToHumanSizeString(share.size)}</td>
|
||||
<td>
|
||||
{moment(share.expiration).unix() === 0
|
||||
? "Never"
|
||||
: moment(share.expiration).format("LLL")}
|
||||
</td>
|
||||
<td>
|
||||
<Group position="right">
|
||||
<ActionIcon
|
||||
color="victoria"
|
||||
variant="light"
|
||||
size={25}
|
||||
onClick={() => {
|
||||
if (window.isSecureContext) {
|
||||
clipboard.copy(
|
||||
`${config.get("general.appUrl")}/s/${share.id}`,
|
||||
);
|
||||
toast.success(t("common.notify.copied"));
|
||||
} else {
|
||||
showShareLinkModal(
|
||||
modals,
|
||||
share.id,
|
||||
config.get("general.appUrl"),
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TbLink />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="red"
|
||||
size="sm"
|
||||
onClick={() => deleteShare(share)}
|
||||
>
|
||||
<TbTrash />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const skeletonRows = [...Array(10)].map((v, i) => (
|
||||
<tr key={i}>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
<MediaQuery smallerThan="md" styles={{ display: "none" }}>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
</MediaQuery>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
<td>
|
||||
<Skeleton key={i} height={20} />
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
|
||||
export default ManageShareTable;
|
||||
@@ -25,6 +25,7 @@ import useTranslate from "../../hooks/useTranslate.hook";
|
||||
import authService from "../../services/auth.service";
|
||||
import { getOAuthIcon, getOAuthUrl } from "../../utils/oauth.util";
|
||||
import toast from "../../utils/toast.util";
|
||||
import { safeRedirectPath } from "../../utils/router.util";
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
or: {
|
||||
@@ -98,7 +99,7 @@ const SignInForm = ({ redirectPath }: { redirectPath: string }) => {
|
||||
);
|
||||
} else {
|
||||
await refreshUser();
|
||||
router.replace(redirectPath);
|
||||
router.replace(safeRedirectPath(redirectPath));
|
||||
}
|
||||
})
|
||||
.catch(toast.axiosError);
|
||||
|
||||
@@ -6,15 +6,16 @@ import {
|
||||
PinInput,
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
import { useForm, yupResolver } from "@mantine/form";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import * as yup from "yup";
|
||||
import useTranslate from "../../hooks/useTranslate.hook";
|
||||
import { useForm, yupResolver } from "@mantine/form";
|
||||
import { useState } from "react";
|
||||
import authService from "../../services/auth.service";
|
||||
import toast from "../../utils/toast.util";
|
||||
import { useRouter } from "next/router";
|
||||
import useUser from "../../hooks/user.hook";
|
||||
import authService from "../../services/auth.service";
|
||||
import { safeRedirectPath } from "../../utils/router.util";
|
||||
import toast from "../../utils/toast.util";
|
||||
|
||||
function TotpForm({ redirectPath }: { redirectPath: string }) {
|
||||
const t = useTranslate();
|
||||
@@ -46,7 +47,7 @@ function TotpForm({ redirectPath }: { redirectPath: string }) {
|
||||
router.query.loginToken as string,
|
||||
);
|
||||
await refreshUser();
|
||||
await router.replace(redirectPath);
|
||||
await router.replace(safeRedirectPath(redirectPath));
|
||||
} catch (e) {
|
||||
toast.axiosError(e);
|
||||
form.setFieldError("code", "error");
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { Button, Center, Stack, Text, Title, useMantineTheme } from "@mantine/core";
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
useMantineTheme,
|
||||
} from "@mantine/core";
|
||||
import { modals } from "@mantine/modals";
|
||||
import Link from "next/link";
|
||||
import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||
@@ -116,41 +123,38 @@ const ImagePreview = () => {
|
||||
|
||||
const TextPreview = () => {
|
||||
const { shareId, fileId } = React.useContext(FilePreviewContext);
|
||||
const [ text, setText ] = useState<string>("");
|
||||
const [text, setText] = useState<string>("");
|
||||
const { colorScheme } = useMantineTheme();
|
||||
|
||||
useEffect(() => {
|
||||
api
|
||||
.get(`/shares/${shareId}/files/${fileId}?download=false`)
|
||||
.then((res) => setText(res.data ?? "Preview couldn't be fetched."));
|
||||
}, [ shareId, fileId ]);
|
||||
}, [shareId, fileId]);
|
||||
|
||||
const options = {
|
||||
overrides: {
|
||||
pre: {
|
||||
props: {
|
||||
style: {
|
||||
backgroundColor: colorScheme == "dark"
|
||||
? "rgba(50, 50, 50, 0.5)"
|
||||
: "rgba(220, 220, 220, 0.5)",
|
||||
backgroundColor:
|
||||
colorScheme == "dark"
|
||||
? "rgba(50, 50, 50, 0.5)"
|
||||
: "rgba(220, 220, 220, 0.5)",
|
||||
padding: "0.75em",
|
||||
whiteSpace: "pre-wrap",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
table: {
|
||||
props: {
|
||||
className: "md"
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "md",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Markdown options={options}>
|
||||
{text}
|
||||
</Markdown>
|
||||
);
|
||||
return <Markdown options={options}>{text}</Markdown>;
|
||||
};
|
||||
|
||||
const PdfPreview = () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ const showErrorModal = (
|
||||
modals: ModalsContextProps,
|
||||
title: string,
|
||||
text: string,
|
||||
action: "go-back" | "go-home" = "go-back",
|
||||
) => {
|
||||
return modals.openModal({
|
||||
closeOnClickOutside: false,
|
||||
@@ -15,11 +16,17 @@ const showErrorModal = (
|
||||
closeOnEscape: false,
|
||||
title: title,
|
||||
|
||||
children: <Body text={text} />,
|
||||
children: <Body text={text} action={action} />,
|
||||
});
|
||||
};
|
||||
|
||||
const Body = ({ text }: { text: string }) => {
|
||||
const Body = ({
|
||||
text,
|
||||
action,
|
||||
}: {
|
||||
text: string;
|
||||
action: "go-back" | "go-home";
|
||||
}) => {
|
||||
const modals = useModals();
|
||||
const router = useRouter();
|
||||
return (
|
||||
@@ -29,10 +36,14 @@ const Body = ({ text }: { text: string }) => {
|
||||
<Button
|
||||
onClick={() => {
|
||||
modals.closeAll();
|
||||
router.back();
|
||||
if (action === "go-back") {
|
||||
router.back();
|
||||
} else if (action === "go-home") {
|
||||
router.push("/");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormattedMessage id="common.button.go-back" />
|
||||
<FormattedMessage id={`common.button.${action}`} />
|
||||
</Button>
|
||||
</Stack>
|
||||
</>
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import { Button, Group } from "@mantine/core";
|
||||
import { useModals } from "@mantine/modals";
|
||||
import { cleanNotifications } from "@mantine/notifications";
|
||||
import { AxiosError } from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import pLimit from "p-limit";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Dropzone from "../../components/upload/Dropzone";
|
||||
import FileList from "../../components/upload/FileList";
|
||||
import showCompletedUploadModal from "../../components/upload/modals/showCompletedUploadModal";
|
||||
import useConfig from "../../hooks/config.hook";
|
||||
import useTranslate from "../../hooks/useTranslate.hook";
|
||||
import shareService from "../../services/share.service";
|
||||
import { FileListItem, FileMetaData, FileUpload } from "../../types/File.type";
|
||||
import toast from "../../utils/toast.util";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const promiseLimit = pLimit(3);
|
||||
const chunkSize = 10 * 1024 * 1024; // 10MB
|
||||
let errorToastShown = false;
|
||||
|
||||
const EditableUpload = ({
|
||||
@@ -33,6 +30,8 @@ const EditableUpload = ({
|
||||
const router = useRouter();
|
||||
const config = useConfig();
|
||||
|
||||
const chunkSize = useRef(parseInt(config.get("share.chunkSize")));
|
||||
|
||||
const [existingFiles, setExistingFiles] =
|
||||
useState<Array<FileMetaData & { deleted?: boolean }>>(savedFiles);
|
||||
const [uploadingFiles, setUploadingFiles] = useState<FileUpload[]>([]);
|
||||
@@ -66,7 +65,7 @@ const EditableUpload = ({
|
||||
const fileUploadPromises = files.map(async (file, fileIndex) =>
|
||||
// Limit the number of concurrent uploads to 3
|
||||
promiseLimit(async () => {
|
||||
let fileId: string;
|
||||
let fileId: string | undefined;
|
||||
|
||||
const setFileProgress = (progress: number) => {
|
||||
setUploadingFiles((files) =>
|
||||
@@ -81,38 +80,30 @@ const EditableUpload = ({
|
||||
|
||||
setFileProgress(1);
|
||||
|
||||
let chunks = Math.ceil(file.size / chunkSize);
|
||||
let chunks = Math.ceil(file.size / chunkSize.current);
|
||||
|
||||
// If the file is 0 bytes, we still need to upload 1 chunk
|
||||
if (chunks == 0) chunks++;
|
||||
|
||||
for (let chunkIndex = 0; chunkIndex < chunks; chunkIndex++) {
|
||||
const from = chunkIndex * chunkSize;
|
||||
const to = from + chunkSize;
|
||||
const from = chunkIndex * chunkSize.current;
|
||||
const to = from + chunkSize.current;
|
||||
const blob = file.slice(from, to);
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async (event) =>
|
||||
await shareService
|
||||
.uploadFile(
|
||||
shareId,
|
||||
event,
|
||||
{
|
||||
id: fileId,
|
||||
name: file.name,
|
||||
},
|
||||
chunkIndex,
|
||||
chunks,
|
||||
)
|
||||
.then((response) => {
|
||||
fileId = response.id;
|
||||
resolve(response);
|
||||
})
|
||||
.catch(reject);
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
await shareService
|
||||
.uploadFile(
|
||||
shareId,
|
||||
blob,
|
||||
{
|
||||
id: fileId,
|
||||
name: file.name,
|
||||
},
|
||||
chunkIndex,
|
||||
chunks,
|
||||
)
|
||||
.then((response) => {
|
||||
fileId = response.id;
|
||||
});
|
||||
|
||||
setFileProgress(((chunkIndex + 1) / chunks) * 100);
|
||||
} catch (e) {
|
||||
|
||||
@@ -92,11 +92,16 @@ const CreateUploadModalBody = ({
|
||||
.matches(new RegExp("^[a-zA-Z0-9_-]*$"), {
|
||||
message: t("upload.modal.link.error.invalid"),
|
||||
}),
|
||||
name: yup
|
||||
.string()
|
||||
.transform((value) => value || undefined)
|
||||
.min(3, t("common.error.too-short", { length: 3 }))
|
||||
.max(30, t("common.error.too-long", { length: 30 })),
|
||||
password: yup
|
||||
.string()
|
||||
.transform((value) => value || undefined)
|
||||
.min(3)
|
||||
.max(30),
|
||||
.min(3, t("common.error.too-short", { length: 3 }))
|
||||
.max(30, t("common.error.too-long", { length: 30 })),
|
||||
maxViews: yup
|
||||
.number()
|
||||
.transform((value) => value || undefined)
|
||||
@@ -105,6 +110,7 @@ const CreateUploadModalBody = ({
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: undefined,
|
||||
link: generatedLink,
|
||||
recipients: [] as string[],
|
||||
password: undefined,
|
||||
@@ -154,6 +160,7 @@ const CreateUploadModalBody = ({
|
||||
uploadCallback(
|
||||
{
|
||||
id: values.link,
|
||||
name: values.name,
|
||||
expiration: expirationString,
|
||||
recipients: values.recipients,
|
||||
description: values.description,
|
||||
@@ -308,14 +315,21 @@ const CreateUploadModalBody = ({
|
||||
<Accordion>
|
||||
<Accordion.Item value="description" sx={{ borderBottom: "none" }}>
|
||||
<Accordion.Control>
|
||||
<FormattedMessage id="upload.modal.accordion.description.title" />
|
||||
<FormattedMessage id="upload.modal.accordion.name-and-description.title" />
|
||||
</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
<Stack align="stretch">
|
||||
<TextInput
|
||||
variant="filled"
|
||||
placeholder={t(
|
||||
"upload.modal.accordion.name-and-description.name.placeholder",
|
||||
)}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
<Textarea
|
||||
variant="filled"
|
||||
placeholder={t(
|
||||
"upload.modal.accordion.description.placeholder",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder",
|
||||
)}
|
||||
{...form.getInputProps("description")}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import arabic from "./translations/ar-EG";
|
||||
import danish from "./translations/da-DK";
|
||||
import german from "./translations/de-DE";
|
||||
import greek from "./translations/el-GR";
|
||||
@@ -5,8 +6,10 @@ import english from "./translations/en-US";
|
||||
import spanish from "./translations/es-ES";
|
||||
import finnish from "./translations/fi-FI";
|
||||
import french from "./translations/fr-FR";
|
||||
import hungarian from "./translations/hu-HU";
|
||||
import italian from "./translations/it-IT";
|
||||
import japanese from "./translations/ja-JP";
|
||||
import korean from "./translations/ko-KR";
|
||||
import dutch from "./translations/nl-BE";
|
||||
import polish from "./translations/pl-PL";
|
||||
import portuguese from "./translations/pt-BR";
|
||||
@@ -15,6 +18,7 @@ import slovenian from "./translations/sl-SI";
|
||||
import serbian from "./translations/sr-SP";
|
||||
import swedish from "./translations/sv-SE";
|
||||
import thai from "./translations/th-TH";
|
||||
import ukrainian from "./translations/uk-UA";
|
||||
import chineseSimplified from "./translations/zh-CN";
|
||||
import chineseTraditional from "./translations/zh-TW";
|
||||
|
||||
@@ -69,6 +73,11 @@ export const LOCALES = {
|
||||
code: "ru-RU",
|
||||
messages: russian,
|
||||
},
|
||||
UKRAINIAN: {
|
||||
name: "Українська",
|
||||
code: "uk-UA",
|
||||
messages: ukrainian,
|
||||
},
|
||||
THAI: {
|
||||
name: "ไทย",
|
||||
code: "th-TH",
|
||||
@@ -114,4 +123,19 @@ export const LOCALES = {
|
||||
code: "sl-SI",
|
||||
messages: slovenian,
|
||||
},
|
||||
ARABIC: {
|
||||
name: "العربية",
|
||||
code: "ar-EG",
|
||||
messages: arabic,
|
||||
},
|
||||
HUNGARIAN: {
|
||||
name: "Hungarian",
|
||||
code: "hu-HU",
|
||||
messages: hungarian,
|
||||
},
|
||||
KOREAN: {
|
||||
name: "한국어",
|
||||
code: "ko-KR",
|
||||
messages: korean,
|
||||
},
|
||||
};
|
||||
|
||||
434
frontend/src/i18n/translations/ar-EG.ts
Normal file
434
frontend/src/i18n/translations/ar-EG.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
export default {
|
||||
// Navbar
|
||||
"navbar.upload": "Upload",
|
||||
"navbar.signin": "Sign in",
|
||||
"navbar.home": "Home",
|
||||
"navbar.signup": "Sign Up",
|
||||
"navbar.links.shares": "My shares",
|
||||
"navbar.links.reverse": "Reverse shares",
|
||||
"navbar.avatar.account": "My account",
|
||||
"navbar.avatar.admin": "Administration",
|
||||
"navbar.avatar.signout": "Sign out",
|
||||
// END navbar
|
||||
// /
|
||||
"home.title": "A <h>self-hosted</h> file sharing platform.",
|
||||
"home.description": "Do you really want to give your personal files in the hand of third parties like WeTransfer?",
|
||||
"home.bullet.a.name": "Self-Hosted",
|
||||
"home.bullet.a.description": "Host Pingvin Share on your own machine.",
|
||||
"home.bullet.b.name": "Privacy",
|
||||
"home.bullet.b.description": "Your files are your files and should never get into the hands of third parties.",
|
||||
"home.bullet.c.name": "No annoying file size limit",
|
||||
"home.bullet.c.description": "Upload as big files as you want. Only your hard drive will be your limit.",
|
||||
"home.button.start": "Get started",
|
||||
"home.button.source": "Source code",
|
||||
// END /
|
||||
// /auth/signin
|
||||
"signin.title": "Welcome back",
|
||||
"signin.description": "You don't have an account yet?",
|
||||
"signin.button.signup": "Sign up",
|
||||
"signin.input.email-or-username": "Email or username",
|
||||
"signin.input.email-or-username.placeholder": "Your email or username",
|
||||
"signin.input.password": "Password",
|
||||
"signin.input.password.placeholder": "Your password",
|
||||
"signin.button.submit": "Sign in",
|
||||
"signIn.notify.totp-required.title": "Two-factor authentication required",
|
||||
"signIn.notify.totp-required.description": "Please enter your two-factor authentication code",
|
||||
"signIn.oauth.or": "OR",
|
||||
"signIn.oauth.github": "GitHub",
|
||||
"signIn.oauth.google": "Google",
|
||||
"signIn.oauth.microsoft": "Microsoft",
|
||||
"signIn.oauth.discord": "Discord",
|
||||
"signIn.oauth.oidc": "OpenID",
|
||||
// END /auth/signin
|
||||
// /auth/signup
|
||||
"signup.title": "Create an account",
|
||||
"signup.description": "Already have an account?",
|
||||
"signup.button.signin": "Sign in",
|
||||
"signup.input.username": "Username",
|
||||
"signup.input.username.placeholder": "Your username",
|
||||
"signup.input.email": "Email",
|
||||
"signup.input.email.placeholder": "Your email",
|
||||
"signup.button.submit": "Let's get started",
|
||||
// END /auth/signup
|
||||
// /auth/totp
|
||||
"totp.title": "TOTP Authentication",
|
||||
"totp.button.signIn": "Sign in",
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Forgot your password?",
|
||||
"resetPassword.description": "Enter your email to reset your password.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Back to sign in page",
|
||||
"resetPassword.text.resetPassword": "Reset password",
|
||||
"resetPassword.text.enterNewPassword": "Enter your new password",
|
||||
"resetPassword.input.password": "New password",
|
||||
"resetPassword.notify.passwordReset": "Your password has been reset successfully.",
|
||||
// /account
|
||||
"account.title": "My account",
|
||||
"account.card.info.title": "Account info",
|
||||
"account.card.info.username": "Username",
|
||||
"account.card.info.email": "Email",
|
||||
"account.notify.info.success": "Account updated successfully",
|
||||
"account.card.password.title": "Password",
|
||||
"account.card.password.old": "Old password",
|
||||
"account.card.password.new": "New password",
|
||||
"account.card.password.noPasswordSet": "You don't have a password set. If you want to sign in with email and password you need to set a password.",
|
||||
"account.notify.password.success": "Password changed successfully",
|
||||
"account.card.oauth.title": "Social login",
|
||||
"account.card.oauth.github": "GitHub",
|
||||
"account.card.oauth.google": "Google",
|
||||
"account.card.oauth.microsoft": "Microsoft",
|
||||
"account.card.oauth.discord": "Discord",
|
||||
"account.card.oauth.oidc": "OpenID",
|
||||
"account.card.oauth.link": "Link",
|
||||
"account.card.oauth.unlink": "Unlink",
|
||||
"account.card.oauth.unlinked": "Unlinked",
|
||||
"account.modal.unlink.title": "Unlink account",
|
||||
"account.modal.unlink.description": "Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
|
||||
"account.notify.oauth.unlinked.success": "Unlinked successfully",
|
||||
"account.card.security.title": "Security",
|
||||
"account.card.security.totp.enable.description": "Enter your current password to start enabling TOTP",
|
||||
"account.card.security.totp.disable.description": "Enter your current password to disable TOTP",
|
||||
"account.card.security.totp.button.start": "Start",
|
||||
"account.modal.totp.title": "Enable TOTP",
|
||||
"account.modal.totp.step1": "Step 1: Add your authenticator",
|
||||
"account.modal.totp.step2": "Step 2: Validate your code",
|
||||
"account.modal.totp.enterManually": "Enter manually",
|
||||
"account.modal.totp.code": "Code",
|
||||
"account.modal.totp.clickToCopy": "Click to copy",
|
||||
"account.modal.totp.verify": "Verify",
|
||||
"account.notify.totp.disable": "TOTP disabled successfully",
|
||||
"account.notify.totp.enable": "TOTP enabled successfully",
|
||||
"account.card.language.title": "Language",
|
||||
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.",
|
||||
"account.card.color.title": "Color scheme",
|
||||
// ThemeSwitcher.tsx
|
||||
"account.theme.dark": "Dark",
|
||||
"account.theme.light": "Light",
|
||||
"account.theme.system": "System",
|
||||
"account.button.delete": "Delete Account",
|
||||
"account.modal.delete.title": "Delete Account",
|
||||
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?",
|
||||
// END /account
|
||||
// /account/shares
|
||||
"account.shares.title": "My shares",
|
||||
"account.shares.title.empty": "It's empty here 👀",
|
||||
"account.shares.description.empty": "You don't have any shares.",
|
||||
"account.shares.button.create": "Create one",
|
||||
"account.shares.info.title": "Share informations",
|
||||
"account.shares.table.id": "ID",
|
||||
"account.shares.table.name": "Name",
|
||||
"account.shares.table.description": "Description",
|
||||
"account.shares.table.visitors": "Visitors",
|
||||
"account.shares.table.expiresAt": "Expires at",
|
||||
"account.shares.table.createdAt": "Created at",
|
||||
"account.shares.table.size": "Size",
|
||||
"account.shares.modal.share-informations": "Share informations",
|
||||
"account.shares.modal.share-link": "Share link",
|
||||
"account.shares.modal.delete.title": "Delete share {share}",
|
||||
"account.shares.modal.delete.description": "Do you really want to delete this share?",
|
||||
// END /account/shares
|
||||
// /account/reverseShares
|
||||
"account.reverseShares.title": "Reverse shares",
|
||||
"account.reverseShares.description": "A reverse share allows you to generate a unique URL that allows external users to create a share.",
|
||||
"account.reverseShares.title.empty": "It's empty here 👀",
|
||||
"account.reverseShares.description.empty": "You don't have any reverse shares.",
|
||||
// showCreateReverseShareModal.tsx
|
||||
"account.reverseShares.modal.title": "Create reverse share",
|
||||
"account.reverseShares.modal.expiration.label": "Expiration",
|
||||
"account.reverseShares.modal.expiration.minute-singular": "Minute",
|
||||
"account.reverseShares.modal.expiration.minute-plural": "Minutes",
|
||||
"account.reverseShares.modal.expiration.hour-singular": "Hour",
|
||||
"account.reverseShares.modal.expiration.hour-plural": "Hours",
|
||||
"account.reverseShares.modal.expiration.day-singular": "Day",
|
||||
"account.reverseShares.modal.expiration.day-plural": "Days",
|
||||
"account.reverseShares.modal.expiration.week-singular": "Week",
|
||||
"account.reverseShares.modal.expiration.week-plural": "Weeks",
|
||||
"account.reverseShares.modal.expiration.month-singular": "Month",
|
||||
"account.reverseShares.modal.expiration.month-plural": "Months",
|
||||
"account.reverseShares.modal.expiration.year-singular": "Year",
|
||||
"account.reverseShares.modal.expiration.year-plural": "Years",
|
||||
"account.reverseShares.modal.max-size.label": "Max share size",
|
||||
"account.reverseShares.modal.send-email": "Send email notification",
|
||||
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
|
||||
"account.reverseShares.modal.max-use.label": "Max uses",
|
||||
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
|
||||
"account.reverseShare.never-expires": "This reverse share will never expire.",
|
||||
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
|
||||
"account.reverseShares.table.no-shares": "No shares created yet",
|
||||
"account.reverseShares.table.count.singular": "share",
|
||||
"account.reverseShares.table.count.plural": "shares",
|
||||
"account.reverseShares.table.shares": "Shares",
|
||||
"account.reverseShares.table.remaining": "Remaining uses",
|
||||
"account.reverseShares.table.max-size": "Max share size",
|
||||
"account.reverseShares.table.expires": "Expires at",
|
||||
"account.reverseShares.modal.reverse-share-link": "Reverse share link",
|
||||
"account.reverseShares.modal.delete.title": "Delete reverse share",
|
||||
"account.reverseShares.modal.delete.description": "Do you really want to delete this reverse share? If you do, the associated shares will be deleted as well.",
|
||||
// END /account/reverseShares
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "User management",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
// /admin/users
|
||||
"admin.users.title": "User management",
|
||||
"admin.users.table.username": "Username",
|
||||
"admin.users.table.email": "Email",
|
||||
"admin.users.table.admin": "Admin",
|
||||
"admin.users.edit.update.title": "Update user {username}",
|
||||
"admin.users.edit.update.admin-privileges": "Admin privileges",
|
||||
"admin.users.edit.update.change-password.title": "Change password",
|
||||
"admin.users.edit.update.change-password.field": "New password",
|
||||
"admin.users.edit.update.change-password.button": "Save new password",
|
||||
"admin.users.edit.update.notify.password.success": "Password changed successfully",
|
||||
"admin.users.edit.delete.title": "Delete user {username}",
|
||||
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
|
||||
// showCreateUserModal.tsx
|
||||
"admin.users.modal.create.title": "Create user",
|
||||
"admin.users.modal.create.username": "Username",
|
||||
"admin.users.modal.create.email": "Email",
|
||||
"admin.users.modal.create.password": "Password",
|
||||
"admin.users.modal.create.manual-password": "Set password manually",
|
||||
"admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.",
|
||||
"admin.users.modal.create.admin": "Admin privileges",
|
||||
"admin.users.modal.create.admin.description": "If checked, the user will be able to access the admin panel.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"upload.notify.count-failed": "{count} files failed to upload. Trying again.",
|
||||
// Dropzone.tsx
|
||||
"upload.dropzone.title": "Upload files",
|
||||
"upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.",
|
||||
"upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.",
|
||||
// FileList.tsx
|
||||
"upload.filelist.name": "Name",
|
||||
"upload.filelist.size": "Size",
|
||||
// showCreateUploadModal.tsx
|
||||
"upload.modal.title": "Create Share",
|
||||
"upload.modal.link.error.invalid": "Can only contain letters, numbers, underscores, and hyphens",
|
||||
"upload.modal.link.error.taken": "This link is already in use",
|
||||
"upload.modal.not-signed-in": "You're not signed in",
|
||||
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
|
||||
"upload.modal.expires.never": "never",
|
||||
"upload.modal.expires.never-long": "Never Expires",
|
||||
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
|
||||
"upload.modal.link.label": "Link",
|
||||
"upload.modal.expires.label": "Expiration",
|
||||
"upload.modal.expires.minute-singular": "Minute",
|
||||
"upload.modal.expires.minute-plural": "Minutes",
|
||||
"upload.modal.expires.hour-singular": "Hour",
|
||||
"upload.modal.expires.hour-plural": "Hours",
|
||||
"upload.modal.expires.day-singular": "Day",
|
||||
"upload.modal.expires.day-plural": "Days",
|
||||
"upload.modal.expires.week-singular": "Week",
|
||||
"upload.modal.expires.week-plural": "Weeks",
|
||||
"upload.modal.expires.month-singular": "Month",
|
||||
"upload.modal.expires.month-plural": "Months",
|
||||
"upload.modal.expires.year-singular": "Year",
|
||||
"upload.modal.expires.year-plural": "Years",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Email recipients",
|
||||
"upload.modal.accordion.email.placeholder": "Enter email recipients",
|
||||
"upload.modal.accordion.email.invalid-email": "Invalid email address",
|
||||
"upload.modal.accordion.security.title": "Security options",
|
||||
"upload.modal.accordion.security.password.label": "Password protection",
|
||||
"upload.modal.accordion.security.password.placeholder": "No password",
|
||||
"upload.modal.accordion.security.max-views.label": "Maximum views",
|
||||
"upload.modal.accordion.security.max-views.placeholder": "No limit",
|
||||
// showCompletedUploadModal.tsx
|
||||
"upload.modal.completed.never-expires": "This share will never expire.",
|
||||
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
|
||||
"upload.modal.completed.share-ready": "Share ready",
|
||||
// END /upload
|
||||
// /share/[id]
|
||||
"share.title": "Share {shareId}",
|
||||
"share.description": "Look what I've shared with you!",
|
||||
"share.error.visitor-limit-exceeded.title": "Visitor limit exceeded",
|
||||
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
|
||||
"share.error.removed.title": "Share removed",
|
||||
"share.error.not-found.title": "Share not found",
|
||||
"share.error.not-found.description": "The share you're looking for doesn't exist.",
|
||||
"share.modal.password.title": "Password required",
|
||||
"share.modal.password.description": "To access this share please enter the password for the share.",
|
||||
"share.modal.password": "Password",
|
||||
"share.modal.error.invalid-password": "Invalid password",
|
||||
"share.button.download-all": "Download all",
|
||||
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
|
||||
"share.modal.file-link": "File link",
|
||||
"share.table.name": "Name",
|
||||
"share.table.size": "Size",
|
||||
"share.modal.file-preview.error.not-supported.title": "Preview not supported",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Edit {shareId}",
|
||||
"share.edit.append-upload": "Append file",
|
||||
"share.edit.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"share.edit.notify.save-success": "Share updated successfully",
|
||||
// END /share/[id]/edit
|
||||
// /admin/config
|
||||
"admin.config.title": "Configuration",
|
||||
"admin.config.category.general": "General",
|
||||
"admin.config.category.share": "Share",
|
||||
"admin.config.category.email": "Email",
|
||||
"admin.config.category.smtp": "SMTP",
|
||||
"admin.config.category.oauth": "Social Login",
|
||||
"admin.config.general.app-name": "App name",
|
||||
"admin.config.general.app-name.description": "Name of the application",
|
||||
"admin.config.general.app-url": "App URL",
|
||||
"admin.config.general.app-url.description": "On which URL Pingvin Share is available",
|
||||
"admin.config.general.show-home-page": "Show home page",
|
||||
"admin.config.general.show-home-page.description": "Whether to show the home page",
|
||||
"admin.config.general.logo": "Logo",
|
||||
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.",
|
||||
"admin.config.general.logo.placeholder": "Pick image",
|
||||
"admin.config.email.enable-share-email-recipients": "Enable share email recipients",
|
||||
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
|
||||
"admin.config.email.share-recipients-subject": "Share recipients subject",
|
||||
"admin.config.email.share-recipients-subject.description": "Subject of the email which gets sent to the share recipients.",
|
||||
"admin.config.email.share-recipients-message": "Share recipients message",
|
||||
"admin.config.email.share-recipients-message.description": "Message which gets sent to the share recipients. Available variables:\n {creator} - The username of the creator of the share\n {shareUrl} - The URL of the share\n {desc} - The description of the share\n {expires} - The expiration date of the share\n The variables will be replaced with the actual value.",
|
||||
"admin.config.email.reverse-share-subject": "Reverse share subject",
|
||||
"admin.config.email.reverse-share-subject.description": "Subject of the email which gets sent when someone created a share with your reverse share link.",
|
||||
"admin.config.email.reverse-share-message": "Reverse share message",
|
||||
"admin.config.email.reverse-share-message.description": "Message which gets sent when someone created a share with your reverse share link. {shareUrl} will be replaced with the creator's name and the share URL.",
|
||||
"admin.config.email.reset-password-subject": "Reset password subject",
|
||||
"admin.config.email.reset-password-subject.description": "Subject of the email which gets sent when a user requests a password reset.",
|
||||
"admin.config.email.reset-password-message": "Reset password message",
|
||||
"admin.config.email.reset-password-message.description": "Message which gets sent when a user requests a password reset. {url} will be replaced with the reset password URL.",
|
||||
"admin.config.email.invite-subject": "Invite subject",
|
||||
"admin.config.email.invite-subject.description": "Subject of the email which gets sent when an admin invites a user.",
|
||||
"admin.config.email.invite-message": "Invite message",
|
||||
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL and {password} with the password.",
|
||||
"admin.config.share.allow-registration": "Allow registration",
|
||||
"admin.config.share.allow-registration.description": "Whether registration is allowed",
|
||||
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
|
||||
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
|
||||
"admin.config.share.max-expiration": "Max expiration",
|
||||
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
|
||||
"admin.config.share.max-size": "Max size",
|
||||
"admin.config.share.max-size.description": "Maximum share size in bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip compression level",
|
||||
"admin.config.share.zip-compression-level.description": "Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Enabled",
|
||||
"admin.config.smtp.enabled.description": "Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
"admin.config.smtp.host.description": "Host of the SMTP server",
|
||||
"admin.config.smtp.port": "Port",
|
||||
"admin.config.smtp.port.description": "Port of the SMTP server",
|
||||
"admin.config.smtp.email": "Email",
|
||||
"admin.config.smtp.email.description": "Email address which the emails get sent from",
|
||||
"admin.config.smtp.username": "Username",
|
||||
"admin.config.smtp.username.description": "Username of the SMTP server",
|
||||
"admin.config.smtp.password": "Password",
|
||||
"admin.config.smtp.password.description": "Password of the SMTP server",
|
||||
"admin.config.smtp.button.test": "Send test email",
|
||||
"admin.config.oauth.allow-registration": "Allow registration",
|
||||
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
|
||||
"admin.config.oauth.ignore-totp": "Ignore TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
|
||||
"admin.config.oauth.github-enabled": "GitHub",
|
||||
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled",
|
||||
"admin.config.oauth.github-client-id": "GitHub Client ID",
|
||||
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-secret": "GitHub Client secret",
|
||||
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app",
|
||||
"admin.config.oauth.google-enabled": "Google",
|
||||
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled",
|
||||
"admin.config.oauth.google-client-id": "Google Client ID",
|
||||
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-secret": "Google Client secret",
|
||||
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app",
|
||||
"admin.config.oauth.microsoft-enabled": "Microsoft",
|
||||
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled",
|
||||
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant",
|
||||
"admin.config.oauth.microsoft-tenant.description": "Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
|
||||
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID",
|
||||
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret",
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-client-id": "Discord Client ID",
|
||||
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-secret": "Discord Client secret",
|
||||
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "Whether OpenID Connect login is enabled",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
|
||||
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID Connect OAuth app",
|
||||
// 404
|
||||
"404.description": "Oops this page doesn't exist.",
|
||||
"404.button.home": "Bring me back home",
|
||||
// error
|
||||
"error.title": "Error",
|
||||
"error.description": "Oops!",
|
||||
"error.button.back": "Go back",
|
||||
"error.msg.default": "Something went wrong.",
|
||||
"error.msg.access_denied": "You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token": "The authentication process took too long, please try again.",
|
||||
"error.msg.invalid_token": "Internal Error",
|
||||
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
|
||||
"error.msg.no_email": "Can't get email address from this {0} account.",
|
||||
"error.msg.already_linked": "This {0} account is already linked to another account.",
|
||||
"error.msg.not_linked": "This {0} account haven't linked to any account yet.",
|
||||
"error.msg.unverified_account": "This {0} account is unverified, please try again after verification.",
|
||||
"error.msg.discord_guild_permission_denied": "You are not allowed to sign in.",
|
||||
"error.msg.cannot_get_user_info": "Can not get your user info from this {0} account.",
|
||||
"error.param.provider_github": "GitHub",
|
||||
"error.param.provider_google": "Google",
|
||||
"error.param.provider_microsoft": "Microsoft",
|
||||
"error.param.provider_discord": "Discord",
|
||||
"error.param.provider_oidc": "OpenID Connect",
|
||||
// Common translations
|
||||
"common.button.save": "Save",
|
||||
"common.button.create": "Create",
|
||||
"common.button.submit": "Submit",
|
||||
"common.button.delete": "Delete",
|
||||
"common.button.cancel": "Cancel",
|
||||
"common.button.confirm": "Confirm",
|
||||
"common.button.disable": "Disable",
|
||||
"common.button.share": "Share",
|
||||
"common.button.generate": "Generate",
|
||||
"common.button.done": "Done",
|
||||
"common.text.link": "Link",
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "or",
|
||||
"common.button.go-back": "Go back",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Your link was copied to the clipboard",
|
||||
"common.success": "Success",
|
||||
"common.error": "Error",
|
||||
"common.error.unknown": "An unknown error occurred",
|
||||
"common.error.invalid-email": "Invalid email address",
|
||||
"common.error.too-short": "Must be at least {length} characters",
|
||||
"common.error.too-long": "Must be at most {length} characters",
|
||||
"common.error.exact-length": "Must be exactly {length} characters",
|
||||
"common.error.invalid-number": "Must be a number",
|
||||
"common.error.field-required": "This field is required"
|
||||
};
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Glemt din adgangskode?",
|
||||
"resetPassword.description": "Indtast din e-mail for at nulstille din adgangskode.",
|
||||
"resetPassword.notify.success": "En e-mail er blevet sendt med et link til at nulstille din adgangskode.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Tilbage til login",
|
||||
"resetPassword.text.resetPassword": "Nulstil adgangskode",
|
||||
"resetPassword.text.enterNewPassword": "Indtast din nye adgangskode",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "Brugeradministration",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Konfiguration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Admin rettigheder",
|
||||
"admin.users.modal.create.admin.description": "If checked, the user will be able to access the admin panel.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "Der opstod en fejl under afslutningen af din deling.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Måneder",
|
||||
"upload.modal.expires.year-singular": "År",
|
||||
"upload.modal.expires.year-plural": "År",
|
||||
"upload.modal.accordion.description.title": "Beskrivelse",
|
||||
"upload.modal.accordion.description.placeholder": "Bemærkning til modtagerne af dette share",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "E-mail modtagere",
|
||||
"upload.modal.accordion.email.placeholder": "Indtast e-mail modtagere",
|
||||
"upload.modal.accordion.email.invalid-email": "Ugyldig e-mailadresse",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Maksimal filstørrelse i bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip compression level",
|
||||
"admin.config.share.zip-compression-level.description": "Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Aktiveret",
|
||||
"admin.config.smtp.enabled.description": "Om SMTP er aktiveret. Aktiver kun SMTP, hvis du har indtastet SMTP-server vært, port, e-mail, bruger og adgangskode.",
|
||||
"admin.config.smtp.host": "Vært",
|
||||
@@ -327,7 +340,7 @@ export default {
|
||||
"admin.config.smtp.password": "Adgangskode",
|
||||
"admin.config.smtp.password.description": "Adgangskoden til SMTP serveren",
|
||||
"admin.config.smtp.button.test": "Send test e-mail",
|
||||
"admin.config.oauth.allow-registration": "Allow registration",
|
||||
"admin.config.oauth.allow-registration": "Tillad registrering",
|
||||
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
|
||||
"admin.config.oauth.ignore-totp": "Ignore TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
|
||||
@@ -379,7 +392,7 @@ export default {
|
||||
"error.msg.default": "Something went wrong.",
|
||||
"error.msg.access_denied": "You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token": "The authentication process took too long, please try again.",
|
||||
"error.msg.invalid_token": "Internal Error",
|
||||
"error.msg.invalid_token": "Intern Fejl",
|
||||
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
|
||||
"error.msg.no_email": "Can't get email address from this {0} account.",
|
||||
"error.msg.already_linked": "This {0} account is already linked to another account.",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "eller",
|
||||
"common.button.go-back": "Gå tilbage",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Linket blev kopieret til udklipsholderen",
|
||||
"common.success": "Success",
|
||||
"common.error": "Fejl",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Passwort vergessen?",
|
||||
"resetPassword.description": "Gib deine Email Adresse ein, um dein Passwort zurückzusetzen.",
|
||||
"resetPassword.notify.success": "Ein Link zum Zurücksetzen des Passwortes wurde an deine Emailadresse versandt.",
|
||||
"resetPassword.notify.success": "Wir haben dir einen Link gesendet, unter dem du dein Passwort zurücksetzen kannst.",
|
||||
"resetPassword.button.back": "Zurück zur Anmeldeseite",
|
||||
"resetPassword.text.resetPassword": "Passwort zurücksetzen",
|
||||
"resetPassword.text.enterNewPassword": "Gib dein neues Passwort ein",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Verwaltung",
|
||||
"admin.button.users": "Benutzerverwaltung",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Konfiguration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Administratorrechte",
|
||||
"admin.users.modal.create.admin.description": "Wenn aktiviert, kann der Benutzer auf das Administrator-Panel zugreifen.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "Während der Erstellung der Freigabe ist ein Fehler aufgetreten.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Monate",
|
||||
"upload.modal.expires.year-singular": "Jahr",
|
||||
"upload.modal.expires.year-plural": "Year",
|
||||
"upload.modal.accordion.description.title": "Beschreibung",
|
||||
"upload.modal.accordion.description.placeholder": "Hinweis für die Empfänger dieser Freigabe",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Email Empfänger",
|
||||
"upload.modal.accordion.email.placeholder": "Email der Empfänger eingeben",
|
||||
"upload.modal.accordion.email.invalid-email": "Ungültige Emailadresse",
|
||||
@@ -262,7 +273,7 @@ export default {
|
||||
"share.table.name": "Name",
|
||||
"share.table.size": "Größe",
|
||||
"share.modal.file-preview.error.not-supported.title": "Vorschau wird nicht unterstützt",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
"share.modal.file-preview.error.not-supported.description": "Eine Vorschau für diesen Dateityp wird nicht unterstützt. Bitte lade die Datei herunter, um sie anzusehen.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "{shareId} bearbeiten",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Maximale Größe einer Freigabe in Bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip Komprimierungsstufe",
|
||||
"admin.config.share.zip-compression-level.description": "Passe den Wert an, um ein Gleichgewicht zwischen Dateigröße und Komprimierungsgeschwindigkeit herzustellen. Gültige Werte liegen zwischen 0 und 9, wobei 0 für keine Komprimierung und 9 für maximale Komprimierung steht.",
|
||||
"admin.config.share.chunk-size": "Chunkgröße",
|
||||
"admin.config.share.chunk-size.description": "Passe die Chunkgröße (in Bytes) für deine Uploads an, um die Zuverlässigkeit deiner Internetverbindung auszugleichen. Kleinere Chunks können die Erfolgsraten für instabile Verbindungen verbessern, während größere Chunks Uploads für stabile Verbindungen beschleunigen können.",
|
||||
"admin.config.smtp.enabled": "Aktiviert",
|
||||
"admin.config.smtp.enabled.description": "Gibt an, ob SMTP aktiviert ist. Aktiviere dies nur, wenn Du den Host, den Port, die Email, den Benutzernamen und das Passwort deines SMTP-Servers eingegeben hast.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -353,18 +366,18 @@ export default {
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Client-Secret der Microsoft OAuth-App",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Discord Anmeldung erlaubt",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord Server-ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Die Anmeldung auf Benutzer in einem bestimmten Server beschränken. Leer lassen, um zu deaktivieren.",
|
||||
"admin.config.oauth.discord-client-id": "Discord Client-ID",
|
||||
"admin.config.oauth.discord-client-id.description": "Client-ID der Discord OAuth-App",
|
||||
"admin.config.oauth.discord-client-secret": "Discord Client-Secret",
|
||||
"admin.config.oauth.discord-client-secret.description": "Client-Secret der Discord OAuth-App",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "OpenID Connect Anmeldung erlaubt",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Verbindung Discovery URL",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery-URL der OpenID OAuth App",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect Benutzername anfordern",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Benutzername im OpenID Token. Leer lassen, wenn du nicht weißt, was diese Konfiguration bedeutet.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client-ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Client-ID der OpenID Connect OAuth-App",
|
||||
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client-Secret",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Link öffnen",
|
||||
"common.text.or": "oder",
|
||||
"common.button.go-back": "Zurück",
|
||||
"common.button.go-home": "Zur Startseite",
|
||||
"common.notify.copied": "Dein Link wurde in die Zwischenablage kopiert",
|
||||
"common.success": "Erfolg",
|
||||
"common.error": "Fehler",
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Ξεχάσατε τον κωδικό σας;",
|
||||
"resetPassword.description": "Ελέγξτε το e-mail σας για να κάνετε επαναφορά του κωδικού πρόσβασής σας.",
|
||||
"resetPassword.description": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.notify.success": "Εισάγετε το email σας για επαναφορά κωδικού.",
|
||||
"resetPassword.button.back": "Πίσω στη σελίδα εισόδου",
|
||||
"resetPassword.text.resetPassword": "Επαναφορά κωδικού πρόσβασης",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Διαχείριση",
|
||||
"admin.button.users": "Διαχείριση χρηστών",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Διαμόρφωση",
|
||||
"admin.version": "Έκδοση",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Δικαιώματα διαχειριστή",
|
||||
"admin.users.modal.create.admin.description": "Αν ενεργοποιηθεί, ο χρήστης θα μπορεί να έχει πρόσβαση στον πίνακα διαχείρισης.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Μεταφόρτωση",
|
||||
"upload.notify.generic-error": "Παρουσιάστηκε σφάλμα κατά την ολοκλήρωση της κοινής χρήσης σας.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Μήνες",
|
||||
"upload.modal.expires.year-singular": "Έτος",
|
||||
"upload.modal.expires.year-plural": "Έτη",
|
||||
"upload.modal.accordion.description.title": "Περιγραφή",
|
||||
"upload.modal.accordion.description.placeholder": "Σημείωση για τους παραλήπτες αυτής της κοινοποίησης",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Αποδέκτες email",
|
||||
"upload.modal.accordion.email.placeholder": "Εισάγετε αποδέκτες email",
|
||||
"upload.modal.accordion.email.invalid-email": "Μη έγκυρη διεύθυνση e-mail",
|
||||
@@ -262,7 +273,7 @@ export default {
|
||||
"share.table.name": "Όνομα",
|
||||
"share.table.size": "Μέγεθος",
|
||||
"share.modal.file-preview.error.not-supported.title": "Η προεπισκόπηση δεν υποστηρίζεται",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
"share.modal.file-preview.error.not-supported.description": "Η προεπισκόπηση για αυτό τον τύπο αρχείου δεν υποστηρίζεται. Παρακαλώ κατεβάστε το αρχείο για να το δείτε.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Ενημέρωση {shareId}",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Μέγιστο μέγεθος κοινοποίησης σε bytes",
|
||||
"admin.config.share.zip-compression-level": "Βαθμός συμπίεσης ZIP",
|
||||
"admin.config.share.zip-compression-level.description": "Προσαρμόστε το βαθμό συμπίεσης για να εξισορροπηθεί το μέγεθος του αρχείου και η ταχύτητα επεξεργασίας. Έγκυρες τιμές κυμαίνονται από 0 έως 9, με 0 χωρίς συμπίεση και 9 μέγιστη συμπίεση.",
|
||||
"admin.config.share.chunk-size": "Μέγεθος κομματιών",
|
||||
"admin.config.share.chunk-size.description": "Προσαρμόστε το μέγεθος κομματιών (σε bytes) για να εξισορροπήσετε την αποδοτικότητα και την αξιοπιστία του συστήματος σύμφωνα με τη σύνδεσή σας στο διαδίκτυο. Μικρότερα κομμάτια μπορούν να βελτιώσουν τα ποσοστά επιτυχίας σε ασταθείς συνδέσεις, ενώ μεγαλύτερα κομμάτια επιταχύνουν τις μεταφορτώσεις σε σταθερές συνδέσεις.",
|
||||
"admin.config.smtp.enabled": "Ενεργοποιημένο",
|
||||
"admin.config.smtp.enabled.description": "Εάν η λειτουργία SMTP είναι ενεργοποιημένη. Ενεργοποιήστε τη μόνον όταν ορίσετε σωστά τις παραμέτρους που ακολουθούν.",
|
||||
"admin.config.smtp.host": "Εξυπηρετητής",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Μεταβείτε στο σύνδεσμο",
|
||||
"common.text.or": "ή",
|
||||
"common.button.go-back": "Επιστροφή",
|
||||
"common.button.go-home": "Μετάβαση στην αρχική",
|
||||
"common.notify.copied": "Ο σύνδεσμος σας αντιγράφηκε στο πρόχειρο",
|
||||
"common.success": "Επιτυχία",
|
||||
"common.error": "Σφάλμα",
|
||||
|
||||
@@ -74,7 +74,7 @@ export default {
|
||||
"resetPassword.title": "Forgot your password?",
|
||||
"resetPassword.description": "Enter your email to reset your password.",
|
||||
"resetPassword.notify.success":
|
||||
"An email has been sent with a link to reset your password.",
|
||||
"A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Back to sign in page",
|
||||
"resetPassword.text.resetPassword": "Reset password",
|
||||
"resetPassword.text.enterNewPassword": "Enter your new password",
|
||||
@@ -93,7 +93,8 @@ export default {
|
||||
"account.card.password.title": "Password",
|
||||
"account.card.password.old": "Old password",
|
||||
"account.card.password.new": "New password",
|
||||
"account.card.password.noPasswordSet": "You don't have a password set. If you want to sign in with email and password you need to set a password.",
|
||||
"account.card.password.noPasswordSet":
|
||||
"You don't have a password set. If you want to sign in with email and password you need to set a password.",
|
||||
"account.notify.password.success": "Password changed successfully",
|
||||
|
||||
"account.card.oauth.title": "Social login",
|
||||
@@ -106,10 +107,10 @@ export default {
|
||||
"account.card.oauth.unlink": "Unlink",
|
||||
"account.card.oauth.unlinked": "Unlinked",
|
||||
"account.modal.unlink.title": "Unlink account",
|
||||
"account.modal.unlink.description": "Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
|
||||
"account.modal.unlink.description":
|
||||
"Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
|
||||
"account.notify.oauth.unlinked.success": "Unlinked successfully",
|
||||
|
||||
|
||||
"account.card.security.title": "Security",
|
||||
"account.card.security.totp.enable.description":
|
||||
"Enter your current password to start enabling TOTP",
|
||||
@@ -223,6 +224,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "User management",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
@@ -259,6 +261,19 @@ export default {
|
||||
|
||||
// END /admin/users
|
||||
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description":
|
||||
"Do you really want to delete this share?",
|
||||
|
||||
// END /admin/shares
|
||||
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
|
||||
@@ -288,7 +303,8 @@ export default {
|
||||
|
||||
"upload.modal.expires.never": "never",
|
||||
"upload.modal.expires.never-long": "Never Expires",
|
||||
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
|
||||
"upload.modal.expires.error.too-long":
|
||||
"Expiration exceeds maximum expiration date of {max}.",
|
||||
|
||||
"upload.modal.link.label": "Link",
|
||||
"upload.modal.expires.label": "Expiration",
|
||||
@@ -305,8 +321,9 @@ export default {
|
||||
"upload.modal.expires.year-singular": "Year",
|
||||
"upload.modal.expires.year-plural": "Years",
|
||||
|
||||
"upload.modal.accordion.description.title": "Description",
|
||||
"upload.modal.accordion.description.placeholder":
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder":
|
||||
"Note for the recipients of this share",
|
||||
|
||||
"upload.modal.accordion.email.title": "Email recipients",
|
||||
@@ -361,7 +378,8 @@ export default {
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Edit {shareId}",
|
||||
"share.edit.append-upload": "Append file",
|
||||
"share.edit.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"share.edit.notify.generic-error":
|
||||
"An error occurred while finishing your share.",
|
||||
"share.edit.notify.save-success": "Share updated successfully",
|
||||
// END /share/[id]/edit
|
||||
|
||||
@@ -429,7 +447,9 @@ export default {
|
||||
"admin.config.share.zip-compression-level": "Zip compression level",
|
||||
"admin.config.share.zip-compression-level.description":
|
||||
"Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
|
||||
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
|
||||
"admin.config.smtp.enabled": "Enabled",
|
||||
"admin.config.smtp.enabled.description":
|
||||
"Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
|
||||
@@ -447,47 +467,68 @@ export default {
|
||||
"admin.config.smtp.button.test": "Send test email",
|
||||
|
||||
"admin.config.oauth.allow-registration": "Allow registration",
|
||||
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
|
||||
"admin.config.oauth.allow-registration.description":
|
||||
"Allow users to register via social login",
|
||||
"admin.config.oauth.ignore-totp": "Ignore TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
|
||||
"admin.config.oauth.ignore-totp.description":
|
||||
"Whether to ignore TOTP when user using social login",
|
||||
"admin.config.oauth.github-enabled": "GitHub",
|
||||
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled",
|
||||
"admin.config.oauth.github-enabled.description":
|
||||
"Whether GitHub login is enabled",
|
||||
"admin.config.oauth.github-client-id": "GitHub Client ID",
|
||||
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-id.description":
|
||||
"Client ID of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-secret": "GitHub Client secret",
|
||||
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-secret.description":
|
||||
"Client secret of the GitHub OAuth app",
|
||||
"admin.config.oauth.google-enabled": "Google",
|
||||
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled",
|
||||
"admin.config.oauth.google-enabled.description":
|
||||
"Whether Google login is enabled",
|
||||
"admin.config.oauth.google-client-id": "Google Client ID",
|
||||
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-id.description":
|
||||
"Client ID of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-secret": "Google Client secret",
|
||||
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-secret.description":
|
||||
"Client secret of the Google OAuth app",
|
||||
"admin.config.oauth.microsoft-enabled": "Microsoft",
|
||||
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled",
|
||||
"admin.config.oauth.microsoft-enabled.description":
|
||||
"Whether Microsoft login is enabled",
|
||||
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant",
|
||||
"admin.config.oauth.microsoft-tenant.description": "Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
|
||||
"admin.config.oauth.microsoft-tenant.description":
|
||||
"Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
|
||||
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID",
|
||||
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-id.description":
|
||||
"Client ID of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret",
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-secret.description":
|
||||
"Client secret of the Microsoft OAuth app",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled",
|
||||
"admin.config.oauth.discord-enabled.description":
|
||||
"Whether Discord login is enabled",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-limited-guild.description":
|
||||
"Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-client-id": "Discord Client ID",
|
||||
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-id.description":
|
||||
"Client ID of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-secret": "Discord Client secret",
|
||||
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-secret.description":
|
||||
"Client secret of the Discord OAuth app",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "Whether OpenID Connect login is enabled",
|
||||
"admin.config.oauth.oidc-enabled.description":
|
||||
"Whether OpenID Connect login is enabled",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-discovery-uri.description":
|
||||
"Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-username-claim.description":
|
||||
"Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-id.description":
|
||||
"Client ID of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
|
||||
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-secret.description":
|
||||
"Client secret of the OpenID Connect OAuth app",
|
||||
|
||||
// 404
|
||||
"404.description": "Oops this page doesn't exist.",
|
||||
@@ -498,16 +539,22 @@ export default {
|
||||
"error.description": "Oops!",
|
||||
"error.button.back": "Go back",
|
||||
"error.msg.default": "Something went wrong.",
|
||||
"error.msg.access_denied": "You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token": "The authentication process took too long, please try again.",
|
||||
"error.msg.access_denied":
|
||||
"You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token":
|
||||
"The authentication process took too long, please try again.",
|
||||
"error.msg.invalid_token": "Internal Error",
|
||||
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
|
||||
"error.msg.no_email": "Can't get email address from this {0} account.",
|
||||
"error.msg.already_linked": "This {0} account is already linked to another account.",
|
||||
"error.msg.already_linked":
|
||||
"This {0} account is already linked to another account.",
|
||||
"error.msg.not_linked": "This {0} account haven't linked to any account yet.",
|
||||
"error.msg.unverified_account": "This {0} account is unverified, please try again after verification.",
|
||||
"error.msg.discord_guild_permission_denied": "You are not allowed to sign in.",
|
||||
"error.msg.cannot_get_user_info": "Can not get your user info from this {0} account.",
|
||||
"error.msg.unverified_account":
|
||||
"This {0} account is unverified, please try again after verification.",
|
||||
"error.msg.discord_guild_permission_denied":
|
||||
"You are not allowed to sign in.",
|
||||
"error.msg.cannot_get_user_info":
|
||||
"Can not get your user info from this {0} account.",
|
||||
"error.param.provider_github": "GitHub",
|
||||
"error.param.provider_google": "Google",
|
||||
"error.param.provider_microsoft": "Microsoft",
|
||||
@@ -529,6 +576,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "or",
|
||||
"common.button.go-back": "Go back",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Your link was copied to the clipboard",
|
||||
"common.success": "Success",
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "¿Olvidaste tu contraseña?",
|
||||
"resetPassword.description": "Ingresa tu correo para restablecer tu contraseña.",
|
||||
"resetPassword.notify.success": "Se ha enviado un correo con el enlace para restablecer tu contraseña.",
|
||||
"resetPassword.notify.success": "Se ha enviado un mensaje con un enlace para restablecer tu contraseña.",
|
||||
"resetPassword.button.back": "Volver al inicio de sesión",
|
||||
"resetPassword.text.resetPassword": "Restablecer contraseña",
|
||||
"resetPassword.text.enterNewPassword": "Ingresa tu nueva contraseña",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administración",
|
||||
"admin.button.users": "Gestión de usuarios",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuración",
|
||||
"admin.version": "Versión",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Privilegios de administrador",
|
||||
"admin.users.modal.create.admin.description": "Si se marca, el usuario podrá acceder al panel de administrador.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Subir",
|
||||
"upload.notify.generic-error": "Ha ocurrido un error mientras se compartía tu archivo.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Meses",
|
||||
"upload.modal.expires.year-singular": "Año",
|
||||
"upload.modal.expires.year-plural": "Años",
|
||||
"upload.modal.accordion.description.title": "Descripción",
|
||||
"upload.modal.accordion.description.placeholder": "Nota para los destinatarios de este compartido",
|
||||
"upload.modal.accordion.name-and-description.title": "Nombre y descripción",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Nombre",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Nota para los destinatarios de este compartido",
|
||||
"upload.modal.accordion.email.title": "Correo de los destinatarios",
|
||||
"upload.modal.accordion.email.placeholder": "Ingresa los correos de los destinatarios",
|
||||
"upload.modal.accordion.email.invalid-email": "Dirección de correo inválida",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Tamaño máximo de los archivos, en bytes",
|
||||
"admin.config.share.zip-compression-level": "Nivel de compresión del Zip",
|
||||
"admin.config.share.zip-compression-level.description": "Ajustar el nivel para equilibrar entre el tamaño del archivo y la velocidad de compresión. Los valores válidos van del 0 al 9, siendo 0 sin compresión y 9 el nivel máximo de compresión. ",
|
||||
"admin.config.share.chunk-size": "Tamaño de los fragmentos",
|
||||
"admin.config.share.chunk-size.description": "Ajusta el tamaño de los fragmentos (en bytes) para tus cargas para equilibrar la eficiencia y la fiabilidad según tu conexión a internet. Fragmentos más pequeños pueden mejorar las tasas de éxito para conexiones inestables, mientras que fragmentos más grandes aceleran las cargas para conexiones estables.",
|
||||
"admin.config.smtp.enabled": "Habilitado",
|
||||
"admin.config.smtp.enabled.description": "Si SMTP está habilitado. Active solo si ha introducido el host, el puerto, el correo, el usuario y la contraseña de su servidor SMTP.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Ir al enlace",
|
||||
"common.text.or": "o",
|
||||
"common.button.go-back": "Volver",
|
||||
"common.button.go-home": "Página de inicio",
|
||||
"common.notify.copied": "Tu enlace se ha copiado al portapapeles",
|
||||
"common.success": "Éxito",
|
||||
"common.error": "Error",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Unohditko salasanan?",
|
||||
"resetPassword.description": "Kirjoita sähköpostiosoitteesi palauttaaksesi salasanasi.",
|
||||
"resetPassword.notify.success": "Sähköpostiosoite on lähetetty linkillä, jolla voit nollata salasanasi.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Takaisin kirjautumiseen",
|
||||
"resetPassword.text.resetPassword": "Nollaa salasana",
|
||||
"resetPassword.text.enterNewPassword": "Anna uusi salasana",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Ylläpito",
|
||||
"admin.button.users": "Käyttäjien Hallinta",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Asetukset",
|
||||
"admin.version": "Versio",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Ylläpitäjän oikeudet",
|
||||
"admin.users.modal.create.admin.description": "Jos valittu, käyttäjä voi käyttää hallintapaneelia.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Pilvetä",
|
||||
"upload.notify.generic-error": "Kohdattiin odottamaton virhe jaon luomisessa.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Kuukautta",
|
||||
"upload.modal.expires.year-singular": "Vuosi",
|
||||
"upload.modal.expires.year-plural": "Vuotta",
|
||||
"upload.modal.accordion.description.title": "Kuvaus",
|
||||
"upload.modal.accordion.description.placeholder": "Huomautus tämän jaon vastaanottajille",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Sähköpostin vastaanottajat",
|
||||
"upload.modal.accordion.email.placeholder": "Syötä sähköpostin vastaanottajat",
|
||||
"upload.modal.accordion.email.invalid-email": "Virheellinen sähköpostiosoite",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Jaon enimmäiskoko tavuissa (bytes)",
|
||||
"admin.config.share.zip-compression-level": "Zip puristustaso",
|
||||
"admin.config.share.zip-compression-level.description": "Säädä tasoa tiedoston koon ja pakkausnopeuden välillä. Kelvolliset arvot vaihtelevat 0–9, 0 ei puristusta ja 9 on suurin puristusvoima. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Käytössä",
|
||||
"admin.config.smtp.enabled.description": "Onko SMTP käytössä. Aseta tämä todeksi vain, jos olet syöttänyt SMTP-palvelimen isäntän, portin, sähköpostin, käyttäjän ja salasanan.",
|
||||
"admin.config.smtp.host": "Isäntä",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "tai",
|
||||
"common.button.go-back": "Takaisin",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Linkki kopioitiin leikepöydälle",
|
||||
"common.success": "Suoritettu",
|
||||
"common.error": "Virhe",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Mot de passe oublié ?",
|
||||
"resetPassword.description": "Saisissez votre courriel pour réinitialiser votre mot de passe.",
|
||||
"resetPassword.notify.success": "Un courriel a été envoyé avec un lien pour réinitialiser votre mot de passe.",
|
||||
"resetPassword.notify.success": "Un message avec un lien pour réinitialiser votre mot de passe a été envoyé si le courriel existe.",
|
||||
"resetPassword.button.back": "Retour à la page de connexion",
|
||||
"resetPassword.text.resetPassword": "Réinitialiser le mot de passe",
|
||||
"resetPassword.text.enterNewPassword": "Saisissez votre nouveau mot de passe",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "Gestion des utilisateurs",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Paramètres",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Privilèges d’admin",
|
||||
"admin.users.modal.create.admin.description": "Si coché, l’utilisateur pourra accéder au panneau d'administration.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Envoyer",
|
||||
"upload.notify.generic-error": "Une erreur est survenue durant le traitement de votre partage.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Mois",
|
||||
"upload.modal.expires.year-singular": "An",
|
||||
"upload.modal.expires.year-plural": "Ans",
|
||||
"upload.modal.accordion.description.title": "Description",
|
||||
"upload.modal.accordion.description.placeholder": "Note pour les destinataires de ce partage",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Adresse courriel des destinataires",
|
||||
"upload.modal.accordion.email.placeholder": "Saisir les destinataires de ce partage",
|
||||
"upload.modal.accordion.email.invalid-email": "Courriel invalide",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Taille maximale du partage en octets",
|
||||
"admin.config.share.zip-compression-level": "Niveau de compression",
|
||||
"admin.config.share.zip-compression-level.description": "Ajustez le niveau pour trouver l'équilibre entre la taille du fichier et la vitesse de compression. Les valeurs valides vont de 0 à 9, 0 étant sans compression et 9 étant la compression maximale. ",
|
||||
"admin.config.share.chunk-size": "Taille des tronçons",
|
||||
"admin.config.share.chunk-size.description": "Ajustez la taille des tronçons (en octets) pour que vos téléchargements équilibrent efficacité et fiabilité en fonction de votre connexion Internet. Les petits tronçons peuvent améliorer les taux de succès sur les connexions instables, tandis que les tronçons plus importants accélèrent les téléchargements sur les connexions stables.",
|
||||
"admin.config.smtp.enabled": "Activer",
|
||||
"admin.config.smtp.enabled.description": "Active SMTP. Activez ceci uniquement si vous avez saisi l’hôte, le port, le courriel, l’utilisateur et son mot de passe, de votre serveur SMTP.",
|
||||
"admin.config.smtp.host": "Hôte",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Accéder au lien",
|
||||
"common.text.or": "ou",
|
||||
"common.button.go-back": "Précédent",
|
||||
"common.button.go-home": "Accueil",
|
||||
"common.notify.copied": "Votre lien a été copié dans le presse-papiers",
|
||||
"common.success": "Opération réussie",
|
||||
"common.error": "Erreur",
|
||||
|
||||
434
frontend/src/i18n/translations/hu-HU.ts
Normal file
434
frontend/src/i18n/translations/hu-HU.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
export default {
|
||||
// Navbar
|
||||
"navbar.upload": "Upload",
|
||||
"navbar.signin": "Sign in",
|
||||
"navbar.home": "Home",
|
||||
"navbar.signup": "Sign Up",
|
||||
"navbar.links.shares": "My shares",
|
||||
"navbar.links.reverse": "Reverse shares",
|
||||
"navbar.avatar.account": "My account",
|
||||
"navbar.avatar.admin": "Administration",
|
||||
"navbar.avatar.signout": "Sign out",
|
||||
// END navbar
|
||||
// /
|
||||
"home.title": "A <h>self-hosted</h> file sharing platform.",
|
||||
"home.description": "Do you really want to give your personal files in the hand of third parties like WeTransfer?",
|
||||
"home.bullet.a.name": "Self-Hosted",
|
||||
"home.bullet.a.description": "Host Pingvin Share on your own machine.",
|
||||
"home.bullet.b.name": "Privacy",
|
||||
"home.bullet.b.description": "Your files are your files and should never get into the hands of third parties.",
|
||||
"home.bullet.c.name": "No annoying file size limit",
|
||||
"home.bullet.c.description": "Upload as big files as you want. Only your hard drive will be your limit.",
|
||||
"home.button.start": "Get started",
|
||||
"home.button.source": "Source code",
|
||||
// END /
|
||||
// /auth/signin
|
||||
"signin.title": "Welcome back",
|
||||
"signin.description": "You don't have an account yet?",
|
||||
"signin.button.signup": "Sign up",
|
||||
"signin.input.email-or-username": "Email or username",
|
||||
"signin.input.email-or-username.placeholder": "Your email or username",
|
||||
"signin.input.password": "Password",
|
||||
"signin.input.password.placeholder": "Your password",
|
||||
"signin.button.submit": "Sign in",
|
||||
"signIn.notify.totp-required.title": "Two-factor authentication required",
|
||||
"signIn.notify.totp-required.description": "Please enter your two-factor authentication code",
|
||||
"signIn.oauth.or": "OR",
|
||||
"signIn.oauth.github": "GitHub",
|
||||
"signIn.oauth.google": "Google",
|
||||
"signIn.oauth.microsoft": "Microsoft",
|
||||
"signIn.oauth.discord": "Discord",
|
||||
"signIn.oauth.oidc": "OpenID",
|
||||
// END /auth/signin
|
||||
// /auth/signup
|
||||
"signup.title": "Create an account",
|
||||
"signup.description": "Already have an account?",
|
||||
"signup.button.signin": "Sign in",
|
||||
"signup.input.username": "Username",
|
||||
"signup.input.username.placeholder": "Your username",
|
||||
"signup.input.email": "Email",
|
||||
"signup.input.email.placeholder": "Your email",
|
||||
"signup.button.submit": "Let's get started",
|
||||
// END /auth/signup
|
||||
// /auth/totp
|
||||
"totp.title": "TOTP Authentication",
|
||||
"totp.button.signIn": "Sign in",
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Forgot your password?",
|
||||
"resetPassword.description": "Enter your email to reset your password.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Back to sign in page",
|
||||
"resetPassword.text.resetPassword": "Reset password",
|
||||
"resetPassword.text.enterNewPassword": "Enter your new password",
|
||||
"resetPassword.input.password": "New password",
|
||||
"resetPassword.notify.passwordReset": "Your password has been reset successfully.",
|
||||
// /account
|
||||
"account.title": "My account",
|
||||
"account.card.info.title": "Account info",
|
||||
"account.card.info.username": "Username",
|
||||
"account.card.info.email": "Email",
|
||||
"account.notify.info.success": "Account updated successfully",
|
||||
"account.card.password.title": "Password",
|
||||
"account.card.password.old": "Old password",
|
||||
"account.card.password.new": "New password",
|
||||
"account.card.password.noPasswordSet": "You don't have a password set. If you want to sign in with email and password you need to set a password.",
|
||||
"account.notify.password.success": "Password changed successfully",
|
||||
"account.card.oauth.title": "Social login",
|
||||
"account.card.oauth.github": "GitHub",
|
||||
"account.card.oauth.google": "Google",
|
||||
"account.card.oauth.microsoft": "Microsoft",
|
||||
"account.card.oauth.discord": "Discord",
|
||||
"account.card.oauth.oidc": "OpenID",
|
||||
"account.card.oauth.link": "Link",
|
||||
"account.card.oauth.unlink": "Unlink",
|
||||
"account.card.oauth.unlinked": "Unlinked",
|
||||
"account.modal.unlink.title": "Unlink account",
|
||||
"account.modal.unlink.description": "Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
|
||||
"account.notify.oauth.unlinked.success": "Unlinked successfully",
|
||||
"account.card.security.title": "Security",
|
||||
"account.card.security.totp.enable.description": "Enter your current password to start enabling TOTP",
|
||||
"account.card.security.totp.disable.description": "Enter your current password to disable TOTP",
|
||||
"account.card.security.totp.button.start": "Start",
|
||||
"account.modal.totp.title": "Enable TOTP",
|
||||
"account.modal.totp.step1": "Step 1: Add your authenticator",
|
||||
"account.modal.totp.step2": "Step 2: Validate your code",
|
||||
"account.modal.totp.enterManually": "Enter manually",
|
||||
"account.modal.totp.code": "Code",
|
||||
"account.modal.totp.clickToCopy": "Click to copy",
|
||||
"account.modal.totp.verify": "Verify",
|
||||
"account.notify.totp.disable": "TOTP disabled successfully",
|
||||
"account.notify.totp.enable": "TOTP enabled successfully",
|
||||
"account.card.language.title": "Language",
|
||||
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.",
|
||||
"account.card.color.title": "Color scheme",
|
||||
// ThemeSwitcher.tsx
|
||||
"account.theme.dark": "Dark",
|
||||
"account.theme.light": "Light",
|
||||
"account.theme.system": "System",
|
||||
"account.button.delete": "Delete Account",
|
||||
"account.modal.delete.title": "Delete Account",
|
||||
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?",
|
||||
// END /account
|
||||
// /account/shares
|
||||
"account.shares.title": "My shares",
|
||||
"account.shares.title.empty": "It's empty here 👀",
|
||||
"account.shares.description.empty": "You don't have any shares.",
|
||||
"account.shares.button.create": "Create one",
|
||||
"account.shares.info.title": "Share informations",
|
||||
"account.shares.table.id": "ID",
|
||||
"account.shares.table.name": "Name",
|
||||
"account.shares.table.description": "Description",
|
||||
"account.shares.table.visitors": "Visitors",
|
||||
"account.shares.table.expiresAt": "Expires at",
|
||||
"account.shares.table.createdAt": "Created at",
|
||||
"account.shares.table.size": "Size",
|
||||
"account.shares.modal.share-informations": "Share informations",
|
||||
"account.shares.modal.share-link": "Share link",
|
||||
"account.shares.modal.delete.title": "Delete share {share}",
|
||||
"account.shares.modal.delete.description": "Do you really want to delete this share?",
|
||||
// END /account/shares
|
||||
// /account/reverseShares
|
||||
"account.reverseShares.title": "Reverse shares",
|
||||
"account.reverseShares.description": "A reverse share allows you to generate a unique URL that allows external users to create a share.",
|
||||
"account.reverseShares.title.empty": "It's empty here 👀",
|
||||
"account.reverseShares.description.empty": "You don't have any reverse shares.",
|
||||
// showCreateReverseShareModal.tsx
|
||||
"account.reverseShares.modal.title": "Create reverse share",
|
||||
"account.reverseShares.modal.expiration.label": "Expiration",
|
||||
"account.reverseShares.modal.expiration.minute-singular": "Minute",
|
||||
"account.reverseShares.modal.expiration.minute-plural": "Minutes",
|
||||
"account.reverseShares.modal.expiration.hour-singular": "Hour",
|
||||
"account.reverseShares.modal.expiration.hour-plural": "Hours",
|
||||
"account.reverseShares.modal.expiration.day-singular": "Day",
|
||||
"account.reverseShares.modal.expiration.day-plural": "Days",
|
||||
"account.reverseShares.modal.expiration.week-singular": "Week",
|
||||
"account.reverseShares.modal.expiration.week-plural": "Weeks",
|
||||
"account.reverseShares.modal.expiration.month-singular": "Month",
|
||||
"account.reverseShares.modal.expiration.month-plural": "Months",
|
||||
"account.reverseShares.modal.expiration.year-singular": "Year",
|
||||
"account.reverseShares.modal.expiration.year-plural": "Years",
|
||||
"account.reverseShares.modal.max-size.label": "Max share size",
|
||||
"account.reverseShares.modal.send-email": "Send email notification",
|
||||
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
|
||||
"account.reverseShares.modal.max-use.label": "Max uses",
|
||||
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
|
||||
"account.reverseShare.never-expires": "This reverse share will never expire.",
|
||||
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
|
||||
"account.reverseShares.table.no-shares": "No shares created yet",
|
||||
"account.reverseShares.table.count.singular": "share",
|
||||
"account.reverseShares.table.count.plural": "shares",
|
||||
"account.reverseShares.table.shares": "Shares",
|
||||
"account.reverseShares.table.remaining": "Remaining uses",
|
||||
"account.reverseShares.table.max-size": "Max share size",
|
||||
"account.reverseShares.table.expires": "Expires at",
|
||||
"account.reverseShares.modal.reverse-share-link": "Reverse share link",
|
||||
"account.reverseShares.modal.delete.title": "Delete reverse share",
|
||||
"account.reverseShares.modal.delete.description": "Do you really want to delete this reverse share? If you do, the associated shares will be deleted as well.",
|
||||
// END /account/reverseShares
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "User management",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
// /admin/users
|
||||
"admin.users.title": "User management",
|
||||
"admin.users.table.username": "Username",
|
||||
"admin.users.table.email": "Email",
|
||||
"admin.users.table.admin": "Admin",
|
||||
"admin.users.edit.update.title": "Update user {username}",
|
||||
"admin.users.edit.update.admin-privileges": "Admin privileges",
|
||||
"admin.users.edit.update.change-password.title": "Change password",
|
||||
"admin.users.edit.update.change-password.field": "New password",
|
||||
"admin.users.edit.update.change-password.button": "Save new password",
|
||||
"admin.users.edit.update.notify.password.success": "Password changed successfully",
|
||||
"admin.users.edit.delete.title": "Delete user {username}",
|
||||
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
|
||||
// showCreateUserModal.tsx
|
||||
"admin.users.modal.create.title": "Create user",
|
||||
"admin.users.modal.create.username": "Username",
|
||||
"admin.users.modal.create.email": "Email",
|
||||
"admin.users.modal.create.password": "Password",
|
||||
"admin.users.modal.create.manual-password": "Set password manually",
|
||||
"admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.",
|
||||
"admin.users.modal.create.admin": "Admin privileges",
|
||||
"admin.users.modal.create.admin.description": "If checked, the user will be able to access the admin panel.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"upload.notify.count-failed": "{count} files failed to upload. Trying again.",
|
||||
// Dropzone.tsx
|
||||
"upload.dropzone.title": "Upload files",
|
||||
"upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.",
|
||||
"upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.",
|
||||
// FileList.tsx
|
||||
"upload.filelist.name": "Name",
|
||||
"upload.filelist.size": "Size",
|
||||
// showCreateUploadModal.tsx
|
||||
"upload.modal.title": "Create Share",
|
||||
"upload.modal.link.error.invalid": "Can only contain letters, numbers, underscores, and hyphens",
|
||||
"upload.modal.link.error.taken": "This link is already in use",
|
||||
"upload.modal.not-signed-in": "You're not signed in",
|
||||
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
|
||||
"upload.modal.expires.never": "never",
|
||||
"upload.modal.expires.never-long": "Never Expires",
|
||||
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
|
||||
"upload.modal.link.label": "Link",
|
||||
"upload.modal.expires.label": "Expiration",
|
||||
"upload.modal.expires.minute-singular": "Minute",
|
||||
"upload.modal.expires.minute-plural": "Minutes",
|
||||
"upload.modal.expires.hour-singular": "Hour",
|
||||
"upload.modal.expires.hour-plural": "Hours",
|
||||
"upload.modal.expires.day-singular": "Day",
|
||||
"upload.modal.expires.day-plural": "Days",
|
||||
"upload.modal.expires.week-singular": "Week",
|
||||
"upload.modal.expires.week-plural": "Weeks",
|
||||
"upload.modal.expires.month-singular": "Month",
|
||||
"upload.modal.expires.month-plural": "Months",
|
||||
"upload.modal.expires.year-singular": "Year",
|
||||
"upload.modal.expires.year-plural": "Years",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Email recipients",
|
||||
"upload.modal.accordion.email.placeholder": "Enter email recipients",
|
||||
"upload.modal.accordion.email.invalid-email": "Invalid email address",
|
||||
"upload.modal.accordion.security.title": "Security options",
|
||||
"upload.modal.accordion.security.password.label": "Password protection",
|
||||
"upload.modal.accordion.security.password.placeholder": "No password",
|
||||
"upload.modal.accordion.security.max-views.label": "Maximum views",
|
||||
"upload.modal.accordion.security.max-views.placeholder": "No limit",
|
||||
// showCompletedUploadModal.tsx
|
||||
"upload.modal.completed.never-expires": "This share will never expire.",
|
||||
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
|
||||
"upload.modal.completed.share-ready": "Share ready",
|
||||
// END /upload
|
||||
// /share/[id]
|
||||
"share.title": "Share {shareId}",
|
||||
"share.description": "Look what I've shared with you!",
|
||||
"share.error.visitor-limit-exceeded.title": "Visitor limit exceeded",
|
||||
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
|
||||
"share.error.removed.title": "Share removed",
|
||||
"share.error.not-found.title": "Share not found",
|
||||
"share.error.not-found.description": "The share you're looking for doesn't exist.",
|
||||
"share.modal.password.title": "Password required",
|
||||
"share.modal.password.description": "To access this share please enter the password for the share.",
|
||||
"share.modal.password": "Password",
|
||||
"share.modal.error.invalid-password": "Invalid password",
|
||||
"share.button.download-all": "Download all",
|
||||
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
|
||||
"share.modal.file-link": "File link",
|
||||
"share.table.name": "Name",
|
||||
"share.table.size": "Size",
|
||||
"share.modal.file-preview.error.not-supported.title": "Preview not supported",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Edit {shareId}",
|
||||
"share.edit.append-upload": "Append file",
|
||||
"share.edit.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"share.edit.notify.save-success": "Share updated successfully",
|
||||
// END /share/[id]/edit
|
||||
// /admin/config
|
||||
"admin.config.title": "Configuration",
|
||||
"admin.config.category.general": "General",
|
||||
"admin.config.category.share": "Share",
|
||||
"admin.config.category.email": "Email",
|
||||
"admin.config.category.smtp": "SMTP",
|
||||
"admin.config.category.oauth": "Social Login",
|
||||
"admin.config.general.app-name": "App name",
|
||||
"admin.config.general.app-name.description": "Name of the application",
|
||||
"admin.config.general.app-url": "App URL",
|
||||
"admin.config.general.app-url.description": "On which URL Pingvin Share is available",
|
||||
"admin.config.general.show-home-page": "Show home page",
|
||||
"admin.config.general.show-home-page.description": "Whether to show the home page",
|
||||
"admin.config.general.logo": "Logo",
|
||||
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.",
|
||||
"admin.config.general.logo.placeholder": "Pick image",
|
||||
"admin.config.email.enable-share-email-recipients": "Enable share email recipients",
|
||||
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
|
||||
"admin.config.email.share-recipients-subject": "Share recipients subject",
|
||||
"admin.config.email.share-recipients-subject.description": "Subject of the email which gets sent to the share recipients.",
|
||||
"admin.config.email.share-recipients-message": "Share recipients message",
|
||||
"admin.config.email.share-recipients-message.description": "Message which gets sent to the share recipients. Available variables:\n {creator} - The username of the creator of the share\n {shareUrl} - The URL of the share\n {desc} - The description of the share\n {expires} - The expiration date of the share\n The variables will be replaced with the actual value.",
|
||||
"admin.config.email.reverse-share-subject": "Reverse share subject",
|
||||
"admin.config.email.reverse-share-subject.description": "Subject of the email which gets sent when someone created a share with your reverse share link.",
|
||||
"admin.config.email.reverse-share-message": "Reverse share message",
|
||||
"admin.config.email.reverse-share-message.description": "Message which gets sent when someone created a share with your reverse share link. {shareUrl} will be replaced with the creator's name and the share URL.",
|
||||
"admin.config.email.reset-password-subject": "Reset password subject",
|
||||
"admin.config.email.reset-password-subject.description": "Subject of the email which gets sent when a user requests a password reset.",
|
||||
"admin.config.email.reset-password-message": "Reset password message",
|
||||
"admin.config.email.reset-password-message.description": "Message which gets sent when a user requests a password reset. {url} will be replaced with the reset password URL.",
|
||||
"admin.config.email.invite-subject": "Invite subject",
|
||||
"admin.config.email.invite-subject.description": "Subject of the email which gets sent when an admin invites a user.",
|
||||
"admin.config.email.invite-message": "Invite message",
|
||||
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL and {password} with the password.",
|
||||
"admin.config.share.allow-registration": "Allow registration",
|
||||
"admin.config.share.allow-registration.description": "Whether registration is allowed",
|
||||
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
|
||||
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
|
||||
"admin.config.share.max-expiration": "Max expiration",
|
||||
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
|
||||
"admin.config.share.max-size": "Max size",
|
||||
"admin.config.share.max-size.description": "Maximum share size in bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip compression level",
|
||||
"admin.config.share.zip-compression-level.description": "Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Enabled",
|
||||
"admin.config.smtp.enabled.description": "Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
"admin.config.smtp.host.description": "Host of the SMTP server",
|
||||
"admin.config.smtp.port": "Port",
|
||||
"admin.config.smtp.port.description": "Port of the SMTP server",
|
||||
"admin.config.smtp.email": "Email",
|
||||
"admin.config.smtp.email.description": "Email address which the emails get sent from",
|
||||
"admin.config.smtp.username": "Username",
|
||||
"admin.config.smtp.username.description": "Username of the SMTP server",
|
||||
"admin.config.smtp.password": "Password",
|
||||
"admin.config.smtp.password.description": "Password of the SMTP server",
|
||||
"admin.config.smtp.button.test": "Send test email",
|
||||
"admin.config.oauth.allow-registration": "Allow registration",
|
||||
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
|
||||
"admin.config.oauth.ignore-totp": "Ignore TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
|
||||
"admin.config.oauth.github-enabled": "GitHub",
|
||||
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled",
|
||||
"admin.config.oauth.github-client-id": "GitHub Client ID",
|
||||
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-secret": "GitHub Client secret",
|
||||
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app",
|
||||
"admin.config.oauth.google-enabled": "Google",
|
||||
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled",
|
||||
"admin.config.oauth.google-client-id": "Google Client ID",
|
||||
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-secret": "Google Client secret",
|
||||
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app",
|
||||
"admin.config.oauth.microsoft-enabled": "Microsoft",
|
||||
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled",
|
||||
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant",
|
||||
"admin.config.oauth.microsoft-tenant.description": "Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
|
||||
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID",
|
||||
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret",
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-client-id": "Discord Client ID",
|
||||
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-secret": "Discord Client secret",
|
||||
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "Whether OpenID Connect login is enabled",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
|
||||
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID Connect OAuth app",
|
||||
// 404
|
||||
"404.description": "Oops this page doesn't exist.",
|
||||
"404.button.home": "Bring me back home",
|
||||
// error
|
||||
"error.title": "Error",
|
||||
"error.description": "Oops!",
|
||||
"error.button.back": "Go back",
|
||||
"error.msg.default": "Something went wrong.",
|
||||
"error.msg.access_denied": "You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token": "The authentication process took too long, please try again.",
|
||||
"error.msg.invalid_token": "Internal Error",
|
||||
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
|
||||
"error.msg.no_email": "Can't get email address from this {0} account.",
|
||||
"error.msg.already_linked": "This {0} account is already linked to another account.",
|
||||
"error.msg.not_linked": "This {0} account haven't linked to any account yet.",
|
||||
"error.msg.unverified_account": "This {0} account is unverified, please try again after verification.",
|
||||
"error.msg.discord_guild_permission_denied": "You are not allowed to sign in.",
|
||||
"error.msg.cannot_get_user_info": "Can not get your user info from this {0} account.",
|
||||
"error.param.provider_github": "GitHub",
|
||||
"error.param.provider_google": "Google",
|
||||
"error.param.provider_microsoft": "Microsoft",
|
||||
"error.param.provider_discord": "Discord",
|
||||
"error.param.provider_oidc": "OpenID Connect",
|
||||
// Common translations
|
||||
"common.button.save": "Save",
|
||||
"common.button.create": "Create",
|
||||
"common.button.submit": "Submit",
|
||||
"common.button.delete": "Delete",
|
||||
"common.button.cancel": "Cancel",
|
||||
"common.button.confirm": "Confirm",
|
||||
"common.button.disable": "Disable",
|
||||
"common.button.share": "Share",
|
||||
"common.button.generate": "Generate",
|
||||
"common.button.done": "Done",
|
||||
"common.text.link": "Link",
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "or",
|
||||
"common.button.go-back": "Go back",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Your link was copied to the clipboard",
|
||||
"common.success": "Success",
|
||||
"common.error": "Error",
|
||||
"common.error.unknown": "An unknown error occurred",
|
||||
"common.error.invalid-email": "Invalid email address",
|
||||
"common.error.too-short": "Must be at least {length} characters",
|
||||
"common.error.too-long": "Must be at most {length} characters",
|
||||
"common.error.exact-length": "Must be exactly {length} characters",
|
||||
"common.error.invalid-number": "Must be a number",
|
||||
"common.error.field-required": "This field is required"
|
||||
};
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"navbar.upload": "Carica",
|
||||
"navbar.signin": "Registrati",
|
||||
"navbar.home": "Home",
|
||||
"navbar.signup": "Registrati",
|
||||
"navbar.signup": "Accedi",
|
||||
"navbar.links.shares": "Le mie condivisioni",
|
||||
"navbar.links.reverse": "Condivisioni Inverse",
|
||||
"navbar.avatar.account": "Il mio account",
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Hai dimenticato la password?",
|
||||
"resetPassword.description": "Inserisci la tua email per reimpostare la password.",
|
||||
"resetPassword.notify.success": "Abbiamo inviato un'e-mail all'indirizzo da te indicato. Clicca sul link contenuto nell'e-mail per reimpostare la password del tuo account.",
|
||||
"resetPassword.notify.success": "Un messaggio con un link per reimpostare la password è stato inviato se l'e-mail esiste.",
|
||||
"resetPassword.button.back": "Torna alla pagina di login",
|
||||
"resetPassword.text.resetPassword": "Reimposta password",
|
||||
"resetPassword.text.enterNewPassword": "Inserisci la tua nuova password",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Amministrazione",
|
||||
"admin.button.users": "Gestione degli utenti",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configurazione",
|
||||
"admin.version": "Versione",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Privilegi di amministrazione",
|
||||
"admin.users.modal.create.admin.description": "Se selezionato, l'utente sarà in grado di accedere al pannello amministratore.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "Si è verificato un errore durante il completamento della condivisione.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Mesi",
|
||||
"upload.modal.expires.year-singular": "Anno",
|
||||
"upload.modal.expires.year-plural": "Anni",
|
||||
"upload.modal.accordion.description.title": "Descrizione",
|
||||
"upload.modal.accordion.description.placeholder": "Nota per i destinatari di questa condivisione",
|
||||
"upload.modal.accordion.name-and-description.title": "Nome e descrizione",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Nome",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Nota per i destinatari di questa condivisione",
|
||||
"upload.modal.accordion.email.title": "Destinatari di posta elettronica",
|
||||
"upload.modal.accordion.email.placeholder": "Inserisci le email dei destinatari",
|
||||
"upload.modal.accordion.email.invalid-email": "Indirizzo email non valido",
|
||||
@@ -262,7 +273,7 @@ export default {
|
||||
"share.table.name": "Nome",
|
||||
"share.table.size": "Dimensione",
|
||||
"share.modal.file-preview.error.not-supported.title": "Anteprima non supportata",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
"share.modal.file-preview.error.not-supported.description": "Un'anteprima per questo tipo di file non è supportata. Per favore scarica il file per visualizzarlo.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Modifica {shareId}",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Dimensione massima di condivisione in byte",
|
||||
"admin.config.share.zip-compression-level": "Livello di compressione Zip",
|
||||
"admin.config.share.zip-compression-level.description": "Regola il livello per bilanciare la dimensione del file e la velocità di compressione. Valori validi da 0 a 9, con 0 senza compressione e 9 con compressione massima. ",
|
||||
"admin.config.share.chunk-size": "Dimensione dei chunk",
|
||||
"admin.config.share.chunk-size.description": "Regola la dimensione del chunk (in byte) per i tuoi caricamenti per bilanciare l'efficienza e l'affidabilità in base alla tua connessione internet. I chunk più piccoli possono migliorare i tassi di successo per connessioni instabili, mentre i chunks più grandi velocizzano i caricamenti per connessioni stabili.",
|
||||
"admin.config.smtp.enabled": "Abilitato",
|
||||
"admin.config.smtp.enabled.description": "Indica se SMTP è abilitato. Impostalo a VERO solo se hai inserito host, porta, email, utente e password del tuo server SMTP.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Vai al collegamento",
|
||||
"common.text.or": "o",
|
||||
"common.button.go-back": "Torna indietro",
|
||||
"common.button.go-home": "Vai alla Home Page",
|
||||
"common.notify.copied": "Il tuo collegamento e' stato copiato negli appunti",
|
||||
"common.success": "Successo",
|
||||
"common.error": "Errore",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "パスワードを忘れてしまいましたか?",
|
||||
"resetPassword.description": "登録しているメールアドレスを入力してください。",
|
||||
"resetPassword.notify.success": "パスワードをリセットするためのリンクをメールで送信しました。",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "サインインページに戻る",
|
||||
"resetPassword.text.resetPassword": "パスワードをリセット",
|
||||
"resetPassword.text.enterNewPassword": "新規パスワードを入力",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "管理画面",
|
||||
"admin.button.users": "ユーザー管理",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "設定",
|
||||
"admin.version": "バージョン",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "管理者権限",
|
||||
"admin.users.modal.create.admin.description": "チェックされている場合、ユーザーは管理画面にアクセスできるようになります。",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "アップロード",
|
||||
"upload.notify.generic-error": "共有を仕上げている最中にエラーが発生しました。",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "ヶ月間",
|
||||
"upload.modal.expires.year-singular": "年間",
|
||||
"upload.modal.expires.year-plural": "年間",
|
||||
"upload.modal.accordion.description.title": "説明",
|
||||
"upload.modal.accordion.description.placeholder": "この共有に関する受信者へのメモ",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "メールで受け取る相手",
|
||||
"upload.modal.accordion.email.placeholder": "メールの宛先を入力",
|
||||
"upload.modal.accordion.email.invalid-email": "無効なメールアドレスです",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "最大ファイルサイズ(byte単位)",
|
||||
"admin.config.share.zip-compression-level": "Zip圧縮レベル",
|
||||
"admin.config.share.zip-compression-level.description": "ファイルサイズと圧縮速度のバランスを取るように、レベルを調整できます。有効な値は0~9の間で、0が無圧縮、9で最大限の圧縮となります。 ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "有効",
|
||||
"admin.config.smtp.enabled.description": "SMTPを有効にするかどうかを選択してください。SMTPサーバーのホスト名、ポート番号、電子メールアドレス、ユーザー名、パスワードが入力されている場合にのみ、有効にしてください。",
|
||||
"admin.config.smtp.host": "ホスト名",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "または",
|
||||
"common.button.go-back": "戻る",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "リンクをクリップボードにコピーしました",
|
||||
"common.success": "成功",
|
||||
"common.error": "エラー",
|
||||
|
||||
434
frontend/src/i18n/translations/ko-KR.ts
Normal file
434
frontend/src/i18n/translations/ko-KR.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
export default {
|
||||
// Navbar
|
||||
"navbar.upload": "Upload",
|
||||
"navbar.signin": "Sign in",
|
||||
"navbar.home": "Home",
|
||||
"navbar.signup": "Sign Up",
|
||||
"navbar.links.shares": "My shares",
|
||||
"navbar.links.reverse": "Reverse shares",
|
||||
"navbar.avatar.account": "My account",
|
||||
"navbar.avatar.admin": "Administration",
|
||||
"navbar.avatar.signout": "Sign out",
|
||||
// END navbar
|
||||
// /
|
||||
"home.title": "A <h>self-hosted</h> file sharing platform.",
|
||||
"home.description": "Do you really want to give your personal files in the hand of third parties like WeTransfer?",
|
||||
"home.bullet.a.name": "Self-Hosted",
|
||||
"home.bullet.a.description": "Host Pingvin Share on your own machine.",
|
||||
"home.bullet.b.name": "Privacy",
|
||||
"home.bullet.b.description": "Your files are your files and should never get into the hands of third parties.",
|
||||
"home.bullet.c.name": "No annoying file size limit",
|
||||
"home.bullet.c.description": "Upload as big files as you want. Only your hard drive will be your limit.",
|
||||
"home.button.start": "Get started",
|
||||
"home.button.source": "Source code",
|
||||
// END /
|
||||
// /auth/signin
|
||||
"signin.title": "Welcome back",
|
||||
"signin.description": "You don't have an account yet?",
|
||||
"signin.button.signup": "Sign up",
|
||||
"signin.input.email-or-username": "Email or username",
|
||||
"signin.input.email-or-username.placeholder": "Your email or username",
|
||||
"signin.input.password": "Password",
|
||||
"signin.input.password.placeholder": "Your password",
|
||||
"signin.button.submit": "Sign in",
|
||||
"signIn.notify.totp-required.title": "Two-factor authentication required",
|
||||
"signIn.notify.totp-required.description": "Please enter your two-factor authentication code",
|
||||
"signIn.oauth.or": "OR",
|
||||
"signIn.oauth.github": "GitHub",
|
||||
"signIn.oauth.google": "Google",
|
||||
"signIn.oauth.microsoft": "Microsoft",
|
||||
"signIn.oauth.discord": "Discord",
|
||||
"signIn.oauth.oidc": "OpenID",
|
||||
// END /auth/signin
|
||||
// /auth/signup
|
||||
"signup.title": "Create an account",
|
||||
"signup.description": "Already have an account?",
|
||||
"signup.button.signin": "Sign in",
|
||||
"signup.input.username": "Username",
|
||||
"signup.input.username.placeholder": "Your username",
|
||||
"signup.input.email": "Email",
|
||||
"signup.input.email.placeholder": "Your email",
|
||||
"signup.button.submit": "Let's get started",
|
||||
// END /auth/signup
|
||||
// /auth/totp
|
||||
"totp.title": "TOTP Authentication",
|
||||
"totp.button.signIn": "Sign in",
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Forgot your password?",
|
||||
"resetPassword.description": "Enter your email to reset your password.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Back to sign in page",
|
||||
"resetPassword.text.resetPassword": "Reset password",
|
||||
"resetPassword.text.enterNewPassword": "Enter your new password",
|
||||
"resetPassword.input.password": "New password",
|
||||
"resetPassword.notify.passwordReset": "Your password has been reset successfully.",
|
||||
// /account
|
||||
"account.title": "My account",
|
||||
"account.card.info.title": "Account info",
|
||||
"account.card.info.username": "Username",
|
||||
"account.card.info.email": "Email",
|
||||
"account.notify.info.success": "Account updated successfully",
|
||||
"account.card.password.title": "Password",
|
||||
"account.card.password.old": "Old password",
|
||||
"account.card.password.new": "New password",
|
||||
"account.card.password.noPasswordSet": "You don't have a password set. If you want to sign in with email and password you need to set a password.",
|
||||
"account.notify.password.success": "Password changed successfully",
|
||||
"account.card.oauth.title": "Social login",
|
||||
"account.card.oauth.github": "GitHub",
|
||||
"account.card.oauth.google": "Google",
|
||||
"account.card.oauth.microsoft": "Microsoft",
|
||||
"account.card.oauth.discord": "Discord",
|
||||
"account.card.oauth.oidc": "OpenID",
|
||||
"account.card.oauth.link": "Link",
|
||||
"account.card.oauth.unlink": "Unlink",
|
||||
"account.card.oauth.unlinked": "Unlinked",
|
||||
"account.modal.unlink.title": "Unlink account",
|
||||
"account.modal.unlink.description": "Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
|
||||
"account.notify.oauth.unlinked.success": "Unlinked successfully",
|
||||
"account.card.security.title": "Security",
|
||||
"account.card.security.totp.enable.description": "Enter your current password to start enabling TOTP",
|
||||
"account.card.security.totp.disable.description": "Enter your current password to disable TOTP",
|
||||
"account.card.security.totp.button.start": "Start",
|
||||
"account.modal.totp.title": "Enable TOTP",
|
||||
"account.modal.totp.step1": "Step 1: Add your authenticator",
|
||||
"account.modal.totp.step2": "Step 2: Validate your code",
|
||||
"account.modal.totp.enterManually": "Enter manually",
|
||||
"account.modal.totp.code": "Code",
|
||||
"account.modal.totp.clickToCopy": "Click to copy",
|
||||
"account.modal.totp.verify": "Verify",
|
||||
"account.notify.totp.disable": "TOTP disabled successfully",
|
||||
"account.notify.totp.enable": "TOTP enabled successfully",
|
||||
"account.card.language.title": "Language",
|
||||
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.",
|
||||
"account.card.color.title": "Color scheme",
|
||||
// ThemeSwitcher.tsx
|
||||
"account.theme.dark": "Dark",
|
||||
"account.theme.light": "Light",
|
||||
"account.theme.system": "System",
|
||||
"account.button.delete": "Delete Account",
|
||||
"account.modal.delete.title": "Delete Account",
|
||||
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?",
|
||||
// END /account
|
||||
// /account/shares
|
||||
"account.shares.title": "My shares",
|
||||
"account.shares.title.empty": "It's empty here 👀",
|
||||
"account.shares.description.empty": "You don't have any shares.",
|
||||
"account.shares.button.create": "Create one",
|
||||
"account.shares.info.title": "Share informations",
|
||||
"account.shares.table.id": "ID",
|
||||
"account.shares.table.name": "Name",
|
||||
"account.shares.table.description": "Description",
|
||||
"account.shares.table.visitors": "Visitors",
|
||||
"account.shares.table.expiresAt": "Expires at",
|
||||
"account.shares.table.createdAt": "Created at",
|
||||
"account.shares.table.size": "Size",
|
||||
"account.shares.modal.share-informations": "Share informations",
|
||||
"account.shares.modal.share-link": "Share link",
|
||||
"account.shares.modal.delete.title": "Delete share {share}",
|
||||
"account.shares.modal.delete.description": "Do you really want to delete this share?",
|
||||
// END /account/shares
|
||||
// /account/reverseShares
|
||||
"account.reverseShares.title": "Reverse shares",
|
||||
"account.reverseShares.description": "A reverse share allows you to generate a unique URL that allows external users to create a share.",
|
||||
"account.reverseShares.title.empty": "It's empty here 👀",
|
||||
"account.reverseShares.description.empty": "You don't have any reverse shares.",
|
||||
// showCreateReverseShareModal.tsx
|
||||
"account.reverseShares.modal.title": "Create reverse share",
|
||||
"account.reverseShares.modal.expiration.label": "Expiration",
|
||||
"account.reverseShares.modal.expiration.minute-singular": "Minute",
|
||||
"account.reverseShares.modal.expiration.minute-plural": "Minutes",
|
||||
"account.reverseShares.modal.expiration.hour-singular": "Hour",
|
||||
"account.reverseShares.modal.expiration.hour-plural": "Hours",
|
||||
"account.reverseShares.modal.expiration.day-singular": "Day",
|
||||
"account.reverseShares.modal.expiration.day-plural": "Days",
|
||||
"account.reverseShares.modal.expiration.week-singular": "Week",
|
||||
"account.reverseShares.modal.expiration.week-plural": "Weeks",
|
||||
"account.reverseShares.modal.expiration.month-singular": "Month",
|
||||
"account.reverseShares.modal.expiration.month-plural": "Months",
|
||||
"account.reverseShares.modal.expiration.year-singular": "Year",
|
||||
"account.reverseShares.modal.expiration.year-plural": "Years",
|
||||
"account.reverseShares.modal.max-size.label": "Max share size",
|
||||
"account.reverseShares.modal.send-email": "Send email notification",
|
||||
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
|
||||
"account.reverseShares.modal.max-use.label": "Max uses",
|
||||
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
|
||||
"account.reverseShare.never-expires": "This reverse share will never expire.",
|
||||
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
|
||||
"account.reverseShares.table.no-shares": "No shares created yet",
|
||||
"account.reverseShares.table.count.singular": "share",
|
||||
"account.reverseShares.table.count.plural": "shares",
|
||||
"account.reverseShares.table.shares": "Shares",
|
||||
"account.reverseShares.table.remaining": "Remaining uses",
|
||||
"account.reverseShares.table.max-size": "Max share size",
|
||||
"account.reverseShares.table.expires": "Expires at",
|
||||
"account.reverseShares.modal.reverse-share-link": "Reverse share link",
|
||||
"account.reverseShares.modal.delete.title": "Delete reverse share",
|
||||
"account.reverseShares.modal.delete.description": "Do you really want to delete this reverse share? If you do, the associated shares will be deleted as well.",
|
||||
// END /account/reverseShares
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "User management",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
// /admin/users
|
||||
"admin.users.title": "User management",
|
||||
"admin.users.table.username": "Username",
|
||||
"admin.users.table.email": "Email",
|
||||
"admin.users.table.admin": "Admin",
|
||||
"admin.users.edit.update.title": "Update user {username}",
|
||||
"admin.users.edit.update.admin-privileges": "Admin privileges",
|
||||
"admin.users.edit.update.change-password.title": "Change password",
|
||||
"admin.users.edit.update.change-password.field": "New password",
|
||||
"admin.users.edit.update.change-password.button": "Save new password",
|
||||
"admin.users.edit.update.notify.password.success": "Password changed successfully",
|
||||
"admin.users.edit.delete.title": "Delete user {username}",
|
||||
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
|
||||
// showCreateUserModal.tsx
|
||||
"admin.users.modal.create.title": "Create user",
|
||||
"admin.users.modal.create.username": "Username",
|
||||
"admin.users.modal.create.email": "Email",
|
||||
"admin.users.modal.create.password": "Password",
|
||||
"admin.users.modal.create.manual-password": "Set password manually",
|
||||
"admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.",
|
||||
"admin.users.modal.create.admin": "Admin privileges",
|
||||
"admin.users.modal.create.admin.description": "If checked, the user will be able to access the admin panel.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Upload",
|
||||
"upload.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"upload.notify.count-failed": "{count} files failed to upload. Trying again.",
|
||||
// Dropzone.tsx
|
||||
"upload.dropzone.title": "Upload files",
|
||||
"upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.",
|
||||
"upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.",
|
||||
// FileList.tsx
|
||||
"upload.filelist.name": "Name",
|
||||
"upload.filelist.size": "Size",
|
||||
// showCreateUploadModal.tsx
|
||||
"upload.modal.title": "Create Share",
|
||||
"upload.modal.link.error.invalid": "Can only contain letters, numbers, underscores, and hyphens",
|
||||
"upload.modal.link.error.taken": "This link is already in use",
|
||||
"upload.modal.not-signed-in": "You're not signed in",
|
||||
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
|
||||
"upload.modal.expires.never": "never",
|
||||
"upload.modal.expires.never-long": "Never Expires",
|
||||
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
|
||||
"upload.modal.link.label": "Link",
|
||||
"upload.modal.expires.label": "Expiration",
|
||||
"upload.modal.expires.minute-singular": "Minute",
|
||||
"upload.modal.expires.minute-plural": "Minutes",
|
||||
"upload.modal.expires.hour-singular": "Hour",
|
||||
"upload.modal.expires.hour-plural": "Hours",
|
||||
"upload.modal.expires.day-singular": "Day",
|
||||
"upload.modal.expires.day-plural": "Days",
|
||||
"upload.modal.expires.week-singular": "Week",
|
||||
"upload.modal.expires.week-plural": "Weeks",
|
||||
"upload.modal.expires.month-singular": "Month",
|
||||
"upload.modal.expires.month-plural": "Months",
|
||||
"upload.modal.expires.year-singular": "Year",
|
||||
"upload.modal.expires.year-plural": "Years",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Email recipients",
|
||||
"upload.modal.accordion.email.placeholder": "Enter email recipients",
|
||||
"upload.modal.accordion.email.invalid-email": "Invalid email address",
|
||||
"upload.modal.accordion.security.title": "Security options",
|
||||
"upload.modal.accordion.security.password.label": "Password protection",
|
||||
"upload.modal.accordion.security.password.placeholder": "No password",
|
||||
"upload.modal.accordion.security.max-views.label": "Maximum views",
|
||||
"upload.modal.accordion.security.max-views.placeholder": "No limit",
|
||||
// showCompletedUploadModal.tsx
|
||||
"upload.modal.completed.never-expires": "This share will never expire.",
|
||||
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
|
||||
"upload.modal.completed.share-ready": "Share ready",
|
||||
// END /upload
|
||||
// /share/[id]
|
||||
"share.title": "Share {shareId}",
|
||||
"share.description": "Look what I've shared with you!",
|
||||
"share.error.visitor-limit-exceeded.title": "Visitor limit exceeded",
|
||||
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
|
||||
"share.error.removed.title": "Share removed",
|
||||
"share.error.not-found.title": "Share not found",
|
||||
"share.error.not-found.description": "The share you're looking for doesn't exist.",
|
||||
"share.modal.password.title": "Password required",
|
||||
"share.modal.password.description": "To access this share please enter the password for the share.",
|
||||
"share.modal.password": "Password",
|
||||
"share.modal.error.invalid-password": "Invalid password",
|
||||
"share.button.download-all": "Download all",
|
||||
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
|
||||
"share.modal.file-link": "File link",
|
||||
"share.table.name": "Name",
|
||||
"share.table.size": "Size",
|
||||
"share.modal.file-preview.error.not-supported.title": "Preview not supported",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Edit {shareId}",
|
||||
"share.edit.append-upload": "Append file",
|
||||
"share.edit.notify.generic-error": "An error occurred while finishing your share.",
|
||||
"share.edit.notify.save-success": "Share updated successfully",
|
||||
// END /share/[id]/edit
|
||||
// /admin/config
|
||||
"admin.config.title": "Configuration",
|
||||
"admin.config.category.general": "General",
|
||||
"admin.config.category.share": "Share",
|
||||
"admin.config.category.email": "Email",
|
||||
"admin.config.category.smtp": "SMTP",
|
||||
"admin.config.category.oauth": "Social Login",
|
||||
"admin.config.general.app-name": "App name",
|
||||
"admin.config.general.app-name.description": "Name of the application",
|
||||
"admin.config.general.app-url": "App URL",
|
||||
"admin.config.general.app-url.description": "On which URL Pingvin Share is available",
|
||||
"admin.config.general.show-home-page": "Show home page",
|
||||
"admin.config.general.show-home-page.description": "Whether to show the home page",
|
||||
"admin.config.general.logo": "Logo",
|
||||
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.",
|
||||
"admin.config.general.logo.placeholder": "Pick image",
|
||||
"admin.config.email.enable-share-email-recipients": "Enable share email recipients",
|
||||
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
|
||||
"admin.config.email.share-recipients-subject": "Share recipients subject",
|
||||
"admin.config.email.share-recipients-subject.description": "Subject of the email which gets sent to the share recipients.",
|
||||
"admin.config.email.share-recipients-message": "Share recipients message",
|
||||
"admin.config.email.share-recipients-message.description": "Message which gets sent to the share recipients. Available variables:\n {creator} - The username of the creator of the share\n {shareUrl} - The URL of the share\n {desc} - The description of the share\n {expires} - The expiration date of the share\n The variables will be replaced with the actual value.",
|
||||
"admin.config.email.reverse-share-subject": "Reverse share subject",
|
||||
"admin.config.email.reverse-share-subject.description": "Subject of the email which gets sent when someone created a share with your reverse share link.",
|
||||
"admin.config.email.reverse-share-message": "Reverse share message",
|
||||
"admin.config.email.reverse-share-message.description": "Message which gets sent when someone created a share with your reverse share link. {shareUrl} will be replaced with the creator's name and the share URL.",
|
||||
"admin.config.email.reset-password-subject": "Reset password subject",
|
||||
"admin.config.email.reset-password-subject.description": "Subject of the email which gets sent when a user requests a password reset.",
|
||||
"admin.config.email.reset-password-message": "Reset password message",
|
||||
"admin.config.email.reset-password-message.description": "Message which gets sent when a user requests a password reset. {url} will be replaced with the reset password URL.",
|
||||
"admin.config.email.invite-subject": "Invite subject",
|
||||
"admin.config.email.invite-subject.description": "Subject of the email which gets sent when an admin invites a user.",
|
||||
"admin.config.email.invite-message": "Invite message",
|
||||
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL and {password} with the password.",
|
||||
"admin.config.share.allow-registration": "Allow registration",
|
||||
"admin.config.share.allow-registration.description": "Whether registration is allowed",
|
||||
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
|
||||
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
|
||||
"admin.config.share.max-expiration": "Max expiration",
|
||||
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
|
||||
"admin.config.share.max-size": "Max size",
|
||||
"admin.config.share.max-size.description": "Maximum share size in bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip compression level",
|
||||
"admin.config.share.zip-compression-level.description": "Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Enabled",
|
||||
"admin.config.smtp.enabled.description": "Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
"admin.config.smtp.host.description": "Host of the SMTP server",
|
||||
"admin.config.smtp.port": "Port",
|
||||
"admin.config.smtp.port.description": "Port of the SMTP server",
|
||||
"admin.config.smtp.email": "Email",
|
||||
"admin.config.smtp.email.description": "Email address which the emails get sent from",
|
||||
"admin.config.smtp.username": "Username",
|
||||
"admin.config.smtp.username.description": "Username of the SMTP server",
|
||||
"admin.config.smtp.password": "Password",
|
||||
"admin.config.smtp.password.description": "Password of the SMTP server",
|
||||
"admin.config.smtp.button.test": "Send test email",
|
||||
"admin.config.oauth.allow-registration": "Allow registration",
|
||||
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
|
||||
"admin.config.oauth.ignore-totp": "Ignore TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
|
||||
"admin.config.oauth.github-enabled": "GitHub",
|
||||
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled",
|
||||
"admin.config.oauth.github-client-id": "GitHub Client ID",
|
||||
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app",
|
||||
"admin.config.oauth.github-client-secret": "GitHub Client secret",
|
||||
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app",
|
||||
"admin.config.oauth.google-enabled": "Google",
|
||||
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled",
|
||||
"admin.config.oauth.google-client-id": "Google Client ID",
|
||||
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app",
|
||||
"admin.config.oauth.google-client-secret": "Google Client secret",
|
||||
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app",
|
||||
"admin.config.oauth.microsoft-enabled": "Microsoft",
|
||||
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled",
|
||||
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant",
|
||||
"admin.config.oauth.microsoft-tenant.description": "Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
|
||||
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID",
|
||||
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app",
|
||||
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret",
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled",
|
||||
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
|
||||
"admin.config.oauth.discord-client-id": "Discord Client ID",
|
||||
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app",
|
||||
"admin.config.oauth.discord-client-secret": "Discord Client secret",
|
||||
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "Whether OpenID Connect login is enabled",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID Connect OAuth app",
|
||||
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
|
||||
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID Connect OAuth app",
|
||||
// 404
|
||||
"404.description": "Oops this page doesn't exist.",
|
||||
"404.button.home": "Bring me back home",
|
||||
// error
|
||||
"error.title": "Error",
|
||||
"error.description": "Oops!",
|
||||
"error.button.back": "Go back",
|
||||
"error.msg.default": "Something went wrong.",
|
||||
"error.msg.access_denied": "You canceled the authentication process, please try again.",
|
||||
"error.msg.expired_token": "The authentication process took too long, please try again.",
|
||||
"error.msg.invalid_token": "Internal Error",
|
||||
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
|
||||
"error.msg.no_email": "Can't get email address from this {0} account.",
|
||||
"error.msg.already_linked": "This {0} account is already linked to another account.",
|
||||
"error.msg.not_linked": "This {0} account haven't linked to any account yet.",
|
||||
"error.msg.unverified_account": "This {0} account is unverified, please try again after verification.",
|
||||
"error.msg.discord_guild_permission_denied": "You are not allowed to sign in.",
|
||||
"error.msg.cannot_get_user_info": "Can not get your user info from this {0} account.",
|
||||
"error.param.provider_github": "GitHub",
|
||||
"error.param.provider_google": "Google",
|
||||
"error.param.provider_microsoft": "Microsoft",
|
||||
"error.param.provider_discord": "Discord",
|
||||
"error.param.provider_oidc": "OpenID Connect",
|
||||
// Common translations
|
||||
"common.button.save": "Save",
|
||||
"common.button.create": "Create",
|
||||
"common.button.submit": "Submit",
|
||||
"common.button.delete": "Delete",
|
||||
"common.button.cancel": "Cancel",
|
||||
"common.button.confirm": "Confirm",
|
||||
"common.button.disable": "Disable",
|
||||
"common.button.share": "Share",
|
||||
"common.button.generate": "Generate",
|
||||
"common.button.done": "Done",
|
||||
"common.text.link": "Link",
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "or",
|
||||
"common.button.go-back": "Go back",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Your link was copied to the clipboard",
|
||||
"common.success": "Success",
|
||||
"common.error": "Error",
|
||||
"common.error.unknown": "An unknown error occurred",
|
||||
"common.error.invalid-email": "Invalid email address",
|
||||
"common.error.too-short": "Must be at least {length} characters",
|
||||
"common.error.too-long": "Must be at most {length} characters",
|
||||
"common.error.exact-length": "Must be exactly {length} characters",
|
||||
"common.error.invalid-number": "Must be a number",
|
||||
"common.error.field-required": "This field is required"
|
||||
};
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Wachtwoord vergeten?",
|
||||
"resetPassword.description": "Voer uw e-mailadres in om uw wachtwoord opnieuw in te stellen.",
|
||||
"resetPassword.notify.success": "Een e-mail is verzonden met een link om uw wachtwoord te resetten.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Terug naar login pagina",
|
||||
"resetPassword.text.resetPassword": "Wachtwoord opnieuw instellen",
|
||||
"resetPassword.text.enterNewPassword": "Voer uw nieuwe wachtwoord in",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Instellingen",
|
||||
"admin.button.users": "Gebruikers beheer",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuratie",
|
||||
"admin.version": "Versie",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Beheerdersrechten",
|
||||
"admin.users.modal.create.admin.description": "Indien aangevinkt, heeft de gebruiker toegang tot de beheeromgeving.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Uploaden",
|
||||
"upload.notify.generic-error": "Er is een fout opgetreden tijdens het voltooien van uw share.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Maanden",
|
||||
"upload.modal.expires.year-singular": "Jaar",
|
||||
"upload.modal.expires.year-plural": "Jaren",
|
||||
"upload.modal.accordion.description.title": "Beschrijving",
|
||||
"upload.modal.accordion.description.placeholder": "Opmerking voor de ontvangers van deze share",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "E-mail van de ontvangers",
|
||||
"upload.modal.accordion.email.placeholder": "Voer e-mail ontvangers in",
|
||||
"upload.modal.accordion.email.invalid-email": "Ongeldig e-mailadres",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Maximale share grootte in bytes",
|
||||
"admin.config.share.zip-compression-level": "Zip compressie niveau",
|
||||
"admin.config.share.zip-compression-level.description": "Pas het niveau aan voor evenwicht tussen bestandsgrootte en compressie snelheid. Geldige waarden variëren van 0 tot 9, waarbij 0 geen compressie is en 9 de maximale compressie is. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Inschakelen",
|
||||
"admin.config.smtp.enabled.description": "Of SMTP is ingeschakeld. Stel dit alleen in op true als u de host hebt ingevoerd, poort, e-mail, gebruiker en wachtwoord van uw SMTP-server.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Ga naar de koppeling",
|
||||
"common.text.or": "of",
|
||||
"common.button.go-back": "Ga terug",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Uw link is gekopieerd naar het klembord",
|
||||
"common.success": "Succes",
|
||||
"common.error": "Fout",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Nie pamiętasz hasła?",
|
||||
"resetPassword.description": "Wprowadź swój e-mail, aby zresetować swoje hasło.",
|
||||
"resetPassword.notify.success": "Został wysłany e-mail z linkiem do resetowania hasła.",
|
||||
"resetPassword.notify.success": "Jeśli e-mail istnieje, to została wysłana wiadomość z linkiem do zresetowania hasła.",
|
||||
"resetPassword.button.back": "Powrót do strony logowania",
|
||||
"resetPassword.text.resetPassword": "Resetuj hasło",
|
||||
"resetPassword.text.enterNewPassword": "Wprowadź nowe hasło",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administracja",
|
||||
"admin.button.users": "Zarządzanie użytkownikami",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Konfiguracja",
|
||||
"admin.version": "Wersja",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Uprawnienia administratora",
|
||||
"admin.users.modal.create.admin.description": "Jeśli zaznaczone, użytkownik będzie miał dostęp do panelu administratora.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Prześlij",
|
||||
"upload.notify.generic-error": "Wystąpił błąd podczas zakończenia tworzenia udziału.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Miesiące/ęcy",
|
||||
"upload.modal.expires.year-singular": "Rok",
|
||||
"upload.modal.expires.year-plural": "Lat/a",
|
||||
"upload.modal.accordion.description.title": "Opis",
|
||||
"upload.modal.accordion.description.placeholder": "Notatka dla odbiorców tego udziału",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Odbiorcy wiadomości e-mail",
|
||||
"upload.modal.accordion.email.placeholder": "Wprowadź adresatów wiadomości e-mail",
|
||||
"upload.modal.accordion.email.invalid-email": "Adres e-mail jest nieprawidłowy",
|
||||
@@ -262,7 +273,7 @@ export default {
|
||||
"share.table.name": "Nazwa",
|
||||
"share.table.size": "Rozmiar",
|
||||
"share.modal.file-preview.error.not-supported.title": "Podgląd nie jest obsługiwany",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
"share.modal.file-preview.error.not-supported.description": "Podgląd dla tego typu pliku nie jest obsługiwany. Pobierz plik, aby go zobaczyć.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Edytuj {shareId}",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Maksymalny rozmiar udziału w bajtach",
|
||||
"admin.config.share.zip-compression-level": "Poziom kompresji Zip",
|
||||
"admin.config.share.zip-compression-level.description": "Dostosuj poziom do równowagi między rozmiarem pliku a szybkością kompresji. Prawidłowe wartości mieszczą się w zakresie od 0 do 9, przy czym 0 to brak kompresji a 9 maksymalną kompresją. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Włączony",
|
||||
"admin.config.smtp.enabled.description": "Czy SMTP ma zostać włączony. Ustaw to, tylko jeśli wprowadziłeś host, port, e-mail, nazwę użytkownika i hasło serwera SMTP.",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -404,9 +417,10 @@ export default {
|
||||
"common.button.generate": "Wygeneruj",
|
||||
"common.button.done": "Gotowe",
|
||||
"common.text.link": "Link",
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.navigate-to-link": "Przejdź do linku",
|
||||
"common.text.or": "lub",
|
||||
"common.button.go-back": "Wróć",
|
||||
"common.button.go-home": "Wróć do ekranu głównego",
|
||||
"common.notify.copied": "Link został skopiowany do schowka",
|
||||
"common.success": "Zakończono pomyślnie",
|
||||
"common.error": "Błąd",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Esqueceu a sua senha?",
|
||||
"resetPassword.description": "Insira o seu e-mail para redefinir a sua senha.",
|
||||
"resetPassword.notify.success": "Um e-mail foi enviado com um link para redefinir a sua senha.",
|
||||
"resetPassword.notify.success": "Uma mensagem com um link para redefinir sua senha foi enviada se o e-mail existir.",
|
||||
"resetPassword.button.back": "Voltar para a página inicial",
|
||||
"resetPassword.text.resetPassword": "Redefinir senha",
|
||||
"resetPassword.text.enterNewPassword": "Digite uma nova senha",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administração",
|
||||
"admin.button.users": "Gerenciamento de usuários",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Configuração",
|
||||
"admin.version": "Versão",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Privilégios de administrador",
|
||||
"admin.users.modal.create.admin.description": "Se marcado, o usuário poderá acessar o painel de administração.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Carregar",
|
||||
"upload.notify.generic-error": "Ocorreu um erro ao terminar seu compartilhamento.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Meses",
|
||||
"upload.modal.expires.year-singular": "Ano",
|
||||
"upload.modal.expires.year-plural": "Anos",
|
||||
"upload.modal.accordion.description.title": "Descrição",
|
||||
"upload.modal.accordion.description.placeholder": "Nota para os destinatários deste compartilhamento",
|
||||
"upload.modal.accordion.name-and-description.title": "Nome e descrição",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Nome",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Nota para os destinatários deste compartilhamento",
|
||||
"upload.modal.accordion.email.title": "Destinatários de e-mail",
|
||||
"upload.modal.accordion.email.placeholder": "Insira os destinatários do e-mail",
|
||||
"upload.modal.accordion.email.invalid-email": "Endereço de e-mail inválido",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Tamanho máximo do compartilhamento em bytes",
|
||||
"admin.config.share.zip-compression-level": "Nível de compressão",
|
||||
"admin.config.share.zip-compression-level.description": "Ajuste o nível para equilibrar entre o tamanho do arquivo e a velocidade de compressão. Valores válidos vão de 0 a 9, com 0 sendo sem compressão e 9 sendo compressão máxima. ",
|
||||
"admin.config.share.chunk-size": "Tamanho do pedaço",
|
||||
"admin.config.share.chunk-size.description": "Ajuste o tamanho do pedaço (em bytes) para seus uploads equilibrarem eficiência e confiabilidade de acordo com sua conexão com a internet. Pedaços menores podem aumentar as taxas de sucesso para conexões instáveis, enquanto partes maiores aceleram uploads para conexões estáveis.",
|
||||
"admin.config.smtp.enabled": "Ativado",
|
||||
"admin.config.smtp.enabled.description": "Se o SMTP está habilitado. Apenas defina como verdadeiro se você digitou o servidor, porta, e-mail, usuário e senha do seu servidor SMTP.",
|
||||
"admin.config.smtp.host": "Servidor",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Ir para o link",
|
||||
"common.text.or": "ou",
|
||||
"common.button.go-back": "Voltar",
|
||||
"common.button.go-home": "Voltar para o Início",
|
||||
"common.notify.copied": "O seu link foi copiado para a área de transferência",
|
||||
"common.success": "Sucesso",
|
||||
"common.error": "Erro",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Забыли пароль?",
|
||||
"resetPassword.description": "Введите ваш email для восстановления пароля.",
|
||||
"resetPassword.notify.success": "Вам направлено письмо со ссылкой для сброса пароля.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Вернуться на страницу входа",
|
||||
"resetPassword.text.resetPassword": "Сбросить пароль",
|
||||
"resetPassword.text.enterNewPassword": "Введите новый пароль",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Администрирование",
|
||||
"admin.button.users": "Управление пользователями",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Конфигурация",
|
||||
"admin.version": "Версия",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Права администратора",
|
||||
"admin.users.modal.create.admin.description": "Если отмечено, пользователь будет иметь доступ к панели администратора.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Загрузить",
|
||||
"upload.notify.generic-error": "Произошла ошибка при завершении вашей загрузки.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Месяца(-ев)",
|
||||
"upload.modal.expires.year-singular": "Год",
|
||||
"upload.modal.expires.year-plural": "Года (лет)",
|
||||
"upload.modal.accordion.description.title": "Описание",
|
||||
"upload.modal.accordion.description.placeholder": "Примечание для получателей этой загрузки",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Получатели письма",
|
||||
"upload.modal.accordion.email.placeholder": "Получатели e-mail",
|
||||
"upload.modal.accordion.email.invalid-email": "Недопустимый адрес электронной почты",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Максимальный размер файла в байтах",
|
||||
"admin.config.share.zip-compression-level": "Уровень сжатия Zip",
|
||||
"admin.config.share.zip-compression-level.description": "Регулировка уровня баланса между размером файла и скоростью сжатия. Допустимые значения от 0 до 9, с 0 без сжатия, а 9 - максимальное сжатие. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Включено",
|
||||
"admin.config.smtp.enabled.description": "Включено ли SMTP. Установите значение true только если вы ввели хост, порт, email, пользователь и пароль вашего SMTP-сервера.",
|
||||
"admin.config.smtp.host": "Хост",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "или",
|
||||
"common.button.go-back": "Назад",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Ваша ссылка скопирована в буфер обмена",
|
||||
"common.success": "Успешно",
|
||||
"common.error": "Ошибочка",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Ste pozabili svoje geslo?",
|
||||
"resetPassword.description": "Vnesite svoj e-poštni naslov za ponastavitev gesla.",
|
||||
"resetPassword.notify.success": "Poslali smo e-pošto s povezavo do spremembe gesla.",
|
||||
"resetPassword.notify.success": "Sporočilo s povezavo za ponastavitev vašega gesla je bilo poslano, če vaš e-poštni naslov obstaja.",
|
||||
"resetPassword.button.back": "Nazaj na stran za prijavo",
|
||||
"resetPassword.text.resetPassword": "Ponastavi geslo",
|
||||
"resetPassword.text.enterNewPassword": "Vnesite novo geslo",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administracija",
|
||||
"admin.button.users": "Upravljanje uporabnikov",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Nastavitve",
|
||||
"admin.version": "Različica",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Administratorski privilegiji",
|
||||
"admin.users.modal.create.admin.description": "Če je omogočeno, bo lahko porabnik dostopal do administratorskega vmesnika.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Naložite",
|
||||
"upload.notify.generic-error": "Prišlo je do napake pri ustvarjanju vašega deljenja.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Meseci",
|
||||
"upload.modal.expires.year-singular": "Leto",
|
||||
"upload.modal.expires.year-plural": "Leta",
|
||||
"upload.modal.accordion.description.title": "Opis",
|
||||
"upload.modal.accordion.description.placeholder": "Sporočilo za prejemnika te delitve",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Prejemnik e-pošte",
|
||||
"upload.modal.accordion.email.placeholder": "Vnesite prejemnika e-pošte",
|
||||
"upload.modal.accordion.email.invalid-email": "Neveljaven e-poštni naslov",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Največja velikost delitve v bytih",
|
||||
"admin.config.share.zip-compression-level": "Nivo Zip stiskanja",
|
||||
"admin.config.share.zip-compression-level.description": "Nivo stiskanja, ki uravnoveša med velikostjo datoteke in hitrostjo stiskanja. Veljavne vrednosti so med 0 in 9, kjer 0 pomeni brez kompresije in 9 pomeni največjo kompresijo. ",
|
||||
"admin.config.share.chunk-size": "Velikost delcev",
|
||||
"admin.config.share.chunk-size.description": "Prilagodite velikost delcev (v bajtih) vaših nalaganj, da uravnovesite med učinkovitostjo in zanesljivostjo glede na vašo internetno povezavo. Manjša velikost delcev lahko zviša uspešnost nalaganj pri nestabilni povezavi, medtem ko večja velikost delcev poviša hitrost nalaganja pri stabilni povezavi.",
|
||||
"admin.config.smtp.enabled": "Omogočeno",
|
||||
"admin.config.smtp.enabled.description": "Če je SMTP omogočen. Omogočite samo, če ste vnesli strežnik, vrata, e-pošto, uporabniško ime in geslo vašega SMTP strežnika.",
|
||||
"admin.config.smtp.host": "Gostitelj",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Pojdi na povezavo",
|
||||
"common.text.or": "ali",
|
||||
"common.button.go-back": "Nazaj",
|
||||
"common.button.go-home": "Pojdi domov",
|
||||
"common.notify.copied": "Povezava je bila kopirana v odložišče",
|
||||
"common.success": "Uspešno",
|
||||
"common.error": "Napaka",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Заборавили сте лозинку?",
|
||||
"resetPassword.description": "Унесите своју е-пошту да бисте ресетовали лозинку.",
|
||||
"resetPassword.notify.success": "Послат је емаил са везом за ресетовање ваше лозинке.",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "Назад на страницу за пријаву",
|
||||
"resetPassword.text.resetPassword": "Обнови лозинку",
|
||||
"resetPassword.text.enterNewPassword": "Унесите вашу нову лозинку",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Администрација",
|
||||
"admin.button.users": "Управљање корисницима",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Конфигурација",
|
||||
"admin.version": "Верзија",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Администраторске привилегије",
|
||||
"admin.users.modal.create.admin.description": "Ако је означено, корисник ће моћи да приступи административном панелу.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Пошаљи",
|
||||
"upload.notify.generic-error": "Дошло је до грешке при довршавању дељења.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Месеци",
|
||||
"upload.modal.expires.year-singular": "Година",
|
||||
"upload.modal.expires.year-plural": "Године",
|
||||
"upload.modal.accordion.description.title": "Опис",
|
||||
"upload.modal.accordion.description.placeholder": "Напомена за примаоце овог дељења",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Примаоци е-поште",
|
||||
"upload.modal.accordion.email.placeholder": "Унесите примаоце е-поште",
|
||||
"upload.modal.accordion.email.invalid-email": "Неисправна адреса е-поште",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Максимална величина дељења у бајтовима",
|
||||
"admin.config.share.zip-compression-level": "Ниво zip компресије",
|
||||
"admin.config.share.zip-compression-level.description": "Подесите ниво да бисте балансирали између величине датотеке и брзине компресије. Важеће вредности се крећу од 0 до 9, при чему је 0 без компресије, а 9 је максимална компресија. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Омогућено",
|
||||
"admin.config.smtp.enabled.description": "Да ли је SMTP омогућен. Поставите ово на тачно само ако сте унели хост, порт, е-пошту, корисника и лозинку вашег SMTP сервера.",
|
||||
"admin.config.smtp.host": "Домаћин",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "или",
|
||||
"common.button.go-back": "Иди назад",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "Ваша веза је копирана у clipboard",
|
||||
"common.success": "Успешно",
|
||||
"common.error": "Грешка",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Glömt ditt lösenord?",
|
||||
"resetPassword.description": "Ange din e-postadress för att återställa ditt lösenord.",
|
||||
"resetPassword.notify.success": "Ett e-postmeddelande har skickats till dig med en länk för att återställa lösenordet.",
|
||||
"resetPassword.notify.success": "Ett meddelande med en länk för att återställa ditt lösenord har skickats om e-postadressen finns.",
|
||||
"resetPassword.button.back": "Tillbaka till inloggningssidan",
|
||||
"resetPassword.text.resetPassword": "Återställ lösenord",
|
||||
"resetPassword.text.enterNewPassword": "Ange ditt nya lösenord",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "Administration",
|
||||
"admin.button.users": "Användarhantering",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Konfiguration",
|
||||
"admin.version": "Version",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "Administratörsbehörigheter",
|
||||
"admin.users.modal.create.admin.description": "Om detta markeras kommer användaren att kunna komma åt administratörspanelen.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Ladda upp",
|
||||
"upload.notify.generic-error": "Ett fel uppstod när din delning skulle slutföras.",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "Månader",
|
||||
"upload.modal.expires.year-singular": "År",
|
||||
"upload.modal.expires.year-plural": "År",
|
||||
"upload.modal.accordion.description.title": "Beskrivning",
|
||||
"upload.modal.accordion.description.placeholder": "Anteckning till mottagare av denna delning",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "E-postmottagare",
|
||||
"upload.modal.accordion.email.placeholder": "Ange e-postmottagare",
|
||||
"upload.modal.accordion.email.invalid-email": "Ogiltig e-postadress",
|
||||
@@ -262,7 +273,7 @@ export default {
|
||||
"share.table.name": "Namn",
|
||||
"share.table.size": "Storlek",
|
||||
"share.modal.file-preview.error.not-supported.title": "Förhandsgranskning stöds ej",
|
||||
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
|
||||
"share.modal.file-preview.error.not-supported.description": "En förhandsvisning för filtypen stöds inte. Ladda ner filen för att se den.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Redigera {shareId}",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "Maximal storlek för delning i bytes",
|
||||
"admin.config.share.zip-compression-level": "Komprimeringsnivå för zip",
|
||||
"admin.config.share.zip-compression-level.description": "Justera nivån för att balansera mellan filstorlek och komprimeringshastighet. Giltiga värden varierar från 0 till 9, med 0 som ingen komprimering och 9 som maximal komprimering. ",
|
||||
"admin.config.share.chunk-size": "Bitstorleken",
|
||||
"admin.config.share.chunk-size.description": "Justera bitstorleken (i bytes) för dina uppladdningar för att balansera effektivitet och tillförlitlighet enligt din internetanslutning. Mindre bitar kan öka framgångsgraden för instabila anslutningar, medan större bitar snabbar upp uppladdningar för stabila anslutningar.",
|
||||
"admin.config.smtp.enabled": "Aktiverad",
|
||||
"admin.config.smtp.enabled.description": "Om SMTP skall vara aktiverat. Ange endast detta som sant om du angav adress, port, e-post, användare och lösenord för din SMTP-server.",
|
||||
"admin.config.smtp.host": "Adress",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Gå till länken",
|
||||
"common.text.or": "eller",
|
||||
"common.button.go-back": "Gå tillbaka",
|
||||
"common.button.go-home": "Gå hem",
|
||||
"common.notify.copied": "Din länk har kopierats till urklipp",
|
||||
"common.success": "Slutförd",
|
||||
"common.error": "Fel",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "ลืมรหัสผ่าน?",
|
||||
"resetPassword.description": "กรุณาใส่อีเมล์์์์์์์ของคุณเพื่อรีเซ็ตรหัสผ่าน",
|
||||
"resetPassword.notify.success": "ส่งอีเมล์์์์์์์พร้อมลิงค์เพื่อรีเซ็ตรหัสผ่านของคุณแล้ว",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "กลับไปที่หน้าลงชื่อเข้าใช้",
|
||||
"resetPassword.text.resetPassword": "รีเซ็ตรหัสผ่าน",
|
||||
"resetPassword.text.enterNewPassword": "ป้อนรหัสผ่านใหม่ของคุณ",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "แผงควบคุมระบบ",
|
||||
"admin.button.users": "การจัดการผู้ใช้",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "การตั้งค่า",
|
||||
"admin.version": "เวอร์ชัน",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "สิทธิ์ของผู้ดูแลระบบ",
|
||||
"admin.users.modal.create.admin.description": "หากติ๊กเลือก ผู้ใช้จะสามารถเข้าถึงแผงควบคุมระบบได้",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "อัปโหลด",
|
||||
"upload.notify.generic-error": "เกิดข้อผิดพลาดขณะที่กำลังจัดการการแชร์ของคุณ",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "เดือน",
|
||||
"upload.modal.expires.year-singular": "ปี",
|
||||
"upload.modal.expires.year-plural": "ปี",
|
||||
"upload.modal.accordion.description.title": "คำอธิบาย",
|
||||
"upload.modal.accordion.description.placeholder": "หมายเหตุสำหรับผู้รับการแชร์นี้",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "ผู้รับอีเมล์",
|
||||
"upload.modal.accordion.email.placeholder": "ป้อนผู้รับอีเมล์",
|
||||
"upload.modal.accordion.email.invalid-email": "ที่อยู่อีเมล์ไม่ถูกต้อง",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "ขนาดสูงสุดของแชร์",
|
||||
"admin.config.share.zip-compression-level": "ระดับการบีบอัดไฟล์ Zip",
|
||||
"admin.config.share.zip-compression-level.description": "ปรับระดับเพื่อปรับความสมดุลระหว่างขนาดไฟล์และความเร็วในการบีบอัด ค่าอยู่ระหว่าง 0-9 โดย 0 คือไม่มีการบีบอัดและ 9 คือการบีบอัดสูงสุด",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "เปิด",
|
||||
"admin.config.smtp.enabled.description": "เปิดใช้งาน SMTP สำหรับการส่งอีเมล์์์์์์ เปิดได้เท่านั้นต่อเมื่อคุณใส่ข้อมูลโฮสต์ พอร์ต อีเมล์ ผู้ใช้ และรหัสผ่านของเซิร์ฟเวอร์ SMTP ของคุณ",
|
||||
"admin.config.smtp.host": "โฮสต์",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "หรือ",
|
||||
"common.button.go-back": "ย้อนกลับ",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "คัดลอกไปยังคลิปบอร์ดแล้ว",
|
||||
"common.success": "สำเร็จ",
|
||||
"common.error": "เกิดข้อผิดพลาด",
|
||||
|
||||
434
frontend/src/i18n/translations/uk-UA.ts
Normal file
434
frontend/src/i18n/translations/uk-UA.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
export default {
|
||||
// Navbar
|
||||
"navbar.upload": "Завантажити",
|
||||
"navbar.signin": "Вхід",
|
||||
"navbar.home": "Головна",
|
||||
"navbar.signup": "Зареєструватися",
|
||||
"navbar.links.shares": "Мої завантаження",
|
||||
"navbar.links.reverse": "Зворотні завантаження",
|
||||
"navbar.avatar.account": "Мій аккаунт",
|
||||
"navbar.avatar.admin": "Адміністрування",
|
||||
"navbar.avatar.signout": "Вийти",
|
||||
// END navbar
|
||||
// /
|
||||
"home.title": "Платформа для обміну файлами із <h>власного хостингу</h>.",
|
||||
"home.description": "Ви дійсно бажаєте надати свої особисті файли У руки третіх осіб, таких як WeTransfer?",
|
||||
"home.bullet.a.name": "На власному сервері",
|
||||
"home.bullet.a.description": "Pingvin Share працює на вашій машині.",
|
||||
"home.bullet.b.name": "Конфіденційність",
|
||||
"home.bullet.b.description": "Ваші файли - це ваші файли і ніколи не повинні потрапляти до рук третіх осіб.",
|
||||
"home.bullet.c.name": "Без дратівливого обмеження розміру файлу",
|
||||
"home.bullet.c.description": "Завантажуйте файли з будь-яким розміром. Тільки ваш жорсткий диск буде межею.",
|
||||
"home.button.start": "Почнемо",
|
||||
"home.button.source": "Вихідний код",
|
||||
// END /
|
||||
// /auth/signin
|
||||
"signin.title": "З поверненням",
|
||||
"signin.description": "У вас ще немає облікового запису?",
|
||||
"signin.button.signup": "Зареєструватися",
|
||||
"signin.input.email-or-username": "Email або логін",
|
||||
"signin.input.email-or-username.placeholder": "Ел. пошта або логін",
|
||||
"signin.input.password": "Пароль",
|
||||
"signin.input.password.placeholder": "Ваш пароль",
|
||||
"signin.button.submit": "Вхід",
|
||||
"signIn.notify.totp-required.title": "Потрібна двофакторна аутентифікація",
|
||||
"signIn.notify.totp-required.description": "Будь ласка, введіть код Вашої 2-х факторної аутентифікації",
|
||||
"signIn.oauth.or": "АБО",
|
||||
"signIn.oauth.github": "GitHub",
|
||||
"signIn.oauth.google": "Google",
|
||||
"signIn.oauth.microsoft": "Microsoft",
|
||||
"signIn.oauth.discord": "Discord",
|
||||
"signIn.oauth.oidc": "OpenID",
|
||||
// END /auth/signin
|
||||
// /auth/signup
|
||||
"signup.title": "Створити акаунт",
|
||||
"signup.description": "Уже є обліковий запис?",
|
||||
"signup.button.signin": "Вхід",
|
||||
"signup.input.username": "Логін",
|
||||
"signup.input.username.placeholder": "Ваш логін (ім'я користувача)",
|
||||
"signup.input.email": "Електронна пошта",
|
||||
"signup.input.email.placeholder": "Адреса ел. пошти",
|
||||
"signup.button.submit": "Давайте почнемо",
|
||||
// END /auth/signup
|
||||
// /auth/totp
|
||||
"totp.title": "Авторизація TOTP",
|
||||
"totp.button.signIn": "Увійти",
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "Забули пароль?",
|
||||
"resetPassword.description": "Введіть ваш email для відновлення пароля.",
|
||||
"resetPassword.notify.success": "Відправлено повідомлення з посиланням для скидання пароля, якщо email існує.",
|
||||
"resetPassword.button.back": "Повернутися на сторінку входу",
|
||||
"resetPassword.text.resetPassword": "Скинути пароль",
|
||||
"resetPassword.text.enterNewPassword": "Введіть новий пароль",
|
||||
"resetPassword.input.password": "Новий пароль",
|
||||
"resetPassword.notify.passwordReset": "Ваш пароль було успішно скинуто!",
|
||||
// /account
|
||||
"account.title": "Мій акаунт",
|
||||
"account.card.info.title": "Інформація про акаунт",
|
||||
"account.card.info.username": "Логін",
|
||||
"account.card.info.email": "Електронна пошта",
|
||||
"account.notify.info.success": "Налаштування облікового запису успішно оновлено",
|
||||
"account.card.password.title": "Пароль",
|
||||
"account.card.password.old": "Старий пароль",
|
||||
"account.card.password.new": "Новий пароль",
|
||||
"account.card.password.noPasswordSet": "У вас не встановлено пароль. Якщо ви хочете увійти за допомогою електронної пошти та пароля, вам необхідно встановити пароль.",
|
||||
"account.notify.password.success": "Пароль успішно змінено",
|
||||
"account.card.oauth.title": "Авторизація через соціальні мережі",
|
||||
"account.card.oauth.github": "GitHub",
|
||||
"account.card.oauth.google": "Google",
|
||||
"account.card.oauth.microsoft": "Microsoft",
|
||||
"account.card.oauth.discord": "Discord",
|
||||
"account.card.oauth.oidc": "OpenID",
|
||||
"account.card.oauth.link": "Підключити",
|
||||
"account.card.oauth.unlink": "Відключити",
|
||||
"account.card.oauth.unlinked": "Відключено",
|
||||
"account.modal.unlink.title": "Відключити зв'язок з обліковим записом",
|
||||
"account.modal.unlink.description": "Відключення зв'язку з обліковим записом соціальних акаунтів може призвести до втрати вашого облікового запису, якщо ви не пам'ятаєте своє ім'я користувача і пароль.",
|
||||
"account.notify.oauth.unlinked.success": "Відключення пройшло успішно",
|
||||
"account.card.security.title": "Безпека",
|
||||
"account.card.security.totp.enable.description": "Введіть ваш поточний пароль для початку увімкнення TOTP",
|
||||
"account.card.security.totp.disable.description": "Введіть ваш поточний пароль, щоб відключити TOTP",
|
||||
"account.card.security.totp.button.start": "Почати",
|
||||
"account.modal.totp.title": "Увімкнути TOTP",
|
||||
"account.modal.totp.step1": "Крок 1: Додайте свій аутентифікатор",
|
||||
"account.modal.totp.step2": "Крок 2: Перевірка коду",
|
||||
"account.modal.totp.enterManually": "Ввести вручну",
|
||||
"account.modal.totp.code": "Код",
|
||||
"account.modal.totp.clickToCopy": "Натисніть, щоб скопіювати",
|
||||
"account.modal.totp.verify": "Підтвердити",
|
||||
"account.notify.totp.disable": "TOTP успішно відключено",
|
||||
"account.notify.totp.enable": "TOTP успішно увімкнено",
|
||||
"account.card.language.title": "Мова",
|
||||
"account.card.language.description": "Проєкт перекладено спільнотою. Деякі мови можуть бути неповними.",
|
||||
"account.card.color.title": "Колірна схема",
|
||||
// ThemeSwitcher.tsx
|
||||
"account.theme.dark": "Темна",
|
||||
"account.theme.light": "Світла",
|
||||
"account.theme.system": "Системна",
|
||||
"account.button.delete": "Видалити акаунт",
|
||||
"account.modal.delete.title": "Видалити акаунт",
|
||||
"account.modal.delete.description": "Ви дійсно хочете видалити свій обліковий запис, включно з усіма вашими завантаженнями?",
|
||||
// END /account
|
||||
// /account/shares
|
||||
"account.shares.title": "Мої завантаження",
|
||||
"account.shares.title.empty": "Тут порожньо 👀",
|
||||
"account.shares.description.empty": "У вас немає завантажень.",
|
||||
"account.shares.button.create": "Створити одну",
|
||||
"account.shares.info.title": "Відомості",
|
||||
"account.shares.table.id": "ID",
|
||||
"account.shares.table.name": "Назва",
|
||||
"account.shares.table.description": "Опис",
|
||||
"account.shares.table.visitors": "Відвідувачів",
|
||||
"account.shares.table.expiresAt": "Дійсно до",
|
||||
"account.shares.table.createdAt": "Створено",
|
||||
"account.shares.table.size": "Розмір",
|
||||
"account.shares.modal.share-informations": "Відомості",
|
||||
"account.shares.modal.share-link": "Поділитися посиланням",
|
||||
"account.shares.modal.delete.title": "Видалити завантаження {share}",
|
||||
"account.shares.modal.delete.description": "Ви дійсно хочете видалити це завантаження?",
|
||||
// END /account/shares
|
||||
// /account/reverseShares
|
||||
"account.reverseShares.title": "Зворотні завантаження",
|
||||
"account.reverseShares.description": "Зворотне завантаження дає змогу генерувати унікальний URL, що дозволяє зовнішнім користувачам завантажувати файли.",
|
||||
"account.reverseShares.title.empty": "Тут порожньо 👀",
|
||||
"account.reverseShares.description.empty": "У вас поки що немає зворотних завантажень.",
|
||||
// showCreateReverseShareModal.tsx
|
||||
"account.reverseShares.modal.title": "Створити зворотне посилання на файл",
|
||||
"account.reverseShares.modal.expiration.label": "Закінчується",
|
||||
"account.reverseShares.modal.expiration.minute-singular": "Хвилина",
|
||||
"account.reverseShares.modal.expiration.minute-plural": "Хвилин(и)",
|
||||
"account.reverseShares.modal.expiration.hour-singular": "Година",
|
||||
"account.reverseShares.modal.expiration.hour-plural": "Годин",
|
||||
"account.reverseShares.modal.expiration.day-singular": "День",
|
||||
"account.reverseShares.modal.expiration.day-plural": "Днів",
|
||||
"account.reverseShares.modal.expiration.week-singular": "Тиждень",
|
||||
"account.reverseShares.modal.expiration.week-plural": "Тиждень",
|
||||
"account.reverseShares.modal.expiration.month-singular": "Місяць",
|
||||
"account.reverseShares.modal.expiration.month-plural": "Місяця(-ів)",
|
||||
"account.reverseShares.modal.expiration.year-singular": "Рік",
|
||||
"account.reverseShares.modal.expiration.year-plural": "Роки (роки)",
|
||||
"account.reverseShares.modal.max-size.label": "Макс. розмір завантаження",
|
||||
"account.reverseShares.modal.send-email": "Надіслати повідомлення електронною поштою",
|
||||
"account.reverseShares.modal.send-email.description": "Надсилати повідомлення електронною поштою, коли завантаження створюється за допомогою цього зворотного посилання.",
|
||||
"account.reverseShares.modal.max-use.label": "Максимум використань",
|
||||
"account.reverseShares.modal.max-use.description": "Максимальна кількість разів, коли URL може бути використаний для створення завантаження.",
|
||||
"account.reverseShare.never-expires": "Це зворотне завантаження ніколи не застаріє.",
|
||||
"account.reverseShare.expires-on": "Це зворотне завантаження застаріє {expiration}.",
|
||||
"account.reverseShares.table.no-shares": "Немає створених завантажень",
|
||||
"account.reverseShares.table.count.singular": "завантаження",
|
||||
"account.reverseShares.table.count.plural": "завантаження",
|
||||
"account.reverseShares.table.shares": "Завантаження",
|
||||
"account.reverseShares.table.remaining": "Залишилося використань",
|
||||
"account.reverseShares.table.max-size": "Макс. розмір завантаження",
|
||||
"account.reverseShares.table.expires": "Дійсно до",
|
||||
"account.reverseShares.modal.reverse-share-link": "Посилання зворотного завантаження",
|
||||
"account.reverseShares.modal.delete.title": "Видалити зворотне завантаження",
|
||||
"account.reverseShares.modal.delete.description": "Ви дійсно хочете видалити це зворотне завантаження? Якщо ви це зробите, то всі пов'язані зворотні завантаження будуть також видалені.",
|
||||
// END /account/reverseShares
|
||||
// /admin
|
||||
"admin.title": "Адміністрування",
|
||||
"admin.button.users": "Управління користувачами",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "Конфігурація",
|
||||
"admin.version": "Версія",
|
||||
// END /admin
|
||||
// /admin/users
|
||||
"admin.users.title": "Управління користувачами",
|
||||
"admin.users.table.username": "Логін",
|
||||
"admin.users.table.email": "Електронна пошта",
|
||||
"admin.users.table.admin": "Адміністратор",
|
||||
"admin.users.edit.update.title": "Оновити користувача {username}",
|
||||
"admin.users.edit.update.admin-privileges": "Права адміністратора",
|
||||
"admin.users.edit.update.change-password.title": "Змінити пароль",
|
||||
"admin.users.edit.update.change-password.field": "Новий пароль",
|
||||
"admin.users.edit.update.change-password.button": "Зберегти новий пароль",
|
||||
"admin.users.edit.update.notify.password.success": "Пароль успішно змінено",
|
||||
"admin.users.edit.delete.title": "Видалити користувача {username}",
|
||||
"admin.users.edit.delete.description": "Ви дійсно хочете видалити цього користувача і всі його завантаження?",
|
||||
// showCreateUserModal.tsx
|
||||
"admin.users.modal.create.title": "Створити користувача",
|
||||
"admin.users.modal.create.username": "Логін",
|
||||
"admin.users.modal.create.email": "Електронна пошта",
|
||||
"admin.users.modal.create.password": "Пароль",
|
||||
"admin.users.modal.create.manual-password": "Встановити пароль вручну",
|
||||
"admin.users.modal.create.manual-password.description": "Якщо прапорець не встановлено, користувач отримає лист із посиланням для встановлення пароля.",
|
||||
"admin.users.modal.create.admin": "Права адміністратора",
|
||||
"admin.users.modal.create.admin.description": "Якщо зазначено, користувач матиме доступ до панелі адміністратора.",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "Завантажити",
|
||||
"upload.notify.generic-error": "Сталася помилка під час завершення вашого завантаження.",
|
||||
"upload.notify.count-failed": "Не вдалося завантажити файли {count}. Повтор спроби.",
|
||||
// Dropzone.tsx
|
||||
"upload.dropzone.title": "Завантажити файли",
|
||||
"upload.dropzone.description": "Перетягніть сюди файли для початку завантаження. Ми можемо приймати тільки файли, які менше {maxSize}.",
|
||||
"upload.dropzone.notify.file-too-big": "Ваші файли перевищують максимальний розмір у {maxSize}.",
|
||||
// FileList.tsx
|
||||
"upload.filelist.name": "Назва",
|
||||
"upload.filelist.size": "Розмір",
|
||||
// showCreateUploadModal.tsx
|
||||
"upload.modal.title": "Завантажити",
|
||||
"upload.modal.link.error.invalid": "Ім'я користувача повинно складатися тільки з букв, цифр, підкреслень і дефісів",
|
||||
"upload.modal.link.error.taken": "Це посилання вже використовується",
|
||||
"upload.modal.not-signed-in": "Ви не авторизовані",
|
||||
"upload.modal.not-signed-in-description": "Ви не зможете видалити свої файли вручну і переглянути кількість відвідувачів.",
|
||||
"upload.modal.expires.never": "ніколи",
|
||||
"upload.modal.expires.never-long": "Ніколи не закінчується",
|
||||
"upload.modal.expires.error.too-long": "Термін дії перевищує максимальну дату закінчення терміну дії {max}.",
|
||||
"upload.modal.link.label": "Посилання",
|
||||
"upload.modal.expires.label": "Закінчується",
|
||||
"upload.modal.expires.minute-singular": "Хвилина",
|
||||
"upload.modal.expires.minute-plural": "Хвилин(и)",
|
||||
"upload.modal.expires.hour-singular": "Година",
|
||||
"upload.modal.expires.hour-plural": "Годин",
|
||||
"upload.modal.expires.day-singular": "День",
|
||||
"upload.modal.expires.day-plural": "Днів",
|
||||
"upload.modal.expires.week-singular": "Тиждень",
|
||||
"upload.modal.expires.week-plural": "Тижнів",
|
||||
"upload.modal.expires.month-singular": "Місяць",
|
||||
"upload.modal.expires.month-plural": "Місяця(-ів)",
|
||||
"upload.modal.expires.year-singular": "Рік",
|
||||
"upload.modal.expires.year-plural": "Роки (роки)",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Одержувачі листа",
|
||||
"upload.modal.accordion.email.placeholder": "Одержувачі e-mail",
|
||||
"upload.modal.accordion.email.invalid-email": "Неприпустима адреса електронної пошти",
|
||||
"upload.modal.accordion.security.title": "Параметри безпеки",
|
||||
"upload.modal.accordion.security.password.label": "Захист паролем",
|
||||
"upload.modal.accordion.security.password.placeholder": "Без пароля",
|
||||
"upload.modal.accordion.security.max-views.label": "Максимум переглядів",
|
||||
"upload.modal.accordion.security.max-views.placeholder": "Без обмеження",
|
||||
// showCompletedUploadModal.tsx
|
||||
"upload.modal.completed.never-expires": "Це завантаження ніколи не застаріє.",
|
||||
"upload.modal.completed.expires-on": "Це завантаження застаріє {expiration}.",
|
||||
"upload.modal.completed.share-ready": "Готово",
|
||||
// END /upload
|
||||
// /share/[id]
|
||||
"share.title": "Завантаження {shareId}",
|
||||
"share.description": "Подивіться, чим я поділився з вами!",
|
||||
"share.error.visitor-limit-exceeded.title": "Перевищено ліміт відвідувачів",
|
||||
"share.error.visitor-limit-exceeded.description": "Перевищено ліміт відвідувачів.",
|
||||
"share.error.removed.title": "Завантаження видалено",
|
||||
"share.error.not-found.title": "Завантаження не знайдено",
|
||||
"share.error.not-found.description": "Сторінка, яку ви шукаєте, не існує.",
|
||||
"share.modal.password.title": "Потрібен пароль",
|
||||
"share.modal.password.description": "Для доступу до цього ресурсу введіть пароль для загального доступу.",
|
||||
"share.modal.password": "Пароль",
|
||||
"share.modal.error.invalid-password": "Невірний пароль",
|
||||
"share.button.download-all": "Завантажити все",
|
||||
"share.notify.download-all-preparing": "Завантаження готується. Повторіть спробу через кілька хвилин.",
|
||||
"share.modal.file-link": "Посилання на файл",
|
||||
"share.table.name": "Назва",
|
||||
"share.table.size": "Розмір",
|
||||
"share.modal.file-preview.error.not-supported.title": "Попередній перегляд не підтримується",
|
||||
"share.modal.file-preview.error.not-supported.description": "Попередній перегляд для цього типу файлів не підтримується. Будь ласка, завантажте файл, щоб переглянути його.",
|
||||
// END /share/[id]
|
||||
// /share/[id]/edit
|
||||
"share.edit.title": "Редагувати {shareId}",
|
||||
"share.edit.append-upload": "Додати файл",
|
||||
"share.edit.notify.generic-error": "Сталася помилка під час завершення вашого завантаження.",
|
||||
"share.edit.notify.save-success": "Посилання на ресурс успішно оновлено",
|
||||
// END /share/[id]/edit
|
||||
// /admin/config
|
||||
"admin.config.title": "Конфігурація",
|
||||
"admin.config.category.general": "Загальне",
|
||||
"admin.config.category.share": "Завантаження",
|
||||
"admin.config.category.email": "Електронна пошта",
|
||||
"admin.config.category.smtp": "SMTP",
|
||||
"admin.config.category.oauth": "Авторизація через соціальні мережі",
|
||||
"admin.config.general.app-name": "Назва програми",
|
||||
"admin.config.general.app-name.description": "Видима назва додатка",
|
||||
"admin.config.general.app-url": "URL-адреса програми",
|
||||
"admin.config.general.app-url.description": "Адреса, на якій доступний Pingvin Share",
|
||||
"admin.config.general.show-home-page": "Показувати домашню сторінку",
|
||||
"admin.config.general.show-home-page.description": "Показувати домашню сторінку чи ні",
|
||||
"admin.config.general.logo": "Логотип",
|
||||
"admin.config.general.logo.description": "Змініть свій логотип, завантаживши нове зображення. Зображення має бути PNG і повинно мати формат 1:1.",
|
||||
"admin.config.general.logo.placeholder": "Виберіть зображення",
|
||||
"admin.config.email.enable-share-email-recipients": "Увімкнути обмін з одержувачами електронної пошти",
|
||||
"admin.config.email.enable-share-email-recipients.description": "Чи дозволити надсилання листів одержувачам. Увімкніть, тільки якщо ви ввімкнули SMTP.",
|
||||
"admin.config.email.share-recipients-subject": "Заголовок листа (завантаження)",
|
||||
"admin.config.email.share-recipients-subject.description": "Тема листа, який надсилається одержувачам акції.",
|
||||
"admin.config.email.share-recipients-message": "Повідомлення листа завантаження",
|
||||
"admin.config.email.share-recipients-message.description": "Повідомлення, яке надсилається одержувачам публікації. Доступні змінні:\n {creator} - Ім'я користувача творця завантаження\n {shareUrl} - URL завантаження\n {desc} - Опис завантаження\n {expires} - Дата закінчення завантаження\n Змінні будуть замінені на фактичне значення.",
|
||||
"admin.config.email.reverse-share-subject": "Заголовок листа (зворотне завантаження)",
|
||||
"admin.config.email.reverse-share-subject.description": "Тема листа, який надсилається, коли хтось створив завантаження з вашим зворотним посиланням.",
|
||||
"admin.config.email.reverse-share-message": "Повідомлення листа зворотного завантаження",
|
||||
"admin.config.email.reverse-share-message.description": "Повідомлення, яке надсилається, коли хтось створив завантаження з вашим зворотним посиланням. {shareUrl} буде замінено ім'ям творця та URL-адресою загального доступу.",
|
||||
"admin.config.email.reset-password-subject": "Тема скидання пароля",
|
||||
"admin.config.email.reset-password-subject.description": "Тема листа, який надсилається, коли користувач запитує скидання пароля.",
|
||||
"admin.config.email.reset-password-message": "Повідомлення про скидання пароля",
|
||||
"admin.config.email.reset-password-message.description": "Повідомлення, яке надсилається при запиті скидання пароля. {url} буде замінено посиланням.",
|
||||
"admin.config.email.invite-subject": "Тема запрошення",
|
||||
"admin.config.email.invite-subject.description": "Тема листа, який надсилається, коли адміністратор запрошує користувача.",
|
||||
"admin.config.email.invite-message": "Повідомлення із запрошенням",
|
||||
"admin.config.email.invite-message.description": "Повідомлення запрошення. {url} буде замінено посиланням запрошення, а {password} паролем.",
|
||||
"admin.config.share.allow-registration": "Дозволити реєстрацію",
|
||||
"admin.config.share.allow-registration.description": "Чи дозволена реєстрація",
|
||||
"admin.config.share.allow-unauthenticated-shares": "Дозволити неавторизовані завантаження",
|
||||
"admin.config.share.allow-unauthenticated-shares.description": "Чи можуть неавторизовані користувачі створювати завантаження",
|
||||
"admin.config.share.max-expiration": "Максимальний термін дії",
|
||||
"admin.config.share.max-expiration.description": "Максимальний термін дії загального доступу в годинах. Встановіть значення 0, щоб дозволити необмежений термін дії.",
|
||||
"admin.config.share.max-size": "Максимальний розмір",
|
||||
"admin.config.share.max-size.description": "Максимальний розмір файлу в байтах",
|
||||
"admin.config.share.zip-compression-level": "Рівень стиснення Zip",
|
||||
"admin.config.share.zip-compression-level.description": "Регулювання рівня балансу між розміром файлу і швидкістю стиснення. Допустимі значення від 0 до 9, з 0 без стиснення, а 9 - максимальне стиснення. ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "Увімкнено",
|
||||
"admin.config.smtp.enabled.description": "Чи увімкнено SMTP. Встановіть значення true тільки якщо ви ввели хост, порт, email, користувач і пароль вашого SMTP-сервера.",
|
||||
"admin.config.smtp.host": "Хост",
|
||||
"admin.config.smtp.host.description": "Сервер SMTP-сервера",
|
||||
"admin.config.smtp.port": "Порт",
|
||||
"admin.config.smtp.port.description": "Порт SMTP сервера",
|
||||
"admin.config.smtp.email": "Електронна пошта",
|
||||
"admin.config.smtp.email.description": "Адреса електронної пошти, від якої надсилаються листи",
|
||||
"admin.config.smtp.username": "Логін",
|
||||
"admin.config.smtp.username.description": "Ім'я користувача SMTP-сервера",
|
||||
"admin.config.smtp.password": "Пароль",
|
||||
"admin.config.smtp.password.description": "Пароль SMTP-сервера",
|
||||
"admin.config.smtp.button.test": "Відправити тестовий лист",
|
||||
"admin.config.oauth.allow-registration": "Дозволити реєстрацію",
|
||||
"admin.config.oauth.allow-registration.description": "Дозволити користувачам реєструватися, використовуючи облікові записи соціальних мереж",
|
||||
"admin.config.oauth.ignore-totp": "Ігнорувати TOTP",
|
||||
"admin.config.oauth.ignore-totp.description": "Ігнорувати TOTP при використанні соціальної авторизації",
|
||||
"admin.config.oauth.github-enabled": "GitHub",
|
||||
"admin.config.oauth.github-enabled.description": "Чи ввімкнено логін на GitHub",
|
||||
"admin.config.oauth.github-client-id": "ID клієнта GitHub",
|
||||
"admin.config.oauth.github-client-id.description": "ID клієнта в додатку GitHub OAuth",
|
||||
"admin.config.oauth.github-client-secret": "Секретний ключ клієнта GitHub",
|
||||
"admin.config.oauth.github-client-secret.description": "Секретний ключ клієнта в додатку GitHub OAuth",
|
||||
"admin.config.oauth.google-enabled": "Google",
|
||||
"admin.config.oauth.google-enabled.description": "Чи увімкнено логін Google на GitHub",
|
||||
"admin.config.oauth.google-client-id": "ID клієнта Google",
|
||||
"admin.config.oauth.google-client-id.description": "ID клієнта в додатку Google OAuth",
|
||||
"admin.config.oauth.google-client-secret": "Секретний ключ клієнта Google",
|
||||
"admin.config.oauth.google-client-secret.description": "Секретний ключ клієнта в додатку Google OAuth",
|
||||
"admin.config.oauth.microsoft-enabled": "Microsoft",
|
||||
"admin.config.oauth.microsoft-enabled.description": "Чи ввімкнено логін Microsoft",
|
||||
"admin.config.oauth.microsoft-tenant": "Корпоративний акаунт Microsoft",
|
||||
"admin.config.oauth.microsoft-tenant.description": "Ідентифікатор орендаря додатка Microsoft OAuth\ncommon: Користувачі з особистим обліковим записом Microsoft і робочим або навчальним обліковим записом від Microsoft Entra ID можуть увійти в додаток. organizations: Тільки користувачі з робочим або навчальним обліковим записом від Microsoft Entra ID можуть увійти в застосунок.\nconsumers: Тільки користувачі з особистим обліковим записом Microsoft можуть увійти в застосунок.ім'я домену орендаря Microsoft Entra або ідентифікатор орендаря у форматі GUID: Тільки користувачі з певного орендаря Microsoft Entra (учасники каталогу з робочим або навчальним обліковим записом або гості каталогу з особистим обліковим записом Microsoft) можуть увійти в застосунок.",
|
||||
"admin.config.oauth.microsoft-client-id": "Ідентифікатор клієнта Microsoft",
|
||||
"admin.config.oauth.microsoft-client-id.description": "ID клієнта в додатку Microsoft OAuth",
|
||||
"admin.config.oauth.microsoft-client-secret": "Секретний ключ клієнта Microsoft",
|
||||
"admin.config.oauth.microsoft-client-secret.description": "Секретний ключ клієнта в додатку Microsoft OAuth",
|
||||
"admin.config.oauth.discord-enabled": "Discord",
|
||||
"admin.config.oauth.discord-enabled.description": "Чи увімкнено логін Discord",
|
||||
"admin.config.oauth.discord-limited-guild": "ID обмеженого сервера Discord",
|
||||
"admin.config.oauth.discord-limited-guild.description": "Обмеження входу для користувачів певного сервера. Залиште порожнім, щоб відключити.",
|
||||
"admin.config.oauth.discord-client-id": "ID клієнта Discord",
|
||||
"admin.config.oauth.discord-client-id.description": "ID клієнта в додатку Discord OAuth",
|
||||
"admin.config.oauth.discord-client-secret": "Секретний ключ клієнта Discord",
|
||||
"admin.config.oauth.discord-client-secret.description": "Секретний ключ клієнта в додатку Discord OAuth",
|
||||
"admin.config.oauth.oidc-enabled": "OpenID Connect",
|
||||
"admin.config.oauth.oidc-enabled.description": "Чи ввімкнено логін OpenID Connect",
|
||||
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
|
||||
"admin.config.oauth.oidc-discovery-uri.description": "URI Discovery URI додатка OpenID Connect OAuth",
|
||||
"admin.config.oauth.oidc-username-claim": "Заява на ім'я користувача OpenID Connect",
|
||||
"admin.config.oauth.oidc-username-claim.description": "Заява про ім'я користувача в токені OpenID Connect ID. Залиште порожнім, якщо не знаєте, що це за конфіг.",
|
||||
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
|
||||
"admin.config.oauth.oidc-client-id.description": "Клієнтський ідентифікатор додатка OpenID Connect OAuth",
|
||||
"admin.config.oauth.oidc-client-secret": "Секрет клієнта OpenID Connect",
|
||||
"admin.config.oauth.oidc-client-secret.description": "Клієнтський секрет програми OpenID Connect OAuth",
|
||||
// 404
|
||||
"404.description": "Бляха, цієї строрінки не існує.",
|
||||
"404.button.home": "Поверни мене додому",
|
||||
// error
|
||||
"error.title": "Помилка",
|
||||
"error.description": "Щось пішло не так!",
|
||||
"error.button.back": "Назад",
|
||||
"error.msg.default": "Щось пішло не так.",
|
||||
"error.msg.access_denied": "Ви скасували процес аутентифікації, будь ласка, спробуйте ще раз.",
|
||||
"error.msg.expired_token": "Процес аутентифікації зайняв занадто багато часу, будь ласка, спробуйте ще раз.",
|
||||
"error.msg.invalid_token": "Внутрішня помилка",
|
||||
"error.msg.no_user": "Користувач, пов'язаний з обліковим записом {0}, не існує.",
|
||||
"error.msg.no_email": "Не вдається отримати адресу електронної пошти від облікового запису {0}.",
|
||||
"error.msg.already_linked": "Цей обліковий запис {0} уже прив'язано до іншого акаунта.",
|
||||
"error.msg.not_linked": "Цей обліковий запис {0} ще не прив'язаний до жодного акаунту.",
|
||||
"error.msg.unverified_account": "Цей обліковий запис {0} не підтверджено, повторіть спробу після підтвердження.",
|
||||
"error.msg.discord_guild_permission_denied": "У вас немає дозволу на вхід.",
|
||||
"error.msg.cannot_get_user_info": "Не вдається отримати інфу про користувача з цього {0} облікового запису.",
|
||||
"error.param.provider_github": "GitHub",
|
||||
"error.param.provider_google": "Google",
|
||||
"error.param.provider_microsoft": "Microsoft",
|
||||
"error.param.provider_discord": "Discord",
|
||||
"error.param.provider_oidc": "OpenID Connect",
|
||||
// Common translations
|
||||
"common.button.save": "Зберегти",
|
||||
"common.button.create": "Створити",
|
||||
"common.button.submit": "Відправити",
|
||||
"common.button.delete": "Видалити",
|
||||
"common.button.cancel": "Скасувати",
|
||||
"common.button.confirm": "Підтвердити",
|
||||
"common.button.disable": "Відключити",
|
||||
"common.button.share": "Поділитися",
|
||||
"common.button.generate": "Згенерувати",
|
||||
"common.button.done": "Готово",
|
||||
"common.text.link": "Посилання",
|
||||
"common.text.navigate-to-link": "Перейти до посилання",
|
||||
"common.text.or": "або",
|
||||
"common.button.go-back": "Назад",
|
||||
"common.button.go-home": "Перейти додому",
|
||||
"common.notify.copied": "Ваше посилання скопійовано в буфер обміну",
|
||||
"common.success": "Успішно",
|
||||
"common.error": "Помилка",
|
||||
"common.error.unknown": "Сталася невідома помилка",
|
||||
"common.error.invalid-email": "Неприпустима адреса електронної пошти",
|
||||
"common.error.too-short": "Повинно бути не менше {length} символів",
|
||||
"common.error.too-long": "Повинно бути не більше {length} символів",
|
||||
"common.error.exact-length": "Повинно бути рівно {length} символів",
|
||||
"common.error.invalid-number": "Повинно бути числом",
|
||||
"common.error.field-required": "Поле обов'язкове для заповнення"
|
||||
};
|
||||
@@ -56,8 +56,8 @@ export default {
|
||||
// END /auth/totp
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "忘记密码?",
|
||||
"resetPassword.description": "请输入电子邮件接受重置密码邮件",
|
||||
"resetPassword.notify.success": "一封包含密码重置地址的邮件已发送到你的邮箱中",
|
||||
"resetPassword.description": "请输入电子邮箱地址来接收重置密码邮件",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "返回登录页面",
|
||||
"resetPassword.text.resetPassword": "重置密码",
|
||||
"resetPassword.text.enterNewPassword": "请输入新密码",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "管理",
|
||||
"admin.button.users": "用户管理",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "配置管理",
|
||||
"admin.version": "版本",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "管理员",
|
||||
"admin.users.modal.create.admin.description": "如果勾选,用户将能访问管理员面板",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "上传",
|
||||
"upload.notify.generic-error": "创建共享的过程中发生了错误",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "月",
|
||||
"upload.modal.expires.year-singular": "1 年",
|
||||
"upload.modal.expires.year-plural": "年",
|
||||
"upload.modal.accordion.description.title": "描述",
|
||||
"upload.modal.accordion.description.placeholder": "共享文件备注信息",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "邮件提醒",
|
||||
"upload.modal.accordion.email.placeholder": "收件人电子邮件地址",
|
||||
"upload.modal.accordion.email.invalid-email": "邮件地址不可用",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "最大文件上限,单位 bytes (1GB=1024MB=1048576KB=1073741824bytes)",
|
||||
"admin.config.share.zip-compression-level": "Zip 文件压缩质量",
|
||||
"admin.config.share.zip-compression-level.description": "调整压缩质量来平衡压缩文件的大小和压缩的速度。有效值介于 0 和 9 之间,0 为不压缩,9 为最高质量压缩。 ",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "启用",
|
||||
"admin.config.smtp.enabled.description": "是否开启 SMTP,仅当输入主机名、端口、发送邮箱、用户名和密码后开启",
|
||||
"admin.config.smtp.host": "主机名",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "访问链接",
|
||||
"common.text.or": "或",
|
||||
"common.button.go-back": "返回",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "已复制到剪贴板",
|
||||
"common.success": "成功",
|
||||
"common.error": "错误",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// /auth/reset-password
|
||||
"resetPassword.title": "忘記密碼?",
|
||||
"resetPassword.description": "請輸入Email以讓系統寄送重置密碼郵件",
|
||||
"resetPassword.notify.success": "一封包含密碼重置地址的郵件已發送到您的Email",
|
||||
"resetPassword.notify.success": "A message with a link to reset your password has been sent if the email exists.",
|
||||
"resetPassword.button.back": "返回登入頁面",
|
||||
"resetPassword.text.resetPassword": "重置密碼",
|
||||
"resetPassword.text.enterNewPassword": "請輸入新密碼",
|
||||
@@ -169,6 +169,7 @@ export default {
|
||||
// /admin
|
||||
"admin.title": "管理",
|
||||
"admin.button.users": "使用者管理",
|
||||
"admin.button.shares": "Share management",
|
||||
"admin.button.config": "配置管理",
|
||||
"admin.version": "版本",
|
||||
// END /admin
|
||||
@@ -195,6 +196,15 @@ export default {
|
||||
"admin.users.modal.create.admin": "管理員",
|
||||
"admin.users.modal.create.admin.description": "如果勾選,使用者將能查看管理員面板",
|
||||
// END /admin/users
|
||||
// /admin/shares
|
||||
"admin.shares.title": "Share management",
|
||||
"admin.shares.table.id": "Share ID",
|
||||
"admin.shares.table.username": "Creator",
|
||||
"admin.shares.table.visitors": "Visitors",
|
||||
"admin.shares.table.expires": "Expires At",
|
||||
"admin.shares.edit.delete.title": "Delete share {id}",
|
||||
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
|
||||
// END /admin/shares
|
||||
// /upload
|
||||
"upload.title": "上傳",
|
||||
"upload.notify.generic-error": "建立分享的過程中發生了錯誤",
|
||||
@@ -229,8 +239,9 @@ export default {
|
||||
"upload.modal.expires.month-plural": "月",
|
||||
"upload.modal.expires.year-singular": "年",
|
||||
"upload.modal.expires.year-plural": "年",
|
||||
"upload.modal.accordion.description.title": "描述",
|
||||
"upload.modal.accordion.description.placeholder": "分享檔案備註資訊",
|
||||
"upload.modal.accordion.name-and-description.title": "Name and description",
|
||||
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
|
||||
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
|
||||
"upload.modal.accordion.email.title": "Email提醒",
|
||||
"upload.modal.accordion.email.placeholder": "收件人Email地址",
|
||||
"upload.modal.accordion.email.invalid-email": "Email地址不可用",
|
||||
@@ -314,6 +325,8 @@ export default {
|
||||
"admin.config.share.max-size.description": "最大檔案上限,單位 bytes (1GB=1024MB=1048576KB=1073741824bytes)",
|
||||
"admin.config.share.zip-compression-level": "Zip 壓縮等級",
|
||||
"admin.config.share.zip-compression-level.description": "調整壓縮等級以平衡檔案大小和壓縮速度。 有效值範圍從 0 到 9,其中 0 表示無壓縮,9 表示最大壓縮",
|
||||
"admin.config.share.chunk-size": "Chunk size",
|
||||
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
|
||||
"admin.config.smtp.enabled": "啟用",
|
||||
"admin.config.smtp.enabled.description": "是否開啟 SMTP,需輸入Host、Port、發送郵箱、使用者名稱和密碼後才有作用",
|
||||
"admin.config.smtp.host": "Host",
|
||||
@@ -407,6 +420,7 @@ export default {
|
||||
"common.text.navigate-to-link": "Go to the link",
|
||||
"common.text.or": "或",
|
||||
"common.button.go-back": "返回",
|
||||
"common.button.go-home": "Go home",
|
||||
"common.notify.copied": "已複製到剪貼簿",
|
||||
"common.success": "成功",
|
||||
"common.error": "錯誤",
|
||||
|
||||
@@ -21,9 +21,8 @@ export async function middleware(request: NextRequest) {
|
||||
};
|
||||
|
||||
// Get config from backend
|
||||
const config = await (
|
||||
await fetch(`${request.nextUrl.origin}/api/configs`)
|
||||
).json();
|
||||
const apiUrl = process.env.API_URL || "http://localhost:8080";
|
||||
const config = await (await fetch(`${apiUrl}/api/configs`)).json();
|
||||
|
||||
const getConfig = (key: string) => {
|
||||
return configService.get(key, config);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
createStyles,
|
||||
Group,
|
||||
Text,
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
import { Button, Container, createStyles, Group, Title } from "@mantine/core";
|
||||
import Link from "next/link";
|
||||
import Meta from "../components/Meta";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Meta from "../components/Meta";
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
root: {
|
||||
@@ -21,19 +14,13 @@ const useStyles = createStyles((theme) => ({
|
||||
fontWeight: 900,
|
||||
fontSize: 220,
|
||||
lineHeight: 1,
|
||||
marginBottom: `calc(${theme.spacing.xl} * 100)`,
|
||||
marginBottom: 20,
|
||||
color: theme.colors.gray[2],
|
||||
|
||||
[theme.fn.smallerThan("sm")]: {
|
||||
fontSize: 120,
|
||||
},
|
||||
},
|
||||
|
||||
description: {
|
||||
maxWidth: 500,
|
||||
margin: "auto",
|
||||
marginBottom: `calc(${theme.spacing.xl} * 100)`,
|
||||
},
|
||||
}));
|
||||
|
||||
const ErrorNotFound = () => {
|
||||
@@ -47,12 +34,7 @@ const ErrorNotFound = () => {
|
||||
<Title align="center" order={3}>
|
||||
<FormattedMessage id="404.description" />
|
||||
</Title>
|
||||
<Text
|
||||
color="dimmed"
|
||||
align="center"
|
||||
className={classes.description}
|
||||
></Text>
|
||||
<Group position="center">
|
||||
<Group position="center" mt={50}>
|
||||
<Button component={Link} href="/" variant="light">
|
||||
<FormattedMessage id="404.button.home" />
|
||||
</Button>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { getCookie, setCookie } from "cookies-next";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import type { AppProps } from "next/app";
|
||||
import getConfig from "next/config";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { IntlProvider } from "react-intl";
|
||||
@@ -49,7 +50,12 @@ function App({ Component, pageProps }: AppProps) {
|
||||
}, [router.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
setInterval(async () => await authService.refreshAccessToken(), 30 * 1000);
|
||||
const interval = setInterval(
|
||||
async () => await authService.refreshAccessToken(),
|
||||
2 * 60 * 1000, // 2 minutes
|
||||
);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -80,57 +86,65 @@ function App({ Component, pageProps }: AppProps) {
|
||||
const language = useRef(pageProps.language);
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
messages={i18nUtil.getLocaleByCode(language.current)?.messages}
|
||||
locale={language.current}
|
||||
defaultLocale={LOCALES.ENGLISH.code}
|
||||
>
|
||||
<MantineProvider
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
theme={{ colorScheme, ...globalStyle }}
|
||||
<>
|
||||
<Head>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
||||
/>
|
||||
</Head>
|
||||
<IntlProvider
|
||||
messages={i18nUtil.getLocaleByCode(language.current)?.messages}
|
||||
locale={language.current}
|
||||
defaultLocale={LOCALES.ENGLISH.code}
|
||||
>
|
||||
<ColorSchemeProvider
|
||||
colorScheme={colorScheme}
|
||||
toggleColorScheme={toggleColorScheme}
|
||||
<MantineProvider
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
theme={{ colorScheme, ...globalStyle }}
|
||||
>
|
||||
<GlobalStyle />
|
||||
<Notifications />
|
||||
<ModalsProvider>
|
||||
<ConfigContext.Provider
|
||||
value={{
|
||||
configVariables,
|
||||
refresh: async () => {
|
||||
setConfigVariables(await configService.list());
|
||||
},
|
||||
}}
|
||||
>
|
||||
<UserContext.Provider
|
||||
<ColorSchemeProvider
|
||||
colorScheme={colorScheme}
|
||||
toggleColorScheme={toggleColorScheme}
|
||||
>
|
||||
<GlobalStyle />
|
||||
<Notifications />
|
||||
<ModalsProvider>
|
||||
<ConfigContext.Provider
|
||||
value={{
|
||||
user,
|
||||
refreshUser: async () => {
|
||||
const user = await userService.getCurrentUser();
|
||||
setUser(user);
|
||||
return user;
|
||||
configVariables,
|
||||
refresh: async () => {
|
||||
setConfigVariables(await configService.list());
|
||||
},
|
||||
}}
|
||||
>
|
||||
{excludeDefaultLayoutRoutes.includes(route) ? (
|
||||
<Component {...pageProps} />
|
||||
) : (
|
||||
<>
|
||||
<Header />
|
||||
<Container>
|
||||
<Component {...pageProps} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
</UserContext.Provider>
|
||||
</ConfigContext.Provider>
|
||||
</ModalsProvider>
|
||||
</ColorSchemeProvider>
|
||||
</MantineProvider>
|
||||
</IntlProvider>
|
||||
<UserContext.Provider
|
||||
value={{
|
||||
user,
|
||||
refreshUser: async () => {
|
||||
const user = await userService.getCurrentUser();
|
||||
setUser(user);
|
||||
return user;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{excludeDefaultLayoutRoutes.includes(route) ? (
|
||||
<Component {...pageProps} />
|
||||
) : (
|
||||
<>
|
||||
<Header />
|
||||
<Container>
|
||||
<Component {...pageProps} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
</UserContext.Provider>
|
||||
</ConfigContext.Provider>
|
||||
</ModalsProvider>
|
||||
</ColorSchemeProvider>
|
||||
</MantineProvider>
|
||||
</IntlProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,15 +68,12 @@ const MyShares = () => {
|
||||
<Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.id" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.name" />
|
||||
</th>
|
||||
<MediaQuery smallerThan="md" styles={{ display: "none" }}>
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.description" />
|
||||
</th>
|
||||
</MediaQuery>
|
||||
|
||||
<th>
|
||||
<FormattedMessage id="account.shares.table.visitors" />
|
||||
</th>
|
||||
@@ -90,18 +87,7 @@ const MyShares = () => {
|
||||
{shares.map((share) => (
|
||||
<tr key={share.id}>
|
||||
<td>{share.id}</td>
|
||||
<MediaQuery smallerThan="sm" styles={{ display: "none" }}>
|
||||
<td
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: "300px",
|
||||
}}
|
||||
>
|
||||
{share.description || ""}
|
||||
</td>
|
||||
</MediaQuery>
|
||||
<td>{share.name}</td>
|
||||
<td>{share.views}</td>
|
||||
<td>
|
||||
{moment(share.expiration).unix() === 0
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { TbRefresh, TbSettings, TbUsers } from "react-icons/tb";
|
||||
import { TbLink, TbRefresh, TbSettings, TbUsers } from "react-icons/tb";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Meta from "../../components/Meta";
|
||||
import useTranslate from "../../hooks/useTranslate.hook";
|
||||
@@ -41,6 +41,11 @@ const Admin = () => {
|
||||
icon: TbUsers,
|
||||
route: "/admin/users",
|
||||
},
|
||||
{
|
||||
title: t("admin.button.shares"),
|
||||
icon: TbLink,
|
||||
route: "/admin/shares",
|
||||
},
|
||||
{
|
||||
title: t("admin.button.config"),
|
||||
icon: TbSettings,
|
||||
|
||||
74
frontend/src/pages/admin/shares.tsx
Normal file
74
frontend/src/pages/admin/shares.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Group, Space, Text, Title } from "@mantine/core";
|
||||
import { useModals } from "@mantine/modals";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Meta from "../../components/Meta";
|
||||
import ManageShareTable from "../../components/admin/shares/ManageShareTable";
|
||||
import useTranslate from "../../hooks/useTranslate.hook";
|
||||
import shareService from "../../services/share.service";
|
||||
import { MyShare } from "../../types/share.type";
|
||||
import toast from "../../utils/toast.util";
|
||||
|
||||
const Shares = () => {
|
||||
const [shares, setShares] = useState<MyShare[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const modals = useModals();
|
||||
const t = useTranslate();
|
||||
|
||||
const getShares = () => {
|
||||
setIsLoading(true);
|
||||
shareService.list().then((shares) => {
|
||||
setShares(shares);
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteShare = (share: MyShare) => {
|
||||
modals.openConfirmModal({
|
||||
title: t("admin.shares.edit.delete.title", {
|
||||
id: share.id,
|
||||
}),
|
||||
children: (
|
||||
<Text size="sm">
|
||||
<FormattedMessage id="admin.shares.edit.delete.description" />
|
||||
</Text>
|
||||
),
|
||||
labels: {
|
||||
confirm: t("common.button.delete"),
|
||||
cancel: t("common.button.cancel"),
|
||||
},
|
||||
confirmProps: { color: "red" },
|
||||
onConfirm: async () => {
|
||||
shareService
|
||||
.remove(share.id)
|
||||
.then(() => setShares(shares.filter((v) => v.id != share.id)))
|
||||
.catch(toast.axiosError);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getShares();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Meta title={t("admin.shares.title")} />
|
||||
<Group position="apart" align="baseline" mb={20}>
|
||||
<Title mb={30} order={3}>
|
||||
<FormattedMessage id="admin.shares.title" />
|
||||
</Title>
|
||||
</Group>
|
||||
|
||||
<ManageShareTable
|
||||
shares={shares}
|
||||
deleteShare={deleteShare}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Space h="xl" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Shares;
|
||||
@@ -12,7 +12,7 @@ export const config = {
|
||||
const { apiURL } = getConfig().serverRuntimeConfig;
|
||||
|
||||
// A proxy to the API server only used in development.
|
||||
// In production this route gets overridden by nginx.
|
||||
// In production this route gets overridden by Caddy.
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => {
|
||||
httpProxyMiddleware(req, res, {
|
||||
headers: {
|
||||
|
||||
@@ -4,6 +4,7 @@ import Meta from "../components/Meta";
|
||||
import useTranslate from "../hooks/useTranslate.hook";
|
||||
import { useRouter } from "next/router";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { safeRedirectPath } from "../utils/router.util";
|
||||
|
||||
const useStyle = createStyles({
|
||||
title: {
|
||||
@@ -39,7 +40,9 @@ export default function Error() {
|
||||
</Text>
|
||||
<Button
|
||||
mt="xl"
|
||||
onClick={() => router.push((router.query.redirect as string) || "/")}
|
||||
onClick={() =>
|
||||
router.push(safeRedirectPath(router.query.redirect as string))
|
||||
}
|
||||
>
|
||||
{t("error.button.back")}
|
||||
</Button>
|
||||
|
||||
@@ -37,6 +37,7 @@ const Share = ({ shareId }: { shareId: string }) => {
|
||||
modals,
|
||||
t("share.error.visitor-limit-exceeded.title"),
|
||||
t("share.error.visitor-limit-exceeded.description"),
|
||||
"go-home",
|
||||
);
|
||||
} else {
|
||||
toast.axiosError(e);
|
||||
@@ -58,12 +59,14 @@ const Share = ({ shareId }: { shareId: string }) => {
|
||||
modals,
|
||||
t("share.error.removed.title"),
|
||||
e.response.data.message,
|
||||
"go-home",
|
||||
);
|
||||
} else {
|
||||
showErrorModal(
|
||||
modals,
|
||||
t("share.error.not-found.title"),
|
||||
t("share.error.not-found.description"),
|
||||
"go-home",
|
||||
);
|
||||
}
|
||||
} else if (error == "share_password_required") {
|
||||
@@ -71,7 +74,12 @@ const Share = ({ shareId }: { shareId: string }) => {
|
||||
} else if (error == "share_token_required") {
|
||||
getShareToken();
|
||||
} else {
|
||||
showErrorModal(modals, t("common.error"), t("common.error.unknown"));
|
||||
showErrorModal(
|
||||
modals,
|
||||
t("common.error"),
|
||||
t("common.error.unknown"),
|
||||
"go-home",
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -83,13 +91,13 @@ const Share = ({ shareId }: { shareId: string }) => {
|
||||
return (
|
||||
<>
|
||||
<Meta
|
||||
title={t("share.title", { shareId })}
|
||||
title={t("share.title", { shareId: share?.name || shareId })}
|
||||
description={t("share.description")}
|
||||
/>
|
||||
|
||||
<Group position="apart" mb="lg">
|
||||
<Box style={{ maxWidth: "70%" }}>
|
||||
<Title order={3}>{share?.id}</Title>
|
||||
<Title order={3}>{share?.name || share?.id}</Title>
|
||||
<Text size="sm">{share?.description}</Text>
|
||||
</Box>
|
||||
{share?.files.length > 1 && <DownloadAllButton shareId={shareId} />}
|
||||
|
||||
@@ -30,6 +30,7 @@ const Share = ({ reverseShareToken }: { reverseShareToken: string }) => {
|
||||
modals,
|
||||
"Invalid Link",
|
||||
"This link is invalid. Please check your link.",
|
||||
"go-home",
|
||||
);
|
||||
setIsLoading(false);
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useModals } from "@mantine/modals";
|
||||
import { cleanNotifications } from "@mantine/notifications";
|
||||
import { AxiosError } from "axios";
|
||||
import pLimit from "p-limit";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Meta from "../../components/Meta";
|
||||
import Dropzone from "../../components/upload/Dropzone";
|
||||
@@ -19,7 +19,6 @@ import { CreateShare, Share } from "../../types/share.type";
|
||||
import toast from "../../utils/toast.util";
|
||||
|
||||
const promiseLimit = pLimit(3);
|
||||
const chunkSize = 10 * 1024 * 1024; // 10MB
|
||||
let errorToastShown = false;
|
||||
let createdShare: Share;
|
||||
|
||||
@@ -38,6 +37,8 @@ const Upload = ({
|
||||
const [files, setFiles] = useState<FileUpload[]>([]);
|
||||
const [isUploading, setisUploading] = useState(false);
|
||||
|
||||
const chunkSize = useRef(parseInt(config.get("share.chunkSize")));
|
||||
|
||||
maxShareSize ??= parseInt(config.get("share.maxSize"));
|
||||
|
||||
const uploadFiles = async (share: CreateShare, files: FileUpload[]) => {
|
||||
@@ -54,7 +55,7 @@ const Upload = ({
|
||||
const fileUploadPromises = files.map(async (file, fileIndex) =>
|
||||
// Limit the number of concurrent uploads to 3
|
||||
promiseLimit(async () => {
|
||||
let fileId: string;
|
||||
let fileId;
|
||||
|
||||
const setFileProgress = (progress: number) => {
|
||||
setFiles((files) =>
|
||||
@@ -69,38 +70,30 @@ const Upload = ({
|
||||
|
||||
setFileProgress(1);
|
||||
|
||||
let chunks = Math.ceil(file.size / chunkSize);
|
||||
let chunks = Math.ceil(file.size / chunkSize.current);
|
||||
|
||||
// If the file is 0 bytes, we still need to upload 1 chunk
|
||||
if (chunks == 0) chunks++;
|
||||
|
||||
for (let chunkIndex = 0; chunkIndex < chunks; chunkIndex++) {
|
||||
const from = chunkIndex * chunkSize;
|
||||
const to = from + chunkSize;
|
||||
const from = chunkIndex * chunkSize.current;
|
||||
const to = from + chunkSize.current;
|
||||
const blob = file.slice(from, to);
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async (event) =>
|
||||
await shareService
|
||||
.uploadFile(
|
||||
createdShare.id,
|
||||
event,
|
||||
{
|
||||
id: fileId,
|
||||
name: file.name,
|
||||
},
|
||||
chunkIndex,
|
||||
chunks,
|
||||
)
|
||||
.then((response) => {
|
||||
fileId = response.id;
|
||||
resolve(response);
|
||||
})
|
||||
.catch(reject);
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
await shareService
|
||||
.uploadFile(
|
||||
createdShare.id,
|
||||
blob,
|
||||
{
|
||||
id: fileId,
|
||||
name: file.name,
|
||||
},
|
||||
chunkIndex,
|
||||
chunks,
|
||||
)
|
||||
.then((response) => {
|
||||
fileId = response.id;
|
||||
});
|
||||
|
||||
setFileProgress(((chunkIndex + 1) / chunks) * 100);
|
||||
} catch (e) {
|
||||
|
||||
@@ -36,8 +36,10 @@ const signOut = async () => {
|
||||
const refreshAccessToken = async () => {
|
||||
try {
|
||||
const accessToken = getCookie("access_token") as string;
|
||||
|
||||
// If the access token expires in less than 2 minutes refresh it
|
||||
if (
|
||||
!accessToken ||
|
||||
accessToken &&
|
||||
(jose.decodeJwt(accessToken).exp ?? 0) * 1000 < Date.now() + 2 * 60 * 1000
|
||||
) {
|
||||
await api.post("/auth/token");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { setCookie } from "cookies-next";
|
||||
import { deleteCookie, setCookie } from "cookies-next";
|
||||
import mime from "mime-types";
|
||||
import { FileUploadResponse } from "../types/File.type";
|
||||
|
||||
@@ -11,12 +11,18 @@ import {
|
||||
} from "../types/share.type";
|
||||
import api from "./api.service";
|
||||
|
||||
const list = async (): Promise<MyShare[]> => {
|
||||
return (await api.get(`shares/all`)).data;
|
||||
};
|
||||
|
||||
const create = async (share: CreateShare) => {
|
||||
return (await api.post("shares", share)).data;
|
||||
};
|
||||
|
||||
const completeShare = async (id: string) => {
|
||||
return (await api.post(`shares/${id}/complete`)).data;
|
||||
const response = (await api.post(`shares/${id}/complete`)).data;
|
||||
deleteCookie("reverse_share_token");
|
||||
return response;
|
||||
};
|
||||
|
||||
const revertComplete = async (id: string) => {
|
||||
@@ -77,7 +83,7 @@ const removeFile = async (shareId: string, fileId: string) => {
|
||||
|
||||
const uploadFile = async (
|
||||
shareId: string,
|
||||
readerEvent: ProgressEvent<FileReader>,
|
||||
chunk: Blob,
|
||||
file: {
|
||||
id?: string;
|
||||
name: string;
|
||||
@@ -85,10 +91,8 @@ const uploadFile = async (
|
||||
chunkIndex: number,
|
||||
totalChunks: number,
|
||||
): Promise<FileUploadResponse> => {
|
||||
const data = readerEvent.target!.result;
|
||||
|
||||
return (
|
||||
await api.post(`shares/${shareId}/files`, data, {
|
||||
await api.post(`shares/${shareId}/files`, chunk, {
|
||||
headers: { "Content-Type": "application/octet-stream" },
|
||||
params: {
|
||||
id: file.id,
|
||||
@@ -131,6 +135,7 @@ const removeReverseShare = async (id: string) => {
|
||||
};
|
||||
|
||||
export default {
|
||||
list,
|
||||
create,
|
||||
completeShare,
|
||||
revertComplete,
|
||||
|
||||
@@ -8,11 +8,13 @@ const GlobalStyle = () => {
|
||||
color: "inherit",
|
||||
textDecoration: "none",
|
||||
},
|
||||
"table.md, table.md th:nth-of-type(odd), table.md td:nth-of-type(odd)": {
|
||||
background: theme.colorScheme == "dark"
|
||||
? "rgba(50, 50, 50, 0.5)"
|
||||
: "rgba(220, 220, 220, 0.5)",
|
||||
},
|
||||
"table.md, table.md th:nth-of-type(odd), table.md td:nth-of-type(odd)":
|
||||
{
|
||||
background:
|
||||
theme.colorScheme == "dark"
|
||||
? "rgba(50, 50, 50, 0.5)"
|
||||
: "rgba(220, 220, 220, 0.5)",
|
||||
},
|
||||
"table.md td": {
|
||||
paddingLeft: "0.5em",
|
||||
paddingRight: "0.5em",
|
||||
|
||||
@@ -2,15 +2,18 @@ import User from "./user.type";
|
||||
|
||||
export type Share = {
|
||||
id: string;
|
||||
name?: string;
|
||||
files: any;
|
||||
creator: User;
|
||||
creator?: User;
|
||||
description?: string;
|
||||
expiration: Date;
|
||||
size: number;
|
||||
hasPassword: boolean;
|
||||
};
|
||||
|
||||
export type CreateShare = {
|
||||
id: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
recipients: string[];
|
||||
expiration: string;
|
||||
|
||||
7
frontend/src/utils/router.util.ts
Normal file
7
frontend/src/utils/router.util.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function safeRedirectPath(path: string | undefined) {
|
||||
if (!path) return "/";
|
||||
|
||||
if (!path.startsWith("/")) return `/${path}`;
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
events {}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 3000;
|
||||
client_max_body_size 100M;
|
||||
|
||||
location /api {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header X-Forwarded-Host $host:$server_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3333;
|
||||
proxy_set_header X-Forwarded-Host $host:$server_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pingvin-share",
|
||||
"version": "0.22.0",
|
||||
"version": "0.24.1",
|
||||
"scripts": {
|
||||
"format": "cd frontend && npm run format && cd ../backend && npm run format",
|
||||
"lint": "cd frontend && npm run lint && cd ../backend && npm run lint",
|
||||
|
||||
Reference in New Issue
Block a user