Compare commits

..

6 Commits

Author SHA1 Message Date
Elias Schneider
0670aaa331 release: 1.0.3 2024-09-03 22:56:19 +02:00
Elias Schneider
10b71e7035 chore(translations): update translations via Crowdin (#580)
* New translations en-us.ts (Bulgarian)

* New translations en-us.ts (Bulgarian)

* New translations en-us.ts (Czech)

* New translations en-us.ts (German)

* New translations en-us.ts (Czech)

* New translations en-us.ts (Bulgarian)

* New translations en-us.ts (Italian)

* New translations en-us.ts (French)

* New translations en-us.ts (Czech)
2024-09-03 22:56:05 +02:00
Elias Schneider
dee70987eb fix: improve oidc error logging 2024-09-03 22:55:44 +02:00
Elias Schneider
3d2b978daf refactor: run formatter 2024-09-03 22:54:53 +02:00
Elias Schneider
e813da05ae chore(translations): add Bulgarian language files 2024-08-30 08:33:26 +02:00
Elias Schneider
1fba0fd546 chore(translations): update translations via Crowdin (#571)
* New translations en-us.ts (Vietnamese)

* New translations en-us.ts (Vietnamese)
2024-08-30 08:32:29 +02:00
22 changed files with 863 additions and 321 deletions

View File

@@ -1,3 +1,10 @@
## [1.0.3](https://github.com/stonith404/pingvin-share/compare/v1.0.2...v1.0.3) (2024-09-03)
### Bug Fixes
* improve oidc error logging ([dee7098](https://github.com/stonith404/pingvin-share/commit/dee70987eb74eda4a9ab7332522fa5540cee9761))
## [1.0.2](https://github.com/stonith404/pingvin-share/compare/v1.0.1...v1.0.2) (2024-08-28) ## [1.0.2](https://github.com/stonith404/pingvin-share/compare/v1.0.1...v1.0.2) (2024-08-28)

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.0.2", "version": "1.0.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.0.2", "version": "1.0.3",
"dependencies": { "dependencies": {
"@nestjs/cache-manager": "^2.2.2", "@nestjs/cache-manager": "^2.2.2",
"@nestjs/common": "^10.3.9", "@nestjs/common": "^10.3.9",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.0.2", "version": "1.0.3",
"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

@@ -20,4 +20,4 @@ import { UserModule } from "../user/user.module";
providers: [AuthService, AuthTotpService, JwtStrategy, LdapService], providers: [AuthService, AuthTotpService, JwtStrategy, LdapService],
exports: [AuthService], exports: [AuthService],
}) })
export class AuthModule { } export class AuthModule {}

View File

@@ -29,7 +29,7 @@ export class AuthService {
private emailService: EmailService, private emailService: EmailService,
private ldapService: LdapService, private ldapService: LdapService,
private userService: UserSevice, private userService: UserSevice,
) { } ) {}
private readonly logger = new Logger(AuthService.name); private readonly logger = new Logger(AuthService.name);
async signUp(dto: AuthRegisterDTO, ip: string, isAdmin?: boolean) { async signUp(dto: AuthRegisterDTO, ip: string, isAdmin?: boolean) {
@@ -76,18 +76,28 @@ export class AuthService {
}, },
}); });
if (user?.password && await argon.verify(user.password, dto.password)) { if (user?.password && (await argon.verify(user.password, dto.password))) {
this.logger.log(`Successful password login for user ${user.email} from IP ${ip}`); this.logger.log(
`Successful password login for user ${user.email} from IP ${ip}`,
);
return this.generateToken(user); return this.generateToken(user);
} }
} }
if (this.config.get("ldap.enabled")) { if (this.config.get("ldap.enabled")) {
this.logger.debug(`Trying LDAP login for user ${dto.username}`); this.logger.debug(`Trying LDAP login for user ${dto.username}`);
const ldapUser = await this.ldapService.authenticateUser(dto.username, dto.password); const ldapUser = await this.ldapService.authenticateUser(
dto.username,
dto.password,
);
if (ldapUser) { if (ldapUser) {
const user = await this.userService.findOrCreateFromLDAP(dto.username, ldapUser); const user = await this.userService.findOrCreateFromLDAP(
this.logger.log(`Successful LDAP login for user ${user.email} from IP ${ip}`); dto.username,
ldapUser,
);
this.logger.log(
`Successful LDAP login for user ${user.email} from IP ${ip}`,
);
return this.generateToken(user); return this.generateToken(user);
} }
} }

View File

