Compare commits

...

12 Commits

Author SHA1 Message Date
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
19 changed files with 806 additions and 107 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,16 @@
## [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,45 @@
# 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
# Set user and group IDs for the node user
ARG UID=1000
ARG GID=1000
RUN deluser node
RUN adduser -u $UID -g $GID node -D
USER node
WORKDIR /opt/app/frontend
COPY --from=frontend-builder /opt/app/public ./public
@@ -46,8 +54,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
# 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 && HOSTNAME=0.0.0.0 node frontend/server.js & cd backend && npm run prod

View File

@@ -1,12 +1,12 @@
{
"name": "pingvin-share-backend",
"version": "0.17.5",
"version": "0.18.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "pingvin-share-backend",
"version": "0.17.5",
"version": "0.18.0",
"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.0",
"scripts": {
"build": "nest build",
"dev": "cross-env NODE_ENV=development nest start --watch",

View File

@@ -1,12 +1,12 @@
{
"name": "pingvin-share-frontend",
"version": "0.17.5",
"version": "0.18.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "pingvin-share-frontend",
"version": "0.17.5",
"version": "0.18.0",
"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.0",
"scripts": {
"dev": "next dev",
"build": "next build",

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,12 @@ 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 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 +62,14 @@ export const LOCALES = {
code: "th-TH",
messages: thai,
},
SERBIAN: {
name: "Srpski",
code: "sr-SP",
messages: serbian,
},
DUTCH: {
name: "Nederlands",
code: "nl-BE",
messages: dutch,
},
};

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": "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

@@ -12,7 +12,7 @@ export const config = {
const { apiURL } = getConfig().serverRuntimeConfig;
export default (req: NextApiRequest, res: NextApiResponse) => {
return httpProxyMiddleware(req, res, {
httpProxyMiddleware(req, res, {
headers: {
"X-Forwarded-For": req.socket?.remoteAddress ?? "",
},

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} />}

View File

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