Compare commits

...

19 Commits

Author SHA1 Message Date
Elias Schneider
2e1a2b60c4 release: 0.20.2 2023-11-11 20:29:24 +01:00
Elias Schneider
9896ca0e8c chore(translations): update translations via Crowdin (#313)
* New translations en-us.ts (French)

* New translations en-us.ts (Spanish)

* New translations en-us.ts (Japanese)

* New translations en-us.ts (Japanese)

* New translations en-us.ts (Swedish)

* New translations en-us.ts (Swedish)

* New translations en-us.ts (Swedish)

* New translations en-us.ts (Swedish)

* New translations en-us.ts (Russian)

* New translations en-us.ts (Russian)
2023-11-11 20:27:03 +01:00
Qing Fu
fd44f42f28 fix(oauth): github and discord login error (#323)
* fix(oauth): github and discord login error
fixed #322, fixed #302

* feat(oauth): print log when ErrorPageException occurs

* refactor(oauth): migrate to Logger

* feat(oauth): add logger for OAuthExceptionFilter

* docs(oauth): update oauth login docs
2023-11-11 20:25:05 +01:00
Elias Schneider
966ce261cb fix: reverse shares couldn't be created unauthenticated 2023-11-11 18:57:54 +01:00
Elias Schneider
5503e7a54f chore(translations): add Swedish translation files 2023-11-08 08:18:10 +01:00
Elias Schneider
b49ec93c54 release: 0.20.1 2023-11-05 12:38:13 +01:00
Elias Schneider
e6584322fa chore(translations): update translations via Crowdin (#310)
* New translations en-us.ts (French)

* New translations en-us.ts (Spanish)

* New translations en-us.ts (Danish)

* New translations en-us.ts (German)

* New translations en-us.ts (Finnish)

* New translations en-us.ts (Japanese)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Russian)

* New translations en-us.ts (Serbian (Cyrillic))

* New translations en-us.ts (Portuguese, Brazilian)

* New translations en-us.ts (Thai)

* New translations en-us.ts (Dutch, Belgium)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Portuguese, Brazilian)

* New translations en-us.ts (German)
2023-11-05 12:37:48 +01:00
Elias Schneider
1138cd02b0 fix: share information text color in light mode 2023-11-05 12:36:42 +01:00
Elias Schneider
1ba8d0cbd1 release: 0.20.0 2023-11-04 20:40:20 +01:00
Ivan Li
98380e2d48 feat: ability to add and delete files of existing share (#306)
* feat(share): delete file api, revert complete share api.

* feat(share): share edit page.

* feat(share): Modify the DropZone title of the edit sharing UI.

* feat(share): i18n for edit share. (en, zh)

* feat(share): allow creator get share by id.

* feat(share): add edit button in account/shares.

* style(share): lint.

* chore: some minor adjustments.

* refactor: run formatter

* refactor: remove unused return

---------

Co-authored-by: Elias Schneider <login@eliasschneider.com>
2023-11-04 20:39:58 +01:00
Elias Schneider
e377ed10e1 release: 0.19.2 2023-11-03 14:07:25 +01:00
Elias Schneider
acc35f4717 fix: wrong validation of setting max share expiration to 0 2023-11-03 14:05:43 +01:00
Elias Schneider
33742a043d fix: jwt secret changes on application restart 2023-11-03 13:06:59 +01:00
Elias Schneider
5cee9cbbb9 chore(translations): update translations via Crowdin (#298)
* New translations en-us.ts (French)

* New translations en-us.ts (Spanish)

* New translations en-us.ts (Danish)

* New translations en-us.ts (German)

* New translations en-us.ts (Finnish)

* New translations en-us.ts (Japanese)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Russian)

* New translations en-us.ts (Serbian (Cyrillic))

* New translations en-us.ts (Chinese Simplified)

* New translations en-us.ts (Portuguese, Brazilian)

* New translations en-us.ts (Thai)

* New translations en-us.ts (Dutch, Belgium)

* New translations en-us.ts (Serbian (Cyrillic))

* New translations en-us.ts (Danish)

* New translations en-us.ts (French)

* New translations en-us.ts (French)

* New translations en-us.ts (French)

* New translations en-us.ts (Portuguese, Brazilian)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Polish)

* New translations en-us.ts (Polish)
2023-11-03 10:39:13 +01:00
Elias Schneider
e0fbbeca3c feat: change totp issuer to display logo in 2FAS app 2023-11-03 08:38:23 +01:00
Elias Schneider
bbfc9d6f14 feat: ability to limit the max expiration of a share 2023-10-23 15:17:47 +02:00
Elias Schneider
46b6e56c06 release: 0.19.1 2023-10-22 21:21:37 +02:00
Elias Schneider
05f6582739 chore(translations): update translations via Crowdin (#295)
* New translations en-us.ts (German)

* New translations en-us.ts (Serbian (Cyrillic))

* New translations en-us.ts (Serbian (Cyrillic))

* New translations en-us.ts (Portuguese, Brazilian)
2023-10-22 21:21:17 +02:00
Qing Fu
119b1ec840 fix(oauth): fix wrong redirectUri in oidc after change appUrl (#296) 2023-10-22 21:20:50 +02:00
49 changed files with 1687 additions and 559 deletions

View File

@@ -1,3 +1,46 @@
## [0.20.2](https://github.com/stonith404/pingvin-share/compare/v0.20.1...v0.20.2) (2023-11-11)
### Bug Fixes
* **oauth:** github and discord login error ([#323](https://github.com/stonith404/pingvin-share/issues/323)) ([fd44f42](https://github.com/stonith404/pingvin-share/commit/fd44f42f28c0fa2091876b138f170202d9fde04e)), closes [#322](https://github.com/stonith404/pingvin-share/issues/322) [#302](https://github.com/stonith404/pingvin-share/issues/302)
* reverse shares couldn't be created unauthenticated ([966ce26](https://github.com/stonith404/pingvin-share/commit/966ce261cb4ad99efaadef5c36564fdfaed0d5c4))
## [0.20.1](https://github.com/stonith404/pingvin-share/compare/v0.20.0...v0.20.1) (2023-11-05)
### Bug Fixes
* share information text color in light mode ([1138cd0](https://github.com/stonith404/pingvin-share/commit/1138cd02b0b6ac1d71c4dbc2808110c672237190))
## [0.20.0](https://github.com/stonith404/pingvin-share/compare/v0.19.2...v0.20.0) (2023-11-04)
### Features
* ability to add and delete files of existing share ([#306](https://github.com/stonith404/pingvin-share/issues/306)) ([98380e2](https://github.com/stonith404/pingvin-share/commit/98380e2d48cc8ffa831d9b69cf5c0e8a40e28862))
## [0.19.2](https://github.com/stonith404/pingvin-share/compare/v0.19.1...v0.19.2) (2023-11-03)
### Features
* ability to limit the max expiration of a share ([bbfc9d6](https://github.com/stonith404/pingvin-share/commit/bbfc9d6f147eea404f011c3af9d7dc7655c3d21d))
* change totp issuer to display logo in 2FAS app ([e0fbbec](https://github.com/stonith404/pingvin-share/commit/e0fbbeca3c1a858838b20aeead52694772b7d871))
### Bug Fixes
* jwt secret changes on application restart ([33742a0](https://github.com/stonith404/pingvin-share/commit/33742a043d6549783984ae7e8a3c30f0fe3917de))
* wrong validation of setting max share expiration to `0` ([acc35f4](https://github.com/stonith404/pingvin-share/commit/acc35f47178e230f50ce54d6f1ad5370caa3382d))
## [0.19.1](https://github.com/stonith404/pingvin-share/compare/v0.19.0...v0.19.1) (2023-10-22)
### Bug Fixes
* **oauth:** fix wrong redirectUri in oidc after change appUrl ([#296](https://github.com/stonith404/pingvin-share/issues/296)) ([119b1ec](https://github.com/stonith404/pingvin-share/commit/119b1ec840ad7f4e1c7c4bb476bf1eeed91d9a1a))
## [0.19.0](https://github.com/stonith404/pingvin-share/compare/v0.18.2...v0.19.0) (2023-10-22) ## [0.19.0](https://github.com/stonith404/pingvin-share/compare/v0.18.2...v0.19.0) (2023-10-22)

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "0.19.0", "version": "0.20.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "0.19.0", "version": "0.20.2",
"dependencies": { "dependencies": {
"@nestjs/cache-manager": "^2.1.0", "@nestjs/cache-manager": "^2.1.0",
"@nestjs/common": "^10.1.2", "@nestjs/common": "^10.1.2",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "0.19.0", "version": "0.20.2",
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"dev": "cross-env NODE_ENV=development nest start --watch", "dev": "cross-env NODE_ENV=development nest start --watch",

View File

@@ -5,7 +5,7 @@ const configVariables: ConfigVariables = {
internal: { internal: {
jwtSecret: { jwtSecret: {
type: "string", type: "string",
defaultValue: crypto.randomBytes(256).toString("base64"), value: crypto.randomBytes(256).toString("base64"),
locked: true, locked: true,
}, },
}, },
@@ -37,6 +37,11 @@ const configVariables: ConfigVariables = {
defaultValue: "false", defaultValue: "false",
secret: false, secret: false,
}, },
maxExpiration: {
type: "number",
defaultValue: "0",
secret: false,
},
maxSize: { maxSize: {
type: "number", type: "number",
defaultValue: "1000000000", defaultValue: "1000000000",

View File

@@ -8,7 +8,6 @@ import { User } from "@prisma/client";
import * as argon from "argon2"; import * as argon from "argon2";
import { authenticator, totp } from "otplib"; import { authenticator, totp } from "otplib";
import * as qrcode from "qrcode-svg"; import * as qrcode from "qrcode-svg";
import { ConfigService } from "src/config/config.service";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { AuthService } from "./auth.service"; import { AuthService } from "./auth.service";
import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto"; import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto";
@@ -18,7 +17,6 @@ export class AuthTotpService {
constructor( constructor(
private prisma: PrismaService, private prisma: PrismaService,
private authService: AuthService, private authService: AuthService,
private config: ConfigService,
) {} ) {}
async signInTotp(dto: AuthSignInTotpDTO) { async signInTotp(dto: AuthSignInTotpDTO) {
@@ -78,12 +76,11 @@ export class AuthTotpService {
throw new BadRequestException("TOTP is already enabled"); throw new BadRequestException("TOTP is already enabled");
} }
// TODO: Maybe make the issuer configurable with env vars?
const secret = authenticator.generateSecret(); const secret = authenticator.generateSecret();
const otpURL = totp.keyuri( const otpURL = totp.keyuri(
user.username || user.email, user.username || user.email,
this.config.get("general.appName"), "pingvin-share",
secret, secret,
); );

View File

@@ -1,6 +1,7 @@
import { import {
Body, Body,
Controller, Controller,
Delete,
Get, Get,
Param, Param,
Post, Post,
@@ -81,4 +82,14 @@ export class FileController {
return new StreamableFile(file.file); return new StreamableFile(file.file);
} }
@Delete(":fileId")
@SkipThrottle()
@UseGuards(ShareOwnerGuard)
async remove(
@Param("fileId") fileId: string,
@Param("shareId") shareId: string,
) {
await this.fileService.remove(shareId, fileId);
}
} }

View File

@@ -124,6 +124,18 @@ export class FileService {
}; };
} }
async remove(shareId: string, fileId: string) {
const fileMetaData = await this.prisma.file.findUnique({
where: { id: fileId },
});
if (!fileMetaData) throw new NotFoundException("File not found");
fs.unlinkSync(`${SHARE_DIRECTORY}/${shareId}/${fileId}`);
await this.prisma.file.delete({ where: { id: fileId } });
}
async deleteAllFiles(shareId: string) { async deleteAllFiles(shareId: string) {
await fs.promises.rm(`${SHARE_DIRECTORY}/${shareId}`, { await fs.promises.rm(`${SHARE_DIRECTORY}/${shareId}`, {
recursive: true, recursive: true,

View File

@@ -1,12 +1,16 @@
import { ArgumentsHost, Catch, ExceptionFilter } from "@nestjs/common"; import { ArgumentsHost, Catch, ExceptionFilter, Logger } from "@nestjs/common";
import { ConfigService } from "../../config/config.service"; import { ConfigService } from "../../config/config.service";
import { ErrorPageException } from "../exceptions/errorPage.exception"; import { ErrorPageException } from "../exceptions/errorPage.exception";
@Catch(ErrorPageException) @Catch(ErrorPageException)
export class ErrorPageExceptionFilter implements ExceptionFilter { export class ErrorPageExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger(ErrorPageExceptionFilter.name);
constructor(private config: ConfigService) {} constructor(private config: ConfigService) {}
catch(exception: ErrorPageException, host: ArgumentsHost) { catch(exception: ErrorPageException, host: ArgumentsHost) {
this.logger.error(exception);
const ctx = host.switchToHttp(); const ctx = host.switchToHttp();
const response = ctx.getResponse(); const response = ctx.getResponse();

View File

@@ -3,6 +3,7 @@ import {
Catch, Catch,
ExceptionFilter, ExceptionFilter,
HttpException, HttpException,
Logger,
} from "@nestjs/common"; } from "@nestjs/common";
import { ConfigService } from "../../config/config.service"; import { ConfigService } from "../../config/config.service";
@@ -12,14 +13,20 @@ export class OAuthExceptionFilter implements ExceptionFilter {
access_denied: "access_denied", access_denied: "access_denied",
expired_token: "expired_token", expired_token: "expired_token",
}; };
private readonly logger = new Logger(OAuthExceptionFilter.name);
constructor(private config: ConfigService) {} constructor(private config: ConfigService) {}
catch(_exception: HttpException, host: ArgumentsHost) { catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp(); const ctx = host.switchToHttp();
const response = ctx.getResponse(); const response = ctx.getResponse();
const request = ctx.getRequest(); const request = ctx.getRequest();
this.logger.error(exception.message);
this.logger.error(
"Request query: " + JSON.stringify(request.query, null, 2),
);
const key = this.errorKeys[request.query.error] || "default"; const key = this.errorKeys[request.query.error] || "default";
const url = new URL(`${this.config.get("general.appUrl")}/error`); const url = new URL(`${this.config.get("general.appUrl")}/error`);

View File

@@ -60,8 +60,8 @@ export class DiscordProvider implements OAuthProvider<DiscordToken> {
} }
async getUserInfo(token: OAuthToken<DiscordToken>): Promise<OAuthSignInDto> { async getUserInfo(token: OAuthToken<DiscordToken>): Promise<OAuthSignInDto> {
const res = await fetch("https://discord.com/api/v10/user/@me", { const res = await fetch("https://discord.com/api/v10/users/@me", {
method: "post", method: "get",
headers: { headers: {
Accept: "application/json", Accept: "application/json",
Authorization: `${token.tokenType || "Bearer"} ${token.accessToken}`, Authorization: `${token.tokenType || "Bearer"} ${token.accessToken}`,

View File

@@ -9,7 +9,6 @@ import { OAuthProvider, OAuthToken } from "./oauthProvider.interface";
import { OAuthSignInDto } from "../dto/oauthSignIn.dto"; import { OAuthSignInDto } from "../dto/oauthSignIn.dto";
export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> { export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
protected redirectUri: string;
protected discoveryUri: string; protected discoveryUri: string;
private configuration: OidcConfigurationCache; private configuration: OidcConfigurationCache;
private jwk: OidcJwkCache; private jwk: OidcJwkCache;
@@ -22,9 +21,6 @@ export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
protected cache: Cache, protected cache: Cache,
) { ) {
this.discoveryUri = this.getDiscoveryUri(); this.discoveryUri = this.getDiscoveryUri();
this.redirectUri = `${this.config.get(
"general.appUrl",
)}/api/oauth/callback/${this.name}`;
this.config.addListener("update", (key: string, _: unknown) => { this.config.addListener("update", (key: string, _: unknown) => {
if (this.keyOfConfigUpdateEvents.includes(key)) { if (this.keyOfConfigUpdateEvents.includes(key)) {
this.deinit(); this.deinit();
@@ -33,6 +29,12 @@ export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
}); });
} }
protected getRedirectUri(): string {
return `${this.config.get("general.appUrl")}/api/oauth/callback/${
this.name
}`;
}
async getConfiguration(): Promise<OidcConfiguration> { async getConfiguration(): Promise<OidcConfiguration> {
if (!this.configuration || this.configuration.expires < Date.now()) { if (!this.configuration || this.configuration.expires < Date.now()) {
await this.fetchConfiguration(); await this.fetchConfiguration();
@@ -65,7 +67,7 @@ export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
client_id: this.config.get(`oauth.${this.name}-clientId`), client_id: this.config.get(`oauth.${this.name}-clientId`),
response_type: "code", response_type: "code",
scope: "openid profile email", scope: "openid profile email",
redirect_uri: this.redirectUri, redirect_uri: this.getRedirectUri(),
state, state,
nonce, nonce,
}).toString() }).toString()
@@ -85,7 +87,7 @@ export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
client_secret: this.config.get(`oauth.${this.name}-clientSecret`), client_secret: this.config.get(`oauth.${this.name}-clientSecret`),
grant_type: "authorization_code", grant_type: "authorization_code",
code: query.code, code: query.code,
redirect_uri: this.redirectUri, redirect_uri: this.getRedirectUri(),
}).toString(), }).toString(),
}); });
const token: OidcToken = await res.json(); const token: OidcToken = await res.json();

View File

@@ -41,15 +41,16 @@ export class GitHubProvider implements OAuthProvider<GitHubToken> {
return { return {
accessToken: token.access_token, accessToken: token.access_token,
tokenType: token.token_type, tokenType: token.token_type,
scope: token.scope,
rawToken: token, rawToken: token,
}; };
} }
async getUserInfo(token: OAuthToken<GitHubToken>): Promise<OAuthSignInDto> { async getUserInfo(token: OAuthToken<GitHubToken>): Promise<OAuthSignInDto> {
const user = await this.getGitHubUser(token);
if (!token.scope.includes("user:email")) { if (!token.scope.includes("user:email")) {
throw new BadRequestException("No email permission granted"); throw new BadRequestException("No email permission granted");
} }
const user = await this.getGitHubUser(token);
const email = await this.getGitHubEmail(token); const email = await this.getGitHubEmail(token);
if (!email) { if (!email) {
throw new BadRequestException("No email found"); throw new BadRequestException("No email found");

View File

@@ -3,6 +3,7 @@ import * as moment from "moment";
import { ConfigService } from "src/config/config.service"; import { ConfigService } from "src/config/config.service";
import { FileService } from "src/file/file.service"; import { FileService } from "src/file/file.service";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { parseRelativeDateToAbsolute } from "src/utils/date.util";
import { CreateReverseShareDTO } from "./dto/createReverseShare.dto"; import { CreateReverseShareDTO } from "./dto/createReverseShare.dto";
@Injectable() @Injectable()
@@ -24,6 +25,17 @@ export class ReverseShareService {
) )
.toDate(); .toDate();
const parsedExpiration = parseRelativeDateToAbsolute(data.shareExpiration);
if (
this.config.get("share.maxExpiration") !== 0 &&
parsedExpiration >
moment().add(this.config.get("share.maxExpiration"), "hours").toDate()
) {
throw new BadRequestException(
"Expiration date exceeds maximum expiration date",
);
}
const globalMaxShareSize = this.config.get("share.maxSize"); const globalMaxShareSize = this.config.get("share.maxSize");
if (globalMaxShareSize < data.maxShareSize) if (globalMaxShareSize < data.maxShareSize)

View File

@@ -1,5 +1,4 @@
import { import {
CanActivate,
ExecutionContext, ExecutionContext,
Injectable, Injectable,
NotFoundException, NotFoundException,
@@ -7,12 +6,20 @@ import {
import { User } from "@prisma/client"; import { User } from "@prisma/client";
import { Request } from "express"; import { Request } from "express";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { JwtGuard } from "../../auth/guard/jwt.guard";
import { ConfigService } from "src/config/config.service";
@Injectable() @Injectable()
export class ShareOwnerGuard implements CanActivate { export class ShareOwnerGuard extends JwtGuard {
constructor(private prisma: PrismaService) {} constructor(
configService: ConfigService,
private prisma: PrismaService,
) {
super(configService);
}
async canActivate(context: ExecutionContext) { async canActivate(context: ExecutionContext) {
const request: Request = context.switchToHttp().getRequest(); const request: Request = context.switchToHttp().getRequest();
const shareId = Object.prototype.hasOwnProperty.call( const shareId = Object.prototype.hasOwnProperty.call(
request.params, request.params,
@@ -30,6 +37,8 @@ export class ShareOwnerGuard implements CanActivate {
if (!share.creatorId) return true; if (!share.creatorId) return true;
if (!(await super.canActivate(context))) return false;
return share.creatorId == (request.user as User).id; return share.creatorId == (request.user as User).id;
} }
} }

View File

@@ -43,6 +43,12 @@ export class ShareController {
return new ShareDTO().from(await this.shareService.get(id)); return new ShareDTO().from(await this.shareService.get(id));
} }
@Get(":id/from-owner")
@UseGuards(ShareOwnerGuard)
async getFromOwner(@Param("id") id: string) {
return new ShareDTO().from(await this.shareService.get(id));
}
@Get(":id/metaData") @Get(":id/metaData")
@UseGuards(ShareSecurityGuard) @UseGuards(ShareSecurityGuard)
async getMetaData(@Param("id") id: string) { async getMetaData(@Param("id") id: string) {
@@ -62,12 +68,6 @@ export class ShareController {
); );
} }
@Delete(":id")
@UseGuards(JwtGuard, ShareOwnerGuard)
async remove(@Param("id") id: string) {
await this.shareService.remove(id);
}
@Post(":id/complete") @Post(":id/complete")
@HttpCode(202) @HttpCode(202)
@UseGuards(CreateShareGuard, ShareOwnerGuard) @UseGuards(CreateShareGuard, ShareOwnerGuard)
@@ -78,6 +78,18 @@ export class ShareController {
); );
} }
@Delete(":id/complete")
@UseGuards(ShareOwnerGuard)
async revertComplete(@Param("id") id: string) {
return new ShareDTO().from(await this.shareService.revertComplete(id));
}
@Delete(":id")
@UseGuards(ShareOwnerGuard)
async remove(@Param("id") id: string) {
await this.shareService.remove(id);
}
@Throttle(10, 60) @Throttle(10, 60)
@Get("isShareIdAvailable/:id") @Get("isShareIdAvailable/:id")
async isShareIdAvailable(@Param("id") id: string) { async isShareIdAvailable(@Param("id") id: string) {

View File

@@ -16,6 +16,7 @@ import { EmailService } from "src/email/email.service";
import { FileService } from "src/file/file.service"; import { FileService } from "src/file/file.service";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { ReverseShareService } from "src/reverseShare/reverseShare.service"; import { ReverseShareService } from "src/reverseShare/reverseShare.service";
import { parseRelativeDateToAbsolute } from "src/utils/date.util";
import { SHARE_DIRECTORY } from "../constants"; import { SHARE_DIRECTORY } from "../constants";
import { CreateShareDTO } from "./dto/createShare.dto"; import { CreateShareDTO } from "./dto/createShare.dto";
@@ -51,19 +52,19 @@ export class ShareService {
if (reverseShare) { if (reverseShare) {
expirationDate = reverseShare.shareExpiration; expirationDate = reverseShare.shareExpiration;
} else { } else {
// We have to add an exception for "never" (since moment won't like that) const parsedExpiration = parseRelativeDateToAbsolute(share.expiration);
if (share.expiration !== "never") {
expirationDate = moment() if (
.add( this.config.get("share.maxExpiration") !== 0 &&
share.expiration.split("-")[0], parsedExpiration >
share.expiration.split( moment().add(this.config.get("share.maxExpiration"), "hours").toDate()
"-", ) {
)[1] as moment.unitOfTime.DurationConstructor, throw new BadRequestException(
) "Expiration date exceeds maximum expiration date",
.toDate(); );
} else {
expirationDate = moment(0).toDate();
} }
expirationDate = parsedExpiration;
} }
fs.mkdirSync(`${SHARE_DIRECTORY}/${share.id}`, { fs.mkdirSync(`${SHARE_DIRECTORY}/${share.id}`, {
@@ -181,6 +182,13 @@ export class ShareService {
}); });
} }
async revertComplete(id: string) {
return this.prisma.share.update({
where: { id },
data: { uploadLocked: false, isZipReady: false },
});
}
async getSharesByUser(userId: string) { async getSharesByUser(userId: string) {
const shares = await this.prisma.share.findMany({ const shares = await this.prisma.share.findMany({
where: { where: {

View File

@@ -0,0 +1,12 @@
import * as moment from "moment";
export function parseRelativeDateToAbsolute(relativeDate: string) {
if (relativeDate == "never") return moment(0).toDate();
return moment()
.add(
relativeDate.split("-")[0],
relativeDate.split("-")[1] as moment.unitOfTime.DurationConstructor,
)
.toDate();
}

View File

@@ -10,23 +10,22 @@
### GitHub ### GitHub
Please follow the [official guide](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) Please follow the [official guide](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) to create an OAuth app.
to create an OAuth app.
Redirect URL: `https://<your-domain>/api/oauth/callback/github` Redirect URL: `https://<your-domain>/api/oauth/callback/github`
### Google ### Google
Please follow the [official guide](https://developers.google.com/identity/protocols/oauth2/web-server#prerequisites) to Please follow the [official guide](https://developers.google.com/identity/protocols/oauth2/web-server#prerequisites) to create an OAuth 2.0 App.
create an OAuth 2.0 App.
Redirect URL: `https://<your-domain>/api/oauth/callback/google` Redirect URL: `https://<your-domain>/api/oauth/callback/google`
### Microsoft ### Microsoft
Please follow Please follow the [official guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) to register an application.
the [official guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)
to register an application. > [!IMPORTANT]
> **Microsoft Tenant** you set in the admin panel must match the **supported account types** you set in the Microsoft Entra admin center, otherwise the OAuth login will not work. Refer to the [official documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri) for more details.
Redirect URL: `https://<your-domain>/api/oauth/callback/microsoft` Redirect URL: `https://<your-domain>/api/oauth/callback/microsoft`
@@ -38,7 +37,7 @@ Redirect URL: `https://<your-domain>/api/oauth/callback/discord`
### OpenID Connect ### OpenID Connect
Generic OpenID Connect provider is also supported, we have tested it on Keycloak and Authentik. Generic OpenID Connect provider is also supported, we have tested it on Keycloak, Authentik and Casdoor.
Redirect URL: `https://<your-domain>/api/oauth/callback/oidc` Redirect URL: `https://<your-domain>/api/oauth/callback/oidc`
@@ -74,14 +73,11 @@ const configVariables: ConfigVariables = {
### 2. Create provider class ### 2. Create provider class
#### OpenID Connect #### Generic OpenID Connect
If your provider supports OpenID connect, it's extremely easy to If your provider supports OpenID connect, it's extremely easy to extend [`GenericOidcProvider`](../backend/src/oauth/provider/genericOidc.provider.ts) to add a new OpenID Connect provider.
extend [`GenericOidcProvider`](../backend/src/oauth/provider/genericOidc.provider.ts) to add a new OpenID Connect
provider.
The [Google provider](../backend/src/oauth/provider/google.provider.ts) The [Google provider](../backend/src/oauth/provider/google.provider.ts) and [Microsoft provider](../backend/src/oauth/provider/microsoft.provider.ts) are good examples.
and [Microsoft provider](../backend/src/oauth/provider/microsoft.provider.ts) are good examples.
Here are some discovery URIs for popular providers: Here are some discovery URIs for popular providers:
@@ -95,17 +91,13 @@ Here are some discovery URIs for popular providers:
#### OAuth 2 #### OAuth 2
If your provider only supports OAuth 2, you can If your provider only supports OAuth 2, you can implement [`OAuthProvider`](../backend/src/oauth/provider/oauthProvider.interface.ts) interface to add a new OAuth 2 provider.
implement [`OAuthProvider`](../backend/src/oauth/provider/oauthProvider.interface.ts) interface to add a new OAuth 2
provider.
The [GitHub provider](../backend/src/oauth/provider/github.provider.ts) The [GitHub provider](../backend/src/oauth/provider/github.provider.ts) and [Discord provider](../backend/src/oauth/provider/discord.provider.ts) are good examples.
and [Discord provider](../backend/src/oauth/provider/discord.provider.ts) are good examples.
### 3. Register provider ### 3. Register provider
Register your provider in [`OAuthModule`](../backend/src/oauth/oauth.module.ts) Register your provider in [`OAuthModule`](../backend/src/oauth/oauth.module.ts) and [`OAuthSignInDto`](../backend/src/oauth/dto/oauthSignIn.dto.ts):
and [`OAuthSignInDto`](../backend/src/oauth/dto/oauthSignIn.dto.ts):
```ts ```ts
@Module({ @Module({
@@ -117,8 +109,7 @@ and [`OAuthSignInDto`](../backend/src/oauth/dto/oauthSignIn.dto.ts):
useFactory(github: GitHubProvider, /* your provider */): Record<string, OAuthProvider<unknown>> { useFactory(github: GitHubProvider, /* your provider */): Record<string, OAuthProvider<unknown>> {
return { return {
github, github,
google, /* your provider */
oidc,
}; };
}, },
inject: [GitHubProvider, /* your provider */], inject: [GitHubProvider, /* your provider */],
@@ -131,8 +122,7 @@ export class OAuthModule {
```ts ```ts
export interface OAuthSignInDto { export interface OAuthSignInDto {
provider: 'github' | 'google' | 'microsoft' | 'discord' | 'oidc' /* your provider*/ provider: 'github' | 'google' | 'microsoft' | 'discord' | 'oidc' /* your provider*/;
;
providerId: string; providerId: string;
providerUsername: string; providerUsername: string;
email: string; email: string;
@@ -161,8 +151,7 @@ Add keys below to your i18n text in [locale file](../frontend/src/i18n/translati
- `admin.config.oauth.YOUR_PROVIDER_NAME-enabled` - `admin.config.oauth.YOUR_PROVIDER_NAME-enabled`
- `admin.config.oauth.YOUR_PROVIDER_NAME-client-id` - `admin.config.oauth.YOUR_PROVIDER_NAME-client-id`
- `admin.config.oauth.YOUR_PROVIDER_NAME-client-secret` - `admin.config.oauth.YOUR_PROVIDER_NAME-client-secret`
- `error.param.provider_YOUR_PROVIDER_NAME`
- Other config keys you defined in step 1 - Other config keys you defined in step 1
Congratulations! 🎉 You have successfully added a new OAuth 2 provider! Pull requests are welcome if you want to share Congratulations! 🎉 You have successfully added a new OAuth 2 provider! Pull requests are welcome if you want to share your provider with others.
your provider with others.

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "0.19.0", "version": "0.20.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "0.19.0", "version": "0.20.2",
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "0.19.0", "version": "0.20.2",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",

View File

@@ -12,7 +12,7 @@ const showShareInformationsModal = (
modals: ModalsContextProps, modals: ModalsContextProps,
share: MyShare, share: MyShare,
appUrl: string, appUrl: string,
maxShareSize: number, maxShareSize: number
) => { ) => {
const t = translateOutsideContext(); const t = translateOutsideContext();
const link = `${appUrl}/s/${share.id}`; const link = `${appUrl}/s/${share.id}`;
@@ -36,28 +36,28 @@ const showShareInformationsModal = (
children: ( children: (
<Stack align="stretch" spacing="md"> <Stack align="stretch" spacing="md">
<Text size="sm" color="lightgray"> <Text size="sm">
<b> <b>
<FormattedMessage id="account.shares.table.id" />:{" "} <FormattedMessage id="account.shares.table.id" />:{" "}
</b> </b>
{share.id} {share.id}
</Text> </Text>
<Text size="sm" color="lightgray"> <Text size="sm">
<b> <b>
<FormattedMessage id="account.shares.table.description" />:{" "} <FormattedMessage id="account.shares.table.description" />:{" "}
</b> </b>
{share.description || "No description"} {share.description || "No description"}
</Text> </Text>
<Text size="sm" color="lightgray"> <Text size="sm">
<b> <b>
<FormattedMessage id="account.shares.table.createdAt" />:{" "} <FormattedMessage id="account.shares.table.createdAt" />:{" "}
</b> </b>
{formattedCreatedAt} {formattedCreatedAt}
</Text> </Text>
<Text size="sm" color="lightgray"> <Text size="sm">
<b> <b>
<FormattedMessage id="account.shares.table.expiresAt" />:{" "} <FormattedMessage id="account.shares.table.expiresAt" />:{" "}
</b> </b>
@@ -66,7 +66,7 @@ const showShareInformationsModal = (
<Divider /> <Divider />
<CopyTextField link={link} /> <CopyTextField link={link} />
<Divider /> <Divider />
<Text size="sm" color="lightgray"> <Text size="sm">
<b> <b>
<FormattedMessage id="account.shares.table.size" />:{" "} <FormattedMessage id="account.shares.table.size" />:{" "}
</b> </b>
@@ -76,7 +76,7 @@ const showShareInformationsModal = (
<Flex align="center" justify="center"> <Flex align="center" justify="center">
{shareSize / maxShareSize < 0.1 && ( {shareSize / maxShareSize < 0.1 && (
<Text size="xs" color="lightgray" style={{ marginRight: "4px" }}> <Text size="xs" style={{ marginRight: "4px" }}>
{formattedShareSize} {formattedShareSize}
</Text> </Text>
)} )}
@@ -87,7 +87,7 @@ const showShareInformationsModal = (
size="xl" size="xl"
radius="xl" radius="xl"
/> />
<Text size="xs" color="lightgray" style={{ marginLeft: "4px" }}> <Text size="xs" style={{ marginLeft: "4px" }}>
{formattedMaxShareSize} {formattedMaxShareSize}
</Text> </Text>
</Flex> </Flex>

View File

@@ -12,6 +12,7 @@ import {
import { useForm } from "@mantine/form"; import { useForm } from "@mantine/form";
import { useModals } from "@mantine/modals"; import { useModals } from "@mantine/modals";
import { ModalsContextProps } from "@mantine/modals/lib/context"; import { ModalsContextProps } from "@mantine/modals/lib/context";
import moment from "moment";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import useTranslate, { import useTranslate, {
translateOutsideContext, translateOutsideContext,
@@ -25,6 +26,7 @@ import showCompletedReverseShareModal from "./showCompletedReverseShareModal";
const showCreateReverseShareModal = ( const showCreateReverseShareModal = (
modals: ModalsContextProps, modals: ModalsContextProps,
showSendEmailNotificationOption: boolean, showSendEmailNotificationOption: boolean,
maxExpirationInHours: number,
getReverseShares: () => void, getReverseShares: () => void,
) => { ) => {
const t = translateOutsideContext(); const t = translateOutsideContext();
@@ -34,6 +36,7 @@ const showCreateReverseShareModal = (
<Body <Body
showSendEmailNotificationOption={showSendEmailNotificationOption} showSendEmailNotificationOption={showSendEmailNotificationOption}
getReverseShares={getReverseShares} getReverseShares={getReverseShares}
maxExpirationInHours={maxExpirationInHours}
/> />
), ),
}); });
@@ -42,9 +45,11 @@ const showCreateReverseShareModal = (
const Body = ({ const Body = ({
getReverseShares, getReverseShares,
showSendEmailNotificationOption, showSendEmailNotificationOption,
maxExpirationInHours,
}: { }: {
getReverseShares: () => void; getReverseShares: () => void;
showSendEmailNotificationOption: boolean; showSendEmailNotificationOption: boolean;
maxExpirationInHours: number;
}) => { }) => {
const modals = useModals(); const modals = useModals();
const t = useTranslate(); const t = useTranslate();
@@ -58,27 +63,48 @@ const Body = ({
expiration_unit: "-days", expiration_unit: "-days",
}, },
}); });
const onSubmit = form.onSubmit(async (values) => {
const expirationDate = moment().add(
form.values.expiration_num,
form.values.expiration_unit.replace(
"-",
"",
) as moment.unitOfTime.DurationConstructor,
);
if (
maxExpirationInHours != 0 &&
expirationDate.isAfter(moment().add(maxExpirationInHours, "hours"))
) {
form.setFieldError(
"expiration_num",
t("upload.modal.expires.error.too-long", {
max: moment.duration(maxExpirationInHours, "hours").humanize(),
}),
);
return;
}
shareService
.createReverseShare(
values.expiration_num + values.expiration_unit,
values.maxShareSize,
values.maxUseCount,
values.sendEmailNotification,
)
.then(({ link }) => {
modals.closeAll();
showCompletedReverseShareModal(modals, link, getReverseShares);
})
.catch(toast.axiosError);
});
return ( return (
<Group> <Group>
<form <form onSubmit={onSubmit}>
onSubmit={form.onSubmit(async (values) => {
shareService
.createReverseShare(
values.expiration_num + values.expiration_unit,
values.maxShareSize,
values.maxUseCount,
values.sendEmailNotification,
)
.then(({ link }) => {
modals.closeAll();
showCompletedReverseShareModal(modals, link, getReverseShares);
})
.catch(toast.axiosError);
})}
>
<Stack align="stretch"> <Stack align="stretch">
<div> <div>
<Grid align={form.errors.link ? "center" : "flex-end"}> <Grid align={form.errors.expiration_num ? "center" : "flex-end"}>
<Col xs={6}> <Col xs={6}>
<NumberInput <NumberInput
min={1} min={1}

View File

@@ -33,10 +33,12 @@ const useStyles = createStyles((theme) => ({
})); }));
const Dropzone = ({ const Dropzone = ({
title,
isUploading, isUploading,
maxShareSize, maxShareSize,
showCreateUploadModalCallback, showCreateUploadModalCallback,
}: { }: {
title?: string;
isUploading: boolean; isUploading: boolean;
maxShareSize: number; maxShareSize: number;
showCreateUploadModalCallback: (files: FileUpload[]) => void; showCreateUploadModalCallback: (files: FileUpload[]) => void;
@@ -78,7 +80,7 @@ const Dropzone = ({
<TbCloudUpload size={50} /> <TbCloudUpload size={50} />
</Group> </Group>
<Text align="center" weight={700} size="lg" mt="xl"> <Text align="center" weight={700} size="lg" mt="xl">
<FormattedMessage id="upload.dropzone.title" /> {title || <FormattedMessage id="upload.dropzone.title" />}
</Text> </Text>
<Text align="center" size="sm" mt="xs" color="dimmed"> <Text align="center" size="sm" mt="xs" color="dimmed">
<FormattedMessage <FormattedMessage

View File

@@ -0,0 +1,238 @@
import { Button, Group } from "@mantine/core";
import { useModals } from "@mantine/modals";
import { cleanNotifications } from "@mantine/notifications";
import { AxiosError } from "axios";
import pLimit from "p-limit";
import { useEffect, useMemo, 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 = ({
maxShareSize,
shareId,
files: savedFiles = [],
}: {
maxShareSize?: number;
isReverseShare?: boolean;
shareId: string;
files?: FileMetaData[];
}) => {
const t = useTranslate();
const router = useRouter();
const config = useConfig();
const [existingFiles, setExistingFiles] =
useState<Array<FileMetaData & { deleted?: boolean }>>(savedFiles);
const [uploadingFiles, setUploadingFiles] = useState<FileUpload[]>([]);
const [isUploading, setIsUploading] = useState(false);
const existingAndUploadedFiles: FileListItem[] = useMemo(
() => [...uploadingFiles, ...existingFiles],
[existingFiles, uploadingFiles],
);
const dirty = useMemo(() => {
return (
existingFiles.some((file) => !!file.deleted) || !!uploadingFiles.length
);
}, [existingFiles, uploadingFiles]);
const setFiles = (files: FileListItem[]) => {
const _uploadFiles = files.filter(
(file) => "uploadingProgress" in file,
) as FileUpload[];
const _existingFiles = files.filter(
(file) => !("uploadingProgress" in file),
) as FileMetaData[];
setUploadingFiles(_uploadFiles);
setExistingFiles(_existingFiles);
};
maxShareSize ??= parseInt(config.get("share.maxSize"));
const uploadFiles = async (files: FileUpload[]) => {
const fileUploadPromises = files.map(async (file, fileIndex) =>
// Limit the number of concurrent uploads to 3
promiseLimit(async () => {
let fileId: string;
const setFileProgress = (progress: number) => {
setUploadingFiles((files) =>
files.map((file, callbackIndex) => {
if (fileIndex == callbackIndex) {
file.uploadingProgress = progress;
}
return file;
}),
);
};
setFileProgress(1);
let chunks = Math.ceil(file.size / chunkSize);
// 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 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);
});
setFileProgress(((chunkIndex + 1) / chunks) * 100);
} catch (e) {
if (
e instanceof AxiosError &&
e.response?.data.error == "unexpected_chunk_index"
) {
// Retry with the expected chunk index
chunkIndex = e.response!.data!.expectedChunkIndex - 1;
continue;
} else {
setFileProgress(-1);
// Retry after 5 seconds
await new Promise((resolve) => setTimeout(resolve, 5000));
chunkIndex = -1;
continue;
}
}
}
}),
);
await Promise.all(fileUploadPromises);
};
const removeFiles = async () => {
const removedFiles = existingFiles.filter((file) => !!file.deleted);
if (removedFiles.length > 0) {
await Promise.all(
removedFiles.map(async (file) => {
await shareService.removeFile(shareId, file.id);
}),
);
setExistingFiles(existingFiles.filter((file) => !file.deleted));
}
};
const revertComplete = async () => {
await shareService.revertComplete(shareId).then();
};
const completeShare = async () => {
return await shareService.completeShare(shareId);
};
const save = async () => {
setIsUploading(true);
try {
await revertComplete();
await uploadFiles(uploadingFiles);
const hasFailed = uploadingFiles.some(
(file) => file.uploadingProgress == -1,
);
if (!hasFailed) {
await removeFiles();
}
await completeShare();
if (!hasFailed) {
toast.success(t("share.edit.notify.save-success"));
router.back();
}
} catch {
toast.error(t("share.edit.notify.generic-error"));
} finally {
setIsUploading(false);
}
};
const appendFiles = (appendingFiles: FileUpload[]) => {
setUploadingFiles([...appendingFiles, ...uploadingFiles]);
};
useEffect(() => {
// Check if there are any files that failed to upload
const fileErrorCount = uploadingFiles.filter(
(file) => file.uploadingProgress == -1,
).length;
if (fileErrorCount > 0) {
if (!errorToastShown) {
toast.error(
t("upload.notify.count-failed", { count: fileErrorCount }),
{
withCloseButton: false,
autoClose: false,
},
);
}
errorToastShown = true;
} else {
cleanNotifications();
errorToastShown = false;
}
}, [uploadingFiles]);
return (
<>
<Group position="right" mb={20}>
<Button loading={isUploading} disabled={!dirty} onClick={() => save()}>
<FormattedMessage id="common.button.save" />
</Button>
</Group>
<Dropzone
title={t("share.edit.append-upload")}
maxShareSize={maxShareSize}
showCreateUploadModalCallback={appendFiles}
isUploading={isUploading}
/>
{existingAndUploadedFiles.length > 0 && (
<FileList files={existingAndUploadedFiles} setFiles={setFiles} />
)}
</>
);
};
export default EditableUpload;

View File

@@ -1,41 +1,106 @@
import { ActionIcon, Table } from "@mantine/core"; import { ActionIcon, Table } from "@mantine/core";
import { Dispatch, SetStateAction } from "react";
import { TbTrash } from "react-icons/tb"; import { TbTrash } from "react-icons/tb";
import { FileUpload } from "../../types/File.type"; import { GrUndo } from "react-icons/gr";
import { FileListItem } from "../../types/File.type";
import { byteToHumanSizeString } from "../../utils/fileSize.util"; import { byteToHumanSizeString } from "../../utils/fileSize.util";
import UploadProgressIndicator from "./UploadProgressIndicator"; import UploadProgressIndicator from "./UploadProgressIndicator";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
const FileList = ({ const FileListRow = ({
file,
onRemove,
onRestore,
}: {
file: FileListItem;
onRemove?: () => void;
onRestore?: () => void;
}) => {
{
const uploadable = "uploadingProgress" in file;
const uploading = uploadable && file.uploadingProgress !== 0;
const removable = uploadable
? file.uploadingProgress === 0
: onRemove && !file.deleted;
const restorable = onRestore && !uploadable && !!file.deleted; // maybe undefined, force boolean
const deleted = !uploadable && !!file.deleted;
return (
<tr
style={{
color: deleted ? "rgba(120, 120, 120, 0.5)" : "inherit",
textDecoration: deleted ? "line-through" : "none",
}}
>
<td>{file.name}</td>
<td>{byteToHumanSizeString(+file.size)}</td>
<td>
{removable && (
<ActionIcon
color="red"
variant="light"
size={25}
onClick={onRemove}
>
<TbTrash />
</ActionIcon>
)}
{uploading && (
<UploadProgressIndicator progress={file.uploadingProgress} />
)}
{restorable && (
<ActionIcon
color="primary"
variant="light"
size={25}
onClick={onRestore}
>
<GrUndo />
</ActionIcon>
)}
</td>
</tr>
);
}
};
const FileList = <T extends FileListItem = FileListItem>({
files, files,
setFiles, setFiles,
}: { }: {
files: FileUpload[]; files: T[];
setFiles: Dispatch<SetStateAction<FileUpload[]>>; setFiles: (files: T[]) => void;
}) => { }) => {
const remove = (index: number) => { const remove = (index: number) => {
files.splice(index, 1); const file = files[index];
if ("uploadingProgress" in file) {
files.splice(index, 1);
} else {
files[index] = { ...file, deleted: true };
}
setFiles([...files]); setFiles([...files]);
}; };
const restore = (index: number) => {
const file = files[index];
if ("uploadingProgress" in file) {
return;
} else {
files[index] = { ...file, deleted: false };
}
setFiles([...files]);
};
const rows = files.map((file, i) => ( const rows = files.map((file, i) => (
<tr key={i}> <FileListRow
<td>{file.name}</td> key={i}
<td>{byteToHumanSizeString(file.size)}</td> file={file}
<td> onRemove={() => remove(i)}
{file.uploadingProgress == 0 ? ( onRestore={() => restore(i)}
<ActionIcon />
color="red"
variant="light"
size={25}
onClick={() => remove(i)}
>
<TbTrash />
</ActionIcon>
) : (
<UploadProgressIndicator progress={file.uploadingProgress} />
)}
</td>
</tr>
)); ));
return ( return (

View File

@@ -18,6 +18,7 @@ import {
import { useForm, yupResolver } from "@mantine/form"; import { useForm, yupResolver } from "@mantine/form";
import { useModals } from "@mantine/modals"; import { useModals } from "@mantine/modals";
import { ModalsContextProps } from "@mantine/modals/lib/context"; import { ModalsContextProps } from "@mantine/modals/lib/context";
import moment from "moment";
import { useState } from "react"; import { useState } from "react";
import { TbAlertCircle } from "react-icons/tb"; import { TbAlertCircle } from "react-icons/tb";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@@ -38,6 +39,7 @@ const showCreateUploadModal = (
appUrl: string; appUrl: string;
allowUnauthenticatedShares: boolean; allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean; enableEmailRecepients: boolean;
maxExpirationInHours: number;
}, },
files: FileUpload[], files: FileUpload[],
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void, uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void,
@@ -69,6 +71,7 @@ const CreateUploadModalBody = ({
appUrl: string; appUrl: string;
allowUnauthenticatedShares: boolean; allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean; enableEmailRecepients: boolean;
maxExpirationInHours: number;
}; };
}) => { }) => {
const modals = useModals(); const modals = useModals();
@@ -92,6 +95,7 @@ const CreateUploadModalBody = ({
password: yup.string().min(3).max(30), password: yup.string().min(3).max(30),
maxViews: yup.number().min(1), maxViews: yup.number().min(1),
}); });
const form = useForm({ const form = useForm({
initialValues: { initialValues: {
link: generatedLink, link: generatedLink,
@@ -105,6 +109,56 @@ const CreateUploadModalBody = ({
}, },
validate: yupResolver(validationSchema), validate: yupResolver(validationSchema),
}); });
const onSubmit = form.onSubmit(async (values) => {
if (!(await shareService.isShareIdAvailable(values.link))) {
form.setFieldError("link", t("upload.modal.link.error.taken"));
} else {
const expirationString = form.values.never_expires
? "never"
: form.values.expiration_num + form.values.expiration_unit;
const expirationDate = moment().add(
form.values.expiration_num,
form.values.expiration_unit.replace(
"-",
"",
) as moment.unitOfTime.DurationConstructor,
);
if (
options.maxExpirationInHours != 0 &&
expirationDate.isAfter(
moment().add(options.maxExpirationInHours, "hours"),
)
) {
form.setFieldError(
"expiration_num",
t("upload.modal.expires.error.too-long", {
max: moment
.duration(options.maxExpirationInHours, "hours")
.humanize(),
}),
);
return;
}
uploadCallback(
{
id: values.link,
expiration: expirationString,
recipients: values.recipients,
description: values.description,
security: {
password: values.password,
maxViews: values.maxViews,
},
},
files,
);
modals.closeAll();
}
});
return ( return (
<> <>
{showNotSignedInAlert && !options.isUserSignedIn && ( {showNotSignedInAlert && !options.isUserSignedIn && (
@@ -118,33 +172,9 @@ const CreateUploadModalBody = ({
<FormattedMessage id="upload.modal.not-signed-in-description" /> <FormattedMessage id="upload.modal.not-signed-in-description" />
</Alert> </Alert>
)} )}
<form <form onSubmit={onSubmit}>
onSubmit={form.onSubmit(async (values) => {
if (!(await shareService.isShareIdAvailable(values.link))) {
form.setFieldError("link", t("upload.modal.link.error.taken"));
} else {
const expiration = form.values.never_expires
? "never"
: form.values.expiration_num + form.values.expiration_unit;
uploadCallback(
{
id: values.link,
expiration: expiration,
recipients: values.recipients,
description: values.description,
security: {
password: values.password,
maxViews: values.maxViews,
},
},
files,
);
modals.closeAll();
}
})}
>
<Stack align="stretch"> <Stack align="stretch">
<Group align="end"> <Group align={form.errors.link ? "center" : "flex-end"}>
<TextInput <TextInput
style={{ flex: "1" }} style={{ flex: "1" }}
variant="filled" variant="filled"
@@ -179,7 +209,7 @@ const CreateUploadModalBody = ({
</Text> </Text>
{!options.isReverseShare && ( {!options.isReverseShare && (
<> <>
<Grid align={form.errors.link ? "center" : "flex-end"}> <Grid align={form.errors.expiration_num ? "center" : "flex-end"}>
<Col xs={6}> <Col xs={6}>
<NumberInput <NumberInput
min={1} min={1}

View File

@@ -6,12 +6,13 @@ import finnish from "./translations/fi-FI";
import french from "./translations/fr-FR"; import french from "./translations/fr-FR";
import japanese from "./translations/ja-JP"; import japanese from "./translations/ja-JP";
import dutch from "./translations/nl-BE"; import dutch from "./translations/nl-BE";
import polish from "./translations/pl-PL";
import portuguese from "./translations/pt-BR"; import portuguese from "./translations/pt-BR";
import russian from "./translations/ru-RU"; import russian from "./translations/ru-RU";
import serbian from "./translations/sr-SP"; import serbian from "./translations/sr-SP";
import swedish from "./translations/sv-SE";
import thai from "./translations/th-TH"; import thai from "./translations/th-TH";
import chineseSimplified from "./translations/zh-CN"; import chineseSimplified from "./translations/zh-CN";
import polish from "./translations/pl-PL";
export const LOCALES = { export const LOCALES = {
ENGLISH: { ENGLISH: {
@@ -84,4 +85,9 @@ export const LOCALES = {
code: "pl-PL", code: "pl-PL",
messages: polish, messages: polish,
}, },
SWEDISH: {
name: "Svenska",
code: "sv-SE",
messages: swedish,
},
}; };

View File

@@ -52,7 +52,7 @@ export default {
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "TOTP Authentication",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Log ind",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Glemt din adgangskode?", "resetPassword.title": "Glemt din adgangskode?",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Du vil ikke være i stand til at slette din deling manuelt og se antallet af besøgende.", "upload.modal.not-signed-in-description": "Du vil ikke være i stand til at slette din deling manuelt og se antallet af besøgende.",
"upload.modal.expires.never": "aldrig", "upload.modal.expires.never": "aldrig",
"upload.modal.expires.never-long": "Udløber aldrig", "upload.modal.expires.never-long": "Udløber aldrig",
"upload.modal.expires.error.too-long": "Udløbsdatoen overskrider den maksimalt tilladte udløbsdato på {max}.",
"upload.modal.link.label": "Link", "upload.modal.link.label": "Link",
"upload.modal.expires.label": "Udløb", "upload.modal.expires.label": "Udløb",
"upload.modal.expires.minute-singular": "Minut", "upload.modal.expires.minute-singular": "Minut",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Forhåndsvisning ikke understøttet", "share.modal.file-preview.error.not-supported.title": "Forhåndsvisning ikke understøttet",
"share.modal.file-preview.error.not-supported.description": "En forhåndsvisning for thise filtype er ikke understøttet. Download venligst filen for at se den.", "share.modal.file-preview.error.not-supported.description": "En forhåndsvisning for thise filtype er ikke understøttet. Download venligst filen for at se den.",
// END /share/[id] // 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
"admin.config.title": "Konfiguration", "admin.config.title": "Konfiguration",
"admin.config.category.general": "Generelt", "admin.config.category.general": "Generelt",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Om alle skal kunne oprette en bruger", "admin.config.share.allow-registration.description": "Om alle skal kunne oprette en bruger",
"admin.config.share.allow-unauthenticated-shares": "Tillad uautoriserede delinger", "admin.config.share.allow-unauthenticated-shares": "Tillad uautoriserede delinger",
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares", "admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
"admin.config.share.max-expiration": "Maks. udløb",
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
"admin.config.share.max-size": "Maks. størrelse", "admin.config.share.max-size": "Maks. størrelse",
"admin.config.share.max-size.description": "Maksimal filstørrelse i bytes", "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": "Zip compression level",

View File

@@ -33,7 +33,7 @@ export default {
"signin.button.submit": "Anmelden", "signin.button.submit": "Anmelden",
"signIn.notify.totp-required.title": "Zwei-Faktor-Authentifizierung benötigt", "signIn.notify.totp-required.title": "Zwei-Faktor-Authentifizierung benötigt",
"signIn.notify.totp-required.description": "Bitte füge deinen Zwei-Faktor-Authentifizierungscode ein", "signIn.notify.totp-required.description": "Bitte füge deinen Zwei-Faktor-Authentifizierungscode ein",
"signIn.oauth.or": "OR", "signIn.oauth.or": "ODER",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Lass uns loslegen", "signup.button.submit": "Lass uns loslegen",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "TOTP Authentifizierung",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Anmelden",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Passwort vergessen?", "resetPassword.title": "Passwort vergessen?",
@@ -115,7 +115,7 @@ export default {
"account.shares.title.empty": "Es ist so leer hier 👀", "account.shares.title.empty": "Es ist so leer hier 👀",
"account.shares.description.empty": "Du hast keine Freigaben erstellt.", "account.shares.description.empty": "Du hast keine Freigaben erstellt.",
"account.shares.button.create": "Erstelle eine", "account.shares.button.create": "Erstelle eine",
"account.shares.info.title": "Teile deine Information", "account.shares.info.title": "Freigabe Informationen",
"account.shares.table.id": "ID", "account.shares.table.id": "ID",
"account.shares.table.name": "Name", "account.shares.table.name": "Name",
"account.shares.table.description": "Beschreibung", "account.shares.table.description": "Beschreibung",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Du wirst deine Freigabe nicht löschen können oder die Besucheranzahl sehen.", "upload.modal.not-signed-in-description": "Du wirst deine Freigabe nicht löschen können oder die Besucheranzahl sehen.",
"upload.modal.expires.never": "niemals", "upload.modal.expires.never": "niemals",
"upload.modal.expires.never-long": "Läuft nicht ab", "upload.modal.expires.never-long": "Läuft nicht ab",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "Link", "upload.modal.link.label": "Link",
"upload.modal.expires.label": "Gültig bis", "upload.modal.expires.label": "Gültig bis",
"upload.modal.expires.minute-singular": "Minute", "upload.modal.expires.minute-singular": "Minute",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Vorschau wird nicht unterstützt", "share.modal.file-preview.error.not-supported.title": "Vorschau wird nicht unterstützt",
"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 anzuzeigen.", "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 anzuzeigen.",
// END /share/[id] // 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
"admin.config.title": "Einstellungen", "admin.config.title": "Einstellungen",
"admin.config.category.general": "Allgemein", "admin.config.category.general": "Allgemein",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Gibt an, ob eine Registrierung erlaubt ist", "admin.config.share.allow-registration.description": "Gibt an, ob eine Registrierung erlaubt ist",
"admin.config.share.allow-unauthenticated-shares": "Nicht authentifizierte Freigaben erlauben", "admin.config.share.allow-unauthenticated-shares": "Nicht authentifizierte Freigaben erlauben",
"admin.config.share.allow-unauthenticated-shares.description": "Gibt an, ob nicht authentifizierte Benutzer Freigaben erstellen können", "admin.config.share.allow-unauthenticated-shares.description": "Gibt an, ob nicht authentifizierte Benutzer Freigaben erstellen können",
"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": "Maximale Größe", "admin.config.share.max-size": "Maximale Größe",
"admin.config.share.max-size.description": "Maximale Größe einer Freigabe in Bytes", "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": "Zip Komprimierungsstufe",
@@ -361,9 +370,9 @@ export default {
"404.button.home": "Zurück zur Startseite", "404.button.home": "Zurück zur Startseite",
// error // error
"error.title": "Error", "error.title": "Error",
"error.description": "Oops!", "error.description": "Ups!",
"error.button.back": "Go back", "error.button.back": "Zurück",
"error.msg.default": "Something went wrong.", "error.msg.default": "Etwas ist schief gelaufen.",
"error.msg.access_denied": "You canceled the authentication process, 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.expired_token": "The authentication process took too long, please try again.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "User linked to this {0} account doesn't exist.",

View File

@@ -288,6 +288,7 @@ export default {
"upload.modal.expires.never": "never", "upload.modal.expires.never": "never",
"upload.modal.expires.never-long": "Never Expires", "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.link.label": "Link",
"upload.modal.expires.label": "Expiration", "upload.modal.expires.label": "Expiration",
@@ -357,6 +358,13 @@ export default {
// END /share/[id] // 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
"admin.config.title": "Configuration", "admin.config.title": "Configuration",
"admin.config.category.general": "General", "admin.config.category.general": "General",
@@ -413,6 +421,9 @@ export default {
"Allow unauthenticated shares", "Allow unauthenticated shares",
"admin.config.share.allow-unauthenticated-shares.description": "admin.config.share.allow-unauthenticated-shares.description":
"Whether unauthenticated users can create shares", "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": "Max size",
"admin.config.share.max-size.description": "Maximum share size in bytes", "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": "Zip compression level",

View File

@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Comencemos", "signup.button.submit": "Comencemos",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "Autenticación TOTP",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Iniciar sesión",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "¿Olvidaste tu contraseña?", "resetPassword.title": "¿Olvidaste tu contraseña?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "Contraseña", "account.card.password.title": "Contraseña",
"account.card.password.old": "Anterior contraseña", "account.card.password.old": "Anterior contraseña",
"account.card.password.new": "Nueva contraseña", "account.card.password.new": "Nueva contraseña",
"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": "No tienes una establecida contraseña. Si deseas iniciar sesión con correo electrónico y una contraseña necesitas crear una contraseña.",
"account.notify.password.success": "Contraseña cambiada correctamente", "account.notify.password.success": "Contraseña cambiada correctamente",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Inicio de sesión con red social",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Vincular",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Desvincular",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Desvinculado",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Desvincular cuenta",
"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": "Desvincular tus cuentas sociales puede causar que pierdas tu cuenta si no recuerdas tu nombre de usuario y contraseña.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Desvinculado correctamente",
"account.card.security.title": "Seguridad", "account.card.security.title": "Seguridad",
"account.card.security.totp.enable.description": "Ingrese su contraseña actual para habilitar TOTP", "account.card.security.totp.enable.description": "Ingrese su contraseña actual para habilitar TOTP",
"account.card.security.totp.disable.description": "Ingrese su contraseña actual para deshabilitar TOTP", "account.card.security.totp.disable.description": "Ingrese su contraseña actual para deshabilitar TOTP",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "No podrás eliminar tus compartidos manualmente ni ver el número de visitas.", "upload.modal.not-signed-in-description": "No podrás eliminar tus compartidos manualmente ni ver el número de visitas.",
"upload.modal.expires.never": "nunca", "upload.modal.expires.never": "nunca",
"upload.modal.expires.never-long": "Nunca Expira", "upload.modal.expires.never-long": "Nunca Expira",
"upload.modal.expires.error.too-long": "La caducidad excede la fecha de caducidad máxima de {max}.",
"upload.modal.link.label": "Enlace", "upload.modal.link.label": "Enlace",
"upload.modal.expires.label": "Expiración", "upload.modal.expires.label": "Expiración",
"upload.modal.expires.minute-singular": "Minuto", "upload.modal.expires.minute-singular": "Minuto",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Vista previa no disponible", "share.modal.file-preview.error.not-supported.title": "Vista previa no disponible",
"share.modal.file-preview.error.not-supported.description": "La vista previa para este tipo de archivo no está disponible. Por favor descargue el archivo para verlo.", "share.modal.file-preview.error.not-supported.description": "La vista previa para este tipo de archivo no está disponible. Por favor descargue el archivo para verlo.",
// END /share/[id] // END /share/[id]
// /share/[id]/edit
"share.edit.title": "Editar {shareId}",
"share.edit.append-upload": "Agregar archivo",
"share.edit.notify.generic-error": "Ha ocurrido un error mientras se compartía tu archivo.",
"share.edit.notify.save-success": "Compartir actualizado correctamente",
// END /share/[id]/edit
// /admin/config // /admin/config
"admin.config.title": "Configuración", "admin.config.title": "Configuración",
"admin.config.category.general": "General", "admin.config.category.general": "General",
"admin.config.category.share": "Compartido", "admin.config.category.share": "Compartido",
"admin.config.category.email": "Correo", "admin.config.category.email": "Correo",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Inicio de sesión social",
"admin.config.general.app-name": "Nombre de la App", "admin.config.general.app-name": "Nombre de la App",
"admin.config.general.app-name.description": "Nombre de la aplicación", "admin.config.general.app-name.description": "Nombre de la aplicación",
"admin.config.general.app-url": "App URL", "admin.config.general.app-url": "App URL",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Si se permite el registro", "admin.config.share.allow-registration.description": "Si se permite el registro",
"admin.config.share.allow-unauthenticated-shares": "Permitir compartir sin iniciar sesión", "admin.config.share.allow-unauthenticated-shares": "Permitir compartir sin iniciar sesión",
"admin.config.share.allow-unauthenticated-shares.description": "Si los usuarios que no han iniciado sesión pueden compartir", "admin.config.share.allow-unauthenticated-shares.description": "Si los usuarios que no han iniciado sesión pueden compartir",
"admin.config.share.max-expiration": "Expiración máxima",
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
"admin.config.share.max-size": "Tamaño máximo", "admin.config.share.max-size": "Tamaño máximo",
"admin.config.share.max-size.description": "Tamaño máximo de los archivos, en bytes", "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": "Nivel de compresión del Zip",

View File

@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Et voi poistaa jakoasi manuaalisesti ja tarkastella kävijöiden määrää.", "upload.modal.not-signed-in-description": "Et voi poistaa jakoasi manuaalisesti ja tarkastella kävijöiden määrää.",
"upload.modal.expires.never": "ei koskaan", "upload.modal.expires.never": "ei koskaan",
"upload.modal.expires.never-long": "Ei vanhene koskaan", "upload.modal.expires.never-long": "Ei vanhene koskaan",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "Linkki", "upload.modal.link.label": "Linkki",
"upload.modal.expires.label": "Vanhentuminen", "upload.modal.expires.label": "Vanhentuminen",
"upload.modal.expires.minute-singular": "Minuutti", "upload.modal.expires.minute-singular": "Minuutti",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Esikatselua ei tuettu", "share.modal.file-preview.error.not-supported.title": "Esikatselua ei tuettu",
"share.modal.file-preview.error.not-supported.description": "Esikatselua thise tiedostotyypille ei tueta. Ole hyvä ja lataa tiedosto nähdäksesi sen.", "share.modal.file-preview.error.not-supported.description": "Esikatselua thise tiedostotyypille ei tueta. Ole hyvä ja lataa tiedosto nähdäksesi sen.",
// END /share/[id] // 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
"admin.config.title": "Asetukset", "admin.config.title": "Asetukset",
"admin.config.category.general": "Yleiset", "admin.config.category.general": "Yleiset",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Onko rekisteröinti sallittu", "admin.config.share.allow-registration.description": "Onko rekisteröinti sallittu",
"admin.config.share.allow-unauthenticated-shares": "Salli anonyymit jaot", "admin.config.share.allow-unauthenticated-shares": "Salli anonyymit jaot",
"admin.config.share.allow-unauthenticated-shares.description": "Voiko tunnistamattomat käyttäjät luoda jakoja", "admin.config.share.allow-unauthenticated-shares.description": "Voiko tunnistamattomat käyttäjät luoda jakoja",
"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": "Maksimikoko", "admin.config.share.max-size": "Maksimikoko",
"admin.config.share.max-size.description": "Jaon enimmäiskoko tavuissa (bytes)", "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": "Zip puristustaso",

View File

@@ -1,9 +1,9 @@
export default { export default {
// Navbar // Navbar
"navbar.upload": "Envoyer", "navbar.upload": "Téléverser",
"navbar.signin": "Se connecter", "navbar.signin": "Se connecter",
"navbar.home": "Accueil", "navbar.home": "Accueil",
"navbar.signup": "S'inscrire", "navbar.signup": "Sinscrire",
"navbar.links.shares": "Mes partages", "navbar.links.shares": "Mes partages",
"navbar.links.reverse": "Partages inversés", "navbar.links.reverse": "Partages inversés",
"navbar.avatar.account": "Mon compte", "navbar.avatar.account": "Mon compte",
@@ -18,22 +18,22 @@ export default {
"home.bullet.b.name": "Confidentialité", "home.bullet.b.name": "Confidentialité",
"home.bullet.b.description": "Vos fichiers sont vos fichiers et ne devraient jamais être mis entre les mains de tiers.", "home.bullet.b.description": "Vos fichiers sont vos fichiers et ne devraient jamais être mis entre les mains de tiers.",
"home.bullet.c.name": "Aucune rébarbative limite de taille", "home.bullet.c.name": "Aucune rébarbative limite de taille",
"home.bullet.c.description": "Téléchargez des fichiers volumineux que vous le souhaitez. Seul votre disque dur est la limite.", "home.bullet.c.description": "Téléchargez des fichiers aussi volumineux que vous le souhaitez. Seul votre disque dur est la limite.",
"home.button.start": "Commencer", "home.button.start": "Commencer",
"home.button.source": "Code source", "home.button.source": "Code source",
// END / // END /
// /auth/signin // /auth/signin
"signin.title": "Content de vous revoir", "signin.title": "Content de vous revoir",
"signin.description": "Pas encore de compte ?", "signin.description": "Pas encore de compte ?",
"signin.button.signup": "S'inscrire", "signin.button.signup": "Sinscrire",
"signin.input.email-or-username": "Courriel ou pseudo", "signin.input.email-or-username": "Courriel ou surnom",
"signin.input.email-or-username.placeholder": "Votre courriel ou pseudo", "signin.input.email-or-username.placeholder": "Votre courriel ou surnom",
"signin.input.password": "Mot de passe", "signin.input.password": "Mot de passe",
"signin.input.password.placeholder": "Votre mot de passe", "signin.input.password.placeholder": "Votre mot de passe",
"signin.button.submit": "Se connecter", "signin.button.submit": "Se connecter",
"signIn.notify.totp-required.title": "Une authentification à deux facteurs est requise", "signIn.notify.totp-required.title": "Une authentification à deux facteurs est requise",
"signIn.notify.totp-required.description": "Veuillez entrer votre code d'authentification à deux facteurs", "signIn.notify.totp-required.description": "Veuillez entrer votre code d'authentification à deux facteurs",
"signIn.oauth.or": "OR", "signIn.oauth.or": "OU",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -44,20 +44,20 @@ export default {
"signup.title": "Créer un compte", "signup.title": "Créer un compte",
"signup.description": "Vous avez déjà un compte ?", "signup.description": "Vous avez déjà un compte ?",
"signup.button.signin": "Se connecter", "signup.button.signin": "Se connecter",
"signup.input.username": "Pseudo", "signup.input.username": "Surnom",
"signup.input.username.placeholder": "Votre pseudo", "signup.input.username.placeholder": "Votre surnom",
"signup.input.email": "Adresse email", "signup.input.email": "Adresse email",
"signup.input.email.placeholder": "Votre adresse email", "signup.input.email.placeholder": "Votre courriel",
"signup.button.submit": "Commençons", "signup.button.submit": "Commençons",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "Authentification TOTP",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Se connecter",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Mot de passe oublié ?", "resetPassword.title": "Mot de passe oublié ?",
"resetPassword.description": "Saisissez votre email pour réinitialiser votre mot de passe.", "resetPassword.description": "Saisissez votre courriel pour réinitialiser votre mot de passe.",
"resetPassword.notify.success": "Un email a été envoyé avec un lien 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.button.back": "Retour à la page de connexion", "resetPassword.button.back": "Retour à la page de connexion",
"resetPassword.text.resetPassword": "Réinitialiser le mot de passe", "resetPassword.text.resetPassword": "Réinitialiser le mot de passe",
"resetPassword.text.enterNewPassword": "Saisissez votre nouveau mot de passe", "resetPassword.text.enterNewPassword": "Saisissez votre nouveau mot de passe",
@@ -66,30 +66,30 @@ export default {
// /account // /account
"account.title": "Mon compte", "account.title": "Mon compte",
"account.card.info.title": "Détails du compte", "account.card.info.title": "Détails du compte",
"account.card.info.username": "Pseudo", "account.card.info.username": "Surnom",
"account.card.info.email": "Adresse email", "account.card.info.email": "Adresse email",
"account.notify.info.success": "Compte mis à jour avec succès", "account.notify.info.success": "Compte mis à jour avec succès",
"account.card.password.title": "Mot de passe", "account.card.password.title": "Mot de passe",
"account.card.password.old": "Ancien mot de passe", "account.card.password.old": "Ancien mot de passe",
"account.card.password.new": "Nouveau mot de passe", "account.card.password.new": "Nouveau mot de passe",
"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": "Vous navez pas de mot de passe défini. Si vous voulez vous connecter avec un e-mail et un mot de passe, vous devez définir un mot de passe.",
"account.notify.password.success": "Le mot de passe a été modifié avec succès", "account.notify.password.success": "Le mot de passe a été modifié avec succès",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Identifiant social",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Associer",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Dissocier",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Dissocié",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Dissocier le compte",
"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": "Dissocier vos comptes de réseaux sociaux peut vous faire perdre votre compte si jamais vous ne vous souvenez pas de votre nom dutilisateur et de votre mot de passe.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Dissocié avec succès",
"account.card.security.title": "Sécurité", "account.card.security.title": "Sécurité",
"account.card.security.totp.enable.description": "Entrez votre mot de passe actuel pour commencer à activer TOTP", "account.card.security.totp.enable.description": "Entrez votre mot de passe actuel pour activer TOTP",
"account.card.security.totp.disable.description": "Entrez votre mot de passe pour désactiver TOTP", "account.card.security.totp.disable.description": "Entrez votre mot de passe actuel pour désactiver TOTP",
"account.card.security.totp.button.start": "Commencer", "account.card.security.totp.button.start": "Démarrer",
"account.modal.totp.title": "Activer TOTP", "account.modal.totp.title": "Activer TOTP",
"account.modal.totp.step1": "Étape 1 : Ajouter votre authentificateur", "account.modal.totp.step1": "Étape 1 : Ajouter votre authentificateur",
"account.modal.totp.step2": "Étape 2 : Valider votre code", "account.modal.totp.step2": "Étape 2 : Valider votre code",
@@ -97,8 +97,8 @@ export default {
"account.modal.totp.code": "Code", "account.modal.totp.code": "Code",
"account.modal.totp.clickToCopy": "Cliquez pour copier", "account.modal.totp.clickToCopy": "Cliquez pour copier",
"account.modal.totp.verify": "Vérifier", "account.modal.totp.verify": "Vérifier",
"account.notify.totp.disable": "TOTP désactivé", "account.notify.totp.disable": "TOTP désactivé avec succès",
"account.notify.totp.enable": "TOTP activé", "account.notify.totp.enable": "TOTP activé avec succès",
"account.card.language.title": "Langue", "account.card.language.title": "Langue",
"account.card.language.description": "Le projet est traduit par la communauté. Certaines traductions peuvent être incomplètes.", "account.card.language.description": "Le projet est traduit par la communauté. Certaines traductions peuvent être incomplètes.",
"account.card.color.title": "Thème de couleurs", "account.card.color.title": "Thème de couleurs",
@@ -131,8 +131,8 @@ export default {
// /account/reverseShares // /account/reverseShares
"account.reverseShares.title": "Partages inversés", "account.reverseShares.title": "Partages inversés",
"account.reverseShares.description": "Un partage inversé vous permet de générer une URL unique qui permet à des utilisateurs externes de créer un partage.", "account.reverseShares.description": "Un partage inversé vous permet de générer une URL unique qui permet à des utilisateurs externes de créer un partage.",
"account.reverseShares.title.empty": "Il n'y a rien ici 👀", "account.reverseShares.title.empty": "Cest plutôt vide 👀",
"account.reverseShares.description.empty": "Vous n'avez aucun partage inversé.", "account.reverseShares.description.empty": "Vous navez aucun partage inversé.",
// showCreateReverseShareModal.tsx // showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Créer un partage inversé", "account.reverseShares.modal.title": "Créer un partage inversé",
"account.reverseShares.modal.expiration.label": "Expiration", "account.reverseShares.modal.expiration.label": "Expiration",
@@ -149,8 +149,8 @@ export default {
"account.reverseShares.modal.expiration.year-singular": "An", "account.reverseShares.modal.expiration.year-singular": "An",
"account.reverseShares.modal.expiration.year-plural": "Ans", "account.reverseShares.modal.expiration.year-plural": "Ans",
"account.reverseShares.modal.max-size.label": "Taille maximale du partage", "account.reverseShares.modal.max-size.label": "Taille maximale du partage",
"account.reverseShares.modal.send-email": "Envoyer un email de notification", "account.reverseShares.modal.send-email": "Envoyer un courriel de notification",
"account.reverseShares.modal.send-email.description": "Envoyer une notification par email lorsqu'un partage est créé depuis ce partage inversé.", "account.reverseShares.modal.send-email.description": "Envoyer une notification par courriel lorsqu'un partage est créé depuis ce partage inversé.",
"account.reverseShares.modal.max-use.label": "Nombre d'utilisation max", "account.reverseShares.modal.max-use.label": "Nombre d'utilisation max",
"account.reverseShares.modal.max-use.description": "Le nombre maximal de fois que cette URL peut être utilisée pour créer un partage.", "account.reverseShares.modal.max-use.description": "Le nombre maximal de fois que cette URL peut être utilisée pour créer un partage.",
"account.reverseShare.never-expires": "Ce partage inversé n'expirera jamais.", "account.reverseShare.never-expires": "Ce partage inversé n'expirera jamais.",
@@ -161,10 +161,10 @@ export default {
"account.reverseShares.table.shares": "Partages", "account.reverseShares.table.shares": "Partages",
"account.reverseShares.table.remaining": "Utilisations restantes", "account.reverseShares.table.remaining": "Utilisations restantes",
"account.reverseShares.table.max-size": "Taille maximale du partage", "account.reverseShares.table.max-size": "Taille maximale du partage",
"account.reverseShares.table.expires": "Expire dans", "account.reverseShares.table.expires": "Expire le",
"account.reverseShares.modal.reverse-share-link": "Lien du partage inversé", "account.reverseShares.modal.reverse-share-link": "Lien du partage inversé",
"account.reverseShares.modal.delete.title": "Supprimer le partage inversé", "account.reverseShares.modal.delete.title": "Supprimer le partage inversé",
"account.reverseShares.modal.delete.description": "Voulez-vous vraiment supprimer ce partage inversé ? Si vous le faites, les partages qu'il contient seront également supprimés.", "account.reverseShares.modal.delete.description": "Voulez-vous vraiment supprimer ce partage inversé ? Si vous le faites, les partages quil contient seront également supprimés.",
// END /account/reverseShares // END /account/reverseShares
// /admin // /admin
"admin.title": "Administration", "admin.title": "Administration",
@@ -174,11 +174,11 @@ export default {
// END /admin // END /admin
// /admin/users // /admin/users
"admin.users.title": "Gestion des utilisateurs", "admin.users.title": "Gestion des utilisateurs",
"admin.users.table.username": "Pseudo", "admin.users.table.username": "Surnom",
"admin.users.table.email": "Adresse email", "admin.users.table.email": "Courriel",
"admin.users.table.admin": "Admin", "admin.users.table.admin": "Admin",
"admin.users.edit.update.title": "Modifier l'utilisateur {username}", "admin.users.edit.update.title": "Modifier l'utilisateur {username}",
"admin.users.edit.update.admin-privileges": "Privilèges admin", "admin.users.edit.update.admin-privileges": "Privilèges dadmin",
"admin.users.edit.update.change-password.title": "Changer le mot de passe", "admin.users.edit.update.change-password.title": "Changer le mot de passe",
"admin.users.edit.update.change-password.field": "Nouveau mot de passe", "admin.users.edit.update.change-password.field": "Nouveau mot de passe",
"admin.users.edit.update.change-password.button": "Enregistrer le nouveau mot de passe", "admin.users.edit.update.change-password.button": "Enregistrer le nouveau mot de passe",
@@ -188,17 +188,17 @@ export default {
// showCreateUserModal.tsx // showCreateUserModal.tsx
"admin.users.modal.create.title": "Créer un utilisateur", "admin.users.modal.create.title": "Créer un utilisateur",
"admin.users.modal.create.username": "Surnom", "admin.users.modal.create.username": "Surnom",
"admin.users.modal.create.email": "Email", "admin.users.modal.create.email": "Courriel",
"admin.users.modal.create.password": "Mot de passe", "admin.users.modal.create.password": "Mot de passe",
"admin.users.modal.create.manual-password": "Définir le mot de passe manuellement", "admin.users.modal.create.manual-password": "Définir le mot de passe manuellement",
"admin.users.modal.create.manual-password.description": "S'il n'est pas coché, l'utilisateur recevra un email avec un lien pour définir son mot de passe.", "admin.users.modal.create.manual-password.description": "Sil n'est pas coché, lutilisateur recevra un email avec un lien pour définir son mot de passe.",
"admin.users.modal.create.admin": "Privilèges admin", "admin.users.modal.create.admin": "Privilèges dadmin",
"admin.users.modal.create.admin.description": "Si coché, l'utilisateur pourra accéder au panneau d'administration.", "admin.users.modal.create.admin.description": "Si coché, lutilisateur pourra accéder au panneau d'administration.",
// END /admin/users // END /admin/users
// /upload // /upload
"upload.title": "Envoyer", "upload.title": "Envoyer",
"upload.notify.generic-error": "Une erreur est survenue durant le traitement de votre partage.", "upload.notify.generic-error": "Une erreur est survenue durant le traitement de votre partage.",
"upload.notify.count-failed": "{count} fichier(s) n'a(ont) pas pu être envoyé(s). Veuillez réessayer.", "upload.notify.count-failed": "{count} fichier(s) na(ont) pas pu être envoyé(s). Veuillez réessayer.",
// Dropzone.tsx // Dropzone.tsx
"upload.dropzone.title": "Téléverser des fichiers", "upload.dropzone.title": "Téléverser des fichiers",
"upload.dropzone.description": "Glissez-déposez des fichiers ici pour commencer votre partage. Ils ne peuvent avoir une taille supérieur à {maxSize} au total.", "upload.dropzone.description": "Glissez-déposez des fichiers ici pour commencer votre partage. Ils ne peuvent avoir une taille supérieur à {maxSize} au total.",
@@ -213,7 +213,8 @@ export default {
"upload.modal.not-signed-in": "Vous n'êtes pas connecté", "upload.modal.not-signed-in": "Vous n'êtes pas connecté",
"upload.modal.not-signed-in-description": "Vous ne pourrez pas supprimer votre partage manuellement et afficher le nombre de visiteurs.", "upload.modal.not-signed-in-description": "Vous ne pourrez pas supprimer votre partage manuellement et afficher le nombre de visiteurs.",
"upload.modal.expires.never": "jamais", "upload.modal.expires.never": "jamais",
"upload.modal.expires.never-long": "N'expire jamais", "upload.modal.expires.never-long": "Nexpire jamais",
"upload.modal.expires.error.too-long": "Lexpiration dépasse la date d'expiration du {max}.",
"upload.modal.link.label": "Lien", "upload.modal.link.label": "Lien",
"upload.modal.expires.label": "Expiration", "upload.modal.expires.label": "Expiration",
"upload.modal.expires.minute-singular": "Minute", "upload.modal.expires.minute-singular": "Minute",
@@ -232,25 +233,25 @@ export default {
"upload.modal.accordion.description.placeholder": "Note pour les destinataires de ce partage", "upload.modal.accordion.description.placeholder": "Note pour les destinataires de ce partage",
"upload.modal.accordion.email.title": "Adresse courriel des destinataires", "upload.modal.accordion.email.title": "Adresse courriel des destinataires",
"upload.modal.accordion.email.placeholder": "Saisir les destinataires de ce partage", "upload.modal.accordion.email.placeholder": "Saisir les destinataires de ce partage",
"upload.modal.accordion.email.invalid-email": "Adresse email invalide", "upload.modal.accordion.email.invalid-email": "Courriel invalide",
"upload.modal.accordion.security.title": "Options de sécurité", "upload.modal.accordion.security.title": "Options de sécurité",
"upload.modal.accordion.security.password.label": "Protection par mot de passe", "upload.modal.accordion.security.password.label": "Protection par mot de passe",
"upload.modal.accordion.security.password.placeholder": "Aucun mot de passe", "upload.modal.accordion.security.password.placeholder": "Aucun mot de passe",
"upload.modal.accordion.security.max-views.label": "Nombre de vues maximum", "upload.modal.accordion.security.max-views.label": "Nombre de vues maximum",
"upload.modal.accordion.security.max-views.placeholder": "Aucune limite", "upload.modal.accordion.security.max-views.placeholder": "Aucune limite",
// showCompletedUploadModal.tsx // showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "Ce partage n'expirera jamais.", "upload.modal.completed.never-expires": "Ce partage nexpirera jamais.",
"upload.modal.completed.expires-on": "Ce partage expirera le {expiration}.", "upload.modal.completed.expires-on": "Ce partage expirera le {expiration}.",
"upload.modal.completed.share-ready": "Partage prêt", "upload.modal.completed.share-ready": "Partage prêt",
// END /upload // END /upload
// /share/[id] // /share/[id]
"share.title": "Partage {shareId}", "share.title": "Partage {shareId}",
"share.description": "Regardez ce que j'ai partagé !", "share.description": "Regardez ce que jai partagé !",
"share.error.visitor-limit-exceeded.title": "Limite de visiteurs dépassée", "share.error.visitor-limit-exceeded.title": "Limite de visiteurs dépassée",
"share.error.visitor-limit-exceeded.description": "La limite de visiteurs de ce partage a été dépassée.", "share.error.visitor-limit-exceeded.description": "La limite de visiteurs de ce partage a été dépassée.",
"share.error.removed.title": "Partage supprimé", "share.error.removed.title": "Partage supprimé",
"share.error.not-found.title": "Partage introuvable", "share.error.not-found.title": "Partage introuvable",
"share.error.not-found.description": "Le partage que vous cherchez n'existe pas.", "share.error.not-found.description": "Le partage que vous cherchez nexiste pas.",
"share.modal.password.title": "Mot de passe requis", "share.modal.password.title": "Mot de passe requis",
"share.modal.password.description": "Pour accéder à ce partage, veuillez entrer le mot de passe du partage.", "share.modal.password.description": "Pour accéder à ce partage, veuillez entrer le mot de passe du partage.",
"share.modal.password": "Mot de passe", "share.modal.password": "Mot de passe",
@@ -263,113 +264,121 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Aperçu non supporté", "share.modal.file-preview.error.not-supported.title": "Aperçu non supporté",
"share.modal.file-preview.error.not-supported.description": "Un aperçu pour ce type de fichier n'est pas pris en charge. Veuillez télécharger le fichier pour le voir.", "share.modal.file-preview.error.not-supported.description": "Un aperçu pour ce type de fichier n'est pas pris en charge. Veuillez télécharger le fichier pour le voir.",
// END /share/[id] // END /share/[id]
// /share/[id]/edit
"share.edit.title": "Modifier {shareId}",
"share.edit.append-upload": "Ajouter un fichier",
"share.edit.notify.generic-error": "Une erreur est survenue durant le traitement de votre partage.",
"share.edit.notify.save-success": "Partage mis à jour avec succès",
// END /share/[id]/edit
// /admin/config // /admin/config
"admin.config.title": "Paramètres", "admin.config.title": "Paramètres",
"admin.config.category.general": "Général", "admin.config.category.general": "Général",
"admin.config.category.share": "Partage", "admin.config.category.share": "Partage",
"admin.config.category.email": "Courriel", "admin.config.category.email": "Courriel",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Identifiant social",
"admin.config.general.app-name": "Nom de l'appli", "admin.config.general.app-name": "Nom de lappli",
"admin.config.general.app-name.description": "Le nom de l'application", "admin.config.general.app-name.description": "Le nom de lapplication",
"admin.config.general.app-url": "URL de lappli", "admin.config.general.app-url": "URL de lappli",
"admin.config.general.app-url.description": "Depuis quel URL le partage Pingvin est disponible", "admin.config.general.app-url.description": "Depuis quel URL le partage Pingvin est disponible",
"admin.config.general.show-home-page": "Afficher la page d'accueil", "admin.config.general.show-home-page": "Afficher la page daccueil",
"admin.config.general.show-home-page.description": "Afficher ou non la page d'accueil", "admin.config.general.show-home-page.description": "Afficher ou non la page daccueil",
"admin.config.general.logo": "Logo", "admin.config.general.logo": "Logo",
"admin.config.general.logo.description": "Changez de logo en envoyant une nouvelle image. L'image doit être au format PNG et doit avoir un ratio 1:1.", "admin.config.general.logo.description": "Changez de logo en envoyant une nouvelle image. Limage doit être au format PNG et doit avoir un ratio 1:1.",
"admin.config.general.logo.placeholder": "Sélectionner une image", "admin.config.general.logo.placeholder": "Sélectionner une image",
"admin.config.email.enable-share-email-recipients": "Autoriser le partage par courriel", "admin.config.email.enable-share-email-recipients": "Autoriser le partage par courriel",
"admin.config.email.enable-share-email-recipients.description": "Permet d'envoyer le lien du partage par courriel. N'activez cette option que si vous avez activé SMTP.", "admin.config.email.enable-share-email-recipients.description": "Permet d'envoyer le lien du partage par courriel. N'activez cette option que si vous avez activé SMTP.",
"admin.config.email.share-recipients-subject": "Sujet d'un partage", "admin.config.email.share-recipients-subject": "Sujet dun partage",
"admin.config.email.share-recipients-subject.description": "Intitulé du courriel envoyé aux destinataires d'un partage.", "admin.config.email.share-recipients-subject.description": "Intitulé du courriel envoyé aux destinataires dun partage.",
"admin.config.email.share-recipients-message": "Message d'un partage", "admin.config.email.share-recipients-message": "Message dun partage",
"admin.config.email.share-recipients-message.description": "Contenu du courriel qui est envoyé aux destinataires du partage. Variables possibles :\n• {creator} : Le pseudo de l'auteur du partage\n• {shareUrl} : L'URL du partage\n• {desc} : La description du partage\n• {expires} : La date d'expiration du partage\nLes variables seront remplacées par leur valeur réelle.", "admin.config.email.share-recipients-message.description": "Contenu du courriel qui est envoyé aux destinataires du partage. Variables possibles :\n• {creator} : Le pseudo de lauteur du partage\n• {shareUrl} : LURL du partage\n• {desc} : La description du partage\n• {expires} : La date d'expiration du partage\nLes variables seront remplacées par leur valeur réelle.",
"admin.config.email.reverse-share-subject": "Sujet d'un partage inversé", "admin.config.email.reverse-share-subject": "Sujet dun partage inversé",
"admin.config.email.reverse-share-subject.description": "Intitulé du courriel envoyé lorsque quelqu'un a partagé des fichiers depuis votre partage inversé.", "admin.config.email.reverse-share-subject.description": "Intitulé du courriel envoyé lorsque quelquun a partagé des fichiers depuis votre partage inversé.",
"admin.config.email.reverse-share-message": "Message du partage inversé", "admin.config.email.reverse-share-message": "Message dun partage inversé",
"admin.config.email.reverse-share-message.description": "Contenu du courriel envoyé lorsque quelqu'un partage des fichiers depuis votre partage inversé. {shareUrl} sera remplacé par le nom du créateur et l'URL de partage.", "admin.config.email.reverse-share-message.description": "Contenu du courriel envoyé lorsque quelquun partage des fichiers depuis votre partage inversé. {shareUrl} sera remplacé par le nom du créateur et lURL de partage.",
"admin.config.email.reset-password-subject": "Sujet d'une réinitialisation du mot de passe", "admin.config.email.reset-password-subject": "Sujet dune réinitialisation du mot de passe",
"admin.config.email.reset-password-subject.description": "Intitulé du courriel envoyé lorsqu'un utilisateur demande une réinitialisation de son mot de passe.", "admin.config.email.reset-password-subject.description": "Intitulé du courriel envoyé lorsquun utilisateur demande une réinitialisation de son mot de passe.",
"admin.config.email.reset-password-message": "Message de réinitialisation du mot de passe", "admin.config.email.reset-password-message": "Message de réinitialisation du mot de passe",
"admin.config.email.reset-password-message.description": "Contenu du courriel envoyé lorsqu'un utilisateur demande à réinitialiser son mot de passe. {url} sera remplacé par l'URL de réinitialisation du mot de passe.", "admin.config.email.reset-password-message.description": "Contenu du courriel envoyé lorsquun utilisateur demande à réinitialiser son mot de passe. {url} sera remplacé par lURL de réinitialisation du mot de passe.",
"admin.config.email.invite-subject": "Sujet d'une invitation", "admin.config.email.invite-subject": "Sujet dune invitation",
"admin.config.email.invite-subject.description": "Intitulé du courriel envoyé lorsqu'un administrateur invite un utilisateur.", "admin.config.email.invite-subject.description": "Intitulé du courriel envoyé lorsquun administrateur invite un utilisateur.",
"admin.config.email.invite-message": "Message de l'invitation", "admin.config.email.invite-message": "Message dune invitation",
"admin.config.email.invite-message.description": "Contenu du courriel envoyé lorsqu'un administrateur invite un utilisateur. {url} sera remplacé par l'URL d'invitation et {password} par le mot de passe.", "admin.config.email.invite-message.description": "Contenu du courriel envoyé lorsquun administrateur invite un utilisateur. {url} sera remplacé par lURL d'invitation et {password} par le mot de passe.",
"admin.config.share.allow-registration": "Autoriser les inscriptions", "admin.config.share.allow-registration": "Autoriser les inscriptions",
"admin.config.share.allow-registration.description": "Permet aux visiteurs de créer un compte.", "admin.config.share.allow-registration.description": "Permet aux visiteurs de créer un compte.",
"admin.config.share.allow-unauthenticated-shares": "Autoriser les partages anonymes", "admin.config.share.allow-unauthenticated-shares": "Autoriser les partages anonymes",
"admin.config.share.allow-unauthenticated-shares.description": "Autorise des utilisateurs non authentifiés à créer des partages", "admin.config.share.allow-unauthenticated-shares.description": "Permet aux visiteurs de créer des partages",
"admin.config.share.max-expiration": "Échéance",
"admin.config.share.max-expiration.description": "Échéance du partage en heures. Indiquez 0 pour quil nexpire jamais.",
"admin.config.share.max-size": "Taille max", "admin.config.share.max-size": "Taille max",
"admin.config.share.max-size.description": "Taille maximale du partage en octets", "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": "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.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.smtp.enabled": "Activer", "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 le mot de passe de votre serveur SMTP.", "admin.config.smtp.enabled.description": "Active SMTP. Activez ceci uniquement si vous avez saisi lhôte, le port, le courriel, lutilisateur et son mot de passe, de votre serveur SMTP.",
"admin.config.smtp.host": "Hôte", "admin.config.smtp.host": "Hôte",
"admin.config.smtp.host.description": "Nom du serveur SMTP", "admin.config.smtp.host.description": "Nom du serveur SMTP",
"admin.config.smtp.port": "Port", "admin.config.smtp.port": "Port",
"admin.config.smtp.port.description": "Port du serveur SMTP", "admin.config.smtp.port.description": "Port du serveur SMTP",
"admin.config.smtp.email": "Adresse email", "admin.config.smtp.email": "Courriel",
"admin.config.smtp.email.description": "Adresse à partir de laquelle les emails sont envoyés", "admin.config.smtp.email.description": "Adresse à partir de laquelle les courriels sont envoyés",
"admin.config.smtp.username": "Nom d'utilisateur", "admin.config.smtp.username": "Nom dutilisateur",
"admin.config.smtp.username.description": "Nom d'utilisateur du serveur SMTP", "admin.config.smtp.username.description": "Nom dutilisateur du serveur SMTP",
"admin.config.smtp.password": "Mot de passe", "admin.config.smtp.password": "Mot de passe",
"admin.config.smtp.password.description": "Mot de passe du serveur SMTP", "admin.config.smtp.password.description": "Mot de passe du serveur SMTP",
"admin.config.smtp.button.test": "Envoyer un email de test", "admin.config.smtp.button.test": "Envoyer un courriel de test",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Autoriser linscription",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "Permettre aux utilisateurs de sinscrire via leur identifiant social",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "Ignorer TOTP",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "Ignorer le TOTP lorsque lutilisateur utilise un identifiant social.",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "Permettre la connexion via GitHub.",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "ID client de GitHub",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "LID du client de lapplication OAuth GitHub",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "Secret du client GitHub",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "Le secret du client de lapplication OAuth GitHub",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Permettre la connexion via Google.",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "ID du client Google",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "LID du client de lapplication OAuth Google",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Secret client de Google",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Le secret du client de lapplication OAuth Google",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Permettre la connexion via Microsoft.",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "admin.config.oauth.microsoft-tenant": "Locataire Microsoft",
"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": "ID locataire de l'application OAuth Microsoft\nCommun : les utilisateurs ayant au choix un compte personnel ou dentreprise issue de Microsoft Entra.\nOrganisations : limité aux utilisateurs ayant un compte dentreprise ou duniversité issue de Microsoft Entra.\nPersonnel : limité aux utilisateurs ayant un compte personnel\nDomanial : limité aux utilisateurs d'un domaine Microsoft Entra spécifié ou dun ID locataire (au format GUID), quils soient membres dun registre dentreprise ou duniversité ou bien enregistrés en tant quinvités avec un compte personnel.",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "ID du client Microsoft",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "LID du client de lapplication Microsoft OAuth",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Secret du client Microsoft",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Le secret du client de lapplication Microsoft OAuth",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Permettre la connexion via Discord.",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "ID du client Discord",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "LID du client de lapplication OAuth Discord",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Secret du client Discord",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "Le secret du client de lapplication OAuth Discord",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "Permettre la connexion via OpenID.",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "URI de découverte OpenID",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "URI de découverte de lapplication OpenID OAuth",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "ID du client OpenID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "LID du client de lapplication OAuth OpenID",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "Secret du client OpenID",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "Le secret du client de lapplication OAuth OpenID",
// 404 // 404
"404.description": "Désolé, mais cette page nexiste pas.", "404.description": "Désolé, mais cette page nexiste pas.",
"404.button.home": "Retour à l'accueil", "404.button.home": "Retour à laccueil",
// error // error
"error.title": "Error", "error.title": "Erreur",
"error.description": "Oops!", "error.description": "Oups !",
"error.button.back": "Go back", "error.button.back": "Retour",
"error.msg.default": "Something went wrong.", "error.msg.default": "Quelque chose a mal tourné.",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "Vous avez annulé le processus dauthentification, veuillez réessayer.",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "Le processus dauthentification a pris trop de temps, veuillez réessayer.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "Lutilisateur associé au compte {0} nexiste pas.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Impossible dobtenir le courriel du compte {0}.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "Le compte {0} est déjà associé à un autre compte.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "Le compte {0} nest pas encore associé à compte.",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -33,7 +33,7 @@ export default {
"signin.button.submit": "サインイン", "signin.button.submit": "サインイン",
"signIn.notify.totp-required.title": "二段階認証が必要です", "signIn.notify.totp-required.title": "二段階認証が必要です",
"signIn.notify.totp-required.description": "二段階認証コードを入力してください", "signIn.notify.totp-required.description": "二段階認証コードを入力してください",
"signIn.oauth.or": "OR", "signIn.oauth.or": "または",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "さあ始めましょう", "signup.button.submit": "さあ始めましょう",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "二段階認証",
"totp.button.signIn": "Sign in", "totp.button.signIn": "サインイン",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "パスワードを忘れてしまいましたか?", "resetPassword.title": "パスワードを忘れてしまいましたか?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "パスワード", "account.card.password.title": "パスワード",
"account.card.password.old": "現在のパスワード", "account.card.password.old": "現在のパスワード",
"account.card.password.new": "新規パスワード", "account.card.password.new": "新規パスワード",
"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": "パスワードが設定されていません。メールアドレスとパスワードでサインインしたい場合は、パスワードの設定が必要です。",
"account.notify.password.success": "パスワードの変更に成功しました", "account.notify.password.success": "パスワードの変更に成功しました",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "ソーシャルログイン",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "リンク",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "リンク解除",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "リンクされていません",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "アカウントのリンクを解除",
"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": "ソーシャルアカウントのリンクを解除すると、ユーザー名とパスワードを覚えていない場合にアカウントへのアクセスが失われる可能性があります。",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "リンク解除に成功しました",
"account.card.security.title": "セキュリティ", "account.card.security.title": "セキュリティ",
"account.card.security.totp.enable.description": "2段階認証を有効にするため、現在のパスワードを入力してください", "account.card.security.totp.enable.description": "2段階認証を有効にするため、現在のパスワードを入力してください",
"account.card.security.totp.disable.description": "2段階認証を無効にするため、現在のパスワードを入力してください", "account.card.security.totp.disable.description": "2段階認証を無効にするため、現在のパスワードを入力してください",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "共有の手動削除と訪問者カウンターは表示できません。", "upload.modal.not-signed-in-description": "共有の手動削除と訪問者カウンターは表示できません。",
"upload.modal.expires.never": "永久", "upload.modal.expires.never": "永久",
"upload.modal.expires.never-long": "期限切れにさせない", "upload.modal.expires.never-long": "期限切れにさせない",
"upload.modal.expires.error.too-long": "設定可能な有効期限を越えています。有効期限の上限は{max} です。",
"upload.modal.link.label": "リンク", "upload.modal.link.label": "リンク",
"upload.modal.expires.label": "有効期限", "upload.modal.expires.label": "有効期限",
"upload.modal.expires.minute-singular": "分間", "upload.modal.expires.minute-singular": "分間",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "プレビューに対応していません", "share.modal.file-preview.error.not-supported.title": "プレビューに対応していません",
"share.modal.file-preview.error.not-supported.description": "これらのファイルのプレビューには対応していません。ファイルをダウンロードして、直接確認してください。", "share.modal.file-preview.error.not-supported.description": "これらのファイルのプレビューには対応していません。ファイルをダウンロードして、直接確認してください。",
// END /share/[id] // 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
"admin.config.title": "設定", "admin.config.title": "設定",
"admin.config.category.general": "一般", "admin.config.category.general": "一般",
"admin.config.category.share": "共有", "admin.config.category.share": "共有",
"admin.config.category.email": "メール", "admin.config.category.email": "メール",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "ソーシャルログイン",
"admin.config.general.app-name": "アプリ名", "admin.config.general.app-name": "アプリ名",
"admin.config.general.app-name.description": "アプリの名前", "admin.config.general.app-name.description": "アプリの名前",
"admin.config.general.app-url": "アプリ名", "admin.config.general.app-url": "アプリ名",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "登録を許可するかどうかを選択してください。", "admin.config.share.allow-registration.description": "登録を許可するかどうかを選択してください。",
"admin.config.share.allow-unauthenticated-shares": "ログインしていない状態での共有を許可する", "admin.config.share.allow-unauthenticated-shares": "ログインしていない状態での共有を許可する",
"admin.config.share.allow-unauthenticated-shares.description": "ログインしていないユーザーに共有の作成を許可するかどうかを選択してください。", "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": "最大ファイルサイズ",
"admin.config.share.max-size.description": "最大ファイルサイズbyte単位", "admin.config.share.max-size.description": "最大ファイルサイズbyte単位",
"admin.config.share.zip-compression-level": "Zip圧縮レベル", "admin.config.share.zip-compression-level": "Zip圧縮レベル",
@@ -318,58 +327,58 @@ export default {
"admin.config.smtp.password": "パスワード", "admin.config.smtp.password": "パスワード",
"admin.config.smtp.password.description": "SMTPサーバーのパスワード", "admin.config.smtp.password.description": "SMTPサーバーのパスワード",
"admin.config.smtp.button.test": "テストメールを送信", "admin.config.smtp.button.test": "テストメールを送信",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "登録を許可する",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "ユーザーにソーシャルアカウント経由での登録を許可します",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "二段階認証を無視する",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "ソーシャルログイン時に二段階認証を無視するかどうかを設定します",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "GitHubアカウントを使用したログインを許可するかどうかを設定します",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "GitHub クライアントID",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "GitHub OAuthアプリのクライアントID",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "GitHub クライアントシークレット",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "GitHub OAuthアプリのクライアントシークレット",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Googleアカウントを使用したログインを許可するかどうかを設定します",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "Google クライアントID",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "Google OAuthアプリのクライアントID",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Google クライアントシークレット",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Google OAuthアプリのクライアントシークレット",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Microsoftアカウントを使用したログインを許可するかどうかを設定します",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "admin.config.oauth.microsoft-tenant": "Microsoftテナント",
"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": "Microsoft OAuthアプリのテナントID\ncommon: 個人のMicrosoftアカウントとMicrosoft Entra IDの職場または学校のアカウントを持つユーザーは、アプリケーションにサインインできます。 \norganizations: Microsoft Entra IDからの職場または学校のアカウントを持つユーザーのみがアプリケーションにサインインできます。\nconsumers: 個人のMicrosoftアカウントを持つユーザーのみがアプリケーションにサインインできます。\nMicrosoft Entraテナントのドメイン名またはGUID形式のテナントID: 特定のMicrosoft Entraテナント (職場または学校のアカウントを持つディレクトリメンバーまたはパーソナルMicrosoftアカウントを持つディレクトリゲスト) からのユーザーのみがアプリケーションにサインインできます。",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "Microsoft クライアントID",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "Microsoft OAuthアプリのクライアントID",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Microsoft クライアントシークレット",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Microsoft OAuthアプリのクライアントシークレット",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Discordアカウントを使用したログインを許可するかどうかを設定します",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "Discord クライアントID",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "Discord OAuthアプリのクライアントID",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Discord クライアントシークレット",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "Discord OAuthアプリのクライアントシークレット",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "OpenIDアカウントを使用したログインを許可するかどうかを設定します",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "OpenID OAuthアプリのDiscovery URI",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "OpenID クライアントID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "OpenID OAuthアプリのクライアントID",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "OpenID クライアントシークレット",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "OpenID OAuthアプリのクライアントシークレット",
// 404 // 404
"404.description": "ページが見つかりません。", "404.description": "ページが見つかりません。",
"404.button.home": "ホームに戻る", "404.button.home": "ホームに戻る",
// error // error
"error.title": "Error", "error.title": "エラー",
"error.description": "Oops!", "error.description": "申し訳ありません",
"error.button.back": "Go back", "error.button.back": "戻る",
"error.msg.default": "Something went wrong.", "error.msg.default": "問題が発生しました。",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "認証処理を中止しました、後で再度お試しください。",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "認証処理に時間がかかりすぎています、後で再度お試しください。",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "この{0} アカウントにリンクしたユーザーが存在しません。",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "この{0} アカウントからメールアドレスを取得出来ません。",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "この{0} アカウントは、既に別のアカウントにリンクされています。",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "この{0} アカウントはどのアカウントにもリンクされていません。",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.", "upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
"upload.modal.expires.never": "nooit", "upload.modal.expires.never": "nooit",
"upload.modal.expires.never-long": "Verloopt nooit", "upload.modal.expires.never-long": "Verloopt nooit",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "Koppeling", "upload.modal.link.label": "Koppeling",
"upload.modal.expires.label": "Vervaldatum", "upload.modal.expires.label": "Vervaldatum",
"upload.modal.expires.minute-singular": "Minuut", "upload.modal.expires.minute-singular": "Minuut",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Voorbeeld niet ondersteund", "share.modal.file-preview.error.not-supported.title": "Voorbeeld niet ondersteund",
"share.modal.file-preview.error.not-supported.description": "Een voorbeeld voor dit bestandstype wordt niet ondersteund. Download het bestand om het te bekijken.", "share.modal.file-preview.error.not-supported.description": "Een voorbeeld voor dit bestandstype wordt niet ondersteund. Download het bestand om het te bekijken.",
// END /share/[id] // 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
"admin.config.title": "Configuratie", "admin.config.title": "Configuratie",
"admin.config.category.general": "Algemeen", "admin.config.category.general": "Algemeen",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Of registratie is toegestaan", "admin.config.share.allow-registration.description": "Of registratie is toegestaan",
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares", "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.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 grootte", "admin.config.share.max-size": "Max grootte",
"admin.config.share.max-size.description": "Maximum share size in bytes", "admin.config.share.max-size.description": "Maximum share size in bytes",
"admin.config.share.zip-compression-level": "Zip compressie niveau", "admin.config.share.zip-compression-level": "Zip compressie niveau",

View File

@@ -32,8 +32,8 @@ export default {
"signin.input.password.placeholder": "Twoje hasło", "signin.input.password.placeholder": "Twoje hasło",
"signin.button.submit": "Zaloguj się", "signin.button.submit": "Zaloguj się",
"signIn.notify.totp-required.title": "Wymagane jest uwierzytelnianie dwuetapowe", "signIn.notify.totp-required.title": "Wymagane jest uwierzytelnianie dwuetapowe",
"signIn.notify.totp-required.description": "Podaj kod logowania dwuetapowego", "signIn.notify.totp-required.description": "Wprowadź kod uwierzytelniania dwuetapowego",
"signIn.oauth.or": "OR", "signIn.oauth.or": "LUB",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Zaczynajmy", "signup.button.submit": "Zaczynajmy",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "Uwierzytelnianie TOTP",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Zaloguj się",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Nie pamiętasz hasła?", "resetPassword.title": "Nie pamiętasz hasła?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "Hasło", "account.card.password.title": "Hasło",
"account.card.password.old": "Dotychczasowe hasło", "account.card.password.old": "Dotychczasowe hasło",
"account.card.password.new": "Nowe hasło", "account.card.password.new": "Nowe hasło",
"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": "Nie masz ustawionego hasła. Jeśli chcesz zalogować się za pomocą adresu e-mail i hasła, musisz ustawić hasło.",
"account.notify.password.success": "Hasło zostało pomyślnie zmienione", "account.notify.password.success": "Hasło zostało pomyślnie zmienione",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Logowanie za pomocą konta społecznościowego",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Połącz",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Odłącz",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Rozłączono",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Odłącz konto",
"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": "Odłączenie kont społecznościowych, jeśli nie pamiętasz nazwy użytkownika i hasła, może spowodować utratę konta.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Odłączono pomyślnie",
"account.card.security.title": "Zabezpieczenia", "account.card.security.title": "Zabezpieczenia",
"account.card.security.totp.enable.description": "Wprowadź aktualne hasło, aby móc włączyć TOTP", "account.card.security.totp.enable.description": "Wprowadź aktualne hasło, aby móc włączyć TOTP",
"account.card.security.totp.disable.description": "Wprowadź aktualne hasło, aby wyłączyć TOTP", "account.card.security.totp.disable.description": "Wprowadź aktualne hasło, aby wyłączyć TOTP",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Nie możesz ręcznie usunąć swojego udziału ani wyświetlić licznika odwiedzających.", "upload.modal.not-signed-in-description": "Nie możesz ręcznie usunąć swojego udziału ani wyświetlić licznika odwiedzających.",
"upload.modal.expires.never": "nigdy", "upload.modal.expires.never": "nigdy",
"upload.modal.expires.never-long": "Nigdy nie wygasa", "upload.modal.expires.never-long": "Nigdy nie wygasa",
"upload.modal.expires.error.too-long": "Termin ważności przekracza maksymalną datę wygaśnięcia {max}.",
"upload.modal.link.label": "Link", "upload.modal.link.label": "Link",
"upload.modal.expires.label": "Wygasanie", "upload.modal.expires.label": "Wygasanie",
"upload.modal.expires.minute-singular": "Minuta", "upload.modal.expires.minute-singular": "Minuta",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Podgląd nie jest obsługiwany", "share.modal.file-preview.error.not-supported.title": "Podgląd nie jest obsługiwany",
"share.modal.file-preview.error.not-supported.description": "Podgląd dla tego typu pliku nie jest obsługiwany. Pobierz plik, aby go zobaczyć.", "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] // END /share/[id]
// /share/[id]/edit
"share.edit.title": "Edytuj {shareId}",
"share.edit.append-upload": "Dołącz plik",
"share.edit.notify.generic-error": "W trakcie zakańczania tworzenia udziału wystąpił błąd.",
"share.edit.notify.save-success": "Udział zaktualizowany pomyślnie",
// END /share/[id]/edit
// /admin/config // /admin/config
"admin.config.title": "Konfiguracja", "admin.config.title": "Konfiguracja",
"admin.config.category.general": "Ogólne", "admin.config.category.general": "Ogólne",
"admin.config.category.share": "Udostępnij", "admin.config.category.share": "Udostępnij",
"admin.config.category.email": "Adres e-mail", "admin.config.category.email": "Adres e-mail",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Logowanie za pomocą konta społecznościowego",
"admin.config.general.app-name": "Nazwa aplikacji", "admin.config.general.app-name": "Nazwa aplikacji",
"admin.config.general.app-name.description": "Nazwa aplikacji", "admin.config.general.app-name.description": "Nazwa aplikacji",
"admin.config.general.app-url": "Adres URL aplikacji", "admin.config.general.app-url": "Adres URL aplikacji",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Czy dozwolona jest rejestracja", "admin.config.share.allow-registration.description": "Czy dozwolona jest rejestracja",
"admin.config.share.allow-unauthenticated-shares": "Zezwalaj na nieuwierzytelnione udostępnianie", "admin.config.share.allow-unauthenticated-shares": "Zezwalaj na nieuwierzytelnione udostępnianie",
"admin.config.share.allow-unauthenticated-shares.description": "Czy nieautoryzowani użytkownicy mogą tworzyć udostępnienia", "admin.config.share.allow-unauthenticated-shares.description": "Czy nieautoryzowani użytkownicy mogą tworzyć udostępnienia",
"admin.config.share.max-expiration": "Maksymalny okres ważności",
"admin.config.share.max-expiration.description": "Maksymalny okres ważności udziału w godzinach. Ustaw na 0, aby zezwolić na nieograniczony okres ważności.",
"admin.config.share.max-size": "Rozmiar maksymalny", "admin.config.share.max-size": "Rozmiar maksymalny",
"admin.config.share.max-size.description": "Maksymalny rozmiar udziału w bajtach", "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": "Poziom kompresji Zip",
@@ -318,58 +327,58 @@ export default {
"admin.config.smtp.password": "Hasło", "admin.config.smtp.password": "Hasło",
"admin.config.smtp.password.description": "Hasło serwera SMTP", "admin.config.smtp.password.description": "Hasło serwera SMTP",
"admin.config.smtp.button.test": "Wyślij testowego e-maila", "admin.config.smtp.button.test": "Wyślij testowego e-maila",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Zezwól na rejestrację",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "Zezwalaj użytkownikom na rejestrację za pomocą konta społecznościowego",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "Ignoruj TOTP",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "Czy zignorować TOTP, kiedy użytkownik loguje się za pomocą konta społecznościowego",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "Czy login na GitHub jest włączony",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "ID klienta GitHub",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "ID klienta aplikacji GitHub OAuth",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "Sekret klienta GitHub",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "Sekret klienta aplikacji GitHub OAuth",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Czy jest włączony login na GitHub",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "ID klienta Google",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "ID klienta aplikacji GitHub OAuth",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Sekret klienta Google",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Sekret klienta aplikacji Google OAuth",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Czy jest włączony login na GitHub",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "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 aplikacji Microsoft OAuth\nogólnie: Użytkownicy zarówno z osobistym kontem Microsoft, jak i kontem do pracy lub szkoły z Microsoft Entra ID mogą się zalogować do aplikacji. organizacje: Zalogować do aplikacji mogą tylko użytkownicy z kontami pracowniczymi lub szkolnymi z Microsoft Entra ID.\nkonsumenci: Zalogować się do aplikacji mogą tylko użytkownicy z osobistym kontem Microsoft.\nNazwa domeny lokatora Microsoft Entra lub identyfikator lokatora w formacie GUID: Zalogować się do aplikacji mogą tylko użytkownicy określonego najemcy Microsoft Entra (z listy członków na koncie służbowym lub szkolnym albo z listy gości na koncie osobistym Microsoft).",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "ID klienta Microsoft",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "ID klienta aplikacji Microsoft OAuth",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Sekret klienta Microsoft",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Sekret klienta aplikacji Microsoft OAuth",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Czy jest włączony login na Discord",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "ID klienta Discord",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "ID klienta aplikacji Discord OAuth",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Sekret klienta Discord",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "Sekret klienta aplikacji Discord OAuth",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "Czy jest włączony login OpenID",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "Wykrywanie URI OpenID",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "Wykrywanie URI aplikacji OpenID OAuth",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "ID klienta OpenID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "ID klienta aplikacji OpenID OAuth",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "Sekret klienta OpenID",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "Sekret klienta aplikacji Discord OAuth",
// 404 // 404
"404.description": "Ups! Ta strona nie istnieje.", "404.description": "Ups! Ta strona nie istnieje.",
"404.button.home": "Wróć do strony domowej", "404.button.home": "Wróć do strony domowej",
// error // error
"error.title": "Error", "error.title": "Błąd",
"error.description": "Oops!", "error.description": "Ups!",
"error.button.back": "Go back", "error.button.back": "Wróć",
"error.msg.default": "Something went wrong.", "error.msg.default": "Coś poszło nie tak.",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "Anulowałeś proces uwierzytelniania, spróbuj ponownie.",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "Proces uwierzytelniania trwał zbyt długo, spróbuj ponownie.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "Użytkownik powiązany z tym kontem {0} nie istnieje.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Nie można pobrać adresu e-mail z tego konta {0}.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "To konto {0} zostało już połączone z innym kontem.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "To konto {0} nie zostało jeszcze połączone z żadnym kontem.",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -33,7 +33,7 @@ export default {
"signin.button.submit": "Iniciar sessão", "signin.button.submit": "Iniciar sessão",
"signIn.notify.totp-required.title": "Autenticação de dois fatores necessária", "signIn.notify.totp-required.title": "Autenticação de dois fatores necessária",
"signIn.notify.totp-required.description": "Insira seu código de autenticação de dois fatores", "signIn.notify.totp-required.description": "Insira seu código de autenticação de dois fatores",
"signIn.oauth.or": "OR", "signIn.oauth.or": "OU",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Vamos começar", "signup.button.submit": "Vamos começar",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "Autenticação TOTP",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Iniciar sessão",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Esqueceu a sua senha?", "resetPassword.title": "Esqueceu a sua senha?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "Senha", "account.card.password.title": "Senha",
"account.card.password.old": "Senha antiga", "account.card.password.old": "Senha antiga",
"account.card.password.new": "Nova senha", "account.card.password.new": "Nova senha",
"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": "Você não tem uma senha definida. Se quiser entrar com e-mail e senha você precisa definir uma senha.",
"account.notify.password.success": "Senha alterada com sucesso", "account.notify.password.success": "Senha alterada com sucesso",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Login com Redes Sociais",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Vincular",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Desvincular",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Desvinculado",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Desvincular conta",
"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": "Desvincular suas redes sociais pode fazer com que você perca sua conta se não se lembrar de seu nome de usuário e senha.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Desvinculado com sucesso",
"account.card.security.title": "Segurança", "account.card.security.title": "Segurança",
"account.card.security.totp.enable.description": "Digite a sua senha atual para começar a habilitar o TOTP", "account.card.security.totp.enable.description": "Digite a sua senha atual para começar a habilitar o TOTP",
"account.card.security.totp.disable.description": "Digite a sua senha atual para desabilitar o TOTP", "account.card.security.totp.disable.description": "Digite a sua senha atual para desabilitar o TOTP",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Você não poderá excluir seu compartilhamento manualmente e visualizar a contagem de visitantes.", "upload.modal.not-signed-in-description": "Você não poderá excluir seu compartilhamento manualmente e visualizar a contagem de visitantes.",
"upload.modal.expires.never": "nunca", "upload.modal.expires.never": "nunca",
"upload.modal.expires.never-long": "Nunca expira", "upload.modal.expires.never-long": "Nunca expira",
"upload.modal.expires.error.too-long": "Expiração excede a data de expiração máxima de {max}.",
"upload.modal.link.label": "Link", "upload.modal.link.label": "Link",
"upload.modal.expires.label": "Expiração", "upload.modal.expires.label": "Expiração",
"upload.modal.expires.minute-singular": "Minuto", "upload.modal.expires.minute-singular": "Minuto",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Visualização não suportada", "share.modal.file-preview.error.not-supported.title": "Visualização não suportada",
"share.modal.file-preview.error.not-supported.description": "Uma visualização para este tipo de arquivo não é suportada. Faça o download do arquivo para visualizá-lo.", "share.modal.file-preview.error.not-supported.description": "Uma visualização para este tipo de arquivo não é suportada. Faça o download do arquivo para visualizá-lo.",
// END /share/[id] // END /share/[id]
// /share/[id]/edit
"share.edit.title": "Editar {shareId}",
"share.edit.append-upload": "Anexar arquivo",
"share.edit.notify.generic-error": "Ocorreu um erro ao terminar seu compartilhamento.",
"share.edit.notify.save-success": "Compartilhamento atualizado com sucesso",
// END /share/[id]/edit
// /admin/config // /admin/config
"admin.config.title": "Configuração", "admin.config.title": "Configuração",
"admin.config.category.general": "Geral", "admin.config.category.general": "Geral",
"admin.config.category.share": "Compartilhamento", "admin.config.category.share": "Compartilhamento",
"admin.config.category.email": "E-mail", "admin.config.category.email": "E-mail",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Login com Redes Sociais",
"admin.config.general.app-name": "Nome da aplicação", "admin.config.general.app-name": "Nome da aplicação",
"admin.config.general.app-name.description": "Nome da aplicação", "admin.config.general.app-name.description": "Nome da aplicação",
"admin.config.general.app-url": "URL do Aplicativo", "admin.config.general.app-url": "URL do Aplicativo",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Se o registro é permitido", "admin.config.share.allow-registration.description": "Se o registro é permitido",
"admin.config.share.allow-unauthenticated-shares": "Permitir compartilhamentos sem autenticação", "admin.config.share.allow-unauthenticated-shares": "Permitir compartilhamentos sem autenticação",
"admin.config.share.allow-unauthenticated-shares.description": "Se usuários não autenticados podem criar compartilhamentos", "admin.config.share.allow-unauthenticated-shares.description": "Se usuários não autenticados podem criar compartilhamentos",
"admin.config.share.max-expiration": "Expiração máxima",
"admin.config.share.max-expiration.description": "Validade máxima de ações em horas. Defina 0 para permitir expiração ilimitada.",
"admin.config.share.max-size": "Tamanho máximo", "admin.config.share.max-size": "Tamanho máximo",
"admin.config.share.max-size.description": "Tamanho máximo do compartilhamento em bytes", "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": "Nível de compressão",
@@ -318,58 +327,58 @@ export default {
"admin.config.smtp.password": "Senha", "admin.config.smtp.password": "Senha",
"admin.config.smtp.password.description": "Senha do servidor SMTP", "admin.config.smtp.password.description": "Senha do servidor SMTP",
"admin.config.smtp.button.test": "Enviar email de teste", "admin.config.smtp.button.test": "Enviar email de teste",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Permitir registro",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "Permitir que os usuários se registrem através do login de redes sociais",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "Ignorar TOTP",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "Ignorar o TOTP quando usuário usando login social",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "Se o login GitHub está habilitado",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "Client ID do GitHub",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "ID do cliente do aplicativo GitHub OAuth",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "Client Secret do GitHub",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "ID do cliente do aplicativo GitHub OAuth",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Se o login GitHub está habilitado",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "Client ID do Google",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "ID do cliente do aplicativo GitHub OAuth",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Client Secret do Google",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Client secret do aplicativo GitHub OAuth",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Se o Microsoft login está habilitado",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "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": "O ID do Tenant do app Microsoft OAuth\ncomum: Usuários com uma conta pessoal da Microsoft e uma conta de trabalho ou escola do Microsoft Entra podem entrar no aplicativo. organizações: somente usuários com contas de trabalho ou de escola do Microsoft Entra ID podem entrar no aplicativo.\nconsumidores: Somente usuários com uma conta pessoal da Microsoft podem acessar o aplicativo.\nnome de domínio do tenant Microsoft Entra ou do ID do inquilino no formato GUID: Somente usuários de um tenant Microsoft Entra específico (membros do diretório com uma conta de trabalho ou de diretório com uma conta pessoal da Microsoft) podem entrar no aplicativo.",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "ID do Cliente Microsoft",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "ID do cliente do aplicativo Microsoft OAuth",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Segredo do Cliente Microsoft",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Client secret do aplicativo Microsoft OAuth",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Se o login do Discord está habilitado",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "ID do Cliente Discord",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "ID do cliente do aplicativo Discord OAuth",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Segredo do Cliente Discord",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "ID do cliente do aplicativo Discord OAuth",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "Se o OpenID login está habilitado",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "ID do Cliente OpenID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "ID do cliente do aplicativo OpenID OAuth",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "Segredo do Cliente OpenID",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "ID do cliente do aplicativo OpenID OAuth",
// 404 // 404
"404.description": "Ops, esta página não existe.", "404.description": "Ops, esta página não existe.",
"404.button.home": "Me traga de volta para casa", "404.button.home": "Me traga de volta para casa",
// error // error
"error.title": "Error", "error.title": "Erro",
"error.description": "Oops!", "error.description": "Oops!",
"error.button.back": "Go back", "error.button.back": "Voltar",
"error.msg.default": "Something went wrong.", "error.msg.default": "Algo deu errado.",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "Você cancelou o processo de autenticação, por favor, tente novamente.",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "O processo de autenticação demorou muito. Por favor, tente novamente.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "O usuário vinculado a esta conta {0} não existe.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Não é possível obter o endereço de e-mail desta conta {0}.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "Esta conta {0} já está vinculada a outra conta.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "Esta conta {0} ainda não foi vinculada a nenhuma conta.",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -33,7 +33,7 @@ export default {
"signin.button.submit": "Вход", "signin.button.submit": "Вход",
"signIn.notify.totp-required.title": "Требуется двухфакторная аутентификация", "signIn.notify.totp-required.title": "Требуется двухфакторная аутентификация",
"signIn.notify.totp-required.description": "Пожалуйста, введите код Вашей 2-х факторной аутентификации", "signIn.notify.totp-required.description": "Пожалуйста, введите код Вашей 2-х факторной аутентификации",
"signIn.oauth.or": "OR", "signIn.oauth.or": "ИЛИ",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Давайте начнём", "signup.button.submit": "Давайте начнём",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "Авторизация TOTP",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Войти",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Забыли пароль?", "resetPassword.title": "Забыли пароль?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "Пароль", "account.card.password.title": "Пароль",
"account.card.password.old": "Старый пароль", "account.card.password.old": "Старый пароль",
"account.card.password.new": "Новый пароль", "account.card.password.new": "Новый пароль",
"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": "У вас не установлен пароль. Если вы хотите войти с помощью электронной почты и пароля, вам необходимо установить пароль.",
"account.notify.password.success": "Пароль успешно изменён", "account.notify.password.success": "Пароль успешно изменён",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Авторизация через социальные сети",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Подключить",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Отключить",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Отключен",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Отключить связь с учетной записью",
"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": "Отключение связи с учетной записью социальных аккаунтов может привести к потере вашей учетной записи, если вы не помните свое имя пользователя и пароль.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Отключение прошло успешно",
"account.card.security.title": "Безопасность", "account.card.security.title": "Безопасность",
"account.card.security.totp.enable.description": "Введите ваш текущий пароль для начала включения TOTP", "account.card.security.totp.enable.description": "Введите ваш текущий пароль для начала включения TOTP",
"account.card.security.totp.disable.description": "Введите ваш текущий пароль, чтобы отключить TOTP", "account.card.security.totp.disable.description": "Введите ваш текущий пароль, чтобы отключить TOTP",
@@ -134,7 +134,7 @@ export default {
"account.reverseShares.title.empty": "Тут пусто 👀", "account.reverseShares.title.empty": "Тут пусто 👀",
"account.reverseShares.description.empty": "У вас пока нет обратных загрузок.", "account.reverseShares.description.empty": "У вас пока нет обратных загрузок.",
// showCreateReverseShareModal.tsx // showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share", "account.reverseShares.modal.title": "Создать обратную ссылку на файл",
"account.reverseShares.modal.expiration.label": "Истекает", "account.reverseShares.modal.expiration.label": "Истекает",
"account.reverseShares.modal.expiration.minute-singular": "Минута", "account.reverseShares.modal.expiration.minute-singular": "Минута",
"account.reverseShares.modal.expiration.minute-plural": "Минут(ы)", "account.reverseShares.modal.expiration.minute-plural": "Минут(ы)",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Вы не сможете удалить свои файлы вручную и просмотреть количество посетителей.", "upload.modal.not-signed-in-description": "Вы не сможете удалить свои файлы вручную и просмотреть количество посетителей.",
"upload.modal.expires.never": "никогда", "upload.modal.expires.never": "никогда",
"upload.modal.expires.never-long": "Никогда не истекает", "upload.modal.expires.never-long": "Никогда не истекает",
"upload.modal.expires.error.too-long": "Срок действия превышает максимальную дату окончания срока действия {max}.",
"upload.modal.link.label": "Ссылка", "upload.modal.link.label": "Ссылка",
"upload.modal.expires.label": "Истекает", "upload.modal.expires.label": "Истекает",
"upload.modal.expires.minute-singular": "Минута", "upload.modal.expires.minute-singular": "Минута",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Предпросмотр не поддерживается", "share.modal.file-preview.error.not-supported.title": "Предпросмотр не поддерживается",
"share.modal.file-preview.error.not-supported.description": "Предварительный просмотр этого типа файла не поддерживается. Пожалуйста, скачайте файл для его просмотра.", "share.modal.file-preview.error.not-supported.description": "Предварительный просмотр этого типа файла не поддерживается. Пожалуйста, скачайте файл для его просмотра.",
// END /share/[id] // 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
"admin.config.title": "Конфигурация", "admin.config.title": "Конфигурация",
"admin.config.category.general": "Общее", "admin.config.category.general": "Общее",
"admin.config.category.share": "Загрузки", "admin.config.category.share": "Загрузки",
"admin.config.category.email": "Электронная почта", "admin.config.category.email": "Электронная почта",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Авторизация через социальные сети",
"admin.config.general.app-name": "Название приложения", "admin.config.general.app-name": "Название приложения",
"admin.config.general.app-name.description": "Видимое название приложения", "admin.config.general.app-name.description": "Видимое название приложения",
"admin.config.general.app-url": "URL-адрес приложения", "admin.config.general.app-url": "URL-адрес приложения",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Разрешена ли регистрация", "admin.config.share.allow-registration.description": "Разрешена ли регистрация",
"admin.config.share.allow-unauthenticated-shares": "Разрешить неавторизованные загрузки", "admin.config.share.allow-unauthenticated-shares": "Разрешить неавторизованные загрузки",
"admin.config.share.allow-unauthenticated-shares.description": "Могут ли неавторизованные пользователи создавать загрузки", "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": "Максимальный размер",
"admin.config.share.max-size.description": "Максимальный размер файла в байтах", "admin.config.share.max-size.description": "Максимальный размер файла в байтах",
"admin.config.share.zip-compression-level": "Уровень сжатия Zip", "admin.config.share.zip-compression-level": "Уровень сжатия Zip",
@@ -318,58 +327,58 @@ export default {
"admin.config.smtp.password": "Пароль", "admin.config.smtp.password": "Пароль",
"admin.config.smtp.password.description": "Пароль SMTP-сервера", "admin.config.smtp.password.description": "Пароль SMTP-сервера",
"admin.config.smtp.button.test": "Отправить тестовое письмо", "admin.config.smtp.button.test": "Отправить тестовое письмо",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Разрешить регистрацию",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "Разрешить пользователям регистрироваться используя учетные записи социальных сетей",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "Игнорировать TOTP",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "Игнорировать TOTP при использовании социальной авторизации",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "Включен ли логин на GitHub",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "ID клиента GitHub",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "ID клиента в приложении GitHub OAuth",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "Секретный ключ клиента GitHub",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "Секретный ключ клиента в приложении GitHub OAuth",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Включен ли логин Google на GitHub",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "ID клиента Google",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "ID клиента в приложении Google OAuth",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Секретный ключ клиента Google",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Секретный ключ клиента в приложении Google OAuth",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Включен ли логин Microsoft",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "admin.config.oauth.microsoft-tenant": "Корпоративный аккаунт Microsoft",
"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": "Идентификатор арендатора приложения Microsoft OAuth\ncommon: Пользователи с личным аккаунтом Microsoft и рабочим или учебным аккаунтом от Microsoft Entra ID могут войти в приложение. organizations: Только пользователи с рабочим или учебным аккаунтом от Microsoft Entra ID могут войти в приложение.\nconsumers: Только пользователи с личным аккаунтом Microsoft могут войти в приложение.\nимя домена арендатора Microsoft Entra или идентификатор арендатора в формате GUID: Только пользователи из определенного арендатора Microsoft Entra (участники каталога с рабочим или учебным аккаунтом или гости каталога с личным аккаунтом Microsoft) могут войти в приложение.",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "Идентификатор клиента Microsoft",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "ID клиента в приложении Microsoft OAuth",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Секретный ключ клиента Microsoft",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Секретный ключ клиента в приложении Microsoft OAuth",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Включен ли логин Discord",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "ID клиента Discord",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "ID клиента в приложении Discord OAuth",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Секретный ключ клиента Discord",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "Секретный ключ клиента в приложении Discord OAuth",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "Включен ли логин OpenID",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "Discovery URI приложения OpenID OAuth",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "ID клиента OpenID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "ID клиента в приложении OpenID OAuth",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "Секретный ключ клиента OpenID",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "Секретный ключ клиента в приложении OpenID OAuth",
// 404 // 404
"404.description": "Упс, этой страницы не существует.", "404.description": "Упс, этой страницы не существует.",
"404.button.home": "Верните меня домой", "404.button.home": "Верните меня домой",
// error // error
"error.title": "Error", "error.title": "Ошибка",
"error.description": "Oops!", "error.description": "Что-то пошло не так!",
"error.button.back": "Go back", "error.button.back": "Назад",
"error.msg.default": "Something went wrong.", "error.msg.default": "Что-то пошло не так.",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "Вы отменили процесс аутентификации, пожалуйста, попробуйте еще раз.",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "Процесс аутентификации занял слишком много времени, пожалуйста, попробуйте еще раз.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "Пользователь связанный с учетной записью {0} не существует.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Не удается получить адрес электронной почты от учетной записи {0}.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "Эта учетная запись {0} уже привязана к другому аккаунту.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "Эта учетная запись {0} ещё не привязана ни к одному аккаунту.",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -33,7 +33,7 @@ export default {
"signin.button.submit": "Пријавите се", "signin.button.submit": "Пријавите се",
"signIn.notify.totp-required.title": "Потребна је двофакторска аутентификација", "signIn.notify.totp-required.title": "Потребна је двофакторска аутентификација",
"signIn.notify.totp-required.description": "Унесите свој двофакторски код за аутентификацију", "signIn.notify.totp-required.description": "Унесите свој двофакторски код за аутентификацију",
"signIn.oauth.or": "OR", "signIn.oauth.or": "Или",
"signIn.oauth.github": "GitHub", "signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google", "signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft", "signIn.oauth.microsoft": "Microsoft",
@@ -51,8 +51,8 @@ export default {
"signup.button.submit": "Хајде да почнемо", "signup.button.submit": "Хајде да почнемо",
// END /auth/signup // END /auth/signup
// /auth/totp // /auth/totp
"totp.title": "TOTP Authentication", "totp.title": "ТОТП аутентификација",
"totp.button.signIn": "Sign in", "totp.button.signIn": "Пријавите се",
// END /auth/totp // END /auth/totp
// /auth/reset-password // /auth/reset-password
"resetPassword.title": "Заборавили сте лозинку?", "resetPassword.title": "Заборавили сте лозинку?",
@@ -72,20 +72,20 @@ export default {
"account.card.password.title": "Лозинка", "account.card.password.title": "Лозинка",
"account.card.password.old": "Стара лозинка", "account.card.password.old": "Стара лозинка",
"account.card.password.new": "Нова лозинка", "account.card.password.new": "Нова лозинка",
"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": "Немате постављену лозинку. Ако желите да се пријавите помоћу е-поште и лозинке, потребно је да поставите лозинку.",
"account.notify.password.success": "Лозинка је успешно промењена", "account.notify.password.success": "Лозинка је успешно промењена",
"account.card.oauth.title": "Social login", "account.card.oauth.title": "Социал логин",
"account.card.oauth.github": "GitHub", "account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google", "account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft", "account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord", "account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID", "account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link", "account.card.oauth.link": "Link",
"account.card.oauth.unlink": "Unlink", "account.card.oauth.unlink": "Прекини везу",
"account.card.oauth.unlinked": "Unlinked", "account.card.oauth.unlinked": "Веза је прекинута",
"account.modal.unlink.title": "Unlink account", "account.modal.unlink.title": "Прекини везу са налогом",
"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": "Прекидање везе са вашим друштвеним налозима може довести до губитка налога ако се не сећате корисничког имена и лозинке.",
"account.notify.oauth.unlinked.success": "Unlinked successfully", "account.notify.oauth.unlinked.success": "Веза је прекинута",
"account.card.security.title": "Безбедност", "account.card.security.title": "Безбедност",
"account.card.security.totp.enable.description": "Унесите своју тренутну лозинку да бисте почели да омогућавате ТОТП", "account.card.security.totp.enable.description": "Унесите своју тренутну лозинку да бисте почели да омогућавате ТОТП",
"account.card.security.totp.disable.description": "Унесите своју тренутну лозинку да бисте онемогућили ТОТП", "account.card.security.totp.disable.description": "Унесите своју тренутну лозинку да бисте онемогућили ТОТП",
@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "Нећете моћи ручно да избришете своје дељење и видите број посетилаца.", "upload.modal.not-signed-in-description": "Нећете моћи ручно да избришете своје дељење и видите број посетилаца.",
"upload.modal.expires.never": "никад", "upload.modal.expires.never": "никад",
"upload.modal.expires.never-long": "Никада не истиче", "upload.modal.expires.never-long": "Никада не истиче",
"upload.modal.expires.error.too-long": "Истек премашује максимални датум истека од {max}.",
"upload.modal.link.label": "Линк", "upload.modal.link.label": "Линк",
"upload.modal.expires.label": "Истиче", "upload.modal.expires.label": "Истиче",
"upload.modal.expires.minute-singular": "Минут", "upload.modal.expires.minute-singular": "Минут",
@@ -263,13 +264,19 @@ export default {
"share.modal.file-preview.error.not-supported.title": "Преглед није подржан", "share.modal.file-preview.error.not-supported.title": "Преглед није подржан",
"share.modal.file-preview.error.not-supported.description": "Преглед за овај тип датотеке није подржан. Преузмите датотеку да бисте је видели.", "share.modal.file-preview.error.not-supported.description": "Преглед за овај тип датотеке није подржан. Преузмите датотеку да бисте је видели.",
// END /share/[id] // 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
"admin.config.title": "Конфигурација", "admin.config.title": "Конфигурација",
"admin.config.category.general": "Опште", "admin.config.category.general": "Опште",
"admin.config.category.share": "Дељење", "admin.config.category.share": "Дељење",
"admin.config.category.email": "E-пошта", "admin.config.category.email": "E-пошта",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login", "admin.config.category.oauth": "Социал Логин",
"admin.config.general.app-name": "Назив апликације", "admin.config.general.app-name": "Назив апликације",
"admin.config.general.app-name.description": "Назив апликације", "admin.config.general.app-name.description": "Назив апликације",
"admin.config.general.app-url": "URL апликације", "admin.config.general.app-url": "URL апликације",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "Да ли је регистрација дозвољена", "admin.config.share.allow-registration.description": "Да ли је регистрација дозвољена",
"admin.config.share.allow-unauthenticated-shares": "Дозволи дељење без аутентификације", "admin.config.share.allow-unauthenticated-shares": "Дозволи дељење без аутентификације",
"admin.config.share.allow-unauthenticated-shares.description": "Да ли корисници без аутентификације могу да креирају дељења", "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": "Максимална величина",
"admin.config.share.max-size.description": "Максимална величина дељења у бајтовима", "admin.config.share.max-size.description": "Максимална величина дељења у бајтовима",
"admin.config.share.zip-compression-level": "Ниво zip компресије", "admin.config.share.zip-compression-level": "Ниво zip компресије",
@@ -318,58 +327,58 @@ export default {
"admin.config.smtp.password": "Лозинка", "admin.config.smtp.password": "Лозинка",
"admin.config.smtp.password.description": "Лозинка SMTP сервера", "admin.config.smtp.password.description": "Лозинка SMTP сервера",
"admin.config.smtp.button.test": "Пошаљи тестну е-пошту", "admin.config.smtp.button.test": "Пошаљи тестну е-пошту",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Дозволи регистрацију",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login", "admin.config.oauth.allow-registration.description": "Дозволите корисницима да се региструју путем друштвене пријаве",
"admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp": "Занемари ТОТП",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", "admin.config.oauth.ignore-totp.description": "Да ли да игноришете ТОТП када корисник користи пријаву на друштвеним мрежама",
"admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", "admin.config.oauth.github-enabled.description": "Да ли је пријављивање на GitHub омогућено",
"admin.config.oauth.github-client-id": "GitHub Client ID", "admin.config.oauth.github-client-id": "GitHub ИД клијента",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app", "admin.config.oauth.github-client-id.description": "ИД клијента GitHub OAuth апликације",
"admin.config.oauth.github-client-secret": "GitHub Client secret", "admin.config.oauth.github-client-secret": "Тајна GitHub клијента",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app", "admin.config.oauth.github-client-secret.description": "Тајна клијента GitHub OAuth апликације",
"admin.config.oauth.google-enabled": "Google", "admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled", "admin.config.oauth.google-enabled.description": "Да ли је пријављивање на Google омогућено",
"admin.config.oauth.google-client-id": "Google Client ID", "admin.config.oauth.google-client-id": "ИД Google клијента",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app", "admin.config.oauth.google-client-id.description": "ИД клијента Google OAuth апликације",
"admin.config.oauth.google-client-secret": "Google Client secret", "admin.config.oauth.google-client-secret": "Тајна Google клијента",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app", "admin.config.oauth.google-client-secret.description": "Тајна клијента Google OAuth апликације",
"admin.config.oauth.microsoft-enabled": "Microsoft", "admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled", "admin.config.oauth.microsoft-enabled.description": "Да ли је пријављивање на Microsoft омогућено",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant", "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": "ИД закупца за Microsoft OAuth апликацију\nуобичајено: Корисници са личним Microsoft налогом и пословним или школским налогом са Microsoft Entra ID-а могу да се пријаве у апликацију. организације: Само корисници са пословним или школским налозима са Microsoft Entra ID-а могу да се пријаве у апликацију.\nпотрошачи: Само корисници са личним Microsoft налогом могу да се пријаве у апликацију.\nиме домена закупца Microsoft Entra ID или ИД закупца у ГУИД формату: Само корисници из одређеног Microsoft Entra ID станара (чланови директоријума са пословним или школским налогом или гости директоријума са личним Microsoft налогом) могу да се пријаве у апликацију.",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID", "admin.config.oauth.microsoft-client-id": "Microsotf Цлиент ИД",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-id.description": "ИД клијента Microsoft OAuth апликације",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret", "admin.config.oauth.microsoft-client-secret": "Тајна Microsoft клијента",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app", "admin.config.oauth.microsoft-client-secret.description": "Тајна клијента за Microsot OAuth апликацију",
"admin.config.oauth.discord-enabled": "Discord", "admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled", "admin.config.oauth.discord-enabled.description": "Да ли је пријављивање на Discord омогућено",
"admin.config.oauth.discord-client-id": "Discord Client ID", "admin.config.oauth.discord-client-id": "Discord ИД клијента",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app", "admin.config.oauth.discord-client-id.description": "ИД клијента Discord OAuth апликације",
"admin.config.oauth.discord-client-secret": "Discord Client secret", "admin.config.oauth.discord-client-secret": "Discord клијент тајна",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app", "admin.config.oauth.discord-client-secret.description": "Тајна клијента Discord OAuth апликације",
"admin.config.oauth.oidc-enabled": "OpenID", "admin.config.oauth.oidc-enabled": "OpenID",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled", "admin.config.oauth.oidc-enabled.description": "Да ли је пријављивање на OpenID омогућено",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI", "admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app", "admin.config.oauth.oidc-discovery-uri.description": "УРИ за откривање OpenID OAuth апликације",
"admin.config.oauth.oidc-client-id": "OpenID Client ID", "admin.config.oauth.oidc-client-id": "OpenID ИД клијента",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app", "admin.config.oauth.oidc-client-id.description": "ИД клијента OpenID OAuth апликације",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret", "admin.config.oauth.oidc-client-secret": "Тајна OpenID клијента",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app", "admin.config.oauth.oidc-client-secret.description": "Тајна клијента OpenID OAuth апликације",
// 404 // 404
"404.description": "Опа - Ова страна не постоји.", "404.description": "Опа - Ова страна не постоји.",
"404.button.home": "Врати ме на почетак", "404.button.home": "Врати ме на почетак",
// error // error
"error.title": "Error", "error.title": "Грешка",
"error.description": "Oops!", "error.description": "Ooпс!",
"error.button.back": "Go back", "error.button.back": "Иди назад",
"error.msg.default": "Something went wrong.", "error.msg.default": "Нешто је пошло наопако.",
"error.msg.access_denied": "You canceled the authentication process, please try again.", "error.msg.access_denied": "Отказали сте процес аутентификације, покушајте поново.",
"error.msg.expired_token": "The authentication process took too long, please try again.", "error.msg.expired_token": "Процес аутентификације је трајао предуго, покушајте поново.",
"error.msg.no_user": "User linked to this {0} account doesn't exist.", "error.msg.no_user": "Корисник повезан са овим {0} налогом не постоји.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Не могу да добијем адресу е-поште са овог {0} налога.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "Овај {0} налог је већ повезан са другим налогом.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.", "error.msg.not_linked": "Овај {0} налог још увек није повезан ни са једним налогом.",
"error.param.provider_github": "GitHub", "error.param.provider_github": "GitHub",
"error.param.provider_google": "Google", "error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft", "error.param.provider_microsoft": "Microsoft",

View File

@@ -0,0 +1,411 @@
export default {
// Navbar
"navbar.upload": "Ladda upp",
"navbar.signin": "Logga in",
"navbar.home": "Startsida",
"navbar.signup": "Skapa konto",
"navbar.links.shares": "Mina delningar",
"navbar.links.reverse": "Omvända delningar",
"navbar.avatar.account": "Mitt konto",
"navbar.avatar.admin": "Administration",
"navbar.avatar.signout": "Logga ut",
// END navbar
// /
"home.title": "En <h>egen</h> fildelningsplattform.",
"home.description": "Vill du verkligen lägga dina personliga filer hos en tredje part som WeTransfer?",
"home.bullet.a.name": "Lokalt installerad",
"home.bullet.a.description": "Hosta Pingvin Share på din egen maskin.",
"home.bullet.b.name": "Sekretess",
"home.bullet.b.description": "Dina filer är dina filer och bör aldrig hamna i händerna på tredje part.",
"home.bullet.c.name": "Ingen irriterande filstorleksbegränsning",
"home.bullet.c.description": "Ladda upp så stora filer som du vill. Endast din hårddisk kommer att vara din gräns.",
"home.button.start": "Kom igång",
"home.button.source": "Källkod",
// END /
// /auth/signin
"signin.title": "Välkommen tillbaka",
"signin.description": "Har du inget konto än?",
"signin.button.signup": "Skapa konto",
"signin.input.email-or-username": "E-post eller användarnamn",
"signin.input.email-or-username.placeholder": "Din e-postadress eller ditt användarnamn",
"signin.input.password": "Lösenord",
"signin.input.password.placeholder": "Lösenord",
"signin.button.submit": "Logga in",
"signIn.notify.totp-required.title": "Tvåfaktorsautentisering krävs",
"signIn.notify.totp-required.description": "Vänligen ange din tvåfaktorsautentiseringskod",
"signIn.oauth.or": "ELLER",
"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": "Skapa ett konto",
"signup.description": "Har du redan ett konto?",
"signup.button.signin": "Logga in",
"signup.input.username": "Användarnamn",
"signup.input.username.placeholder": "Ditt användarnamn",
"signup.input.email": "E-post",
"signup.input.email.placeholder": "Din e-post",
"signup.button.submit": "Kom igång",
// END /auth/signup
// /auth/totp
"totp.title": "TOTP-autentisering",
"totp.button.signIn": "Logga in",
// END /auth/totp
// /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.button.back": "Tillbaka till inloggningssidan",
"resetPassword.text.resetPassword": "Återställ lösenord",
"resetPassword.text.enterNewPassword": "Ange ditt nya lösenord",
"resetPassword.input.password": "Nytt lösenord",
"resetPassword.notify.passwordReset": "Ditt lösenord har återställts.",
// /account
"account.title": "Mitt konto",
"account.card.info.title": "Kontoinformation",
"account.card.info.username": "Användarnamn",
"account.card.info.email": "E-post",
"account.notify.info.success": "Kontot uppdaterades",
"account.card.password.title": "Lösenord",
"account.card.password.old": "Gammalt lösenord",
"account.card.password.new": "Nytt lösenord",
"account.card.password.noPasswordSet": "Du har inget lösenord. Om du vill logga in med e-post och lösenord måste du ange ett lösenord.",
"account.notify.password.success": "Lösenordet har ändrats",
"account.card.oauth.title": "Inloggning via sociala nätverk",
"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": "Länka",
"account.card.oauth.unlink": "Avlänka",
"account.card.oauth.unlinked": "Avlänkad",
"account.modal.unlink.title": "Avlänka konto",
"account.modal.unlink.description": "Om du kopplar bort dina sociala konton kan det leda till att du förlorar ditt konto om du inte kommer ihåg ditt användarnamn och lösenord.",
"account.notify.oauth.unlinked.success": "Avlänkning utförd",
"account.card.security.title": "Säkerhet",
"account.card.security.totp.enable.description": "Ange ditt nuvarande lösenord för att aktivera TOTP",
"account.card.security.totp.disable.description": "Ange ditt lösenord för att inaktivera TOTP",
"account.card.security.totp.button.start": "Start",
"account.modal.totp.title": "Aktivera TOTP",
"account.modal.totp.step1": "Steg 1: Lägg till din autentiserare",
"account.modal.totp.step2": "Steg 2: Bekräfta din kod",
"account.modal.totp.enterManually": "Ange manuellt",
"account.modal.totp.code": "Kod",
"account.modal.totp.clickToCopy": "Klicka för att kopiera",
"account.modal.totp.verify": "Verifiera",
"account.notify.totp.disable": "TOTP har inaktiverats",
"account.notify.totp.enable": "TOTP aktiverat",
"account.card.language.title": "Språk",
"account.card.language.description": "Projektet är översatt av gemenskapen. Vissa översättningar kan vara ofullständiga.",
"account.card.color.title": "Färgschema",
// ThemeSwitcher.tsx
"account.theme.dark": "Mörk",
"account.theme.light": "Ljus",
"account.theme.system": "System",
"account.button.delete": "Ta bort konto",
"account.modal.delete.title": "Ta bort konto",
"account.modal.delete.description": "Vill du verkligen ta bort ditt konto inklusive alla dina aktiva delningar?",
// END /account
// /account/shares
"account.shares.title": "Mina delningar",
"account.shares.title.empty": "Här var det tomt 👀",
"account.shares.description.empty": "Du har inga delningar.",
"account.shares.button.create": "Skapa en",
"account.shares.info.title": "Information om delning",
"account.shares.table.id": "ID",
"account.shares.table.name": "Namn",
"account.shares.table.description": "Beskrivning",
"account.shares.table.visitors": "Besökare",
"account.shares.table.expiresAt": "Förfaller den",
"account.shares.table.createdAt": "Skapad den",
"account.shares.table.size": "Storlek",
"account.shares.modal.share-informations": "Information om delning",
"account.shares.modal.share-link": "Delningslänk",
"account.shares.modal.delete.title": "Ta bort delning {share}",
"account.shares.modal.delete.description": "Vill du verkligen ta bort denna delning?",
// END /account/shares
// /account/reverseShares
"account.reverseShares.title": "Omvända delningar",
"account.reverseShares.description": "En omvänd delning gör att du kan generera en unik URL som tillåter externa användare att skapa en delning.",
"account.reverseShares.title.empty": "Här var det tomt 👀",
"account.reverseShares.description.empty": "Du har inga omvända delningar.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Skapa omvänd delning",
"account.reverseShares.modal.expiration.label": "Förfaller",
"account.reverseShares.modal.expiration.minute-singular": "Minut",
"account.reverseShares.modal.expiration.minute-plural": "Minuter",
"account.reverseShares.modal.expiration.hour-singular": "Timme",
"account.reverseShares.modal.expiration.hour-plural": "Timmar",
"account.reverseShares.modal.expiration.day-singular": "Dag",
"account.reverseShares.modal.expiration.day-plural": "Dagar",
"account.reverseShares.modal.expiration.week-singular": "Vecka",
"account.reverseShares.modal.expiration.week-plural": "Veckor",
"account.reverseShares.modal.expiration.month-singular": "Månad",
"account.reverseShares.modal.expiration.month-plural": "Månader",
"account.reverseShares.modal.expiration.year-singular": "År",
"account.reverseShares.modal.expiration.year-plural": "År",
"account.reverseShares.modal.max-size.label": "Max storlek på delning",
"account.reverseShares.modal.send-email": "Skicka e-postavisering",
"account.reverseShares.modal.send-email.description": "Skicka ett e-postmeddelande när en delning skapas med denna länk för omvänd delning.",
"account.reverseShares.modal.max-use.label": "Maxanvändningar",
"account.reverseShares.modal.max-use.description": "Den maximala mängden gånger denna URL kan användas för att skapa en delning.",
"account.reverseShare.never-expires": "Denna omvända delning kommer aldrig att förfalla.",
"account.reverseShare.expires-on": "Denna sammanlagda delning löper ut på {expiration}.",
"account.reverseShares.table.no-shares": "Inga delningar har skapats ännu",
"account.reverseShares.table.count.singular": "delning",
"account.reverseShares.table.count.plural": "delningar",
"account.reverseShares.table.shares": "Delningar",
"account.reverseShares.table.remaining": "Återstående användningar",
"account.reverseShares.table.max-size": "Max storlek på delning",
"account.reverseShares.table.expires": "Förfaller den",
"account.reverseShares.modal.reverse-share-link": "Omvänd delningslänk",
"account.reverseShares.modal.delete.title": "Ta bort omvänd delning",
"account.reverseShares.modal.delete.description": "Vill du verkligen ta bort denna omvänd delning? Om du gör det, kommer de tillhörande delningarna också att raderas.",
// END /account/reverseShares
// /admin
"admin.title": "Administration",
"admin.button.users": "Användarhantering",
"admin.button.config": "Konfiguration",
"admin.version": "Version",
// END /admin
// /admin/users
"admin.users.title": "Användarhantering",
"admin.users.table.username": "Användarnamn",
"admin.users.table.email": "E-post",
"admin.users.table.admin": "Administratör",
"admin.users.edit.update.title": "Uppdatera användare {username}",
"admin.users.edit.update.admin-privileges": "Administratörsbehörigheter",
"admin.users.edit.update.change-password.title": "Ändra lösenord",
"admin.users.edit.update.change-password.field": "Nytt lösenord",
"admin.users.edit.update.change-password.button": "Spara nytt lösenord",
"admin.users.edit.update.notify.password.success": "Lösenordet har ändrats",
"admin.users.edit.delete.title": "Ta bort användare {username}",
"admin.users.edit.delete.description": "Vill du verkligen ta bort denna användare och alla deras delningar?",
// showCreateUserModal.tsx
"admin.users.modal.create.title": "Skapa användare",
"admin.users.modal.create.username": "Användarnamn",
"admin.users.modal.create.email": "E-post",
"admin.users.modal.create.password": "Lösenord",
"admin.users.modal.create.manual-password": "Sätt lösenord manuellt",
"admin.users.modal.create.manual-password.description": "Om den inte är markerad kommer användaren att få ett e-postmeddelande med en länk för att ange lösenordet.",
"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
// /upload
"upload.title": "Ladda upp",
"upload.notify.generic-error": "Ett fel uppstod när din delning skulle slutföras.",
"upload.notify.count-failed": "{count} filer kunde inte laddas upp. Försöker igen.",
// Dropzone.tsx
"upload.dropzone.title": "Ladde upp filer",
"upload.dropzone.description": "Drag och släpp filer här för att starta din delning. Vi kan endast acceptera filer som är mindre än {maxSize} totalt.",
"upload.dropzone.notify.file-too-big": "Dina filer överskrider den maximala storleken på {maxSize}.",
// FileList.tsx
"upload.filelist.name": "Namn",
"upload.filelist.size": "Storlek",
// showCreateUploadModal.tsx
"upload.modal.title": "Skapa delning",
"upload.modal.link.error.invalid": "Kan endast innehålla bokstäver, siffror, understreck och bindestreck",
"upload.modal.link.error.taken": "Denna länk används redan",
"upload.modal.not-signed-in": "Du är inte inloggad",
"upload.modal.not-signed-in-description": "Du kommer inte att kunna ta bort din delning manuellt och visa antalet besökare.",
"upload.modal.expires.never": "aldrig",
"upload.modal.expires.never-long": "Upphör aldrig",
"upload.modal.expires.error.too-long": "Förfallodatum överskrider maximalt utgångsdatum för {max}.",
"upload.modal.link.label": "Länk",
"upload.modal.expires.label": "Förfaller",
"upload.modal.expires.minute-singular": "Minut",
"upload.modal.expires.minute-plural": "Minuter",
"upload.modal.expires.hour-singular": "Timme",
"upload.modal.expires.hour-plural": "Timmar",
"upload.modal.expires.day-singular": "Dag",
"upload.modal.expires.day-plural": "Dagar",
"upload.modal.expires.week-singular": "Vecka",
"upload.modal.expires.week-plural": "Veckor",
"upload.modal.expires.month-singular": "Månad",
"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.email.title": "E-postmottagare",
"upload.modal.accordion.email.placeholder": "Ange e-postmottagare",
"upload.modal.accordion.email.invalid-email": "Ogiltig e-postadress",
"upload.modal.accordion.security.title": "Säkerhetsalternativ",
"upload.modal.accordion.security.password.label": "Lösenordsskydd",
"upload.modal.accordion.security.password.placeholder": "Inget lösenord",
"upload.modal.accordion.security.max-views.label": "Max antal visningar",
"upload.modal.accordion.security.max-views.placeholder": "Ingen gräns",
// showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "Denna delning kommer aldrig att upphöra.",
"upload.modal.completed.expires-on": "Denna delning upphör att gälla {expiration}.",
"upload.modal.completed.share-ready": "Delning redo",
// END /upload
// /share/[id]
"share.title": "Delning {shareId}",
"share.description": "Titta vad jag har delat med dig!",
"share.error.visitor-limit-exceeded.title": "Besökargränsen överskriden",
"share.error.visitor-limit-exceeded.description": "Gränsen för antalet besökare för denna delning har överskridits.",
"share.error.removed.title": "Delning borttagen",
"share.error.not-found.title": "Delningen hittades inte",
"share.error.not-found.description": "Delningen du letar efter existerar inte.",
"share.modal.password.title": "Lösenord krävs",
"share.modal.password.description": "För att komma åt denna delning, vänligen ange lösenordet för delningen.",
"share.modal.password": "Lösenord",
"share.modal.error.invalid-password": "Ogiltigt lösenord",
"share.button.download-all": "Ladda ner allt",
"share.notify.download-all-preparing": "Delningen förbereds. Försök igen om några minuter.",
"share.modal.file-link": "Fillänk",
"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": "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}",
"share.edit.append-upload": "Lägg till fil",
"share.edit.notify.generic-error": "Ett fel uppstod när din delning skulle slutföras.",
"share.edit.notify.save-success": "Delningen har uppdaterats",
// END /share/[id]/edit
// /admin/config
"admin.config.title": "Konfiguration",
"admin.config.category.general": "Allmänt",
"admin.config.category.share": "Delning",
"admin.config.category.email": "E-post",
"admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Inloggning via sociala nätverk",
"admin.config.general.app-name": "Appnamn",
"admin.config.general.app-name.description": "Namn på applikationen",
"admin.config.general.app-url": "Appens URL",
"admin.config.general.app-url.description": "På vilken URL Pingvin Share finns",
"admin.config.general.show-home-page": "Visa startsidan",
"admin.config.general.show-home-page.description": "Om du vill visa startsidan",
"admin.config.general.logo": "Logotyp",
"admin.config.general.logo.description": "Ändra din logotyp genom att ladda upp en ny bild. Bilden måste vara en PNG och bör ha formatet 1:1.",
"admin.config.general.logo.placeholder": "Välj bild",
"admin.config.email.enable-share-email-recipients": "Aktivera e-postmottagare för delning",
"admin.config.email.enable-share-email-recipients.description": "Om du vill tillåta e-post till delningsmottagare. Aktivera endast detta om du har aktiverat 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": "Meddelande som skickas till delningens mottagare. Tillgängliga variabler:\n {creator} - Användarnamnet för skaparen av delningen\n {shareUrl} - URL för delningen\n {desc} - Beskrivningen av delningen\n {expires} - Förfallodatumet för delningen\n Variablerna kommer att ersättas med det faktiska värdet.",
"admin.config.email.reverse-share-subject": "Omvänd delning ämne",
"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": "Återställ lösenord meddelande",
"admin.config.email.reset-password-message.description": "Meddelande som skickas när en användare begär en lösenordsåterställning. {url} kommer att ersättas med länken för lösenordsåterställningen.",
"admin.config.email.invite-subject": "Inbjudan ämne",
"admin.config.email.invite-subject.description": "Ämne i e-postmeddelandet som skickas när en administratör bjuder in en användare.",
"admin.config.email.invite-message": "Inbjudningsmeddelanden",
"admin.config.email.invite-message.description": "Meddelande som skickas när en administratör bjuder in en användare. {url} kommer att ersättas med inbjudningsadressen och {password} med lösenordet.",
"admin.config.share.allow-registration": "Tillåt registrering",
"admin.config.share.allow-registration.description": "Om registrering är tillåten",
"admin.config.share.allow-unauthenticated-shares": "Tillåt oautentiserade delningar",
"admin.config.share.allow-unauthenticated-shares.description": "Om oautentiserade användare kan skapa delningar",
"admin.config.share.max-expiration": "Max utgångsdatum",
"admin.config.share.max-expiration.description": "Max längd innan en delning förfaller i timmar. Sätt till 0 för att tillåta obegränsad förfallotid.",
"admin.config.share.max-size": "Max storlek",
"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": "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.smtp.enabled": "Aktiverad",
"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": "Adress",
"admin.config.smtp.host.description": "Adress för SMTP-servern",
"admin.config.smtp.port": "Port",
"admin.config.smtp.port.description": "Port för SMTP-servern",
"admin.config.smtp.email": "E-post",
"admin.config.smtp.email.description": "E-postadress som e-postmeddelanden skickas från",
"admin.config.smtp.username": "Användarnamn",
"admin.config.smtp.username.description": "Användarnamn för SMTP-servern",
"admin.config.smtp.password": "Lösenord",
"admin.config.smtp.password.description": "Lösenord för SMTP-servern",
"admin.config.smtp.button.test": "Skicka testmeddelande",
"admin.config.oauth.allow-registration": "Tillåt registrering",
"admin.config.oauth.allow-registration.description": "Tillåt användare att registrera sig via social inloggning",
"admin.config.oauth.ignore-totp": "Ignorera TOTP",
"admin.config.oauth.ignore-totp.description": "Om du vill ignorera TOTP när användaren använder social inloggning",
"admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Om GitHub-inloggning är aktiverad",
"admin.config.oauth.github-client-id": "GitHub Client ID",
"admin.config.oauth.github-client-id.description": "Client-ID för GitHub OAuth appen",
"admin.config.oauth.github-client-secret": "GitHub Client secret",
"admin.config.oauth.github-client-secret.description": "Client secret för GitHub OAuth appen",
"admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Om Google-inloggning är aktiverad",
"admin.config.oauth.google-client-id": "Google Client ID",
"admin.config.oauth.google-client-id.description": "Client-ID för Google OAuth appen",
"admin.config.oauth.google-client-secret": "Google Client secret",
"admin.config.oauth.google-client-secret.description": "Client secret för Google OAuth appen",
"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-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",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID login is enabled",
"admin.config.oauth.oidc-discovery-uri": "OpenID Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID OAuth app",
"admin.config.oauth.oidc-client-id": "OpenID Client ID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID OAuth app",
"admin.config.oauth.oidc-client-secret": "OpenID Client secret",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID OAuth app",
// 404
"404.description": "Hoppsan den här sidan finns inte.",
"404.button.home": "Ta mig tillbaka hem",
// error
"error.title": "Fel",
"error.description": "Hoppsan!",
"error.button.back": "Gå tillbaka",
"error.msg.default": "Någonting gick fel.",
"error.msg.access_denied": "Du avbröt autentiseringsprocessen, försök igen.",
"error.msg.expired_token": "Autentiseringsprocessen tog för lång tid, försök igen.",
"error.msg.no_user": "Användare som är länkad till detta {0} konto finns inte.",
"error.msg.no_email": "Kan inte hämta e-postadress från detta {0} konto.",
"error.msg.already_linked": "Detta {0} konto är redan länkat till ett annat konto.",
"error.msg.not_linked": "Detta {0} konto har ännu inte länkat till något konto.",
"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",
// Common translations
"common.button.save": "Spara",
"common.button.create": "Skapa",
"common.button.submit": "Skicka",
"common.button.delete": "Ta bort",
"common.button.cancel": "Avbryt",
"common.button.confirm": "Bekräfta",
"common.button.disable": "Inaktivera",
"common.button.share": "Delning",
"common.button.generate": "Generera",
"common.button.done": "Klar",
"common.text.link": "Länk",
"common.text.or": "eller",
"common.button.go-back": "Gå tillbaka",
"common.notify.copied": "Din länk har kopierats till urklipp",
"common.success": "Slutförd",
"common.error": "Fel",
"common.error.unknown": "Ett okänt fel har uppstått",
"common.error.invalid-email": "Ogiltig e-postadress",
"common.error.too-short": "Måste minst vara {length} tecken långt",
"common.error.too-long": "Får högst innehålla {length} tecken",
"common.error.exact-length": "Måste vara exakt {length} tecken långt",
"common.error.invalid-number": "Måste vara ett tal",
"common.error.field-required": "Obligatoriskt fält"
};

View File

@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "คุณจะไม่สามารถลบการแชร์ของคุณด้วยตนเองและดูจำนวนผู้เข้าชมได้", "upload.modal.not-signed-in-description": "คุณจะไม่สามารถลบการแชร์ของคุณด้วยตนเองและดูจำนวนผู้เข้าชมได้",
"upload.modal.expires.never": "ไม่มีกำหนด", "upload.modal.expires.never": "ไม่มีกำหนด",
"upload.modal.expires.never-long": "ไม่มีกำหนดหมดอายุ", "upload.modal.expires.never-long": "ไม่มีกำหนดหมดอายุ",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "ลิงค์", "upload.modal.link.label": "ลิงค์",
"upload.modal.expires.label": "หมดอายุ", "upload.modal.expires.label": "หมดอายุ",
"upload.modal.expires.minute-singular": "นาที", "upload.modal.expires.minute-singular": "นาที",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "ไม่รองรับการแสดงตัวอย่าง", "share.modal.file-preview.error.not-supported.title": "ไม่รองรับการแสดงตัวอย่าง",
"share.modal.file-preview.error.not-supported.description": "ไม่รองรับการแสดงตัวอย่างสำหรับไฟล์ประเภทนี้ โปรดดาวน์โหลดไฟล์เพื่อดู", "share.modal.file-preview.error.not-supported.description": "ไม่รองรับการแสดงตัวอย่างสำหรับไฟล์ประเภทนี้ โปรดดาวน์โหลดไฟล์เพื่อดู",
// END /share/[id] // 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
"admin.config.title": "การตั้งค่า", "admin.config.title": "การตั้งค่า",
"admin.config.category.general": "ทั่วไป", "admin.config.category.general": "ทั่วไป",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "อนุญาตให้ผู้ใช้ลงทะเบียนด้วยตัวเองเพื่อสร้างแชร์", "admin.config.share.allow-registration.description": "อนุญาตให้ผู้ใช้ลงทะเบียนด้วยตัวเองเพื่อสร้างแชร์",
"admin.config.share.allow-unauthenticated-shares": "อนุญาตให้แชร์โดยไม่ต้องเข้าสู่ระบบ", "admin.config.share.allow-unauthenticated-shares": "อนุญาตให้แชร์โดยไม่ต้องเข้าสู่ระบบ",
"admin.config.share.allow-unauthenticated-shares.description": "อนุญาตให้ผู้ใช้ที่ไม่ได้เข้าสู่ระบบสร้างแชร์", "admin.config.share.allow-unauthenticated-shares.description": "อนุญาตให้ผู้ใช้ที่ไม่ได้เข้าสู่ระบบสร้างแชร์",
"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": "ขนาดสูงสุด", "admin.config.share.max-size": "ขนาดสูงสุด",
"admin.config.share.max-size.description": "ขนาดสูงสุดของแชร์", "admin.config.share.max-size.description": "ขนาดสูงสุดของแชร์",
"admin.config.share.zip-compression-level": "ระดับการบีบอัดไฟล์ Zip", "admin.config.share.zip-compression-level": "ระดับการบีบอัดไฟล์ Zip",

View File

@@ -214,6 +214,7 @@ export default {
"upload.modal.not-signed-in-description": "你将不能删除你的共享或查看访问次数", "upload.modal.not-signed-in-description": "你将不能删除你的共享或查看访问次数",
"upload.modal.expires.never": "永不", "upload.modal.expires.never": "永不",
"upload.modal.expires.never-long": "永不过期", "upload.modal.expires.never-long": "永不过期",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "共享链接", "upload.modal.link.label": "共享链接",
"upload.modal.expires.label": "过期时间", "upload.modal.expires.label": "过期时间",
"upload.modal.expires.minute-singular": "1 分钟", "upload.modal.expires.minute-singular": "1 分钟",
@@ -263,6 +264,12 @@ export default {
"share.modal.file-preview.error.not-supported.title": "该文件类型不支持预览", "share.modal.file-preview.error.not-supported.title": "该文件类型不支持预览",
"share.modal.file-preview.error.not-supported.description": "该文件类型不支持预览,请下载后打开查看", "share.modal.file-preview.error.not-supported.description": "该文件类型不支持预览,请下载后打开查看",
// END /share/[id] // 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
"admin.config.title": "配置管理", "admin.config.title": "配置管理",
"admin.config.category.general": "通用", "admin.config.category.general": "通用",
@@ -301,6 +308,8 @@ export default {
"admin.config.share.allow-registration.description": "是否允许注册", "admin.config.share.allow-registration.description": "是否允许注册",
"admin.config.share.allow-unauthenticated-shares": "是否允许未验证的共享", "admin.config.share.allow-unauthenticated-shares": "是否允许未验证的共享",
"admin.config.share.allow-unauthenticated-shares.description": "是否允许未验证的用户创建共享", "admin.config.share.allow-unauthenticated-shares.description": "是否允许未验证的用户创建共享",
"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": "最大文件上限", "admin.config.share.max-size": "最大文件上限",
"admin.config.share.max-size.description": "最大文件上限,单位 bytes (1GB=1024MB=1048576KB=1073741824bytes)", "admin.config.share.max-size.description": "最大文件上限,单位 bytes (1GB=1024MB=1048576KB=1073741824bytes)",
"admin.config.share.zip-compression-level": "Zip compression level", "admin.config.share.zip-compression-level": "Zip compression level",

View File

@@ -77,6 +77,7 @@ const MyShares = () => {
showCreateReverseShareModal( showCreateReverseShareModal(
modals, modals,
config.get("smtp.enabled"), config.get("smtp.enabled"),
config.get("share.maxExpiration"),
getReverseShares, getReverseShares,
) )
} }

View File

@@ -16,7 +16,7 @@ import { useModals } from "@mantine/modals";
import moment from "moment"; import moment from "moment";
import Link from "next/link"; import Link from "next/link";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { TbInfoCircle, TbLink, TbTrash } from "react-icons/tb"; import { TbEdit, TbInfoCircle, TbLink, TbTrash } from "react-icons/tb";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import Meta from "../../components/Meta"; import Meta from "../../components/Meta";
import showShareInformationsModal from "../../components/account/showShareInformationsModal"; import showShareInformationsModal from "../../components/account/showShareInformationsModal";
@@ -110,6 +110,11 @@ const MyShares = () => {
</td> </td>
<td> <td>
<Group position="right"> <Group position="right">
<Link href={`/share/${share.id}/edit`}>
<ActionIcon color="orange" variant="light" size={25}>
<TbEdit />
</ActionIcon>
</Link>
<ActionIcon <ActionIcon
color="blue" color="blue"
variant="light" variant="light"

View File

@@ -0,0 +1,65 @@
import { LoadingOverlay } from "@mantine/core";
import { useModals } from "@mantine/modals";
import { GetServerSidePropsContext } from "next";
import { useEffect, useState } from "react";
import showErrorModal from "../../../components/share/showErrorModal";
import shareService from "../../../services/share.service";
import { Share as ShareType } from "../../../types/share.type";
import useTranslate from "../../../hooks/useTranslate.hook";
import EditableUpload from "../../../components/upload/EditableUpload";
import Meta from "../../../components/Meta";
export function getServerSideProps(context: GetServerSidePropsContext) {
return {
props: { shareId: context.params!.shareId },
};
}
const Share = ({ shareId }: { shareId: string }) => {
const t = useTranslate();
const modals = useModals();
const [isLoading, setIsLoading] = useState(true);
const [share, setShare] = useState<ShareType>();
useEffect(() => {
shareService
.getFromOwner(shareId)
.then((share) => {
setShare(share);
})
.catch((e) => {
const { error } = e.response.data;
if (e.response.status == 404) {
if (error == "share_removed") {
showErrorModal(
modals,
t("share.error.removed.title"),
e.response.data.message,
);
} else {
showErrorModal(
modals,
t("share.error.not-found.title"),
t("share.error.not-found.description"),
);
}
} else {
showErrorModal(modals, t("common.error"), t("common.error.unknown"));
}
})
.finally(() => {
setIsLoading(false);
});
}, []);
if (isLoading) return <LoadingOverlay visible />;
return (
<>
<Meta title={t("share.edit.title", { shareId })} />
<EditableUpload shareId={shareId} files={share?.files || []} />
</>
);
};
export default Share;

View File

@@ -42,7 +42,14 @@ const Upload = ({
const uploadFiles = async (share: CreateShare, files: FileUpload[]) => { const uploadFiles = async (share: CreateShare, files: FileUpload[]) => {
setisUploading(true); setisUploading(true);
createdShare = await shareService.create(share);
try {
createdShare = await shareService.create(share);
} catch (e) {
toast.axiosError(e);
setisUploading(false);
return;
}
const fileUploadPromises = files.map(async (file, fileIndex) => const fileUploadPromises = files.map(async (file, fileIndex) =>
// Limit the number of concurrent uploads to 3 // Limit the number of concurrent uploads to 3
@@ -132,6 +139,7 @@ const Upload = ({
"share.allowUnauthenticatedShares", "share.allowUnauthenticatedShares",
), ),
enableEmailRecepients: config.get("email.enableShareEmailRecipients"), enableEmailRecepients: config.get("email.enableShareEmailRecipients"),
maxExpirationInHours: config.get("share.maxExpiration"),
}, },
files, files,
uploadFiles, uploadFiles,
@@ -194,7 +202,9 @@ const Upload = ({
showCreateUploadModalCallback={showCreateUploadModalCallback} showCreateUploadModalCallback={showCreateUploadModalCallback}
isUploading={isUploading} isUploading={isUploading}
/> />
{files.length > 0 && <FileList files={files} setFiles={setFiles} />} {files.length > 0 && (
<FileList<FileUpload> files={files} setFiles={setFiles} />
)}
</> </>
); );
}; };

View File

@@ -19,10 +19,18 @@ const completeShare = async (id: string) => {
return (await api.post(`shares/${id}/complete`)).data; return (await api.post(`shares/${id}/complete`)).data;
}; };
const revertComplete = async (id: string) => {
return (await api.delete(`shares/${id}/complete`)).data;
};
const get = async (id: string): Promise<Share> => { const get = async (id: string): Promise<Share> => {
return (await api.get(`shares/${id}`)).data; return (await api.get(`shares/${id}`)).data;
}; };
const getFromOwner = async (id: string): Promise<Share> => {
return (await api.get(`shares/${id}/from-owner`)).data;
};
const getMetaData = async (id: string): Promise<ShareMetaData> => { const getMetaData = async (id: string): Promise<ShareMetaData> => {
return (await api.get(`shares/${id}/metaData`)).data; return (await api.get(`shares/${id}/metaData`)).data;
}; };
@@ -63,6 +71,10 @@ const downloadFile = async (shareId: string, fileId: string) => {
window.location.href = `${window.location.origin}/api/shares/${shareId}/files/${fileId}`; window.location.href = `${window.location.origin}/api/shares/${shareId}/files/${fileId}`;
}; };
const removeFile = async (shareId: string, fileId: string) => {
await api.delete(`shares/${shareId}/files/${fileId}`);
};
const uploadFile = async ( const uploadFile = async (
shareId: string, shareId: string,
readerEvent: ProgressEvent<FileReader>, readerEvent: ProgressEvent<FileReader>,
@@ -121,14 +133,17 @@ const removeReverseShare = async (id: string) => {
export default { export default {
create, create,
completeShare, completeShare,
revertComplete,
getShareToken, getShareToken,
get, get,
getFromOwner,
remove, remove,
getMetaData, getMetaData,
doesFileSupportPreview, doesFileSupportPreview,
getMyShares, getMyShares,
isShareIdAvailable, isShareIdAvailable,
downloadFile, downloadFile,
removeFile,
uploadFile, uploadFile,
setReverseShare, setReverseShare,
createReverseShare, createReverseShare,

View File

@@ -7,3 +7,5 @@ export type FileMetaData = {
name: string; name: string;
size: string; size: string;
}; };
export type FileListItem = FileUpload | (FileMetaData & { deleted?: boolean });

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share", "name": "pingvin-share",
"version": "0.19.0", "version": "0.20.2",
"scripts": { "scripts": {
"format": "cd frontend && npm run format && cd ../backend && npm run format", "format": "cd frontend && npm run format && cd ../backend && npm run format",
"lint": "cd frontend && npm run lint && cd ../backend && npm run lint", "lint": "cd frontend && npm run lint && cd ../backend && npm run lint",