Compare commits

..

19 Commits

Author SHA1 Message Date
Elias Schneider
b088a5ef2a release: 0.18.2 2023-10-09 11:20:06 +02:00
Elias Schneider
c502cd58db chore(translations): update translations via Crowdin (#278)
* New translations en-us.ts (Japanese)

* New translations en-us.ts (Japanese)

* New translations en-us.ts (Japanese)
2023-10-09 11:19:48 +02:00
Elias Schneider
97e7d7190d fix: memory leak while downloading large files 2023-10-09 11:14:51 +02:00
Elias Schneider
38919003e9 fix: disable image optimizations for logo to prevent caching issues with custom logos 2023-10-09 10:40:55 +02:00
Elias Schneider
f15a8dc277 chore(translations): add files for Japanese 2023-10-06 09:21:14 +02:00
Elias Schneider
92927b1373 release: 0.18.1 2023-09-22 11:31:03 +02:00
Elias Schneider
6a4108ed61 fix: permission changes of docker container brakes existing installations 2023-09-22 11:30:53 +02:00
Elias Schneider
c9f1be2faf release: 0.18.0 2023-09-21 16:24:07 +02:00
Elias Schneider
57be6945f2 chore(ci/cd): cache Docker build 2023-09-21 16:09:23 +02:00
Elias Schneider
82abe52ea5 chore(translations): update translations via Crowdin (#253)
* New translations en-us.ts (German)

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

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

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

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

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

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

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

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

* New translations en-us.ts (Dutch, Belgium)
2023-09-21 16:05:42 +02:00
KdF
6fa7af7905 fix(docker): Updated to newest version of alpine linux and fixed missing dependencies (#255)
* Updated docker file

* yes

* Update Dockerfile

Co-authored-by: Elias Schneider <login@eliasschneider.com>

---------

Co-authored-by: Elias Schneider <login@eliasschneider.com>
2023-09-21 16:04:02 +02:00
Elias Schneider
13e7a30bb9 feat: show upload modal on file drop 2023-09-21 15:59:55 +02:00
Elias Schneider
955af04e32 chore(translations): add Dutch files 2023-09-18 17:48:38 +02:00
Elias Schneider
035e67f759 chore(translations): update translations via Crowdin (#250)
* New translations en-US.ts (Serbian (Cyrillic))

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

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

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

* New translations en-US.ts (Serbian (Cyrillic))
2023-09-18 11:23:55 +02:00
Elias Schneider
167ec782ef New translations en-US.ts (Spanish) (#248) 2023-09-12 11:47:12 +02:00
Elias Schneider
743c33475f chore(translations): add Serbian files 2023-09-12 11:45:20 +02:00
adriadam10
3f1d3b7833 Run docker container as non root user (#242)
* Run docker container as non root user

* Pass UID and GID as a variable + alpine-based image

* change apt-get to apk

* chore: remove unnecessary packages from Dockerfile

* chore: remove unnecessary `chown`

---------

Co-authored-by: Elias Schneider <login@eliasschneider.com>
2023-09-11 16:14:42 +02:00
Elias Schneider
3d76e41cd8 chore(translations): update translations via Crowdin (#239)
* New translations en-US.ts (Portuguese, Brazilian)

* New translations en-US.ts (French)
2023-09-09 20:56:57 +02:00
Elias Schneider
e9efbc17bc fix: nextjs proxy warning 2023-09-05 14:58:38 +02:00
29 changed files with 1202 additions and 128 deletions

View File

@@ -1,4 +1,4 @@
name: Create Docker Image
name: Build and Push Docker Image
on:
release:
@@ -10,15 +10,25 @@ jobs:
steps:
- name: checkout code
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: login to docker registry
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Build the image
run: |
docker buildx build --push \
--tag stonith404/pingvin-share:latest \
--tag stonith404/pingvin-share:${{ github.ref_name }} \
--platform linux/amd64,linux/arm64 .
- name: Login to Docker registry
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: stonith404/pingvin-share:latest,stonith404/pingvin-share:${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -1,3 +1,31 @@
## [0.18.2](https://github.com/stonith404/pingvin-share/compare/v0.18.1...v0.18.2) (2023-10-09)
### Bug Fixes
* disable image optimizations for logo to prevent caching issues with custom logos ([3891900](https://github.com/stonith404/pingvin-share/commit/38919003e9091203b507d0f0b061f4a1835ff4f4))
* memory leak while downloading large files ([97e7d71](https://github.com/stonith404/pingvin-share/commit/97e7d7190dfe219caf441dffcd7830c304c3c939))
## [0.18.1](https://github.com/stonith404/pingvin-share/compare/v0.18.0...v0.18.1) (2023-09-22)
### Bug Fixes
* permission changes of docker container brakes existing installations ([6a4108e](https://github.com/stonith404/pingvin-share/commit/6a4108ed6138e7297e66fd1e38450f23afe99aae))
## [0.18.0](https://github.com/stonith404/pingvin-share/compare/v0.17.5...v0.18.0) (2023-09-21)
### Features
* show upload modal on file drop ([13e7a30](https://github.com/stonith404/pingvin-share/commit/13e7a30bb96faeb25936ff08a107834fd7af5766))
### Bug Fixes
* **docker:** Updated to newest version of alpine linux and fixed missing dependencies ([#255](https://github.com/stonith404/pingvin-share/issues/255)) ([6fa7af7](https://github.com/stonith404/pingvin-share/commit/6fa7af79051c964060bd291c9faad90fc01a1b72))
* nextjs proxy warning ([e9efbc1](https://github.com/stonith404/pingvin-share/commit/e9efbc17bcf4827e935e2018dcdf3b70a9a49991))
## [0.17.5](https://github.com/stonith404/pingvin-share/compare/v0.17.4...v0.17.5) (2023-09-03)

View File

@@ -1,37 +1,40 @@
# Using node slim because prisma ORM needs libc for ARM builds
# Stage 1: on frontend dependency change
FROM node:19-slim AS frontend-dependencies
# Stage 1: Frontend dependencies
FROM node:20-alpine AS frontend-dependencies
WORKDIR /opt/app
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
# Stage 2: on frontend change
FROM node:19-slim AS frontend-builder
# Stage 2: Build frontend
FROM node:20-alpine AS frontend-builder
WORKDIR /opt/app
COPY ./frontend .
COPY --from=frontend-dependencies /opt/app/node_modules ./node_modules
RUN npm run build
# Stage 3: on backend dependency change
FROM node:19-slim AS backend-dependencies
# Stage 3: Backend dependencies
FROM node:20-alpine AS backend-dependencies
WORKDIR /opt/app
COPY backend/package.json backend/package-lock.json ./
RUN npm ci
# Stage 4:on backend change
FROM node:19-slim AS backend-builder
RUN apt-get update && apt-get install -y openssl
# Stage 4: Build backend
FROM node:20-alpine AS backend-builder
WORKDIR /opt/app
COPY ./backend .
COPY --from=backend-dependencies /opt/app/node_modules ./node_modules
RUN npx prisma generate
RUN npm run build && npm prune --production
RUN npm run build && npm prune --production
# Stage 5: Final image
FROM node:19-slim AS runner
FROM node:20-alpine AS runner
ENV NODE_ENV=docker
RUN apt-get update && apt-get install -y curl openssl
# Alpine specific dependencies
RUN apk update --no-cache
RUN apk upgrade --no-cache
RUN apk add --no-cache curl nginx
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
WORKDIR /opt/app/frontend
COPY --from=frontend-builder /opt/app/public ./public
@@ -46,8 +49,12 @@ COPY --from=backend-builder /opt/app/prisma ./prisma
COPY --from=backend-builder /opt/app/package.json ./
WORKDIR /opt/app
EXPOSE 3000
# Add a health check to ensure the container is healthy
HEALTHCHECK --interval=10s --timeout=3s CMD curl -f http://localhost:3000/api/health || exit 1
# HOSTNAME=0.0.0.0 fixes https://github.com/vercel/next.js/issues/51684. It can be removed as soon as the issue is fixed
CMD cp -rn /tmp/img /opt/app/frontend/public && HOSTNAME=0.0.0.0 node frontend/server.js & cd backend && npm run prod
# Application startup
# HOSTNAME=0.0.0.0 fixes https://github.com/vercel/next.js/issues/51684. It can be removed as soon as the issue is fixed
CMD cp -rn /tmp/img /opt/app/frontend/public && nginx && PORT=3333 HOSTNAME=0.0.0.0 node frontend/server.js & cd backend && npm run prod

View File

@@ -63,6 +63,8 @@ npm run build
pm2 start --name="pingvin-share-frontend" npm -- run start
```
**Uploading Large Files**: By default, Pingvin Share uses a built-in reverse proxy to reduce the installation steps. However, this reverse proxy is not optimized for uploading large files. If you wish to upload larger files, you can either use the Docker installation or set up your own reverse proxy. An example configuration for Nginx can be found in `/nginx/nginx.conf`.
The website is now listening on `http://localhost:3000`, have fun with Pingvin Share 🐧!
### Integrations

View File

@@ -1,12 +1,12 @@
{
"name": "pingvin-share-backend",
"version": "0.17.5",
"version": "0.18.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "pingvin-share-backend",
"version": "0.17.5",
"version": "0.18.2",
"dependencies": {
"@nestjs/common": "^10.1.2",
"@nestjs/config": "^3.0.0",

View File

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

View File

@@ -0,0 +1,19 @@
import { Controller, Get, Res } from "@nestjs/common";
import { Response } from "express";
import { PrismaService } from "./prisma/prisma.service";
@Controller("/")
export class AppController {
constructor(private prismaService: PrismaService) {}
@Get("health")
async health(@Res({ passthrough: true }) res: Response) {
try {
await this.prismaService.config.findMany();
return "OK";
} catch {
res.statusCode = 500;
return "ERROR";
}
}
}

View File

@@ -14,6 +14,7 @@ import { ShareModule } from "./share/share.module";
import { UserModule } from "./user/user.module";
import { ClamScanModule } from "./clamscan/clamscan.module";
import { ReverseShareModule } from "./reverseShare/reverseShare.module";
import { AppController } from "./app.controller";
@Module({
imports: [
@@ -33,6 +34,9 @@ import { ReverseShareModule } from "./reverseShare/reverseShare.module";
ClamScanModule,
ReverseShareModule,
],
controllers:[
AppController,
],
providers: [
{
provide: APP_GUARD,

View File

@@ -7,7 +7,8 @@ const IMAGES_PATH = "../frontend/public/img";
@Injectable()
export class LogoService {
async create(file: Buffer) {
fs.writeFileSync(`${IMAGES_PATH}/logo.png`, file, "binary");
const resized = await sharp(file).resize(900).toBuffer();
fs.writeFileSync(`${IMAGES_PATH}/logo.png`, resized, "binary");
this.createFavicon(file);
this.createPWAIcons(file);
}
@@ -25,7 +26,7 @@ export class LogoService {
fs.promises.writeFile(
`${IMAGES_PATH}/icons/icon-${size}x${size}.png`,
resized,
"binary",
"binary"
);
}
}

View File

@@ -11,6 +11,7 @@
"react-hooks/exhaustive-deps": ["off"],
"import/no-anonymous-default-export": ["off"],
"no-unused-vars": ["warn"],
"react/no-unescaped-entities": ["off"]
"react/no-unescaped-entities": ["off"],
"@next/next/no-img-element": ["off"]
}
}

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,6 +1,4 @@
import Image from "next/image";
const Logo = ({ height, width }: { height: number; width: number }) => {
return <Image src="/img/logo.png" alt="logo" height={height} width={width} />;
return <img src="/img/logo.png" alt="logo" height={height} width={width} />;
};
export default Logo;

View File

@@ -1,6 +1,6 @@
import { Button, Center, createStyles, Group, Text } from "@mantine/core";
import { Dropzone as MantineDropzone } from "@mantine/dropzone";
import { Dispatch, ForwardedRef, SetStateAction, useRef } from "react";
import { ForwardedRef, useRef } from "react";
import { TbCloudUpload, TbUpload } from "react-icons/tb";
import { FormattedMessage } from "react-intl";
import useTranslate from "../../hooks/useTranslate.hook";
@@ -35,13 +35,11 @@ const useStyles = createStyles((theme) => ({
const Dropzone = ({
isUploading,
maxShareSize,
files,
setFiles,
showCreateUploadModalCallback,
}: {
isUploading: boolean;
maxShareSize: number;
files: FileUpload[];
setFiles: Dispatch<SetStateAction<FileUpload[]>>;
showCreateUploadModalCallback: (files: FileUpload[]) => void;
}) => {
const t = useTranslate();
@@ -55,24 +53,21 @@ const Dropzone = ({
}}
disabled={isUploading}
openRef={openRef as ForwardedRef<() => void>}
onDrop={(newFiles: FileUpload[]) => {
const fileSizeSum = [...newFiles, ...files].reduce(
(n, { size }) => n + size,
0,
);
onDrop={(files: FileUpload[]) => {
const fileSizeSum = files.reduce((n, { size }) => n + size, 0);
if (fileSizeSum > maxShareSize) {
toast.error(
t("upload.dropzone.notify.file-too-big", {
maxSize: byteToHumanSizeString(maxShareSize),
}),
})
);
} else {
newFiles = newFiles.map((newFile) => {
files = files.map((newFile) => {
newFile.uploadingProgress = 0;
return newFile;
});
setFiles([...newFiles, ...files]);
showCreateUploadModalCallback(files);
}
}}
className={classes.dropzone}

View File

@@ -26,6 +26,7 @@ import useTranslate, {
translateOutsideContext,
} from "../../../hooks/useTranslate.hook";
import shareService from "../../../services/share.service";
import { FileUpload } from "../../../types/File.type";
import { CreateShare } from "../../../types/share.type";
import { getExpirationPreview } from "../../../utils/date.util";
@@ -38,7 +39,8 @@ const showCreateUploadModal = (
allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean;
},
uploadCallback: (createShare: CreateShare) => void,
files: FileUpload[],
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void
) => {
const t = translateOutsideContext();
@@ -47,6 +49,7 @@ const showCreateUploadModal = (
children: (
<CreateUploadModalBody
options={options}
files={files}
uploadCallback={uploadCallback}
/>
),
@@ -55,9 +58,11 @@ const showCreateUploadModal = (
const CreateUploadModalBody = ({
uploadCallback,
files,
options,
}: {
uploadCallback: (createShare: CreateShare) => void;
files: FileUpload[];
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void;
options: {
isUserSignedIn: boolean;
isReverseShare: boolean;
@@ -121,16 +126,19 @@ const CreateUploadModalBody = ({
const expiration = form.values.never_expires
? "never"
: form.values.expiration_num + form.values.expiration_unit;
uploadCallback({
id: values.link,
expiration: expiration,
recipients: values.recipients,
description: values.description,
security: {
password: values.password,
maxViews: values.maxViews,
uploadCallback(
{
id: values.link,
expiration: expiration,
recipients: values.recipients,
description: values.description,
security: {
password: values.password,
maxViews: values.maxViews,
},
},
});
files
);
modals.closeAll();
}
})}
@@ -152,7 +160,7 @@ const CreateUploadModalBody = ({
"link",
Buffer.from(Math.random().toString(), "utf8")
.toString("base64")
.substr(10, 7),
.substr(10, 7)
)
}
>
@@ -251,7 +259,7 @@ const CreateUploadModalBody = ({
neverExpires: t("upload.modal.completed.never-expires"),
expiresOn: t("upload.modal.completed.expires-on"),
},
form,
form
)}
</Text>
</>
@@ -266,7 +274,7 @@ const CreateUploadModalBody = ({
<Textarea
variant="filled"
placeholder={t(
"upload.modal.accordion.description.placeholder",
"upload.modal.accordion.description.placeholder"
)}
{...form.getInputProps("description")}
/>
@@ -290,7 +298,7 @@ const CreateUploadModalBody = ({
if (!query.match(/^\S+@\S+\.\S+$/)) {
form.setFieldError(
"recipients",
t("upload.modal.accordion.email.invalid-email"),
t("upload.modal.accordion.email.invalid-email")
);
} else {
form.setFieldError("recipients", null);
@@ -316,7 +324,7 @@ const CreateUploadModalBody = ({
<PasswordInput
variant="filled"
placeholder={t(
"upload.modal.accordion.security.password.placeholder",
"upload.modal.accordion.security.password.placeholder"
)}
label={t("upload.modal.accordion.security.password.label")}
autoComplete="off"
@@ -327,7 +335,7 @@ const CreateUploadModalBody = ({
type="number"
variant="filled"
placeholder={t(
"upload.modal.accordion.security.max-views.placeholder",
"upload.modal.accordion.security.max-views.placeholder"
)}
label={t("upload.modal.accordion.security.max-views.label")}
{...form.getInputProps("maxViews")}
@@ -336,7 +344,7 @@ const CreateUploadModalBody = ({
</Accordion.Panel>
</Accordion.Item>
</Accordion>
<Button type="submit">
<Button type="submit" data-autofocus>
<FormattedMessage id="common.button.share" />
</Button>
</Stack>

View File

@@ -4,10 +4,13 @@ import english from "./translations/en-US";
import spanish from "./translations/es-ES";
import finnish from "./translations/fi-FI";
import french from "./translations/fr-FR";
import japanese from "./translations/ja-JP";
import dutch from "./translations/nl-BE";
import portuguese from "./translations/pt-BR";
import russian from "./translations/ru-RU";
import chineseSimplified from "./translations/zh-CN";
import serbian from "./translations/sr-SP";
import thai from "./translations/th-TH";
import chineseSimplified from "./translations/zh-CN";
export const LOCALES = {
ENGLISH: {
@@ -60,4 +63,19 @@ export const LOCALES = {
code: "th-TH",
messages: thai,
},
SERBIAN: {
name: "Srpski",
code: "sr-SP",
messages: serbian,
},
DUTCH: {
name: "Nederlands",
code: "nl-BE",
messages: dutch,
},
JAPANESE: {
name: "日本語",
code: "ja-JP",
messages: japanese,
},
};

View File

@@ -111,7 +111,7 @@ export default {
"account.reverseShares.title.empty": "Es ist leer hier 👀",
"account.reverseShares.description.empty": "Du hast keine externen Freigaben erstellt.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.title": "Externe Freigabe erstellen",
"account.reverseShares.modal.expiration.label": "Gültig bis",
"account.reverseShares.modal.expiration.minute-singular": "Minute",
"account.reverseShares.modal.expiration.minute-plural": "Minuten",

View File

@@ -5,7 +5,7 @@ export default {
"navbar.home": "Inicio",
"navbar.signup": "Registrarse",
"navbar.links.shares": "Mis compartidos",
"navbar.links.reverse": "Reverse Shares",
"navbar.links.reverse": "Comparticiones inversas",
"navbar.avatar.account": "Mi cuenta",
"navbar.avatar.admin": "Administración",
"navbar.avatar.signout": "Cerrar sesión",
@@ -106,12 +106,12 @@ export default {
"account.shares.modal.delete.description": "¿Seguro que quieres eliminar este compartido?",
// END /account/shares
// /account/reverseShares
"account.reverseShares.title": "Reverse Shares",
"account.reverseShares.description": "Un Reverse Share te permite generar una URL única con la que usuarios externos pueden compartir archivos.",
"account.reverseShares.title": "Comparticiones inversas",
"account.reverseShares.description": "Una compartición inversa te permite generar una URL única con la que usuarios externos pueden compartir archivos.",
"account.reverseShares.title.empty": "Aquí está vacío 👀",
"account.reverseShares.description.empty": "No tienes ningún Reverse Share.",
"account.reverseShares.description.empty": "No tienes ninguna compartición inversa.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.title": "Crear compartición inversa",
"account.reverseShares.modal.expiration.label": "Expiración",
"account.reverseShares.modal.expiration.minute-singular": "Minuto",
"account.reverseShares.modal.expiration.minute-plural": "Minutos",
@@ -127,11 +127,11 @@ export default {
"account.reverseShares.modal.expiration.year-plural": "Años",
"account.reverseShares.modal.max-size.label": "Tamaño máximo del compartido",
"account.reverseShares.modal.send-email": "Enviar notificación por correo",
"account.reverseShares.modal.send-email.description": "Enviar una notificación por correo cuando se comparta algo con este enlace de Reverse Share.",
"account.reverseShares.modal.send-email.description": "Enviar una notificación por correo cuando se comparta algo con este enlace de compartición inversa.",
"account.reverseShares.modal.max-use.label": "Máximo de usos",
"account.reverseShares.modal.max-use.description": "Cantidad máxima de veces que esta URL se puede usar para crear un compartido.",
"account.reverseShare.never-expires": "Esta Reverse Share nunca expirará.",
"account.reverseShare.expires-on": "Esta Reverse Share expirará en {expiration}.",
"account.reverseShare.never-expires": "Esta compartición inversa nunca expirará.",
"account.reverseShare.expires-on": "Esta compartición inversa expirará en {expiration}.",
"account.reverseShares.table.no-shares": "Todavía no se han creado compartidos",
"account.reverseShares.table.count.singular": "compartido",
"account.reverseShares.table.count.plural": "compartidos",
@@ -139,9 +139,9 @@ export default {
"account.reverseShares.table.remaining": "Usos restantes",
"account.reverseShares.table.max-size": "Tamaño máximo del compartido",
"account.reverseShares.table.expires": "Expira en",
"account.reverseShares.modal.reverse-share-link": "Enlace de Reverse Share",
"account.reverseShares.modal.delete.title": "Eliminar Reverse Share",
"account.reverseShares.modal.delete.description": "¿Seguro que quieres eliminar esta Reverse Share? Si lo haces, todos los archivos asociados también serán eliminados.",
"account.reverseShares.modal.reverse-share-link": "Enlace de compartición inversa",
"account.reverseShares.modal.delete.title": "Eliminar compartición inversa",
"account.reverseShares.modal.delete.description": "¿Seguro que quieres eliminar esta compartición inversa? Si lo haces, todos los archivos asociados también serán eliminados.",
// END /account/reverseShares
// /admin
"admin.title": "Administración",
@@ -261,10 +261,10 @@ export default {
"admin.config.email.share-recipients-subject.description": "Asunto del correo el cual es enviado al destinatario del compartido.",
"admin.config.email.share-recipients-message": "Mensaje destinatario",
"admin.config.email.share-recipients-message.description": "Mensaje el cual es enviado al destinatario del compartido. Variables disponibles:\n{creator} - Nombre del creador del compartido\n {shareUrl} - URL del compartido\n {desc} - Descripción del compartido\n {expires} - Fecha de expiración del compartido\nLas variables serán remplazadas con los valores reales.",
"admin.config.email.reverse-share-subject": "Asunto del Reverse Share",
"admin.config.email.reverse-share-subject.description": "Asunto del correo el cual se envía cuando alguien comparte algo con tu enlace de Reverse Share.",
"admin.config.email.reverse-share-message": "Mensaje del Reverse Share",
"admin.config.email.reverse-share-message.description": "Mensaje que se envía cuando alguien comparte algo con tu enlace de Reverse Share. {shareUrl} Se remplazará con el nombre del creador y la URL del compartido.",
"admin.config.email.reverse-share-subject": "Asunto de la compartición inversa",
"admin.config.email.reverse-share-subject.description": "Asunto del correo el cual se envía cuando alguien comparte algo con tu enlace de compartición inversa.",
"admin.config.email.reverse-share-message": "Mensaje de la compartición inversa",
"admin.config.email.reverse-share-message.description": "Mensaje que se envía cuando alguien comparte algo con tu enlace de compartición inversa. {shareUrl} Se remplazará con el nombre del creador y la URL del compartido.",
"admin.config.email.reset-password-subject": "Asunto restablecer contraseña",
"admin.config.email.reset-password-subject.description": "Asunto del correo que se envía cuando un usuario solicita restablecer la contraseña.",
"admin.config.email.reset-password-message": "Mensaje restablecer contraseña",

View File

@@ -111,7 +111,7 @@ export default {
"account.reverseShares.title.empty": "Il n'y a rien ici 👀",
"account.reverseShares.description.empty": "Vous n'avez aucun partage inversé.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.title": "Créer un partage inversé",
"account.reverseShares.modal.expiration.label": "Expiration",
"account.reverseShares.modal.expiration.minute-singular": "Minute",
"account.reverseShares.modal.expiration.minute-plural": "Minutes",

View File

@@ -0,0 +1,324 @@
export default {
// Navbar
"navbar.upload": "アップロード",
"navbar.signin": "サインイン",
"navbar.home": "ホーム",
"navbar.signup": "会員登録",
"navbar.links.shares": "自分の共有",
"navbar.links.reverse": "自分と共有",
"navbar.avatar.account": "マイアカウント",
"navbar.avatar.admin": "管理画面",
"navbar.avatar.signout": "サインアウト",
// END navbar
// /
"home.title": "<h>セルフホスト</h>のファイル共有プラットフォーム。",
"home.description": "WeTransferのようなサードパーティーサービスに自分のファイルを渡したいですか",
"home.bullet.a.name": "セルフホスト",
"home.bullet.a.description": "Pingvin Shareをあなたのマシンでホストしましょう。",
"home.bullet.b.name": "プライバシー",
"home.bullet.b.description": "あなたのファイルはあなたのものであり、決して第三者の手に入るべきではありません。",
"home.bullet.c.name": "ファイルサイズ制限に悩まされることはありません",
"home.bullet.c.description": "大きなファイルもアップロード。ストレージのサイズだけが唯一の制限です。",
"home.button.start": "始めましょう",
"home.button.source": "ソースコード",
// END /
// /auth/signin
"signin.title": "おかえりなさい",
"signin.description": "アカウントをお持ちではありませんか?",
"signin.button.signup": "会員登録",
"signin.input.email-or-username": "メールアドレスまたはユーザー名",
"signin.input.email-or-username.placeholder": "メールアドレスまたはユーザー名",
"signin.input.password": "パスワード",
"signin.input.password.placeholder": "あなたのパスワード",
"signin.button.submit": "サインイン",
"signIn.notify.totp-required.title": "二段階認証が必要です",
"signIn.notify.totp-required.description": "二段階認証コードを入力してください",
// END /auth/signin
// /auth/signup
"signup.title": "アカウントを作成",
"signup.description": "既にアカウントをお持ちですか?",
"signup.button.signin": "サインイン",
"signup.input.username": "ユーザー名",
"signup.input.username.placeholder": "あなたのユーザー名",
"signup.input.email": "メールアドレス",
"signup.input.email.placeholder": "あなたのメールアドレス",
"signup.button.submit": "さあ始めましょう",
// END /auth/signup
// /auth/reset-password
"resetPassword.title": "パスワードを忘れてしまいましたか?",
"resetPassword.description": "登録しているメールアドレスを入力してください。",
"resetPassword.notify.success": "パスワードをリセットするためのリンクをメールで送信しました。",
"resetPassword.button.back": "サインインページに戻る",
"resetPassword.text.resetPassword": "パスワードをリセット",
"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.notify.password.success": "Password changed successfully",
"account.card.security.title": "Security",
"account.card.security.totp.enable.description": "Enter your current password to start enabling TOTP",
"account.card.security.totp.disable.description": "Enter your current password to disable TOTP",
"account.card.security.totp.button.start": "Start",
"account.modal.totp.title": "Enable TOTP",
"account.modal.totp.step1": "Step 1: Add your authenticator",
"account.modal.totp.step2": "Step 2: Validate your code",
"account.modal.totp.enterManually": "Enter manually",
"account.modal.totp.code": "Code",
"account.modal.totp.clickToCopy": "Click to copy",
"account.modal.totp.verify": "Verify",
"account.notify.totp.disable": "TOTP disabled successfully",
"account.notify.totp.enable": "TOTP enabled successfully",
"account.card.language.title": "Language",
"account.card.language.description": "The project is translated by the community. Some languages might be incomplete.",
"account.card.color.title": "Color scheme",
// ThemeSwitcher.tsx
"account.theme.dark": "Dark",
"account.theme.light": "Light",
"account.theme.system": "System",
"account.button.delete": "Delete Account",
"account.modal.delete.title": "Delete Account",
"account.modal.delete.description": "Do you really want to delete your account including all your active shares?",
// END /account
// /account/shares
"account.shares.title": "My shares",
"account.shares.title.empty": "It's empty here 👀",
"account.shares.description.empty": "You don't have any shares.",
"account.shares.button.create": "Create one",
"account.shares.info.title": "Share informations",
"account.shares.table.id": "ID",
"account.shares.table.name": "Name",
"account.shares.table.description": "Description",
"account.shares.table.visitors": "Visitors",
"account.shares.table.expiresAt": "Expires at",
"account.shares.table.createdAt": "Created at",
"account.shares.table.size": "Size",
"account.shares.modal.share-informations": "Share informations",
"account.shares.modal.share-link": "Share link",
"account.shares.modal.delete.title": "Delete share {share}",
"account.shares.modal.delete.description": "Do you really want to delete this share?",
// END /account/shares
// /account/reverseShares
"account.reverseShares.title": "Reverse shares",
"account.reverseShares.description": "A reverse share allows you to generate a unique URL that allows external users to create a share.",
"account.reverseShares.title.empty": "It's empty here 👀",
"account.reverseShares.description.empty": "You don't have any reverse shares.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.expiration.label": "Expiration",
"account.reverseShares.modal.expiration.minute-singular": "Minute",
"account.reverseShares.modal.expiration.minute-plural": "Minutes",
"account.reverseShares.modal.expiration.hour-singular": "Hour",
"account.reverseShares.modal.expiration.hour-plural": "Hours",
"account.reverseShares.modal.expiration.day-singular": "Day",
"account.reverseShares.modal.expiration.day-plural": "Days",
"account.reverseShares.modal.expiration.week-singular": "Week",
"account.reverseShares.modal.expiration.week-plural": "Weeks",
"account.reverseShares.modal.expiration.month-singular": "Month",
"account.reverseShares.modal.expiration.month-plural": "Months",
"account.reverseShares.modal.expiration.year-singular": "Year",
"account.reverseShares.modal.expiration.year-plural": "Years",
"account.reverseShares.modal.max-size.label": "Max share size",
"account.reverseShares.modal.send-email": "Send email notification",
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
"account.reverseShares.modal.max-use.label": "Max uses",
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
"account.reverseShare.never-expires": "This reverse share will never expire.",
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
"account.reverseShares.table.no-shares": "No shares created yet",
"account.reverseShares.table.count.singular": "share",
"account.reverseShares.table.count.plural": "shares",
"account.reverseShares.table.shares": "Shares",
"account.reverseShares.table.remaining": "Remaining uses",
"account.reverseShares.table.max-size": "Max share size",
"account.reverseShares.table.expires": "Expires at",
"account.reverseShares.modal.reverse-share-link": "Reverse share link",
"account.reverseShares.modal.delete.title": "Delete reverse share",
"account.reverseShares.modal.delete.description": "Do you really want to delete this reverse share? If you do, the associated shares will be deleted as well.",
// END /account/reverseShares
// /admin
"admin.title": "Administration",
"admin.button.users": "User management",
"admin.button.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
// /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.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.description.title": "Description",
"upload.modal.accordion.description.placeholder": "Note for the recipients of this share",
"upload.modal.accordion.email.title": "Email recipients",
"upload.modal.accordion.email.placeholder": "Enter email recipients",
"upload.modal.accordion.email.invalid-email": "Invalid email address",
"upload.modal.accordion.security.title": "Security options",
"upload.modal.accordion.security.password.label": "Password protection",
"upload.modal.accordion.security.password.placeholder": "No password",
"upload.modal.accordion.security.max-views.label": "Maximum views",
"upload.modal.accordion.security.max-views.placeholder": "No limit",
// showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "This share will never expire.",
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
"upload.modal.completed.share-ready": "Share ready",
// END /upload
// /share/[id]
"share.title": "Share {shareId}",
"share.description": "Look what I've shared with you!",
"share.error.visitor-limit-exceeded.title": "Visitor limit exceeded",
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
"share.error.removed.title": "Share removed",
"share.error.not-found.title": "Share not found",
"share.error.not-found.description": "The share you're looking for doesn't exist.",
"share.modal.password.title": "Password required",
"share.modal.password.description": "To access this share please enter the password for the share.",
"share.modal.password": "Password",
"share.modal.error.invalid-password": "Invalid password",
"share.button.download-all": "Download all",
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
"share.modal.file-link": "File link",
"share.table.name": "Name",
"share.table.size": "Size",
"share.modal.file-preview.error.not-supported.title": "Preview not supported",
"share.modal.file-preview.error.not-supported.description": "A preview for thise file type is unsupported. Please download the file to view it.",
// END /share/[id]
// /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.general.app-name": "App name",
"admin.config.general.app-name.description": "Name of the application",
"admin.config.general.app-url": "App URL",
"admin.config.general.app-url.description": "On which URL Pingvin Share is available",
"admin.config.general.show-home-page": "Show home page",
"admin.config.general.show-home-page.description": "Whether to show the home page",
"admin.config.general.logo": "Logo",
"admin.config.general.logo.description": "Change your logo by uploading a new image. The image must be a PNG and should have the format 1:1.",
"admin.config.general.logo.placeholder": "Pick image",
"admin.config.email.enable-share-email-recipients": "Enable share email recipients",
"admin.config.email.enable-share-email-recipients.description": "Whether to allow emails to share recipients. Only enable this if you have enabled SMTP.",
"admin.config.email.share-recipients-subject": "Share recipients subject",
"admin.config.email.share-recipients-subject.description": "Subject of the email which gets sent to the share recipients.",
"admin.config.email.share-recipients-message": "Share recipients message",
"admin.config.email.share-recipients-message.description": "Message which gets sent to the share recipients. Available variables:\n {creator} - The username of the creator of the share\n {shareUrl} - The URL of the share\n {desc} - The description of the share\n {expires} - The expiration date of the share\n The variables will be replaced with the actual value.",
"admin.config.email.reverse-share-subject": "Reverse share subject",
"admin.config.email.reverse-share-subject.description": "Subject of the email which gets sent when someone created a share with your reverse share link.",
"admin.config.email.reverse-share-message": "Reverse share message",
"admin.config.email.reverse-share-message.description": "Message which gets sent when someone created a share with your reverse share link. {shareUrl} will be replaced with the creator's name and the share URL.",
"admin.config.email.reset-password-subject": "Reset password subject",
"admin.config.email.reset-password-subject.description": "Subject of the email which gets sent when a user requests a password reset.",
"admin.config.email.reset-password-message": "Reset password message",
"admin.config.email.reset-password-message.description": "Message which gets sent when a user requests a password reset. {url} will be replaced with the reset password URL.",
"admin.config.email.invite-subject": "Invite subject",
"admin.config.email.invite-subject.description": "Subject of the email which gets sent when an admin invites a user.",
"admin.config.email.invite-message": "Invite message",
"admin.config.email.invite-message.description": "Message which gets sent when an admin invites a user. {url} will be replaced with the invite URL and {password} with the password.",
"admin.config.share.allow-registration": "Allow registration",
"admin.config.share.allow-registration.description": "Whether registration is allowed",
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
"admin.config.share.max-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.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",
// 404
"404.description": "Oops this page doesn't exist.",
"404.button.home": "Bring me back home",
// 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.or": "or",
"common.button.go-back": "Go back",
"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

@@ -0,0 +1,324 @@
export default {
// Navbar
"navbar.upload": "Verzenden",
"navbar.signin": "Aanmelden",
"navbar.home": "Startpagina",
"navbar.signup": "Registreren",
"navbar.links.shares": "Mijn gedeelde bestanden",
"navbar.links.reverse": "Reverse shares",
"navbar.avatar.account": "Mijn account",
"navbar.avatar.admin": "Beheer",
"navbar.avatar.signout": "Afmelden",
// END navbar
// /
"home.title": "Een <h>zelfgehost</h> platform voor het delen van bestanden.",
"home.description": "Wil je echt je persoonlijke bestanden geven aan derden zoals WeTransfer?",
"home.bullet.a.name": "Zelf-gehost",
"home.bullet.a.description": "Host Pingvin Share op uw eigen machine.",
"home.bullet.b.name": "Privacy",
"home.bullet.b.description": "Uw bestanden zijn van u en mogen nooit in handen komen van derden.",
"home.bullet.c.name": "Geen vervelende limiet voor bestandsgrootte",
"home.bullet.c.description": "Upload zo grote bestanden als je wilt. Alleen je harde schijf is je limiet.",
"home.button.start": "Aan de slag",
"home.button.source": "Bron code",
// END /
// /auth/signin
"signin.title": "Welkom terug",
"signin.description": "Heeft u nog geen account?",
"signin.button.signup": "Registreren",
"signin.input.email-or-username": "E-mailadres of gebruikersnaam",
"signin.input.email-or-username.placeholder": "Uw e-mailadres of gebruikersnaam",
"signin.input.password": "Wachtwoord",
"signin.input.password.placeholder": "Uw wachtwoord",
"signin.button.submit": "Aanmelden",
"signIn.notify.totp-required.title": "Tweestapsverificatie vereist",
"signIn.notify.totp-required.description": "Voer uw tweestapsverificatiecode in",
// END /auth/signin
// /auth/signup
"signup.title": "Account aanmaken",
"signup.description": "Heeft u al een account?",
"signup.button.signin": "Aanmelden",
"signup.input.username": "Gebruikersnaam",
"signup.input.username.placeholder": "Uw gebruikersnaam",
"signup.input.email": "E-mailadres",
"signup.input.email.placeholder": "Uw e-mailadres",
"signup.button.submit": "Laten we beginnen",
// END /auth/signup
// /auth/reset-password
"resetPassword.title": "Wachtwoord vergeten?",
"resetPassword.description": "Voer uw e-mailadres in om uw wachtwoord opnieuw in te stellen.",
"resetPassword.notify.success": "Een e-mail is verzonden met een link om uw wachtwoord te resetten.",
"resetPassword.button.back": "Terug naar login pagina",
"resetPassword.text.resetPassword": "Wachtwoord opnieuw instellen",
"resetPassword.text.enterNewPassword": "Voer uw nieuwe wachtwoord in",
"resetPassword.input.password": "Nieuw wachtwoord",
"resetPassword.notify.passwordReset": "Uw wachtwoord is met succes opnieuw ingesteld.",
// /account
"account.title": "Mijn account",
"account.card.info.title": "Account informatie",
"account.card.info.username": "Gebruikersnaam",
"account.card.info.email": "E-mailadres",
"account.notify.info.success": "Account succesvol bijgewerkt",
"account.card.password.title": "Wachtwoord",
"account.card.password.old": "Oud wachtwoord",
"account.card.password.new": "Nieuw wachtwoord",
"account.notify.password.success": "Wachtwoord succesvol gewijzigd",
"account.card.security.title": "Beveiliging",
"account.card.security.totp.enable.description": "Voer uw huidige wachtwoord in om TOTP in te schakelen",
"account.card.security.totp.disable.description": "Voer uw huidige wachtwoord in om TOTP uit te schakelen",
"account.card.security.totp.button.start": "Start",
"account.modal.totp.title": "TOTP inschakelen",
"account.modal.totp.step1": "Stap 1: Voeg uw authenticator toe",
"account.modal.totp.step2": "Stap 2: Valideer uw code",
"account.modal.totp.enterManually": "Handmatig invoeren",
"account.modal.totp.code": "Code",
"account.modal.totp.clickToCopy": "Klik om te kopiëren",
"account.modal.totp.verify": "Verifiëren",
"account.notify.totp.disable": "TOTP succesvol uitgeschakeld",
"account.notify.totp.enable": "TOTP succesvol ingeschakeld",
"account.card.language.title": "Taal",
"account.card.language.description": "Het project is vertaald door de community. Sommige talen zijn mogelijk onvolledig.",
"account.card.color.title": "Kleuren schema",
// ThemeSwitcher.tsx
"account.theme.dark": "Donker",
"account.theme.light": "Licht",
"account.theme.system": "Systeem",
"account.button.delete": "Account verwijderen",
"account.modal.delete.title": "Account verwijderen",
"account.modal.delete.description": "Weet u zeker dat u uw account met al uw gedeelde bestanden wilt verwijderen?",
// END /account
// /account/shares
"account.shares.title": "Mijn gedeelde bestanden",
"account.shares.title.empty": "Het is hier leeg 👀",
"account.shares.description.empty": "U heeft geen gedeelde bestanden.",
"account.shares.button.create": "Maak er één",
"account.shares.info.title": "Gegevens delen",
"account.shares.table.id": "ID",
"account.shares.table.name": "Naam",
"account.shares.table.description": "Beschrijving",
"account.shares.table.visitors": "Bezoekers",
"account.shares.table.expiresAt": "Verloopt op",
"account.shares.table.createdAt": "Aangemaakt op",
"account.shares.table.size": "Grootte",
"account.shares.modal.share-informations": "Gegevens delen",
"account.shares.modal.share-link": "Deel 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": "Het is hier leeg 👀",
"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": "Vervaldatum",
"account.reverseShares.modal.expiration.minute-singular": "Minuut",
"account.reverseShares.modal.expiration.minute-plural": "Minuten",
"account.reverseShares.modal.expiration.hour-singular": "Uur",
"account.reverseShares.modal.expiration.hour-plural": "Uren",
"account.reverseShares.modal.expiration.day-singular": "Dag",
"account.reverseShares.modal.expiration.day-plural": "Dagen",
"account.reverseShares.modal.expiration.week-singular": "Week",
"account.reverseShares.modal.expiration.week-plural": "Weken",
"account.reverseShares.modal.expiration.month-singular": "Maand",
"account.reverseShares.modal.expiration.month-plural": "Maanden",
"account.reverseShares.modal.expiration.year-singular": "Jaar",
"account.reverseShares.modal.expiration.year-plural": "Jaren",
"account.reverseShares.modal.max-size.label": "Max share size",
"account.reverseShares.modal.send-email": "Stuur e-mail notificatie",
"account.reverseShares.modal.send-email.description": "Send an email notification when a share is created with this reverse share link.",
"account.reverseShares.modal.max-use.label": "Max uses",
"account.reverseShares.modal.max-use.description": "The maximum amount of times this URL can be used to create a share.",
"account.reverseShare.never-expires": "This reverse share will never expire.",
"account.reverseShare.expires-on": "This reverse share will expire on {expiration}.",
"account.reverseShares.table.no-shares": "No shares created yet",
"account.reverseShares.table.count.singular": "share",
"account.reverseShares.table.count.plural": "shares",
"account.reverseShares.table.shares": "Shares",
"account.reverseShares.table.remaining": "Remaining uses",
"account.reverseShares.table.max-size": "Max share size",
"account.reverseShares.table.expires": "Verloopt op",
"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": "Beheer",
"admin.button.users": "Gebruikers beheer",
"admin.button.config": "Configuratie",
"admin.version": "Versie",
// END /admin
// /admin/users
"admin.users.title": "Gebruikers beheren",
"admin.users.table.username": "Gebruikersnaam",
"admin.users.table.email": "E-mailadres",
"admin.users.table.admin": "Beheerder",
"admin.users.edit.update.title": "Gebruiker {username} bijwerken",
"admin.users.edit.update.admin-privileges": "Beheerder privileges",
"admin.users.edit.update.change-password.title": "Wachtwoord wijzigen",
"admin.users.edit.update.change-password.field": "Nieuw wachtwoord",
"admin.users.edit.update.change-password.button": "Nieuw wachtwoord opslaan",
"admin.users.edit.update.notify.password.success": "Wachtwoord succesvol gewijzigd",
"admin.users.edit.delete.title": "Gebruiker {username} verwijderen",
"admin.users.edit.delete.description": "Do you really want to delete this user and all his shares?",
// showCreateUserModal.tsx
"admin.users.modal.create.title": "Gebruiker aanmaken",
"admin.users.modal.create.username": "Gebruikersnaam",
"admin.users.modal.create.email": "E-mailadres",
"admin.users.modal.create.password": "Wachtwoord",
"admin.users.modal.create.manual-password": "Wachtwoord handmatig instellen",
"admin.users.modal.create.manual-password.description": "Indien niet aangevinkt, ontvangt de gebruiker een e-mail met een link om zijn wachtwoord in te stellen.",
"admin.users.modal.create.admin": "Beheerder privileges",
"admin.users.modal.create.admin.description": "Indien aangevinkt, heeft de gebruiker toegang tot de beheeromgeving.",
// END /admin/users
// /upload
"upload.title": "Uploaden",
"upload.notify.generic-error": "An error occurred while finishing your share.",
"upload.notify.count-failed": "{count} bestanden konden niet worden geüpload. Opnieuw proberen.",
// Dropzone.tsx
"upload.dropzone.title": "Bestanden uploaden",
"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": "Naam",
"upload.filelist.size": "Grootte",
// 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": "Deze link is al in gebruik",
"upload.modal.not-signed-in": "U bent niet aangemeld",
"upload.modal.not-signed-in-description": "You will be unable to delete your share manually and view the visitor count.",
"upload.modal.expires.never": "nooit",
"upload.modal.expires.never-long": "Verloopt nooit",
"upload.modal.link.label": "Koppeling",
"upload.modal.expires.label": "Vervaldatum",
"upload.modal.expires.minute-singular": "Minuut",
"upload.modal.expires.minute-plural": "Minuten",
"upload.modal.expires.hour-singular": "Uur",
"upload.modal.expires.hour-plural": "Uren",
"upload.modal.expires.day-singular": "Dag",
"upload.modal.expires.day-plural": "Dagen",
"upload.modal.expires.week-singular": "Week",
"upload.modal.expires.week-plural": "Weken",
"upload.modal.expires.month-singular": "Maand",
"upload.modal.expires.month-plural": "Maanden",
"upload.modal.expires.year-singular": "Jaar",
"upload.modal.expires.year-plural": "Jaren",
"upload.modal.accordion.description.title": "Beschrijving",
"upload.modal.accordion.description.placeholder": "Note for the recipients of this share",
"upload.modal.accordion.email.title": "E-mail ontvangers",
"upload.modal.accordion.email.placeholder": "Voer e-mail ontvangers in",
"upload.modal.accordion.email.invalid-email": "Ongeldig e-mailadres",
"upload.modal.accordion.security.title": "Beveiliging opties",
"upload.modal.accordion.security.password.label": "Paswoord beveiling",
"upload.modal.accordion.security.password.placeholder": "Geen wachtwoord",
"upload.modal.accordion.security.max-views.label": "Maximum aantal weergaven",
"upload.modal.accordion.security.max-views.placeholder": "Onbeperkt",
// showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "This share will never expire.",
"upload.modal.completed.expires-on": "This share will expire on {expiration}.",
"upload.modal.completed.share-ready": "Share ready",
// END /upload
// /share/[id]
"share.title": "Share {shareId}",
"share.description": "Kijk eens wat ik met je heb gedeeld!",
"share.error.visitor-limit-exceeded.title": "Bezoekerslimiet overschreden",
"share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.",
"share.error.removed.title": "Share removed",
"share.error.not-found.title": "Share not found",
"share.error.not-found.description": "The share you're looking for doesn't exist.",
"share.modal.password.title": "Wachtwoord vereist",
"share.modal.password.description": "To access this share please enter the password for the share.",
"share.modal.password": "Wachtwoord",
"share.modal.error.invalid-password": "Ongeldig wachtwoord",
"share.button.download-all": "Alles downloaden",
"share.notify.download-all-preparing": "The share is preparing. Try again in a few minutes.",
"share.modal.file-link": "Bestand koppeling",
"share.table.name": "Naam",
"share.table.size": "Grootte",
"share.modal.file-preview.error.not-supported.title": "Voorbeeld niet ondersteund",
"share.modal.file-preview.error.not-supported.description": "Een voorbeeld voor dit bestandstype wordt niet ondersteund. Download het bestand om het te bekijken.",
// END /share/[id]
// /admin/config
"admin.config.title": "Configuratie",
"admin.config.category.general": "Algemeen",
"admin.config.category.share": "Delen",
"admin.config.category.email": "E-mail",
"admin.config.category.smtp": "SMTP",
"admin.config.general.app-name": "App naam",
"admin.config.general.app-name.description": "Naam van de applicatie",
"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": "Toon startpagina",
"admin.config.general.show-home-page.description": "Toon of verberg de home pagina",
"admin.config.general.logo": "Logo",
"admin.config.general.logo.description": "Verander uw logo door een nieuwe afbeelding te uploaden. De afbeelding moet PNG zijn en het formaat moet 1:1 hebben.",
"admin.config.general.logo.placeholder": "Afbeelding kiezen",
"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 wachtwoord onderwerp",
"admin.config.email.reset-password-subject.description": "Onderwerp van de e-mail die wordt verzonden wanneer een gebruiker een wachtwoordreset aanvraagt.",
"admin.config.email.reset-password-message": "Wachtwoord opnieuw instellen bericht",
"admin.config.email.reset-password-message.description": "Bericht dat wordt verzonden wanneer een gebruiker een wachtwoord reset aanvraagt. {url} zal worden vervangen door de wachtwoord reset URL.",
"admin.config.email.invite-subject": "Onderwerp uitnodiging",
"admin.config.email.invite-subject.description": "Onderwerp van de e-mail die wordt verzonden wanneer een beheerder een gebruiker uitnodigt.",
"admin.config.email.invite-message": "Bericht uitnodiging",
"admin.config.email.invite-message.description": "Bericht dat wordt verzonden wanneer een beheerder een gebruiker uitnodigt. {url} zal worden vervangen door de uitnodigings-URL en {password} met het wachtwoord.",
"admin.config.share.allow-registration": "Sta registratie toe",
"admin.config.share.allow-registration.description": "Of registratie is toegestaan",
"admin.config.share.allow-unauthenticated-shares": "Allow unauthenticated shares",
"admin.config.share.allow-unauthenticated-shares.description": "Whether unauthenticated users can create shares",
"admin.config.share.max-size": "Max grootte",
"admin.config.share.max-size.description": "Maximum share size in bytes",
"admin.config.share.zip-compression-level": "Zip compressie niveau",
"admin.config.share.zip-compression-level.description": "Pas het niveau aan voor evenwicht tussen bestandsgrootte en compressie snelheid. Geldige waarden variëren van 0 tot 9, waarbij 0 geen compressie is en 9 de maximale compressie is. ",
"admin.config.smtp.enabled": "Inschakelen",
"admin.config.smtp.enabled.description": "Of SMTP is ingeschakeld. Stel dit alleen in op true als u de host hebt ingevoerd, poort, e-mail, gebruiker en wachtwoord van uw SMTP-server.",
"admin.config.smtp.host": "Host",
"admin.config.smtp.host.description": "Host van de SMTP-server",
"admin.config.smtp.port": "Poort",
"admin.config.smtp.port.description": "Poort van de SMTP-server",
"admin.config.smtp.email": "E-mail",
"admin.config.smtp.email.description": "E-mailadres waar de e-mails van worden verzonden",
"admin.config.smtp.username": "Gebruikersnaam",
"admin.config.smtp.username.description": "Gebruikersnaam van de SMTP-server",
"admin.config.smtp.password": "Wachtwoord",
"admin.config.smtp.password.description": "Wachtwoord van de SMTP-server",
"admin.config.smtp.button.test": "Test e-mail verzenden",
// 404
"404.description": "Oeps, deze pagina bestaat niet.",
"404.button.home": "Breng me terug naar huis",
// Common translations
"common.button.save": "Opslaan",
"common.button.create": "Aanmaken",
"common.button.submit": "Verzenden",
"common.button.delete": "Verwijderen",
"common.button.cancel": "Annuleer",
"common.button.confirm": "Bevestigen",
"common.button.disable": "Uitschakelen",
"common.button.share": "Delen",
"common.button.generate": "Genereren",
"common.button.done": "Voltooid",
"common.text.link": "Koppeling",
"common.text.or": "of",
"common.button.go-back": "Ga terug",
"common.notify.copied": "Uw link is gekopieerd naar het klembord",
"common.success": "Succes",
"common.error": "Fout",
"common.error.unknown": "Er is een onbekende fout opgetreden",
"common.error.invalid-email": "Ongeldig e-mailadres",
"common.error.too-short": "Moet ten minste {length} tekens bevatten",
"common.error.too-long": "Moet maximaal {length} tekens bevatten",
"common.error.exact-length": "Moet precies {length} tekens bevatten",
"common.error.invalid-number": "Moet een getal zijn",
"common.error.field-required": "Dit veld is verplicht"
};

View File

@@ -111,7 +111,7 @@ export default {
"account.reverseShares.title.empty": "Está vazio aqui 👀",
"account.reverseShares.description.empty": "Você não tem nenhum compartilhamento reverso.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Create reverse share",
"account.reverseShares.modal.title": "Criar compartilhamento reverso",
"account.reverseShares.modal.expiration.label": "Expiração",
"account.reverseShares.modal.expiration.minute-singular": "Minuto",
"account.reverseShares.modal.expiration.minute-plural": "Minutos",

View File

@@ -0,0 +1,324 @@
export default {
// Navbar
"navbar.upload": "Пошаљи",
"navbar.signin": "Пријавите се",
"navbar.home": "Почетна",
"navbar.signup": "Региструј се",
"navbar.links.shares": "Moja дељења",
"navbar.links.reverse": "Обрнуто дељење",
"navbar.avatar.account": "Мој налог",
"navbar.avatar.admin": "Администрација",
"navbar.avatar.signout": "Одјави се",
// END navbar
// /
"home.title": "<h>self-hosted</h> платформа за дељење фајлова.",
"home.description": "Да ли заиста желите да дате своје личне датотеке у руке трећих страна као што је WeTransfer?",
"home.bullet.a.name": "Личан хостинг",
"home.bullet.a.description": "Хостујте Pingvin Share на својој машини.",
"home.bullet.b.name": "Privatnost",
"home.bullet.b.description": "Ваше датотеке су ваше датотеке и никада не би требало да дођу у руке трећих лица.",
"home.bullet.c.name": "Нема досадног ограничења величине датотеке",
"home.bullet.c.description": "Отпремите онолико великих датотека колико желите. Само ваш чврсти диск ће бити ваше ограничење.",
"home.button.start": "Почети",
"home.button.source": "Изворни код",
// END /
// /auth/signin
"signin.title": "Добродошли назад",
"signin.description": "Још увек немате налог?",
"signin.button.signup": "Региструј се",
"signin.input.email-or-username": "Е-пошта или корисничко име",
"signin.input.email-or-username.placeholder": "Ваша Е-пошта или корисничко име",
"signin.input.password": "Лозинка",
"signin.input.password.placeholder": "Ваша лозинка",
"signin.button.submit": "Пријавите се",
"signIn.notify.totp-required.title": "Потребна је двофакторска аутентификација",
"signIn.notify.totp-required.description": "Унесите свој двофакторски код за аутентификацију",
// END /auth/signin
// /auth/signup
"signup.title": "Направи налог",
"signup.description": "Већ имате налог?",
"signup.button.signin": "Пријавите се",
"signup.input.username": "Корисничко име",
"signup.input.username.placeholder": "Ваше корисничко име",
"signup.input.email": "E-пошта",
"signup.input.email.placeholder": "Ваш и-мејл",
"signup.button.submit": "Хајде да почнемо",
// END /auth/signup
// /auth/reset-password
"resetPassword.title": "Заборавили сте лозинку?",
"resetPassword.description": "Унесите своју е-пошту да бисте ресетовали лозинку.",
"resetPassword.notify.success": "Послат је емаил са везом за ресетовање ваше лозинке.",
"resetPassword.button.back": "Назад на страницу за пријаву",
"resetPassword.text.resetPassword": "Обнови лозинку",
"resetPassword.text.enterNewPassword": "Унесите вашу нову лозинку",
"resetPassword.input.password": "Нова лозинка",
"resetPassword.notify.passwordReset": "Ваша лозинка је успешно ресетована.",
// /account
"account.title": "Мој налог",
"account.card.info.title": "Подаци о налогу",
"account.card.info.username": "Корисничко име",
"account.card.info.email": "E-пошта",
"account.notify.info.success": "Налог је успешно ажуриран",
"account.card.password.title": "Лозинка",
"account.card.password.old": "Стара лозинка",
"account.card.password.new": "Нова лозинка",
"account.notify.password.success": "Лозинка је успешно промењена",
"account.card.security.title": "Безбедност",
"account.card.security.totp.enable.description": "Унесите своју тренутну лозинку да бисте почели да омогућавате ТОТП",
"account.card.security.totp.disable.description": "Унесите своју тренутну лозинку да бисте онемогућили ТОТП",
"account.card.security.totp.button.start": "Започни",
"account.modal.totp.title": "Омогући ТОТП",
"account.modal.totp.step1": "Корак 1: Додајте свој аутентификатор",
"account.modal.totp.step2": "Корак 2: Потврдите свој код",
"account.modal.totp.enterManually": "Унесите ручно",
"account.modal.totp.code": "Код",
"account.modal.totp.clickToCopy": "Кликните за копирање",
"account.modal.totp.verify": "Верификуј",
"account.notify.totp.disable": "ТОТП је успешно онемогућен",
"account.notify.totp.enable": "ТОТП је успешно омогућен",
"account.card.language.title": "Језик",
"account.card.language.description": "Пројекат је преведен од стране заједнице. Неки језици могу бити непотпуни.",
"account.card.color.title": "Шема боја",
// ThemeSwitcher.tsx
"account.theme.dark": "Тамно",
"account.theme.light": "Светло",
"account.theme.system": "Систем",
"account.button.delete": "Избриши Налог",
"account.modal.delete.title": "Избриши Налог",
"account.modal.delete.description": "Да ли заиста желите да избришете свој налог укључујући све ваше активне дељења?",
// END /account
// /account/shares
"account.shares.title": "Moja дељења",
"account.shares.title.empty": "Овде је празно 👀",
"account.shares.description.empty": "Немате никаква дељења.",
"account.shares.button.create": "Направите",
"account.shares.info.title": "Делите информације",
"account.shares.table.id": "ИД",
"account.shares.table.name": "Назив",
"account.shares.table.description": "Опис",
"account.shares.table.visitors": "Посетици",
"account.shares.table.expiresAt": "Истиче у",
"account.shares.table.createdAt": "Направљено у",
"account.shares.table.size": "Величина",
"account.shares.modal.share-informations": "Делите информације",
"account.shares.modal.share-link": "Дели везу",
"account.shares.modal.delete.title": "Избриши дељење {share}",
"account.shares.modal.delete.description": "Да ли заиста желите да избришете ово дељење?",
// END /account/shares
// /account/reverseShares
"account.reverseShares.title": "Обрнуто дељење",
"account.reverseShares.description": "Обрнуто дељење вам омогућава да генеришете јединствени URL који омогућава спољним корисницима да креирају дељење.",
"account.reverseShares.title.empty": "Овде је празно 👀",
"account.reverseShares.description.empty": "Немате обрнутих дељења.",
// showCreateReverseShareModal.tsx
"account.reverseShares.modal.title": "Креирајте обрнуто дељење",
"account.reverseShares.modal.expiration.label": "Истиче",
"account.reverseShares.modal.expiration.minute-singular": "Минут",
"account.reverseShares.modal.expiration.minute-plural": "Минуте",
"account.reverseShares.modal.expiration.hour-singular": "Сат",
"account.reverseShares.modal.expiration.hour-plural": "Сати",
"account.reverseShares.modal.expiration.day-singular": "Дан",
"account.reverseShares.modal.expiration.day-plural": "Дани",
"account.reverseShares.modal.expiration.week-singular": "Седмица",
"account.reverseShares.modal.expiration.week-plural": "Седмице",
"account.reverseShares.modal.expiration.month-singular": "Месец",
"account.reverseShares.modal.expiration.month-plural": "Месеци",
"account.reverseShares.modal.expiration.year-singular": "Година",
"account.reverseShares.modal.expiration.year-plural": "Године",
"account.reverseShares.modal.max-size.label": "Максимална величина дељења",
"account.reverseShares.modal.send-email": "Пошаљите обавештење путем е-поште",
"account.reverseShares.modal.send-email.description": "Пошаљите обавештење е-поштом када се креира дељење помоћу ове обрнуте везе за дељење.",
"account.reverseShares.modal.max-use.label": "Максималан број коришћења",
"account.reverseShares.modal.max-use.description": "Максималан број пута који овај URL може да се користи за прављење дељења.",
"account.reverseShare.never-expires": "Ово обрнуто дељење никада неће истећи.",
"account.reverseShare.expires-on": "Ово обрнуто дељење ће истећи {expiration}.",
"account.reverseShares.table.no-shares": "Још нема креираних дељења",
"account.reverseShares.table.count.singular": "дељење",
"account.reverseShares.table.count.plural": "дељења",
"account.reverseShares.table.shares": "Дељења",
"account.reverseShares.table.remaining": "Преостала употреба",
"account.reverseShares.table.max-size": "Максимална величина дељења",
"account.reverseShares.table.expires": "Истиче у",
"account.reverseShares.modal.reverse-share-link": "Линк за обрнуто дељење",
"account.reverseShares.modal.delete.title": "Обришите обрнуто дељење",
"account.reverseShares.modal.delete.description": "Да ли заиста желите да избришете ово обрнуто дељење? Ако то учините, придружена дељења ће такође бити избрисана.",
// END /account/reverseShares
// /admin
"admin.title": "Администрација",
"admin.button.users": "Управљање корисницима",
"admin.button.config": "Конфигурација",
"admin.version": "Верзија",
// END /admin
// /admin/users
"admin.users.title": "Управљање корисницима",
"admin.users.table.username": "Корисничко име",
"admin.users.table.email": "E-пошта",
"admin.users.table.admin": "Админ",
"admin.users.edit.update.title": "Ажурирајте корисника {username}",
"admin.users.edit.update.admin-privileges": "Администраторске привилегије",
"admin.users.edit.update.change-password.title": "Промените лозинку",
"admin.users.edit.update.change-password.field": "Нова лозинка",
"admin.users.edit.update.change-password.button": "Снимите нову лозинку",
"admin.users.edit.update.notify.password.success": "Лозинка је успешно промењена",
"admin.users.edit.delete.title": "Обришите корисника {username}",
"admin.users.edit.delete.description": "Да ли заиста желите да избришете овог корисника и сва његова дељења?",
// showCreateUserModal.tsx
"admin.users.modal.create.title": "Креирај корисника",
"admin.users.modal.create.username": "Корисничко име",
"admin.users.modal.create.email": "E-пошта",
"admin.users.modal.create.password": "Лозинка",
"admin.users.modal.create.manual-password": "Поставите лозинку ручно",
"admin.users.modal.create.manual-password.description": "Ако није означено, корисник ће добити е-пошту са везом за постављање лозинке.",
"admin.users.modal.create.admin": "Администраторске привилегије",
"admin.users.modal.create.admin.description": "Ако је означено, корисник ће моћи да приступи административном панелу.",
// END /admin/users
// /upload
"upload.title": "Пошаљи",
"upload.notify.generic-error": "Дошло је до грешке при довршавању дељења.",
"upload.notify.count-failed": "Отпремање {count} датотека није успело. Покушавам поново.",
// Dropzone.tsx
"upload.dropzone.title": "Пошаљи датотеке",
"upload.dropzone.description": "Превуците и отпустите датотеке овде да бисте започели дељење. Можемо да прихватимо само датотеке које су укупно мање од {maxSize}.",
"upload.dropzone.notify.file-too-big": "Ваше датотеке премашују максималну величину дељења од {maxSize}.",
// FileList.tsx
"upload.filelist.name": "Назив",
"upload.filelist.size": "Величина",
// showCreateUploadModal.tsx
"upload.modal.title": "Направи дељење",
"upload.modal.link.error.invalid": "Може да садржи само слова, бројеве, доње црте и цртице",
"upload.modal.link.error.taken": "Овај линк је већ у употреби",
"upload.modal.not-signed-in": "Нисте пријављени",
"upload.modal.not-signed-in-description": "Нећете моћи ручно да избришете своје дељење и видите број посетилаца.",
"upload.modal.expires.never": "никад",
"upload.modal.expires.never-long": "Никада не истиче",
"upload.modal.link.label": "Линк",
"upload.modal.expires.label": "Истиче",
"upload.modal.expires.minute-singular": "Минут",
"upload.modal.expires.minute-plural": "Минуте",
"upload.modal.expires.hour-singular": "Сат",
"upload.modal.expires.hour-plural": "Сати",
"upload.modal.expires.day-singular": "Дан",
"upload.modal.expires.day-plural": "Дани",
"upload.modal.expires.week-singular": "Седмица",
"upload.modal.expires.week-plural": "Седмице",
"upload.modal.expires.month-singular": "Месец",
"upload.modal.expires.month-plural": "Месеци",
"upload.modal.expires.year-singular": "Година",
"upload.modal.expires.year-plural": "Године",
"upload.modal.accordion.description.title": "Опис",
"upload.modal.accordion.description.placeholder": "Напомена за примаоце овог дељења",
"upload.modal.accordion.email.title": "Примаоци е-поште",
"upload.modal.accordion.email.placeholder": "Унесите примаоце е-поште",
"upload.modal.accordion.email.invalid-email": "Неисправна адреса е-поште",
"upload.modal.accordion.security.title": "Сигурносна подешавања",
"upload.modal.accordion.security.password.label": "Заштита лозинком",
"upload.modal.accordion.security.password.placeholder": "Нема лозинке",
"upload.modal.accordion.security.max-views.label": "Максималан број прегледа",
"upload.modal.accordion.security.max-views.placeholder": "Без лимита",
// showCompletedUploadModal.tsx
"upload.modal.completed.never-expires": "Ово дељење никада неће истећи.",
"upload.modal.completed.expires-on": "Ово дељење ће истећи {expiration}.",
"upload.modal.completed.share-ready": "Дељење је спремно",
// END /upload
// /share/[id]
"share.title": "Дељење {shareId}",
"share.description": "Погледајте шта сам поделио са вама!",
"share.error.visitor-limit-exceeded.title": "Прекорачено је ограничење посетилаца",
"share.error.visitor-limit-exceeded.description": "Ограничење посетилаца из овог дељења је премашено.",
"share.error.removed.title": "Дељење је уклоњено",
"share.error.not-found.title": "Дељење није пронађено",
"share.error.not-found.description": "Удео који тражите не постоји.",
"share.modal.password.title": "Обавезна лозинка",
"share.modal.password.description": "Да бисте приступили овом дељењу, унесите лозинку за дељење.",
"share.modal.password": "Лозинка",
"share.modal.error.invalid-password": "Неисправна лозинка",
"share.button.download-all": "Преузми све",
"share.notify.download-all-preparing": "Дељење се спрема. Покушајте поново за неколико минута.",
"share.modal.file-link": "Веза датотеке",
"share.table.name": "Назив",
"share.table.size": "Величина",
"share.modal.file-preview.error.not-supported.title": "Преглед није подржан",
"share.modal.file-preview.error.not-supported.description": "Преглед за овај тип датотеке није подржан. Преузмите датотеку да бисте је видели.",
// END /share/[id]
// /admin/config
"admin.config.title": "Конфигурација",
"admin.config.category.general": "Опште",
"admin.config.category.share": "Дељење",
"admin.config.category.email": "E-пошта",
"admin.config.category.smtp": "SMTP",
"admin.config.general.app-name": "Назив апликације",
"admin.config.general.app-name.description": "Назив апликације",
"admin.config.general.app-url": "URL апликације",
"admin.config.general.app-url.description": "На којој URL адреси је доступан Pingvin Share",
"admin.config.general.show-home-page": "Прикажи почетну страницу",
"admin.config.general.show-home-page.description": "Да ли да се прикаже почетна страница",
"admin.config.general.logo": "Лого",
"admin.config.general.logo.description": "Промените свој логотип тако што ћете отпремити нову слику. Слика мора да буде PNG и треба да има формат 1:1.",
"admin.config.general.logo.placeholder": "Изабери слику",
"admin.config.email.enable-share-email-recipients": "Омогућите дељење прималаца е-поште",
"admin.config.email.enable-share-email-recipients.description": "Да ли да дозволите да имејлови деле примаоце. Омогућите ово само ако сте омогућили SMTP.",
"admin.config.email.share-recipients-subject": "Поделите наслов примаоца",
"admin.config.email.share-recipients-subject.description": "Тема е-поруке која се шаље примаоцима дељења.",
"admin.config.email.share-recipients-message": "Делите поруку примаоца",
"admin.config.email.share-recipients-message.description": "Порука која се шаље примаоцима дељења. Доступне променљиве:\n {creator} корисничко име креатора дељења\n {shareUrl} URL дељења\n {desc} Опис дељења\n {expires} - Датум истека акције\n Променљиве ће бити замењене стварном вредношћу.",
"admin.config.email.reverse-share-subject": "Тема обрнутог дељења",
"admin.config.email.reverse-share-subject.description": "Тема е-поруке која се шаље када је неко направио дељење са вашом обрнутим линком за дељење.",
"admin.config.email.reverse-share-message": "Обрнуто дељење порука",
"admin.config.email.reverse-share-message.description": "Порука која се шаље када је неко направио дељење са вашом обрнутом везом за дељење. {shareUrl} ће бити замењен именом креатора и УРЛ-ом за дељење.",
"admin.config.email.reset-password-subject": "Ресетујте тему лозинке",
"admin.config.email.reset-password-subject.description": "Предмет е-поште која се шаље када корисник затражи ресетовање лозинке.",
"admin.config.email.reset-password-message": "Порука за ресетовање лозинке",
"admin.config.email.reset-password-message.description": "Порука која се шаље када корисник затражи ресетовање лозинке. {url} ће бити замењен УРЛ-ом за ресетовање лозинке.",
"admin.config.email.invite-subject": "Позивна тема",
"admin.config.email.invite-subject.description": "Тема е-поруке која се шаље када администратор позове корисника.",
"admin.config.email.invite-message": "Позивна порука",
"admin.config.email.invite-message.description": "Порука која се шаље када администратор позове корисника. {url} ће бити замењен УРЛ-ом позива, а {password} лозинком.",
"admin.config.share.allow-registration": "Дозволи регистрацију",
"admin.config.share.allow-registration.description": "Да ли је регистрација дозвољена",
"admin.config.share.allow-unauthenticated-shares": "Дозволи дељење без аутентификације",
"admin.config.share.allow-unauthenticated-shares.description": "Да ли корисници без аутентификације могу да креирају дељења",
"admin.config.share.max-size": "Максимална величина",
"admin.config.share.max-size.description": "Максимална величина дељења у бајтовима",
"admin.config.share.zip-compression-level": "Ниво zip компресије",
"admin.config.share.zip-compression-level.description": "Подесите ниво да бисте балансирали између величине датотеке и брзине компресије. Важеће вредности се крећу од 0 до 9, при чему је 0 без компресије, а 9 је максимална компресија. ",
"admin.config.smtp.enabled": "Омогућено",
"admin.config.smtp.enabled.description": "Да ли је SMTP омогућен. Поставите ово на тачно само ако сте унели хост, порт, е-пошту, корисника и лозинку вашег SMTP сервера.",
"admin.config.smtp.host": "Домаћин",
"admin.config.smtp.host.description": "Домаћин SMTP сервера",
"admin.config.smtp.port": "Порт",
"admin.config.smtp.port.description": "Порт домаћина SMTP сервера",
"admin.config.smtp.email": "E-пошта",
"admin.config.smtp.email.description": "Адреса е-поште са које се е-поруке шаљу",
"admin.config.smtp.username": "Корисничко име",
"admin.config.smtp.username.description": "Корисничко име SMTP сервера",
"admin.config.smtp.password": "Лозинка",
"admin.config.smtp.password.description": "Лозинка SMTP сервера",
"admin.config.smtp.button.test": "Пошаљи тестну е-пошту",
// 404
"404.description": "Опа - Ова страна не постоји.",
"404.button.home": "Врати ме на почетак",
// Common translations
"common.button.save": "Сачувај",
"common.button.create": "Направи",
"common.button.submit": "Пошаљи",
"common.button.delete": "Обриши",
"common.button.cancel": "Откажи",
"common.button.confirm": "Потврди",
"common.button.disable": "Онемогући",
"common.button.share": "Дељење",
"common.button.generate": "Генериши",
"common.button.done": "Готово",
"common.text.link": "Линк",
"common.text.or": "или",
"common.button.go-back": "Иди назад",
"common.notify.copied": "Ваша веза је копирана у clipboard",
"common.success": "Успешно",
"common.error": "Грешка",
"common.error.unknown": "Дошло је до непознате грешке",
"common.error.invalid-email": "Неисправна адреса е-поште",
"common.error.too-short": "Мора да има најмање {length} знакова",
"common.error.too-long": "Мора да има највише {length} знакова",
"common.error.exact-length": "Мора да има тачно {length} знакова",
"common.error.invalid-number": "Мора бити број",
"common.error.field-required": "Поље је обавезно"
};

View File

@@ -11,8 +11,10 @@ export const config = {
const { apiURL } = getConfig().serverRuntimeConfig;
// A proxy to the API server only used in development.
// In production this route gets overridden by nginx.
export default (req: NextApiRequest, res: NextApiResponse) => {
return httpProxyMiddleware(req, res, {
httpProxyMiddleware(req, res, {
headers: {
"X-Forwarded-For": req.socket?.remoteAddress ?? "",
},

View File

@@ -1,14 +0,0 @@
import axios from "axios";
import { NextApiRequest, NextApiResponse } from "next";
import getConfig from "next/config";
const { apiURL } = getConfig().serverRuntimeConfig;
export default async (req: NextApiRequest, res: NextApiResponse) => {
const apiStatus = await axios
.get(`${apiURL}/api/configs`)
.then(() => "OK")
.catch(() => "ERROR");
res.status(apiStatus == "OK" ? 200 : 500).send(apiStatus);
};

View File

@@ -40,7 +40,7 @@ const Upload = ({
maxShareSize ??= parseInt(config.get("share.maxSize"));
const uploadFiles = async (share: CreateShare) => {
const uploadFiles = async (share: CreateShare, files: FileUpload[]) => {
setisUploading(true);
createdShare = await shareService.create(share);
@@ -56,7 +56,7 @@ const Upload = ({
file.uploadingProgress = progress;
}
return file;
}),
})
);
};
@@ -84,7 +84,7 @@ const Upload = ({
name: file.name,
},
chunkIndex,
chunks,
chunks
)
.then((response) => {
fileId = response.id;
@@ -114,16 +114,34 @@ const Upload = ({
}
}
}
}),
})
);
Promise.all(fileUploadPromises);
};
const showCreateUploadModalCallback = (files: FileUpload[]) => {
setFiles(files);
showCreateUploadModal(
modals,
{
isUserSignedIn: user ? true : false,
isReverseShare,
appUrl: config.get("general.appUrl"),
allowUnauthenticatedShares: config.get(
"share.allowUnauthenticatedShares"
),
enableEmailRecepients: config.get("email.enableShareEmailRecipients"),
},
files,
uploadFiles
);
};
useEffect(() => {
// Check if there are any files that failed to upload
const fileErrorCount = files.filter(
(file) => file.uploadingProgress == -1,
(file) => file.uploadingProgress == -1
).length;
if (fileErrorCount > 0) {
@@ -133,7 +151,7 @@ const Upload = ({
{
withCloseButton: false,
autoClose: false,
},
}
);
}
errorToastShown = true;
@@ -166,31 +184,14 @@ const Upload = ({
<Button
loading={isUploading}
disabled={files.length <= 0}
onClick={() => {
showCreateUploadModal(
modals,
{
isUserSignedIn: user ? true : false,
isReverseShare,
appUrl: config.get("general.appUrl"),
allowUnauthenticatedShares: config.get(
"share.allowUnauthenticatedShares",
),
enableEmailRecepients: config.get(
"email.enableShareEmailRecipients",
),
},
uploadFiles,
);
}}
onClick={() => showCreateUploadModalCallback(files)}
>
<FormattedMessage id="common.button.share" />
</Button>
</Group>
<Dropzone
maxShareSize={maxShareSize}
files={files}
setFiles={setFiles}
showCreateUploadModalCallback={showCreateUploadModalCallback}
isUploading={isUploading}
/>
{files.length > 0 && <FileList files={files} setFiles={setFiles} />}

22
nginx/nginx.conf Normal file
View File

@@ -0,0 +1,22 @@
events {}
http {
server {
listen 3000;
client_max_body_size 100M;
location /api {
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://localhost:3333;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

View File

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