@@ -1,16 +1,26 @@
import { Inject, Injectable, Logger } from "@nestjs/common"; import { Inject, Injectable, Logger } from "@nestjs/common";
import * as ldap from "ldapjs"; import * as ldap from "ldapjs";
import { AttributeJson, InvalidCredentialsError, SearchCallbackResponse, SearchOptions } from "ldapjs"; import {
AttributeJson,
InvalidCredentialsError,
SearchCallbackResponse,
SearchOptions,
} from "ldapjs";
import { inspect } from "node:util"; import { inspect } from "node:util";
import { ConfigService } from "../config/config.service"; import { ConfigService } from "../config/config.service";
type LdapSearchEntry = { type LdapSearchEntry = {
objectName: string, objectName: string;
attributes: AttributeJson[], attributes: AttributeJson[];
}; };
async function ldapExecuteSearch(client: ldap.Client, base: string, options: SearchOptions): Promise<LdapSearchEntry[]> { async function ldapExecuteSearch(
const searchResponse = await new Promise<SearchCallbackResponse>((resolve, reject) => { client: ldap.Client,
base: string,
options: SearchOptions,
): Promise<LdapSearchEntry[]> {
const searchResponse = await new Promise<SearchCallbackResponse>(
(resolve, reject) => {
client.search(base, options, (err, res) => { client.search(base, options, (err, res) => {
if (err) { if (err) {
reject(err); reject(err);
@@ -18,45 +28,62 @@ async function ldapExecuteSearch(client: ldap.Client, base: string, options: Sea
resolve(res); resolve(res);
} }
}); });
}); },
);
return await new Promise<any[]>((resolve, reject) => { return await new Promise<any[]>((resolve, reject) => {
const entries: LdapSearchEntry[] = []; const entries: LdapSearchEntry[] = [];
searchResponse.on("searchEntry", entry => entries.push({ attributes: entry.pojo.attributes, objectName: entry.pojo.objectName })); searchResponse.on("searchEntry", (entry) =>
entries.push({
attributes: entry.pojo.attributes,
objectName: entry.pojo.objectName,
}),
);
searchResponse.once("error", reject); searchResponse.once("error", reject);
searchResponse.once("end", () => resolve(entries)); searchResponse.once("end", () => resolve(entries));
}); });
} }
async function ldapBindUser(client: ldap.Client, dn: string, password: string): Promise<void> { async function ldapBindUser(
client: ldap.Client,
dn: string,
password: string,
): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
client.bind(dn, password, error => { client.bind(dn, password, (error) => {
if (error) { if (error) {
reject(error); reject(error);
} else { } else {
resolve(); resolve();
} }
}); });
}) });
} }
async function ldapCreateConnection(logger: Logger, url: string): Promise<ldap.Client> { async function ldapCreateConnection(
logger: Logger,
url: string,
): Promise<ldap.Client> {
const ldapClient = ldap.createClient({ const ldapClient = ldap.createClient({
url: url.split(","), url: url.split(","),
connectTimeout: 10_000, connectTimeout: 10_000,
timeout: 10_000 timeout: 10_000,
}); });
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
ldapClient.once("error", reject); ldapClient.once("error", reject);
ldapClient.on("setupError", reject); ldapClient.on("setupError", reject);
ldapClient.on("socketTimeout", reject); ldapClient.on("socketTimeout", reject);
ldapClient.on("connectRefused", () => reject(new Error("connection has been refused"))); ldapClient.on("connectRefused", () =>
ldapClient.on("connectTimeout", () => reject(new Error("connect timed out"))); reject(new Error("connection has been refused")),
);
ldapClient.on("connectTimeout", () =>
reject(new Error("connect timed out")),
);
ldapClient.on("connectError", reject); ldapClient.on("connectError", reject);
ldapClient.on("connect", resolve); ldapClient.on("connect", resolve);
}).catch(error => { }).catch((error) => {
logger.error(`Connect error: ${inspect(error)}`); logger.error(`Connect error: ${inspect(error)}`);
ldapClient.destroy(); ldapClient.destroy();
throw error; throw error;
@@ -66,8 +93,8 @@ async function ldapCreateConnection(logger: Logger, url: string): Promise<ldap.C
} }
export type LdapAuthenticateResult = { export type LdapAuthenticateResult = {
userDn: string, userDn: string;
attributes: Record<string, string[]> attributes: Record<string, string[]>;
}; };
@Injectable() @Injectable()
@@ -76,7 +103,7 @@ export class LdapService {
constructor( constructor(
@Inject(ConfigService) @Inject(ConfigService)
private readonly serviceConfig: ConfigService, private readonly serviceConfig: ConfigService,
) { } ) {}
private async createLdapConnection(): Promise<ldap.Client> { private async createLdapConnection(): Promise<ldap.Client> {
const ldapUrl = this.serviceConfig.get("ldap.url"); const ldapUrl = this.serviceConfig.get("ldap.url");
@@ -89,7 +116,11 @@ export class LdapService {
const bindDn = this.serviceConfig.get("ldap.bindDn") || null; const bindDn = this.serviceConfig.get("ldap.bindDn") || null;
if (bindDn) { if (bindDn) {
try { try {
await ldapBindUser(ldapClient, bindDn, this.serviceConfig.get("ldap.bindPassword")) await ldapBindUser(
ldapClient,
bindDn,
this.serviceConfig.get("ldap.bindPassword"),
);
} catch (error) { } catch (error) {
this.logger.warn(`Failed to bind to default user: ${error}`); this.logger.warn(`Failed to bind to default user: ${error}`);
throw new Error("failed to bind to default user"); throw new Error("failed to bind to default user");
@@ -103,20 +134,24 @@ export class LdapService {
} }
} }
public async authenticateUser(username: string, password: string): Promise<LdapAuthenticateResult | null> { public async authenticateUser(
username: string,
password: string,
): Promise<LdapAuthenticateResult | null> {
if (!username.match(/^[a-zA-Z0-0]+$/)) { if (!username.match(/^[a-zA-Z0-0]+$/)) {
return null; return null;
} }
const searchBase = this.serviceConfig.get("ldap.searchBase"); const searchBase = this.serviceConfig.get("ldap.searchBase");
const searchQuery = this.serviceConfig.get("ldap.searchQuery") const searchQuery = this.serviceConfig
.get("ldap.searchQuery")
.replaceAll("%username%", username); .replaceAll("%username%", username);
const ldapClient = await this.createLdapConnection(); const ldapClient = await this.createLdapConnection();
try { try {
const [result] = await ldapExecuteSearch(ldapClient, searchBase, { const [result] = await ldapExecuteSearch(ldapClient, searchBase, {
filter: searchQuery, filter: searchQuery,
scope: "sub" scope: "sub",
}); });
if (!result) { if (!result) {
@@ -134,7 +169,12 @@ export class LdapService {
*/ */
return { return {
userDn: result.objectName, userDn: result.objectName,
attributes: Object.fromEntries(result.attributes.map(attribute => [attribute.type, attribute.values])), attributes: Object.fromEntries(
result.attributes.map((attribute) => [
attribute.type,
attribute.values,
]),
),
}; };
} catch (error) { } catch (error) {
if (error instanceof InvalidCredentialsError) { if (error instanceof InvalidCredentialsError) {

View File

@@ -1,13 +1,13 @@
import { Logger } from "@nestjs/common"; import { InternalServerErrorException, Logger } from "@nestjs/common";
import { ConfigService } from "../../config/config.service";
import { JwtService } from "@nestjs/jwt"; import { JwtService } from "@nestjs/jwt";
import { Cache } from "cache-manager"; import { Cache } from "cache-manager";
import * as jmespath from "jmespath"; import * as jmespath from "jmespath";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { ConfigService } from "../../config/config.service";
import { OAuthCallbackDto } from "../dto/oauthCallback.dto"; import { OAuthCallbackDto } from "../dto/oauthCallback.dto";
import { OAuthProvider, OAuthToken } from "./oauthProvider.interface";
import { OAuthSignInDto } from "../dto/oauthSignIn.dto"; import { OAuthSignInDto } from "../dto/oauthSignIn.dto";
import { ErrorPageException } from "../exceptions/errorPage.exception"; import { ErrorPageException } from "../exceptions/errorPage.exception";
import { OAuthProvider, OAuthToken } from "./oauthProvider.interface";
export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> { export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
protected discoveryUri: string; protected discoveryUri: string;
@@ -116,7 +116,13 @@ export abstract class GenericOidcProvider implements OAuthProvider<OidcToken> {
}, },
): Promise<OAuthSignInDto> { ): Promise<OAuthSignInDto> {
const idTokenData = this.decodeIdToken(token.idToken); const idTokenData = this.decodeIdToken(token.idToken);
// maybe it's not necessary to verify the id token since it's directly obtained from the provider
if (!idTokenData) {
this.logger.error(
`Can not get ID Token from response ${JSON.stringify(token.rawToken, undefined, 2)}`,
);
throw new InternalServerErrorException();
}
const key = `oauth-${this.name}-nonce-${query.state}`; const key = `oauth-${this.name}-nonce-${query.state}`;
const nonce = await this.cache.get(key); const nonce = await this.cache.get(key);

View File

@@ -34,7 +34,9 @@ export class UserDTO {
totpVerified: boolean; totpVerified: boolean;
from(partial: Partial<UserDTO>) { from(partial: Partial<UserDTO>) {
const result = plainToClass(UserDTO, partial, { excludeExtraneousValues: true }); const result = plainToClass(UserDTO, partial, {
excludeExtraneousValues: true,
});
result.isLdap = partial.ldapDN?.length > 0; result.isLdap = partial.ldapDN?.length > 0;
return result; return result;
} }

View File

@@ -8,6 +8,6 @@ import { FileModule } from "src/file/file.module";
imports: [EmailModule, FileModule], imports: [EmailModule, FileModule],
providers: [UserSevice], providers: [UserSevice],
controllers: [UserController], controllers: [UserController],
exports: [UserSevice] exports: [UserSevice],
}) })
export class UserModule { } export class UserModule {}

View File

@@ -17,7 +17,7 @@ export class UserSevice {
private emailService: EmailService, private emailService: EmailService,
private fileService: FileService, private fileService: FileService,
private configService: ConfigService, private configService: ConfigService,
) { } ) {}
async list() { async list() {
return await this.prisma.user.findMany(); return await this.prisma.user.findMany();
@@ -94,7 +94,9 @@ export class UserSevice {
async findOrCreateFromLDAP(username: string, ldap: LdapAuthenticateResult) { async findOrCreateFromLDAP(username: string, ldap: LdapAuthenticateResult) {
const passwordHash = await argon.hash(crypto.randomUUID()); const passwordHash = await argon.hash(crypto.randomUUID());
const userEmail = ldap.attributes["userPrincipalName"]?.at(0) ?? `${crypto.randomUUID()}@ldap.local`; const userEmail =
ldap.attributes["userPrincipalName"]?.at(0) ??
`${crypto.randomUUID()}@ldap.local`;
const adminGroup = this.configService.get("ldap.adminGroups"); const adminGroup = this.configService.get("ldap.adminGroups");
const isAdmin = ldap.attributes["memberOf"]?.includes(adminGroup) ?? false; const isAdmin = ldap.attributes["memberOf"]?.includes(adminGroup) ?? false;
try { try {
@@ -114,8 +116,8 @@ export class UserSevice {
ldapDN: ldap.userDn, ldapDN: ldap.userDn,
}, },
where: { where: {
ldapDN: ldap.userDn ldapDN: ldap.userDn,
} },
}); });
} catch (e) { } catch (e) {
if (e instanceof PrismaClientKnownRequestError) { if (e instanceof PrismaClientKnownRequestError) {

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "1.0.2", "version": "1.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "1.0.2", "version": "1.0.3",
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.4", "@emotion/react": "^11.11.4",
"@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": "1.0.2", "version": "1.0.3",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",

View File

@@ -24,6 +24,7 @@ import chineseTraditional from "./translations/zh-TW";
import turkish from "./translations/tr-TR"; import turkish from "./translations/tr-TR";
import czech from "./translations/cs-CZ"; import czech from "./translations/cs-CZ";
import viatnamese from "./translations/vi-VN"; import viatnamese from "./translations/vi-VN";
import bulgarian from "./translations/bg-BG";
export const LOCALES = { export const LOCALES = {
ENGLISH: { ENGLISH: {
@@ -156,4 +157,9 @@ export const LOCALES = {
code: "vi-VN", code: "vi-VN",
messages: viatnamese, messages: viatnamese,
}, },
BULGARIAN: {
name: "Български",
code: "bg-BG",
messages: bulgarian,
},
}; };

View File

@@ -0,0 +1,471 @@
export default {
// Navbar
"navbar.upload": "Upload",
"navbar.signin": "Sign in",
"navbar.home": "Home",
"navbar.signup": "Sign Up",
"navbar.links.shares": "My shares",
"navbar.links.reverse": "Обратни споделяния",
"navbar.avatar.account": "My account",
"navbar.avatar.admin": "Administration",
"navbar.avatar.signout": "Sign out",
// END navbar
// /
"home.title": "A <h>self-hosted</h> file sharing platform.",
"home.description": "Do you really want to give your personal files in the hand of third parties like WeTransfer?",
"home.bullet.a.name": "Self-Hosted",
"home.bullet.a.description": "Host Pingvin Share on your own machine.",
"home.bullet.b.name": "Privacy",
"home.bullet.b.description": "Your files are your files and should never get into the hands of third parties.",
"home.bullet.c.name": "No annoying file size limit",
"home.bullet.c.description": "Upload as big files as you want. Only your hard drive will be your limit.",
"home.button.start": "Get started",
"home.button.source": "Source code",
// END /
// /auth/signin
"signin.title": "Welcome back",
"signin.description": "You don't have an account yet?",
"signin.button.signup": "Sign up",
"signin.input.email-or-username": "Email or username",
"signin.input.email-or-username.placeholder": "Your email or username",
"signin.input.password": "Password",
"signin.input.password.placeholder": "Your password",
"signin.button.submit": "Вписване",
"signIn.notify.totp-required.title": "Two-factor authentication required",
"signIn.notify.totp-required.description": "Please enter your two-factor authentication code",
"signIn.oauth.or": "OR",
"signIn.oauth.signInWith": "Sign in with",
"signIn.oauth.github": "GitHub",
"signIn.oauth.google": "Google",
"signIn.oauth.microsoft": "Microsoft",
"signIn.oauth.discord": "Discord",
"signIn.oauth.oidc": "OpenID",
// END /auth/signin
// /auth/signup
"signup.title": "Create an account",
"signup.description": "Already have an account?",
"signup.button.signin": "Sign in",
"signup.input.username": "Username",
"signup.input.username.placeholder": "Your username",
"signup.input.email": "Email",
"signup.input.email.placeholder": "Your email",
"signup.button.submit": "Let's get started",
// END /auth/signup
// /auth/totp
"totp.title": "TOTP Authentication",
"totp.button.signIn": "Sign in",
// END /auth/totp
// /auth/reset-password
"resetPassword.title": "Forgot your password?",
"resetPassword.description": "Enter your email to reset your password.",
"resetPassword.notify.success": "В случай, че имейлът съществува ще бъде изпратено съобщение с връзка за възстановяване на паролата.",
"resetPassword.button.back": "Back to sign in page",
"resetPassword.text.resetPassword": "Reset password",
"resetPassword.text.enterNewPassword": "Въведете нова парола",
"resetPassword.input.password": "Нова парола",
"resetPassword.notify.passwordReset": "Your password has been reset successfully.",
// /account
"account.title": "My account",
"account.card.info.title": "Account info",
"account.card.info.username": "Username",
"account.card.info.email": "Email",
"account.notify.info.success": "Account updated successfully",
"account.card.password.title": "Password",
"account.card.password.old": "Old password",
"account.card.password.new": "New password",
"account.card.password.noPasswordSet": "You don't have a password set. If you want to sign in with email and password you need to set a password.",
"account.notify.password.success": "Password changed successfully",
"account.card.oauth.title": "Social login",
"account.card.oauth.github": "GitHub",
"account.card.oauth.google": "Google",
"account.card.oauth.microsoft": "Microsoft",
"account.card.oauth.discord": "Discord",
"account.card.oauth.oidc": "OpenID",
"account.card.oauth.link": "Link",
"account.card.oauth.unlink": "Unlink",
"account.card.oauth.unlinked": "Unlinked",
"account.modal.unlink.title": "Unlink account",
"account.modal.unlink.description": "Unlinking your social accounts may cause you to lose your account if you don't remember your username and password.",
"account.notify.oauth.unlinked.success": "Unlinked successfully",
"account.card.security.title": "Security",
"account.card.security.totp.enable.description": "Enter your current password to start enabling TOTP",
"account.card.security.totp.disable.description": "Enter your current password to disable TOTP",
"account.card.security.totp.button.start": "Start",
"account.modal.totp.title": "Enable TOTP",
"account.modal.totp.step1": "Step 1: Add your authenticator",
"account.modal.totp.step2": "Step 2: Validate your code",
"account.modal.totp.enterManually": "Enter manually",
"account.modal.totp.code": "Code",
"common.button.clickToCopy": "Click to copy",
"account.modal.totp.verify": "Verify",
"account.notify.totp.disable": "TOTP disabled successfully",
"account.notify.totp.enable": "TOTP enabled successfully",
"account.card.language.title": "Language",
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.",
"account.card.color.title": "Color scheme",
// ThemeSwitcher.tsx
"account.theme.dark": "Dark",
"account.theme.light": "Light",
"account.theme.system": "System",
"account.button.delete": "Delete Account",
"account.modal.delete.title": "Delete Account",
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?",
// END /account
// /account/shares
"account.shares.title": "My shares",
"account.shares.title.empty": "It's empty here 👀",
"account.shares.description.empty": "You don't have any shares.",
"account.shares.button.create": "Create one",
"account.shares.info.title": "Share informations",
"account.shares.table.id": "ID",
"account.shares.table.name": "Име",
"account.shares.table.description": "Description",
"account.shares.table.visitors": "Посетители",
"account.shares.table.expiresAt": "Expires at",
"account.shares.table.createdAt": "Created at",
"account.shares.table.size": "Size",
"account.shares.modal.share-informations": "Share informations",
"account.shares.modal.share-link": "Share link",
"account.shares.modal.delete.title": "Delete share {share}",
"account.shares.modal.delete.description": "Do you really want to delete this share?",
// END /account/shares
// /account/reverseShares
"account.reverseShares.title": "Reverse shares",
"account.reverseShares.description": "A reverse share allows you to generate a unique URL that allows external users to create a share.",
"account.reverseShares.title.empty": "It's empty here 👀",
"account.reverseShares.description.empty": "You don't have any reverse shares.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.expiration.label": "Expiration",
"account.reverseShares.modal.expiration.minute-singular": "Minute",
"account.reverseShares.modal.expiration.minute-plural": "Minutes",
"account.reverseShares.modal.expiration.hour-singular": "Hour",
"account.reverseShares.modal.expiration.hour-plural": "Hours",
"account.reverseShares.modal.expiration.day-singular": "Day",
"account.reverseShares.modal.expiration.day-plural": "Days",
"account.reverseShares.modal.expiration.week-singular": "Week",
"account.reverseShares.modal.expiration.week-plural": "Weeks",
"account.reverseShares.modal.expiration.month-singular": "Month",
"account.reverseShares.modal.expiration.month-plural": "Months",
"account.reverseShares.modal.expiration.year-singular": "Year",
"account.reverseShares.modal.expiration.year-plural": "Years",
"account.reverseShares.modal.max-size.label": "Max share size",
"account.reverseShares.modal.send-email": "Send email notification",
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
"account.reverseShares.modal.simplified": "Simple mode",
"account.reverseShares.modal.simplified.description": "Make it easy for the person uploading the file to share it with you. They will be able to customize only the name and description of the share.",
"account.reverseShares.modal.public-access": "Public access",
"account.reverseShares.modal.public-access.description": "Make the created shares with this reverse share public. If disabled, only you and the creator of the share can view it.",
"account.reverseShares.modal.max-use.label": "Max uses",
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
"account.reverseShare.never-expires": "This reverse share will never expire.",
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
"account.reverseShares.table.no-shares": "No shares created yet",
"account.reverseShares.table.count.singular": "share",
"account.reverseShares.table.count.plural": "shares",
"account.reverseShares.table.shares": "Shares",
"account.reverseShares.table.remaining": "Remaining uses",
"account.reverseShares.table.max-size": "Max share size",
"account.reverseShares.table.expires": "Expires at",
"account.reverseShares.modal.reverse-share-link": "Reverse share link",
"account.reverseShares.modal.delete.title": "Delete reverse share",
"account.reverseShares.modal.delete.description": "Do you really want to delete this reverse share? If you do, the associated shares will be deleted as well.",
// END /account/reverseShares
// /admin
"admin.title": "Administration",
"admin.button.users": "User management",
"admin.button.shares": "Share management",
"admin.button.config": "Configuration",
"admin.version": "Version",
// END /admin
// /admin/users
"admin.users.title": "User management",
"admin.users.table.username": "Username",
"admin.users.table.email": "Email",
"admin.users.table.admin": "Admin",
"admin.users.edit.update.title": "Update user {username}",
"admin.users.edit.update.admin-privileges": "Admin privileges",
"admin.users.edit.update.change-password.title": "Change password",
"admin.users.edit.update.change-password.field": "New password",
"admin.users.edit.update.change-password.button": "Save new password",
"admin.users.edit.update.notify.password.success": "Password changed successfully",
"admin.users.edit.delete.title": "Delete user {username}",
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
// showCreateUserModal.tsx
"admin.users.modal.create.title": "Create user",
"admin.users.modal.create.username": "Username",
"admin.users.modal.create.email": "Email",
"admin.users.modal.create.password": "Password",
"admin.users.modal.create.manual-password": "Set password manually",
"admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.",
"admin.users.modal.create.admin": "Admin privileges",
"admin.users.modal.create.admin.description": "If checked, the user will be able to access the admin panel.",
// END /admin/users
// /admin/shares
"admin.shares.title": "Share management",
"admin.shares.table.id": "Share ID",
"admin.shares.table.username": "Creator",
"admin.shares.table.visitors": "Visitors",
"admin.shares.table.expires": "Expires At",
"admin.shares.edit.delete.title": "Delete share {id}",
"admin.shares.edit.delete.description": "Do you really want to delete this share?",
// END /admin/shares
// /upload
"upload.title": "Upload",
"upload.notify.generic-error": "An error occurred while finishing your share.",
"upload.notify.count-failed": "{count} files failed to upload. Trying again.",
// Dropzone.tsx
"upload.dropzone.title": "Upload files",
"upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.",
"upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.",
// FileList.tsx
"upload.filelist.name": "Name",
"upload.filelist.size": "Size",
// showCreateUploadModal.tsx
"upload.modal.title": "Create Share",
"upload.modal.link.error.invalid": "Can only contain letters, numbers, underscores, and hyphens",
"upload.modal.link.error.taken": "This link is already in use",
"upload.modal.not-signed-in": "You're not signed in",
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
"upload.modal.expires.never": "never",
"upload.modal.expires.never-long": "Never Expires",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.",
"upload.modal.link.label": "Link",
"upload.modal.expires.label": "Expiration",
"upload.modal.expires.minute-singular": "Minute",
"upload.modal.expires.minute-plural": "Minutes",
"upload.modal.expires.hour-singular": "Hour",
"upload.modal.expires.hour-plural": "Hours",
"upload.modal.expires.day-singular": "Day",
"upload.modal.expires.day-plural": "Days",
"upload.modal.expires.week-singular": "Week",
"upload.modal.expires.week-plural": "Weeks",
"upload.modal.expires.month-singular": "Month",
"upload.modal.expires.month-plural": "Months",
"upload.modal.expires.year-singular": "Year",
"upload.modal.expires.year-plural": "Years",
"upload.modal.accordion.name-and-description.title": "Name and description",
"upload.modal.accordion.name-and-description.name.placeholder": "Name",
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
"upload.modal.accordion.email.title": "Email recipients",
"upload.modal.accordion.email.placeholder": "Enter email recipients",
"upload.modal.accordion.email.invalid-email": "Invalid email address",
"upload.modal.accordion.security.title": "Security options",
"upload.modal.accordion.security.password.label": "Password protection",
"upload.modal.accordion.security.password.placeholder": "No password",
"upload.modal.accordion.security.max-views.label": "Maximum views",
"upload.modal.accordion.security.max-views.placeholder": "No limit",
// showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "This share will never expire.",
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
"upload.modal.completed.share-ready": "Share ready",
"upload.modal.completed.notified-reverse-share-creator": "We have notified the creator of the reverse share. You can also manually share this link with them through other means.",
// END /upload
// /share/[id]
"share.title": "Share {shareId}",
"share.description": "Look what I've shared with you!",
"share.error.visitor-limit-exceeded.title": "Visitor limit exceeded",
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
"share.error.removed.title": "Share removed",
"share.error.not-found.title": "Share not found",
"share.error.not-found.description": "The share you're looking for doesn't exist.",
"share.error.access-denied.title": "Private share",
"share.error.access-denied.description": "The current account does not have permission to access this share",
"share.modal.password.title": "Password required",
"share.modal.password.description": "To access this share please enter the password for the share.",
"share.modal.password": "Password",
"share.modal.error.invalid-password": "Invalid password",
"share.button.download-all": "Download all",
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
"share.modal.file-link": "File link",
"share.table.name": "Name",
"share.table.size": "Size",
"share.modal.file-preview.error.not-supported.title": "Preview not supported",
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
// END /share/[id]
// /share/[id]/edit
"share.edit.title": "Edit {shareId}",
"share.edit.append-upload": "Append file",
"share.edit.notify.generic-error": "An error occurred while finishing your share.",
"share.edit.notify.save-success": "Share updated successfully",
// END /share/[id]/edit
// /admin/config
"admin.config.title": "Configuration",
"admin.config.category.general": "General",
"admin.config.category.share": "Share",
"admin.config.category.email": "Email",
"admin.config.category.smtp": "SMTP",
"admin.config.category.oauth": "Social Login",
"admin.config.general.app-name": "App name",
"admin.config.general.app-name.description": "Name of the application",
"admin.config.general.app-url": "App URL",
"admin.config.general.app-url.description": "On which URL Pingvin Share is available",
"admin.config.general.show-home-page": "Show home page",
"admin.config.general.show-home-page.description": "Whether to show the home page",
"admin.config.general.session-duration": "Session Duration",
"admin.config.general.session-duration.description": "Time in hours after which a user must log in again (default: 3 months).",
"admin.config.general.logo": "Logo",
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.",
"admin.config.general.logo.placeholder": "Pick image",
"admin.config.email.enable-share-email-recipients": "Enable share email recipients",
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
"admin.config.email.share-recipients-subject": "Share recipients subject",
"admin.config.email.share-recipients-subject.description": "Subject of the email which gets sent to the share recipients.",
"admin.config.email.share-recipients-message": "Share recipients message",
"admin.config.email.share-recipients-message.description": "Message which gets sent to the share recipients. Available variables:\n {creator} - The username of the creator of the share\n {shareUrl} - The URL of the share\n {desc} - The description of the share\n {expires} - The expiration date of the share\n The variables will be replaced with the actual value.",
"admin.config.email.reverse-share-subject": "Reverse share subject",
"admin.config.email.reverse-share-subject.description": "Subject of the email which gets sent when someone created a share with your reverse share link.",
"admin.config.email.reverse-share-message": "Reverse share message",
"admin.config.email.reverse-share-message.description": "Message which gets sent when someone created a share with your reverse share link. {shareUrl} will be replaced with the creator's name and the share URL.",
"admin.config.email.reset-password-subject": "Reset password subject",
"admin.config.email.reset-password-subject.description": "Subject of the email which gets sent when a user requests a password reset.",
"admin.config.email.reset-password-message": "Reset password message",
"admin.config.email.reset-password-message.description": "Message which gets sent when a user requests a password reset. {url} will be replaced with the reset password URL.",
"admin.config.email.invite-subject": "Invite subject",
"admin.config.email.invite-subject.description": "Subject of the email which gets sent when an admin invites a user.",
"admin.config.email.invite-message": "Invite message",
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL, {email} with the email and {password} with the password of the user.",
"admin.config.share.allow-registration": "Allow registration",
"admin.config.share.allow-registration.description": "Whether registration is allowed",
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
"admin.config.share.max-expiration": "Max expiration",
"admin.config.share.max-expiration.description": "Maximum share expiration in hours. Set to 0 to allow unlimited expiration.",
"admin.config.share.max-size": "Max size",
"admin.config.share.max-size.description": "Maximum share size in bytes",
"admin.config.share.zip-compression-level": "Zip compression level",
"admin.config.share.zip-compression-level.description": "Adjust the level to balance between file size and compression speed. Valid values range from 0 to 9, with 0 being no compression and 9 being maximum compression. ",
"admin.config.share.chunk-size": "Chunk size",
"admin.config.share.chunk-size.description": "Adjust the chunk size (in bytes) for your uploads to balance efficiency and reliability according to your internet connection. Smaller chunks can enhance success rates for unstable connections, while larger chunks speed up uploads for stable connections.",
"admin.config.share.auto-open-share-modal": "Auto open create share modal",
"admin.config.share.auto-open-share-modal.description": "The share creation modal automatically appears when a user selects files, eliminating the need to manually click the button.",
"admin.config.smtp.enabled": "Enabled",
"admin.config.smtp.enabled.description": "Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
"admin.config.smtp.host": "Host",
"admin.config.smtp.host.description": "Host of the SMTP server",
"admin.config.smtp.port": "Port",
"admin.config.smtp.port.description": "Port of the SMTP server",
"admin.config.smtp.email": "Email",
"admin.config.smtp.email.description": "Email address which the emails get sent from",
"admin.config.smtp.username": "Username",
"admin.config.smtp.username.description": "Username of the SMTP server",
"admin.config.smtp.password": "Password",
"admin.config.smtp.password.description": "Password of the SMTP server",
"admin.config.smtp.button.test": "Send test email",
"admin.config.smtp.allow-unauthorized-certificates": "Trust unauthorized SMTP server certificates",
"admin.config.smtp.allow-unauthorized-certificates.description": "Only set this to true if you need to trust self signed certificates.",
"admin.config.oauth.allow-registration": "Allow registration",
"admin.config.oauth.allow-registration.description": "Allow users to register via social login",
"admin.config.oauth.ignore-totp": "Ignore TOTP",
"admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login",
"admin.config.oauth.disable-password": "Disable password login",
"admin.config.oauth.disable-password.description": "Whether to disable password login\nMake sure that an OAuth provider is properly configured before activating this configuration to avoid being locked out.",
"admin.config.oauth.github-enabled": "GitHub",
"admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled",
"admin.config.oauth.github-client-id": "GitHub Client ID",
"admin.config.oauth.github-client-id.description": "Client ID of the GitHub OAuth app",
"admin.config.oauth.github-client-secret": "GitHub Client secret",
"admin.config.oauth.github-client-secret.description": "Client secret of the GitHub OAuth app",
"admin.config.oauth.google-enabled": "Google",
"admin.config.oauth.google-enabled.description": "Whether Google login is enabled",
"admin.config.oauth.google-client-id": "Google Client ID",
"admin.config.oauth.google-client-id.description": "Client ID of the Google OAuth app",
"admin.config.oauth.google-client-secret": "Google Client secret",
"admin.config.oauth.google-client-secret.description": "Client secret of the Google OAuth app",
"admin.config.oauth.microsoft-enabled": "Microsoft",
"admin.config.oauth.microsoft-enabled.description": "Whether Microsoft login is enabled",
"admin.config.oauth.microsoft-tenant": "Microsoft Tenant",
"admin.config.oauth.microsoft-tenant.description": "Tenant ID of the Microsoft OAuth app\ncommon: Users with both a personal Microsoft account and a work or school account from Microsoft Entra ID can sign in to the application. organizations: Only users with work or school accounts from Microsoft Entra ID can sign in to the application.\nconsumers: Only users with a personal Microsoft account can sign in to the application.\ndomain name of the Microsoft Entra tenant or the tenant ID in GUID format: Only users from a specific Microsoft Entra tenant (directory members with a work or school account or directory guests with a personal Microsoft account) can sign in to the application.",
"admin.config.oauth.microsoft-client-id": "Microsoft Client ID",
"admin.config.oauth.microsoft-client-id.description": "Client ID of the Microsoft OAuth app",
"admin.config.oauth.microsoft-client-secret": "Microsoft Client secret",
"admin.config.oauth.microsoft-client-secret.description": "Client secret of the Microsoft OAuth app",
"admin.config.oauth.discord-enabled": "Discord",
"admin.config.oauth.discord-enabled.description": "Whether Discord login is enabled",
"admin.config.oauth.discord-limited-guild": "Discord limited server ID",
"admin.config.oauth.discord-limited-guild.description": "Limit signing in to users in a specific server. Leave it blank to disable.",
"admin.config.oauth.discord-client-id": "Discord Client ID",
"admin.config.oauth.discord-client-id.description": "Client ID of the Discord OAuth app",
"admin.config.oauth.discord-client-secret": "Discord Client secret",
"admin.config.oauth.discord-client-secret.description": "Client secret of the Discord OAuth app",
"admin.config.oauth.oidc-enabled": "OpenID Connect",
"admin.config.oauth.oidc-enabled.description": "Whether OpenID Connect login is enabled",
"admin.config.oauth.oidc-discovery-uri": "OpenID Connect Discovery URI",
"admin.config.oauth.oidc-discovery-uri.description": "Discovery URI of the OpenID Connect OAuth app",
"admin.config.oauth.oidc-username-claim": "OpenID Connect username claim",
"admin.config.oauth.oidc-username-claim.description": "Username claim in OpenID Connect ID token. Leave it blank if you don't know what this config is.",
"admin.config.oauth.oidc-role-path": "Path to roles in OpenID Connect token",
"admin.config.oauth.oidc-role-path.description": "Must be a valid JMES path referencing an array of roles. " + "Managing access rights using OpenID Connect roles is only recommended if no other identity provider is configured and password login is disabled. " + "Leave it blank if you don't know what this config is.",
"admin.config.oauth.oidc-role-general-access": "OpenID Connect role for general access",
"admin.config.oauth.oidc-role-general-access.description": "Role required for general access. Must be present in a users roles for them to log in. " + "Leave it blank if you don't know what this config is.",
"admin.config.oauth.oidc-role-admin-access": "OpenID Connect role for admin access",
"admin.config.oauth.oidc-role-admin-access.description": "Role required for administrative access. Must be present in a users roles for them to access the admin panel. " + "Leave it blank if you don't know what this config is.",
"admin.config.oauth.oidc-client-id": "OpenID Connect Client ID",
"admin.config.oauth.oidc-client-id.description": "Client ID of the OpenID Connect OAuth app",
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
"admin.config.oauth.oidc-client-secret.description": "Client secret of the OpenID Connect OAuth app",
"admin.config.category.ldap": "LDAP",
"admin.config.ldap.enabled": "Enabled LDAP",
"admin.config.ldap.enabled.description": "Use LDAP authentication for user login",
"admin.config.ldap.url": "Server URL",
"admin.config.ldap.url.description": "URL of the LDAP server",
"admin.config.ldap.bind-dn": "Bind DN",
"admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search",
"admin.config.ldap.bind-password": "Bind password",
"admin.config.ldap.bind-password.description": "Password for the user search user",
"admin.config.ldap.search-base": "User base",
"admin.config.ldap.search-base.description": "Base location, where the user search will be performed",
"admin.config.ldap.search-query": "User query",
"admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.",
"admin.config.ldap.admin-groups": "Admin group",
"admin.config.ldap.admin-groups.description": "Group required for administrative access.",
// 404
"404.description": "Oops this page doesn't exist.",
"404.button.home": "Bring me back home",
// error
"error.title": "Error",
"error.description": "Oops!",
"error.button.back": "Go back",
"error.msg.default": "Something went wrong.",
"error.msg.access_denied": "You canceled the authentication process, please try again.",
"error.msg.expired_token": "The authentication process took too long, please try again.",
"error.msg.invalid_token": "Internal Error",
"error.msg.no_user": "User linked to this {0} account doesn't exist.",
"error.msg.no_email": "Can't get email address from this {0} account.",
"error.msg.already_linked": "This {0} account is already linked to another account.",
"error.msg.not_linked": "This {0} account haven't linked to any account yet.",
"error.msg.unverified_account": "This {0} account is unverified, please try again after verification.",
"error.msg.user_not_allowed": "You are not allowed to sign in.",
"error.msg.cannot_get_user_info": "Can not get your user info from this {0} account.",
"error.param.provider_github": "GitHub",
"error.param.provider_google": "Google",
"error.param.provider_microsoft": "Microsoft",
"error.param.provider_discord": "Discord",
"error.param.provider_oidc": "OpenID Connect",
// Common translations
"common.button.save": "Save",
"common.button.create": "Create",
"common.button.submit": "Submit",
"common.button.delete": "Delete",
"common.button.cancel": "Cancel",
"common.button.confirm": "Confirm",
"common.button.disable": "Disable",
"common.button.share": "Share",
"common.button.generate": "Generate",
"common.button.done": "Done",
"common.text.link": "Link",
"common.text.navigate-to-link": "Go to the link",
"common.text.or": "or",
"common.button.go-back": "Go back",
"common.button.go-home": "Go home",
"common.notify.copied": "Your link was copied to the clipboard",
"common.success": "Success",
"common.error": "Error",
"common.error.unknown": "An unknown error occurred",
"common.error.invalid-email": "Invalid email address",
"common.error.too-short": "Must be at least {length} characters",
"common.error.too-long": "Must be at most {length} characters",
"common.error.exact-length": "Must be exactly {length} characters",
"common.error.invalid-number": "Must be a number",
"common.error.field-required": "This field is required"
};

View File

@@ -4,8 +4,8 @@ export default {
"navbar.signin": "Přihlásit se", "navbar.signin": "Přihlásit se",
"navbar.home": "Domů", "navbar.home": "Domů",
"navbar.signup": "Zaregistrovat se", "navbar.signup": "Zaregistrovat se",
"navbar.links.shares": "Mé sdílení", "navbar.links.shares": "Má sdílení",
"navbar.links.reverse": "Zpětné sdílení", "navbar.links.reverse": "Zpětná sdílení",
"navbar.avatar.account": "Můj účet", "navbar.avatar.account": "Můj účet",
"navbar.avatar.admin": "Administrace", "navbar.avatar.admin": "Administrace",
"navbar.avatar.signout": "Odhlásit se", "navbar.avatar.signout": "Odhlásit se",
@@ -90,50 +90,50 @@ export default {
"account.card.security.title": "Zabezpečení", "account.card.security.title": "Zabezpečení",
"account.card.security.totp.enable.description": "Zadejte své současné heslo, abyste mohli povolit TOTP", "account.card.security.totp.enable.description": "Zadejte své současné heslo, abyste mohli povolit TOTP",
"account.card.security.totp.disable.description": "Zadejte své současné heslo pro zakázání TOTP", "account.card.security.totp.disable.description": "Zadejte své současné heslo pro zakázání TOTP",
"account.card.security.totp.button.start": "Start", "account.card.security.totp.button.start": "Začít",
"account.modal.totp.title": "Enable TOTP", "account.modal.totp.title": "Povolit TOTP",
"account.modal.totp.step1": "Step 1: Add your authenticator", "account.modal.totp.step1": "Krok 1: Přidejte váš autentifikátor",
"account.modal.totp.step2": "Step 2: Validate your code", "account.modal.totp.step2": "Krok 2: Ověřte váš kód",
"account.modal.totp.enterManually": "Enter manually", "account.modal.totp.enterManually": "Zadat ručně",
"account.modal.totp.code": "Code", "account.modal.totp.code": "Kód",
"common.button.clickToCopy": "Click to copy", "common.button.clickToCopy": "Kliknutím zkopírujete",
"account.modal.totp.verify": "Verify", "account.modal.totp.verify": "Ověřit",
"account.notify.totp.disable": "TOTP disabled successfully", "account.notify.totp.disable": "TOTP úspěšně zakázáno",
"account.notify.totp.enable": "TOTP enabled successfully", "account.notify.totp.enable": "TOTP úspěšně povoleno",
"account.card.language.title": "Language", "account.card.language.title": "Jazyk",
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.", "account.card.language.description": "Projekt je přeložen komunitou. Některé jazyky mohou být neúplné.",
"account.card.color.title": "Color scheme", "account.card.color.title": "Barevné schéma",
// ThemeSwitcher.tsx // ThemeSwitcher.tsx
"account.theme.dark": "Dark", "account.theme.dark": "Tmavé",
"account.theme.light": "Light", "account.theme.light": "Světlé",
"account.theme.system": "System", "account.theme.system": "Systémové",
"account.button.delete": "Delete Account", "account.button.delete": "Odstranit účet",
"account.modal.delete.title": "Delete Account", "account.modal.delete.title": "Odstranit účet",
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?", "account.modal.delete.description": "Opravdu chcete odstranit svůj účet včetně všech aktivních sdílení?",
// END /account // END /account
// /account/shares // /account/shares
"account.shares.title": "My shares", "account.shares.title": "Má sdílení",
"account.shares.title.empty": "It's empty here 👀", "account.shares.title.empty": "Je tu prázdno 👀",
"account.shares.description.empty": "You don't have any shares.", "account.shares.description.empty": "Nemáte žádná sdílení.",
"account.shares.button.create": "Create one", "account.shares.button.create": "Create one",
"account.shares.info.title": "Share informations", "account.shares.info.title": "Share informations",
"account.shares.table.id": "ID", "account.shares.table.id": "ID",
"account.shares.table.name": "Name", "account.shares.table.name": "Název",
"account.shares.table.description": "Description", "account.shares.table.description": "Popis",
"account.shares.table.visitors": "Visitors", "account.shares.table.visitors": "Návštěvníci",
"account.shares.table.expiresAt": "Expires at", "account.shares.table.expiresAt": "Vyprší",
"account.shares.table.createdAt": "Created at", "account.shares.table.createdAt": "Vytvořeno",
"account.shares.table.size": "Size", "account.shares.table.size": "Velikost",
"account.shares.modal.share-informations": "Share informations", "account.shares.modal.share-informations": "Share informations",
"account.shares.modal.share-link": "Share link", "account.shares.modal.share-link": "Odkaz na sdílení",
"account.shares.modal.delete.title": "Delete share {share}", "account.shares.modal.delete.title": "Odstranit sdílení {share}",
"account.shares.modal.delete.description": "Do you really want to delete this share?", "account.shares.modal.delete.description": "Opravdu chcete odstranit toto sdílení?",
// END /account/shares // END /account/shares
// /account/reverseShares // /account/reverseShares
"account.reverseShares.title": "Reverse shares", "account.reverseShares.title": "Zpětná sdílení",
"account.reverseShares.description": "Zpětné sdílení umožňuje vygenerovat jedinečné URL, které umožní externím uživatelům vytvořit sdílet soubory.", "account.reverseShares.description": "Zpětné sdílení umožňuje vygenerovat jedinečné URL, které umožní externím uživatelům vytvořit sdílet soubory.",
"account.reverseShares.title.empty": "Je tu prázdno 👀", "account.reverseShares.title.empty": "Je tu prázdno 👀",
"account.reverseShares.description.empty": "You don't have any reverse shares.", "account.reverseShares.description.empty": "Nemáte žádná zpětná sdílení.",
// showCreateReverseShareModal.tsx // showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Vytvořit zpětné sdílení", "account.reverseShares.modal.title": "Vytvořit zpětné sdílení",
"account.reverseShares.modal.expiration.label": "Expirace", "account.reverseShares.modal.expiration.label": "Expirace",
@@ -146,18 +146,18 @@ export default {
"account.reverseShares.modal.expiration.week-singular": "Týden", "account.reverseShares.modal.expiration.week-singular": "Týden",
"account.reverseShares.modal.expiration.week-plural": "Týdnů", "account.reverseShares.modal.expiration.week-plural": "Týdnů",
"account.reverseShares.modal.expiration.month-singular": "Měsíc", "account.reverseShares.modal.expiration.month-singular": "Měsíc",
"account.reverseShares.modal.expiration.month-plural": "Months", "account.reverseShares.modal.expiration.month-plural": "Měsíců",
"account.reverseShares.modal.expiration.year-singular": "Year", "account.reverseShares.modal.expiration.year-singular": "Rok",
"account.reverseShares.modal.expiration.year-plural": "Years", "account.reverseShares.modal.expiration.year-plural": "Let",
"account.reverseShares.modal.max-size.label": "Max share size", "account.reverseShares.modal.max-size.label": "Max. velikost sdílení",
"account.reverseShares.modal.send-email": "Send email notification", "account.reverseShares.modal.send-email": "Odeslat oznámení e-mailem",
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.", "account.reverseShares.modal.send-email.description": "Odeslat e-mailové upozornění, pokud je s tímto odkazem pro zpětné sdílení vytvořeno sdílení.",
"account.reverseShares.modal.simplified": "Simple mode", "account.reverseShares.modal.simplified": "Zjednodušený režim",
"account.reverseShares.modal.simplified.description": "Make it easy for the person uploading the file to share it with you. They will be able to customize only the name and description of the share.", "account.reverseShares.modal.simplified.description": "Usnadněte osobě, která nahrála soubor, sdílet jej s vámi. Budou moci upravit pouze název a popis sdílení.",
"account.reverseShares.modal.public-access": "Public access", "account.reverseShares.modal.public-access": "Veřejný přístup",
"account.reverseShares.modal.public-access.description": "Make the created shares with this reverse share public. If disabled, only you and the creator of the share can view it.", "account.reverseShares.modal.public-access.description": "Make the created shares with this reverse share public. If disabled, only you and the creator of the share can view it.",
"account.reverseShares.modal.max-use.label": "Max uses", "account.reverseShares.modal.max-use.label": "Max. použití",
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.", "account.reverseShares.modal.max-use.description": "Maximální počet sdílení, která mohou být vytvořena za pomoci tohoto URL.",
"account.reverseShare.never-expires": "Toto zpětné sdílení nikdy nevyprší.", "account.reverseShare.never-expires": "Toto zpětné sdílení nikdy nevyprší.",
"account.reverseShare.expires-on": "Toto zpětné sdílení vyprší {expiration}.", "account.reverseShare.expires-on": "Toto zpětné sdílení vyprší {expiration}.",
"account.reverseShares.table.no-shares": "Zatím nebyla vytvořena žádná sdílení", "account.reverseShares.table.no-shares": "Zatím nebyla vytvořena žádná sdílení",
@@ -219,31 +219,31 @@ export default {
"upload.dropzone.description": "Pro zahájení sdílení přetáhněte soubory sem. Můžeme přijmout pouze soubory, které jsou menší než {maxSize}.", "upload.dropzone.description": "Pro zahájení sdílení přetáhněte soubory sem. Můžeme přijmout pouze soubory, které jsou menší než {maxSize}.",
"upload.dropzone.notify.file-too-big": "Vaše soubory přesahují maximální velikost {maxSize}.", "upload.dropzone.notify.file-too-big": "Vaše soubory přesahují maximální velikost {maxSize}.",
// FileList.tsx // FileList.tsx
"upload.filelist.name": "Name", "upload.filelist.name": "Název",
"upload.filelist.size": "Velikost", "upload.filelist.size": "Velikost",
// showCreateUploadModal.tsx // showCreateUploadModal.tsx
"upload.modal.title": "Create Share", "upload.modal.title": "Vytvořit sdílení",
"upload.modal.link.error.invalid": "Může obsahovat pouze písmena, číslice, podtržítka a pomlčky", "upload.modal.link.error.invalid": "Může obsahovat pouze písmena, číslice, podtržítka a pomlčky",
"upload.modal.link.error.taken": "Tento odkaz je již používán", "upload.modal.link.error.taken": "Tento odkaz je již používán",
"upload.modal.not-signed-in": "Nejste přihlášeni", "upload.modal.not-signed-in": "Nejste přihlášeni",
"upload.modal.not-signed-in-description": "Nebudete moci ručně odstranit své sdílení a zobrazit počet návštěvníků.", "upload.modal.not-signed-in-description": "Nebudete moci ručně odstranit své sdílení a zobrazit počet návštěvníků.",
"upload.modal.expires.never": "never", "upload.modal.expires.never": "nikdy",
"upload.modal.expires.never-long": "Nikdy nevyprší", "upload.modal.expires.never-long": "Nikdy nevyprší",
"upload.modal.expires.error.too-long": "Expiration exceeds maximum expiration date of {max}.", "upload.modal.expires.error.too-long": "Platnosti přesahuje maximální datum vypršení platnosti {max}.",
"upload.modal.link.label": "Odkaz", "upload.modal.link.label": "Odkaz",
"upload.modal.expires.label": "Expirace", "upload.modal.expires.label": "Expirace",
"upload.modal.expires.minute-singular": "Minute", "upload.modal.expires.minute-singular": "Minuta",
"upload.modal.expires.minute-plural": "Minutes", "upload.modal.expires.minute-plural": "Minut",
"upload.modal.expires.hour-singular": "Hour", "upload.modal.expires.hour-singular": "Hodina",
"upload.modal.expires.hour-plural": "Hours", "upload.modal.expires.hour-plural": "Hodin",
"upload.modal.expires.day-singular": "Day", "upload.modal.expires.day-singular": "Den",
"upload.modal.expires.day-plural": "Days", "upload.modal.expires.day-plural": "D",
"upload.modal.expires.week-singular": "Week", "upload.modal.expires.week-singular": "Týden",
"upload.modal.expires.week-plural": "Weeks", "upload.modal.expires.week-plural": "Týdnů",
"upload.modal.expires.month-singular": "Month", "upload.modal.expires.month-singular": "Měsíc",
"upload.modal.expires.month-plural": "Months", "upload.modal.expires.month-plural": "Měsíců",
"upload.modal.expires.year-singular": "Year", "upload.modal.expires.year-singular": "Rok",
"upload.modal.expires.year-plural": "Years", "upload.modal.expires.year-plural": "Let",
"upload.modal.accordion.name-and-description.title": "Název a popis", "upload.modal.accordion.name-and-description.title": "Název a popis",
"upload.modal.accordion.name-and-description.name.placeholder": "Název", "upload.modal.accordion.name-and-description.name.placeholder": "Název",
"upload.modal.accordion.name-and-description.description.placeholder": "Poznámka pro příjemce tohoto sdílení", "upload.modal.accordion.name-and-description.description.placeholder": "Poznámka pro příjemce tohoto sdílení",
@@ -274,39 +274,39 @@ export default {
"share.modal.password.title": "Heslo vyžadováno", "share.modal.password.title": "Heslo vyžadováno",
"share.modal.password.description": "Pro přístup k tomuto sdílení zadejte prosím heslo pro toto sdílení.", "share.modal.password.description": "Pro přístup k tomuto sdílení zadejte prosím heslo pro toto sdílení.",
"share.modal.password": "Heslo", "share.modal.password": "Heslo",
"share.modal.error.invalid-password": "Invalid password", "share.modal.error.invalid-password": "Neplatné heslo",
"share.button.download-all": "Download all", "share.button.download-all": "Stáhnout vše",
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.", "share.notify.download-all-preparing": "Sdílení se připravuje. Zkuste to znovu za pár minut.",
"share.modal.file-link": "File link", "share.modal.file-link": "Odkaz na soubor",
"share.table.name": "Name", "share.table.name": "Název",
"share.table.size": "Size", "share.table.size": "Velikost",
"share.modal.file-preview.error.not-supported.title": "Preview not supported", "share.modal.file-preview.error.not-supported.title": "Náhled není podporován",
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.", "share.modal.file-preview.error.not-supported.description": "Náhled pro tento typ souboru není podporován. Stáhněte si soubor pro jeho zobrazení.",
// END /share/[id] // END /share/[id]
// /share/[id]/edit // /share/[id]/edit
"share.edit.title": "Edit {shareId}", "share.edit.title": "Upravit {shareId}",
"share.edit.append-upload": "Append file", "share.edit.append-upload": "Připojit soubor",
"share.edit.notify.generic-error": "An error occurred while finishing your share.", "share.edit.notify.generic-error": "Při dokončování vašeho sdílení došlo k chybě.",
"share.edit.notify.save-success": "Share updated successfully", "share.edit.notify.save-success": "Sdílení úspěšně aktualizováno",
// END /share/[id]/edit // END /share/[id]/edit
// /admin/config // /admin/config
"admin.config.title": "Configuration", "admin.config.title": "Nastavení",
"admin.config.category.general": "General", "admin.config.category.general": "Obecné",
"admin.config.category.share": "Share", "admin.config.category.share": "Sdílení",
"admin.config.category.email": "Email", "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": "Přihlášení přes sociální sítě",
"admin.config.general.app-name": "App name", "admin.config.general.app-name": "Název aplikace",
"admin.config.general.app-name.description": "Name of the application", "admin.config.general.app-name.description": "Název aplikace",
"admin.config.general.app-url": "App URL", "admin.config.general.app-url": "URL aplikace",
"admin.config.general.app-url.description": "On which URL Pingvin Share is available", "admin.config.general.app-url.description": "Na kterém URL je Pingvin Share k dispozici",
"admin.config.general.show-home-page": "Show home page", "admin.config.general.show-home-page": "Zobrazit domovskou stránku",
"admin.config.general.show-home-page.description": "Whether to show the home page", "admin.config.general.show-home-page.description": "Zda zobrazovat domovskou stránku",
"admin.config.general.session-duration": "Session Duration", "admin.config.general.session-duration": "Délka trvání relace",
"admin.config.general.session-duration.description": "Time in hours after which a user must log in again (default: 3 months).", "admin.config.general.session-duration.description": "Čas v hodinách, po kterém se uživatel musí znovu přihlásit (výchozí: 3 měsíce).",
"admin.config.general.logo": "Logo", "admin.config.general.logo": "Logo",
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.", "admin.config.general.logo.description": "Změňte své logo nahráním nového obrázku. Obrázek musí být PNG a měl by mít formát 1:1.",
"admin.config.general.logo.placeholder": "Pick image", "admin.config.general.logo.placeholder": "Vybrat obrázek",
"admin.config.email.enable-share-email-recipients": "Enable share email recipients", "admin.config.email.enable-share-email-recipients": "Enable share email recipients",
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.", "admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
"admin.config.email.share-recipients-subject": "Share recipients subject", "admin.config.email.share-recipients-subject": "Share recipients subject",
@@ -316,7 +316,7 @@ export default {
"admin.config.email.reverse-share-subject": "Předmět e-mailu o zpětném sdílení", "admin.config.email.reverse-share-subject": "Předmět e-mailu o zpětném sdílení",
"admin.config.email.reverse-share-subject.description": "Předmět e-mailu, který bude odeslán, když někdo vytvoří sdílení s vaším odkazem na zpětné sdílení.", "admin.config.email.reverse-share-subject.description": "Předmět e-mailu, který bude odeslán, když někdo vytvoří sdílení s vaším odkazem na zpětné sdílení.",
"admin.config.email.reverse-share-message": "Zpráva o zpětném sdílení", "admin.config.email.reverse-share-message": "Zpráva o zpětném sdílení",
"admin.config.email.reverse-share-message.description": "Zpráva, která bude odeslána, když někdo vytvoří sdílení s vaším odkazem na reverzní sdílení. {shareUrl} bude nahrazeno jménem tvůrce a URL pro sdílení.", "admin.config.email.reverse-share-message.description": "Zpráva, která bude odeslána, když někdo vytvoří sdílení s vaším odkazem na zpětné sdílení. {shareUrl} bude nahrazeno jménem tvůrce a URL pro sdílení.",
"admin.config.email.reset-password-subject": "Předmět e-mailu pro obnovení hesla", "admin.config.email.reset-password-subject": "Předmět e-mailu pro obnovení hesla",
"admin.config.email.reset-password-subject.description": "Předmět e-mailu, který bude odeslán, když uživatel požádá o obnovení hesla.", "admin.config.email.reset-password-subject.description": "Předmět e-mailu, který bude odeslán, když uživatel požádá o obnovení hesla.",
"admin.config.email.reset-password-message": "Zpráva o obnovení hesla", "admin.config.email.reset-password-message": "Zpráva o obnovení hesla",
@@ -463,9 +463,9 @@ export default {
"common.error": "Chyba", "common.error": "Chyba",
"common.error.unknown": "Došlo k neznámé chybě", "common.error.unknown": "Došlo k neznámé chybě",
"common.error.invalid-email": "Invalid email address", "common.error.invalid-email": "Invalid email address",
"common.error.too-short": "Must be at least {length} characters", "common.error.too-short": "Musí mít alespoň {length} znaků",
"common.error.too-long": "Must be at most {length} characters", "common.error.too-long": "Musí mít maximálně {length} znaků",
"common.error.exact-length": "Must be exactly {length} characters", "common.error.exact-length": "Musí mít přesně {length} znaků",
"common.error.invalid-number": "Must be a number", "common.error.invalid-number": "Musí být číslo",
"common.error.field-required": "This field is required" "common.error.field-required": "Toto pole je povinné"
}; };

View File

@@ -417,7 +417,7 @@ export default {
"admin.config.ldap.search-base.description": "Base location, where the user search will be performed", "admin.config.ldap.search-base.description": "Base location, where the user search will be performed",
"admin.config.ldap.search-query": "User query", "admin.config.ldap.search-query": "User query",
"admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.", "admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.",
"admin.config.ldap.admin-groups": "Admin group", "admin.config.ldap.admin-groups": "Administratorengruppe",
"admin.config.ldap.admin-groups.description": "Group required for administrative access.", "admin.config.ldap.admin-groups.description": "Group required for administrative access.",
// 404 // 404
"404.description": "Ups, diese Seite existiert nicht.", "404.description": "Ups, diese Seite existiert nicht.",

View File

@@ -405,19 +405,19 @@ export default {
"admin.config.oauth.oidc-client-secret": "Secret du client OpenID", "admin.config.oauth.oidc-client-secret": "Secret du client OpenID",
"admin.config.oauth.oidc-client-secret.description": "Le secret du client de lapplication OAuth OpenID Connect", "admin.config.oauth.oidc-client-secret.description": "Le secret du client de lapplication OAuth OpenID Connect",
"admin.config.category.ldap": "LDAP", "admin.config.category.ldap": "LDAP",
"admin.config.ldap.enabled": "Enabled LDAP", "admin.config.ldap.enabled": "Activer LDAP",
"admin.config.ldap.enabled.description": "Use LDAP authentication for user login", "admin.config.ldap.enabled.description": "Utiliser l'authentification LDAP pour la connexion de l'utilisateur",
"admin.config.ldap.url": "Server URL", "admin.config.ldap.url": "URL du serveur",
"admin.config.ldap.url.description": "URL of the LDAP server", "admin.config.ldap.url.description": "URL du serveur LDAP",
"admin.config.ldap.bind-dn": "Bind DN", "admin.config.ldap.bind-dn": "Lier le DN",
"admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search", "admin.config.ldap.bind-dn.description": "Utilisateur par défaut qui sera utilisé pour exécuter la recherche de l'utilisateur",
"admin.config.ldap.bind-password": "Bind password", "admin.config.ldap.bind-password": "Lier le mot de passe",
"admin.config.ldap.bind-password.description": "Password for the user search user", "admin.config.ldap.bind-password.description": "Mot de passe pour l'utilisateur recherché",
"admin.config.ldap.search-base": "User base", "admin.config.ldap.search-base": "Base d'utilisateurs",
"admin.config.ldap.search-base.description": "Base location, where the user search will be performed", "admin.config.ldap.search-base.description": "Emplacement de base, où la recherche de l'utilisateur sera effectuée",
"admin.config.ldap.search-query": "User query", "admin.config.ldap.search-query": "Requête utilisateur",
"admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.", "admin.config.ldap.search-query.description": "La requête utilisateur sera utilisée pour rechercher dans la base d'utilisateurs de l'utilisateur LDAP. %username% peut être utilisé comme espace réservé pour les entrées données par l'utilisateur.",
"admin.config.ldap.admin-groups": "Admin group", "admin.config.ldap.admin-groups": "Groupe administrateur",
"admin.config.ldap.admin-groups.description": "Group required for administrative access.", "admin.config.ldap.admin-groups.description": "Group required for administrative access.",
// 404 // 404
"404.description": "Désolé, mais cette page nexiste pas.", "404.description": "Désolé, mais cette page nexiste pas.",

View File

@@ -324,7 +324,7 @@ export default {
"admin.config.email.invite-subject": "Oggetto dell'email di invito", "admin.config.email.invite-subject": "Oggetto dell'email di invito",
"admin.config.email.invite-subject.description": "Oggetto dell'email che viene inviata quando un amministratore invita un utente.", "admin.config.email.invite-subject.description": "Oggetto dell'email che viene inviata quando un amministratore invita un utente.",
"admin.config.email.invite-message": "Testo dell'email di invito", "admin.config.email.invite-message": "Testo dell'email di invito",
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL, {email} with the email and {password} with the password of the user.", "admin.config.email.invite-message.description": "Messaggio che viene inviato quando un amministratore invita un utente. {url} sarà sostituito con l'URL di invito, {email} con l'email e {password} con la password dell'utente.",
"admin.config.share.allow-registration": "Consenti la registrazione", "admin.config.share.allow-registration": "Consenti la registrazione",
"admin.config.share.allow-registration.description": "Indica se la registrazione è autorizzata", "admin.config.share.allow-registration.description": "Indica se la registrazione è autorizzata",
"admin.config.share.allow-unauthenticated-shares": "Consenti condivisioni non autenticate", "admin.config.share.allow-unauthenticated-shares": "Consenti condivisioni non autenticate",
@@ -405,20 +405,20 @@ export default {
"admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret", "admin.config.oauth.oidc-client-secret": "OpenID Connect Client secret",
"admin.config.oauth.oidc-client-secret.description": "Client secret dell'app OAuth OpenID Connect", "admin.config.oauth.oidc-client-secret.description": "Client secret dell'app OAuth OpenID Connect",
"admin.config.category.ldap": "LDAP", "admin.config.category.ldap": "LDAP",
"admin.config.ldap.enabled": "Enabled LDAP", "admin.config.ldap.enabled": "LDAP Abilitato",
"admin.config.ldap.enabled.description": "Use LDAP authentication for user login", "admin.config.ldap.enabled.description": "Usa autenticazione LDAP per l'accesso utente",
"admin.config.ldap.url": "Server URL", "admin.config.ldap.url": "Server Url",
"admin.config.ldap.url.description": "URL of the LDAP server", "admin.config.ldap.url.description": "URL del server LDAP",
"admin.config.ldap.bind-dn": "Bind DN", "admin.config.ldap.bind-dn": "Associa DN",
"admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search", "admin.config.ldap.bind-dn.description": "Utente predefinito che verrà usato per eseguire la ricerca utente",
"admin.config.ldap.bind-password": "Bind password", "admin.config.ldap.bind-password": "Associa password",
"admin.config.ldap.bind-password.description": "Password for the user search user", "admin.config.ldap.bind-password.description": "Password per l'utente di ricerca",
"admin.config.ldap.search-base": "User base", "admin.config.ldap.search-base": "Base utenti",
"admin.config.ldap.search-base.description": "Base location, where the user search will be performed", "admin.config.ldap.search-base.description": "Posizione di base, dove verrà eseguita la ricerca dell'utente",
"admin.config.ldap.search-query": "User query", "admin.config.ldap.search-query": "Interrogazione utente",
"admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.", "admin.config.ldap.search-query.description": "La query utente verrà utilizzata per cercare la 'base utente' per l'utente LDAP. %username% può essere usato come segnaposto per l'input dato dall'utente.",
"admin.config.ldap.admin-groups": "Admin group", "admin.config.ldap.admin-groups": "Gruppo di amministrazione",
"admin.config.ldap.admin-groups.description": "Group required for administrative access.", "admin.config.ldap.admin-groups.description": "Gruppo richiesto per laccesso amministrativo.",
// 404 // 404
"404.description": "Ops, questa pagina non esiste.", "404.description": "Ops, questa pagina non esiste.",
"404.button.home": "Riportami a casa", "404.button.home": "Riportami a casa",

View File

@@ -60,14 +60,14 @@ export default {
"resetPassword.description": "Nhập email để khôi phục mật khẩu.", "resetPassword.description": "Nhập email để khôi phục mật khẩu.",
"resetPassword.notify.success": "Email khôi phục mật khẩu đã được gửi nếu như địa chỉ email này tồn tại.", "resetPassword.notify.success": "Email khôi phục mật khẩu đã được gửi nếu như địa chỉ email này tồn tại.",
"resetPassword.button.back": "Quay lại trang đăng nhập", "resetPassword.button.back": "Quay lại trang đăng nhập",
"resetPassword.text.resetPassword": "Reset password", "resetPassword.text.resetPassword": "Đặt lại mật khẩu",
"resetPassword.text.enterNewPassword": "Enter your new password", "resetPassword.text.enterNewPassword": "Mật khẩu mới",
"resetPassword.input.password": "New password", "resetPassword.input.password": "Mật khẩu mới",
"resetPassword.notify.passwordReset": "Your password has been reset successfully.", "resetPassword.notify.passwordReset": "Mật khẩu đã được thay đổi!",
// /account // /account
"account.title": "Tài khoản", "account.title": "Tài khoản",
"account.card.info.title": "Thông tin tài khoản", "account.card.info.title": "Thông tin tài khoản",
"account.card.info.username": "Username", "account.card.info.username": "Tên đăng nhập",
"account.card.info.email": "Email", "account.card.info.email": "Email",
"account.notify.info.success": "Cập nhật tài khoản thành công", "account.notify.info.success": "Cập nhật tài khoản thành công",
"account.card.password.title": "Mật khẩu", "account.card.password.title": "Mật khẩu",
@@ -94,10 +94,10 @@ export default {
"account.modal.totp.title": "Bật TOTP", "account.modal.totp.title": "Bật TOTP",
"account.modal.totp.step1": "Step 1: Add your authenticator", "account.modal.totp.step1": "Step 1: Add your authenticator",
"account.modal.totp.step2": "Step 2: Validate your code", "account.modal.totp.step2": "Step 2: Validate your code",
"account.modal.totp.enterManually": "Enter manually", "account.modal.totp.enterManually": "Nhập thủ công",
"account.modal.totp.code": "Code", "account.modal.totp.code": "",
"common.button.clickToCopy": "Nhấn để sao chép", "common.button.clickToCopy": "Nhấn để sao chép",
"account.modal.totp.verify": "Verify", "account.modal.totp.verify": "Xác thực",
"account.notify.totp.disable": "Tắt TOTP thành công", "account.notify.totp.disable": "Tắt TOTP thành công",
"account.notify.totp.enable": "Bật TOTP thành công", "account.notify.totp.enable": "Bật TOTP thành công",
"account.card.language.title": "Ngôn ngữ", "account.card.language.title": "Ngôn ngữ",
@@ -185,17 +185,17 @@ export default {
"admin.users.table.admin": "Admin", "admin.users.table.admin": "Admin",
"admin.users.edit.update.title": "Update user {username}", "admin.users.edit.update.title": "Update user {username}",
"admin.users.edit.update.admin-privileges": "Admin privileges", "admin.users.edit.update.admin-privileges": "Admin privileges",
"admin.users.edit.update.change-password.title": "Change password", "admin.users.edit.update.change-password.title": "Đổi mật khẩu",
"admin.users.edit.update.change-password.field": "New password", "admin.users.edit.update.change-password.field": "Mật khẩu mới",
"admin.users.edit.update.change-password.button": "Save new password", "admin.users.edit.update.change-password.button": "Đổi mật khẩu",
"admin.users.edit.update.notify.password.success": "Password changed successfully", "admin.users.edit.update.notify.password.success": "Thay đổi mật khẩu thành công",
"admin.users.edit.delete.title": "Delete user {username}", "admin.users.edit.delete.title": "Xóa tài khoản {username}",
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?", "admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
// showCreateUserModal.tsx // showCreateUserModal.tsx
"admin.users.modal.create.title": "Create user", "admin.users.modal.create.title": "Create user",
"admin.users.modal.create.username": "Username", "admin.users.modal.create.username": "Username",
"admin.users.modal.create.email": "Email", "admin.users.modal.create.email": "Email",
"admin.users.modal.create.password": "Password", "admin.users.modal.create.password": "Mật khẩu",
"admin.users.modal.create.manual-password": "Set password manually", "admin.users.modal.create.manual-password": "Set password manually",
"admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.", "admin.users.modal.create.manual-password.description": "If not checked, the user will receive an email with a link to set their password.",
"admin.users.modal.create.admin": "Admin privileges", "admin.users.modal.create.admin": "Admin privileges",
@@ -204,14 +204,14 @@ export default {
// /admin/shares // /admin/shares
"admin.shares.title": "Share management", "admin.shares.title": "Share management",
"admin.shares.table.id": "Share ID", "admin.shares.table.id": "Share ID",
"admin.shares.table.username": "Creator", "admin.shares.table.username": "Người tạo",
"admin.shares.table.visitors": "Visitors", "admin.shares.table.visitors": "Lượng truy cập",
"admin.shares.table.expires": "Expires At", "admin.shares.table.expires": "Hết hạn vào",
"admin.shares.edit.delete.title": "Delete share {id}", "admin.shares.edit.delete.title": "Delete share {id}",
"admin.shares.edit.delete.description": "Do you really want to delete this share?", "admin.shares.edit.delete.description": "Do you really want to delete this share?",
// END /admin/shares // END /admin/shares
// /upload // /upload
"upload.title": "Upload", "upload.title": "Tải lên",
"upload.notify.generic-error": "An error occurred while finishing your share.", "upload.notify.generic-error": "An error occurred while finishing your share.",
"upload.notify.count-failed": "{count} files failed to upload. Trying again.", "upload.notify.count-failed": "{count} files failed to upload. Trying again.",
// Dropzone.tsx // Dropzone.tsx
@@ -219,13 +219,13 @@ export default {
"upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.", "upload.dropzone.description": "Drag'n'drop files here to start your share. We can accept only files that are less than {maxSize} in total.",
"upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.", "upload.dropzone.notify.file-too-big": "Your files exceed the maximum share size of {maxSize}.",
// FileList.tsx // FileList.tsx
"upload.filelist.name": "Name", "upload.filelist.name": "Tên",
"upload.filelist.size": "Size", "upload.filelist.size": "Kích thước",
// showCreateUploadModal.tsx // showCreateUploadModal.tsx
"upload.modal.title": "Create Share", "upload.modal.title": "Create Share",
"upload.modal.link.error.invalid": "Can only contain letters, numbers, underscores, and hyphens", "upload.modal.link.error.invalid": "Chỉ được phép sử dụng chữ, số, dấu gạch dưới và dấu gạch ngang",
"upload.modal.link.error.taken": "This link is already in use", "upload.modal.link.error.taken": "Liên kết đã được sử dụng",
"upload.modal.not-signed-in": "You're not signed in", "upload.modal.not-signed-in": "Bạn chưa đăng nhập",
"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": "never", "upload.modal.expires.never": "never",
"upload.modal.expires.never-long": "Never Expires", "upload.modal.expires.never-long": "Never Expires",
@@ -244,17 +244,17 @@ export default {
"upload.modal.expires.month-plural": "Tháng", "upload.modal.expires.month-plural": "Tháng",
"upload.modal.expires.year-singular": "Năm", "upload.modal.expires.year-singular": "Năm",
"upload.modal.expires.year-plural": "Năm", "upload.modal.expires.year-plural": "Năm",
"upload.modal.accordion.name-and-description.title": "Name and description", "upload.modal.accordion.name-and-description.title": "Tên và miêu tả",
"upload.modal.accordion.name-and-description.name.placeholder": "Tên", "upload.modal.accordion.name-and-description.name.placeholder": "Tên",
"upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share", "upload.modal.accordion.name-and-description.description.placeholder": "Note for the recipients of this share",
"upload.modal.accordion.email.title": "Email recipients", "upload.modal.accordion.email.title": "Email recipients",
"upload.modal.accordion.email.placeholder": "Enter email recipients", "upload.modal.accordion.email.placeholder": "Enter email recipients",
"upload.modal.accordion.email.invalid-email": "Invalid email address", "upload.modal.accordion.email.invalid-email": "Địa chỉ email không hợp lệ",
"upload.modal.accordion.security.title": "Security options", "upload.modal.accordion.security.title": "Tùy chọn bảo mật",
"upload.modal.accordion.security.password.label": "Password protection", "upload.modal.accordion.security.password.label": "Bảo vệ bằng mật khẩu",
"upload.modal.accordion.security.password.placeholder": "No password", "upload.modal.accordion.security.password.placeholder": "Không có mật khẩu",
"upload.modal.accordion.security.max-views.label": "Maximum views", "upload.modal.accordion.security.max-views.label": "Lượt xem tối đa",
"upload.modal.accordion.security.max-views.placeholder": "No limit", "upload.modal.accordion.security.max-views.placeholder": "Không giới hạn",
// showCompletedUploadModal.tsx // showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "This share will never expire.", "upload.modal.completed.never-expires": "This share will never expire.",
"upload.modal.completed.expires-on": "This share will expire on {expiration}.", "upload.modal.completed.expires-on": "This share will expire on {expiration}.",
@@ -271,16 +271,16 @@ export default {
"share.error.not-found.description": "The share you're looking for doesn't exist.", "share.error.not-found.description": "The share you're looking for doesn't exist.",
"share.error.access-denied.title": "Private share", "share.error.access-denied.title": "Private share",
"share.error.access-denied.description": "The current account does not have permission to access this share", "share.error.access-denied.description": "The current account does not have permission to access this share",
"share.modal.password.title": "Password required", "share.modal.password.title": "Cần mật khẩu để mở khoá",
"share.modal.password.description": "To access this share please enter the password for the share.", "share.modal.password.description": "To access this share please enter the password for the share.",
"share.modal.password": "Mật khẩu", "share.modal.password": "Mật khẩu",
"share.modal.error.invalid-password": "Mật khẩu không hợp lệ", "share.modal.error.invalid-password": "Mật khẩu không hợp lệ",
"share.button.download-all": "Tải xuống tất cả", "share.button.download-all": "Tải xuống tất cả",
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.", "share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
"share.modal.file-link": "File link", "share.modal.file-link": "File link",
"share.table.name": "Name", "share.table.name": "Tên",
"share.table.size": "Size", "share.table.size": "Kích thước",
"share.modal.file-preview.error.not-supported.title": "Preview not supported", "share.modal.file-preview.error.not-supported.title": "Xem trước không được hỗ trợ",
"share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.", "share.modal.file-preview.error.not-supported.description": "A preview for this file type is unsupported. Please download the file to view it.",
// END /share/[id] // END /share/[id]
// /share/[id]/edit // /share/[id]/edit
@@ -291,7 +291,7 @@ export default {
// END /share/[id]/edit // 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": "Tổng quan",
"admin.config.category.share": "Share", "admin.config.category.share": "Share",
"admin.config.category.email": "Email", "admin.config.category.email": "Email",
"admin.config.category.smtp": "SMTP", "admin.config.category.smtp": "SMTP",
@@ -349,9 +349,9 @@ export default {
"admin.config.smtp.email.description": "Email address which the emails get sent from", "admin.config.smtp.email.description": "Email address which the emails get sent from",
"admin.config.smtp.username": "Username", "admin.config.smtp.username": "Username",
"admin.config.smtp.username.description": "Username of the SMTP server", "admin.config.smtp.username.description": "Username of the SMTP server",
"admin.config.smtp.password": "Password", "admin.config.smtp.password": "Mật khẩu",
"admin.config.smtp.password.description": "Password of the SMTP server", "admin.config.smtp.password.description": "Password of the SMTP server",
"admin.config.smtp.button.test": "Send test email", "admin.config.smtp.button.test": "Gửi email kiểm tra",
"admin.config.smtp.allow-unauthorized-certificates": "Trust unauthorized SMTP server certificates", "admin.config.smtp.allow-unauthorized-certificates": "Trust unauthorized SMTP server certificates",
"admin.config.smtp.allow-unauthorized-certificates.description": "Only set this to true if you need to trust self signed certificates.", "admin.config.smtp.allow-unauthorized-certificates.description": "Only set this to true if you need to trust self signed certificates.",
"admin.config.oauth.allow-registration": "Allow registration", "admin.config.oauth.allow-registration": "Allow registration",
@@ -408,7 +408,7 @@ export default {
"admin.config.ldap.enabled": "Enabled LDAP", "admin.config.ldap.enabled": "Enabled LDAP",
"admin.config.ldap.enabled.description": "Use LDAP authentication for user login", "admin.config.ldap.enabled.description": "Use LDAP authentication for user login",
"admin.config.ldap.url": "Server URL", "admin.config.ldap.url": "Server URL",
"admin.config.ldap.url.description": "URL of the LDAP server", "admin.config.ldap.url.description": "Địa chỉ máy chủ LDAP",
"admin.config.ldap.bind-dn": "Bind DN", "admin.config.ldap.bind-dn": "Bind DN",
"admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search", "admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search",
"admin.config.ldap.bind-password": "Bind password", "admin.config.ldap.bind-password": "Bind password",
@@ -425,11 +425,11 @@ export default {
// error // error
"error.title": "Lỗi", "error.title": "Lỗi",
"error.description": "Oops!", "error.description": "Oops!",
"error.button.back": "Go back", "error.button.back": "Quay lại",
"error.msg.default": "Something went wrong.", "error.msg.default": "Đã xảy ra lỗi.",
"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.invalid_token": "Internal Error", "error.msg.invalid_token": "Lỗi nội bộ",
"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.",
"error.msg.no_email": "Can't get email address from this {0} account.", "error.msg.no_email": "Can't get email address from this {0} account.",
"error.msg.already_linked": "This {0} account is already linked to another account.", "error.msg.already_linked": "This {0} account is already linked to another account.",
@@ -465,7 +465,7 @@ export default {
"common.error.invalid-email": "Invalid email address", "common.error.invalid-email": "Invalid email address",
"common.error.too-short": "Must be at least {length} characters", "common.error.too-short": "Must be at least {length} characters",
"common.error.too-long": "Must be at most {length} characters", "common.error.too-long": "Must be at most {length} characters",
"common.error.exact-length": "Must be exactly {length} characters", "common.error.exact-length": "Bằng {length} kí tự",
"common.error.invalid-number": "Phải là số", "common.error.invalid-number": "Phải là số",
"common.error.field-required": "Trường bắt buộc" "common.error.field-required": "Trường bắt buộc"
}; };

View File

@@ -162,9 +162,7 @@ export default function Home() {
size="md" size="md"
className={classes.control} className={classes.control}
> >
<FormattedMessage <FormattedMessage id="home.button.start" />
id="home.button.start"
/>
</Button> </Button>
<Button <Button
component={Link} component={Link}

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.0.2", "version": "1.0.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.0.2", "version": "1.0.3",
"devDependencies": { "devDependencies": {
"conventional-changelog-cli": "^3.0.0" "conventional-changelog-cli": "^3.0.0"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.0.2", "version": "1.0.3",
"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",