From d6e4dac0322314888f4308892666d40139fc4051 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 18 Jul 2025 11:04:30 +0200 Subject: [PATCH] Add email translations Convert emails from Pug template to Handlebars because i18next doesn't support Pug --- .github/CONTRIBUTING.md | 15 +- .../admin-config-information.component.html | 12 + .../admin-config-information.component.ts | 23 +- .../+admin/system/debug/debug.component.html | 42 +- .../+admin/system/debug/debug.component.scss | 8 +- .../+admin/system/debug/debug.component.ts | 25 +- .../app/+admin/system/debug/debug.service.ts | 14 +- .../my-account-settings.component.html | 1 + client/src/app/app.component.ts | 3 +- client/src/app/app.routes.ts | 4 +- client/src/app/core/users/user.model.ts | 2 + client/src/app/core/users/user.service.ts | 25 +- client/src/app/header/header.component.html | 14 +- client/src/app/header/header.component.ts | 29 +- .../app/menu/language-chooser.component.html | 17 - .../app/menu/language-chooser.component.scss | 11 - .../app/menu/language-chooser.component.ts | 44 - .../menu/quick-settings-modal.component.html | 21 +- .../menu/quick-settings-modal.component.ts | 18 +- .../auth-interceptor.service.ts | 0 .../http/language-interceptor.service.ts | 10 + .../app/shared/shared-main/main-providers.ts | 2 +- .../user-interface-settings.component.html | 19 +- .../user-interface-settings.component.ts | 112 +- .../user-video-settings.component.ts | 8 +- client/src/main.ts | 7 +- client/src/sass/class-helpers/_common.scss | 11 +- client/src/standalone/videos/embed.ts | 2 +- .../src/standalone/videos/shared/auth-http.ts | 4 +- config/default.yaml | 4 + config/production.yaml.example | 6 +- eslint.config.mjs | 3 +- package.json | 6 + packages/core-utils/src/i18n/i18n.ts | 6 +- packages/core-utils/src/renderer/html.ts | 12 +- .../user-settings-export.model.ts | 1 + .../models/src/server/custom-config.model.ts | 2 + packages/models/src/server/debug.model.ts | 20 +- packages/models/src/server/emailer.model.ts | 11 +- .../models/src/server/server-config.model.ts | 2 + .../models/src/users/user-update-me.model.ts | 1 + packages/models/src/users/user.model.ts | 1 + .../src/users/users-command.ts | 157 ++- .../src/api/check-params/contact-form.ts | 4 +- .../tests/src/api/check-params/my-user.ts | 27 +- .../tests/src/api/check-params/users-admin.ts | 2 +- .../api/notifications/admin-notifications.ts | 4 +- .../notifications/caption-notifications.ts | 8 +- .../notifications/comments-notifications.ts | 4 +- packages/tests/src/api/notifications/index.ts | 2 +- .../notifications/moderation-notifications.ts | 3 +- .../api/notifications/notifications-api.ts | 4 +- .../registrations-notifications.ts | 4 +- .../api/notifications/user-notifications.ts | 3 +- packages/tests/src/api/server/config.ts | 6 +- packages/tests/src/api/server/contact-form.ts | 2 +- packages/tests/src/api/server/email.ts | 75 +- packages/tests/src/api/users/registrations.ts | 23 +- packages/tests/src/api/users/user-export.ts | 3 +- packages/tests/src/api/users/user-import.ts | 7 +- .../src/api/users/users-email-verification.ts | 2 +- packages/tests/src/api/users/users.ts | 75 +- packages/tests/src/plugins/filter-hooks.ts | 2 +- packages/tests/src/shared/import-export.ts | 2 +- .../src/shared/mock-servers/mock-email.ts | 36 +- packages/tests/src/shared/notifications.ts | 320 +++-- scripts/build/server.sh | 1 + scripts/dev/server.sh | 3 +- scripts/i18n/update.sh | 4 + server/.i18next-parser.config.ts | 145 +++ .../abuse-new-message/html.hbs | 10 + .../abuse-new-message/html.pug | 11 - .../abuse-state-change/html.hbs | 10 + .../abuse-state-change/html.pug | 9 - .../account-abuse-new/html.hbs | 18 + .../account-abuse-new/html.pug | 14 - .../assets/email-templates/common/base.pug | 219 ---- .../email-templates/common/greetings.pug | 11 - .../assets/email-templates/common/html.hbs | 5 + .../assets/email-templates/common/html.pug | 4 - .../assets/email-templates/common/mixins.pug | 7 - .../email-templates/contact-form/html.hbs | 11 + .../email-templates/contact-form/html.pug | 9 - .../follower-on-channel/html.hbs | 9 + .../follower-on-channel/html.pug | 9 - .../my-user-block-new/html.hbs | 15 + .../my-user-unblocked/html.hbs | 5 + .../assets/email-templates/partials/base.hbs | 268 ++++ .../email-templates/partials/button.hbs | 7 + .../email-templates/password-create/html.hbs | 11 + .../email-templates/password-create/html.pug | 10 - .../email-templates/password-reset/html.hbs | 15 + .../email-templates/password-reset/html.pug | 12 - .../peertube-version-new/html.hbs | 7 + .../peertube-version-new/html.pug | 9 - .../plugin-version-new/html.hbs | 14 + .../plugin-version-new/html.pug | 9 - .../user-export-completed/html.hbs | 10 + .../user-export-completed/html.pug | 9 - .../user-export-errored/html.hbs | 11 + .../user-export-errored/html.pug | 12 - .../user-import-completed/html.hbs | 68 + .../user-import-completed/html.pug | 55 - .../user-import-errored/html.hbs | 11 + .../user-import-errored/html.pug | 12 - .../email-templates/user-registered/html.hbs | 11 + .../email-templates/user-registered/html.pug | 10 - .../html.hbs | 11 + .../html.pug | 10 - .../html.hbs | 7 + .../html.pug | 9 - .../user-registration-request/html.hbs | 7 + .../user-registration-request/html.pug | 9 - .../verify-registration-email/html.hbs | 19 + .../verify-registration-email/html.pug | 16 - .../verify-user-change-email/html.hbs | 13 + .../verify-user-change-email/html.pug | 11 - .../email-templates/video-abuse-new/html.hbs | 27 + .../email-templates/video-abuse-new/html.pug | 18 - .../video-auto-blacklist-new/html.hbs | 13 + .../video-auto-blacklist-new/html.pug | 17 - .../video-comment-abuse-new/html.hbs | 21 + .../video-comment-abuse-new/html.pug | 16 - .../video-comment-mention/html.hbs | 9 + .../video-comment-mention/html.pug | 11 - .../video-comment-new/html.hbs | 13 + .../video-comment-new/html.pug | 16 - .../video-owner-blacklist-new/html.hbs | 15 + .../video-owner-unblacklist/html.hbs | 5 + server/core/controllers/api/client-config.ts | 36 + server/core/controllers/api/config.ts | 2 + server/core/controllers/api/index.ts | 2 + server/core/controllers/api/server/contact.ts | 7 +- server/core/controllers/api/server/debug.ts | 143 ++- server/core/controllers/api/users/index.ts | 24 +- server/core/controllers/api/users/me.ts | 1 + server/core/controllers/client.ts | 4 +- .../feeds/shared/common-feed-utils.ts | 2 +- .../core/helpers/custom-validators/users.ts | 75 +- server/core/helpers/i18n.ts | 76 ++ server/core/helpers/markdown.ts | 21 +- .../core/initializers/checker-before-init.ts | 1 + server/core/initializers/config.ts | 3 + server/core/initializers/constants.ts | 7 +- .../migrations/0910-user-language.ts | 26 + server/core/lib/client-urls.ts | 36 + server/core/lib/emailer.ts | 208 +++- server/core/lib/html/shared/page-html.ts | 13 +- server/core/lib/html/shared/tags-html.ts | 7 +- server/core/lib/notifier/notifier.ts | 21 +- .../abuse/abstract-new-abuse-message.ts | 19 +- .../abuse/abuse-state-change-for-reporter.ts | 31 +- .../shared/abuse/new-abuse-for-moderators.ts | 38 +- .../abuse/new-abuse-message-for-moderators.ts | 8 +- .../abuse/new-abuse-message-for-reporter.ts | 6 +- .../new-auto-blacklist-for-moderators.ts | 24 +- .../blacklist/new-blacklist-for-owner.ts | 22 +- .../shared/blacklist/unblacklist-for-owner.ts | 18 +- ...video-transcription-generated-for-owner.ts | 22 +- .../shared/comment/comment-mention.ts | 22 +- .../comment/new-comment-for-video-owner.ts | 20 +- .../shared/common/abstract-notification.ts | 7 +- .../shared/follow/auto-follow-for-instance.ts | 28 +- .../shared/follow/follow-for-instance.ts | 28 +- .../notifier/shared/follow/follow-for-user.ts | 27 +- .../direct-registration-for-moderators.ts | 23 +- .../new-peertube-version-for-admins.ts | 17 +- .../instance/new-plugin-version-for-admins.ts | 24 +- .../registration-request-for-moderators.ts | 27 +- .../abstract-owned-video-publication.ts | 16 +- .../import-finished-for-owner.ts | 41 +- .../new-video-or-live-for-subscribers.ts | 26 +- .../studio-edition-finished-for-owner.ts | 18 +- server/core/lib/server-config-manager.ts | 20 + .../exporters/user-settings-exporter.ts | 4 +- .../importers/user-settings-importer.ts | 19 +- server/core/lib/user.ts | 4 + server/core/middlewares/validators/config.ts | 1 + .../middlewares/validators/users/users.ts | 6 +- server/core/models/user/user.ts | 20 + server/core/types/express.d.ts | 2 + server/locales/ar/translation.json | 160 +++ server/locales/ca-ES/translation.json | 160 +++ server/locales/cs-CZ/translation.json | 160 +++ server/locales/de-DE/translation.json | 160 +++ server/locales/el-GR/translation.json | 160 +++ server/locales/en-US/translation.json | 160 +++ server/locales/eo/translation.json | 160 +++ server/locales/es-ES/translation.json | 160 +++ server/locales/eu-ES/translation.json | 160 +++ server/locales/fa-IR/translation.json | 160 +++ server/locales/fi-FI/translation.json | 160 +++ server/locales/fr-FR/translation.json | 160 +++ server/locales/gd/translation.json | 160 +++ server/locales/gl-ES/translation.json | 160 +++ server/locales/hr/translation.json | 160 +++ server/locales/hu-HU/translation.json | 160 +++ server/locales/is/translation.json | 160 +++ server/locales/it-IT/translation.json | 160 +++ server/locales/ja-JP/translation.json | 160 +++ server/locales/kab/translation.json | 160 +++ server/locales/nb-NO/translation.json | 160 +++ server/locales/nl-NL/translation.json | 160 +++ server/locales/nn/translation.json | 160 +++ server/locales/oc/translation.json | 160 +++ server/locales/pl-PL/translation.json | 160 +++ server/locales/pt-BR/translation.json | 160 +++ server/locales/pt-PT/translation.json | 160 +++ server/locales/ru-RU/translation.json | 160 +++ server/locales/sk-SK/translation.json | 160 +++ server/locales/sq/translation.json | 160 +++ server/locales/sv-SE/translation.json | 160 +++ server/locales/th-TH/translation.json | 160 +++ server/locales/tok/translation.json | 160 +++ server/locales/tr-TR/translation.json | 160 +++ server/locales/uk-UA/translation.json | 160 +++ server/locales/vi-VN/translation.json | 160 +++ server/locales/zh-Hans-CN/translation.json | 160 +++ server/locales/zh-Hant-TW/translation.json | 160 +++ server/server.ts | 9 +- support/doc/api/openapi.yaml | 30 + support/doc/translation.md | 10 +- yarn.lock | 1107 ++++++++++++++++- 223 files changed, 9859 insertions(+), 1426 deletions(-) delete mode 100644 client/src/app/menu/language-chooser.component.html delete mode 100644 client/src/app/menu/language-chooser.component.scss delete mode 100644 client/src/app/menu/language-chooser.component.ts rename client/src/app/shared/shared-main/{auth => http}/auth-interceptor.service.ts (100%) create mode 100644 client/src/app/shared/shared-main/http/language-interceptor.service.ts create mode 100644 server/.i18next-parser.config.ts create mode 100644 server/core/assets/email-templates/abuse-new-message/html.hbs delete mode 100644 server/core/assets/email-templates/abuse-new-message/html.pug create mode 100644 server/core/assets/email-templates/abuse-state-change/html.hbs delete mode 100644 server/core/assets/email-templates/abuse-state-change/html.pug create mode 100644 server/core/assets/email-templates/account-abuse-new/html.hbs delete mode 100644 server/core/assets/email-templates/account-abuse-new/html.pug delete mode 100644 server/core/assets/email-templates/common/base.pug delete mode 100644 server/core/assets/email-templates/common/greetings.pug create mode 100644 server/core/assets/email-templates/common/html.hbs delete mode 100644 server/core/assets/email-templates/common/html.pug delete mode 100644 server/core/assets/email-templates/common/mixins.pug create mode 100644 server/core/assets/email-templates/contact-form/html.hbs delete mode 100644 server/core/assets/email-templates/contact-form/html.pug create mode 100644 server/core/assets/email-templates/follower-on-channel/html.hbs delete mode 100644 server/core/assets/email-templates/follower-on-channel/html.pug create mode 100644 server/core/assets/email-templates/my-user-block-new/html.hbs create mode 100644 server/core/assets/email-templates/my-user-unblocked/html.hbs create mode 100644 server/core/assets/email-templates/partials/base.hbs create mode 100644 server/core/assets/email-templates/partials/button.hbs create mode 100644 server/core/assets/email-templates/password-create/html.hbs delete mode 100644 server/core/assets/email-templates/password-create/html.pug create mode 100644 server/core/assets/email-templates/password-reset/html.hbs delete mode 100644 server/core/assets/email-templates/password-reset/html.pug create mode 100644 server/core/assets/email-templates/peertube-version-new/html.hbs delete mode 100644 server/core/assets/email-templates/peertube-version-new/html.pug create mode 100644 server/core/assets/email-templates/plugin-version-new/html.hbs delete mode 100644 server/core/assets/email-templates/plugin-version-new/html.pug create mode 100644 server/core/assets/email-templates/user-export-completed/html.hbs delete mode 100644 server/core/assets/email-templates/user-export-completed/html.pug create mode 100644 server/core/assets/email-templates/user-export-errored/html.hbs delete mode 100644 server/core/assets/email-templates/user-export-errored/html.pug create mode 100644 server/core/assets/email-templates/user-import-completed/html.hbs delete mode 100644 server/core/assets/email-templates/user-import-completed/html.pug create mode 100644 server/core/assets/email-templates/user-import-errored/html.hbs delete mode 100644 server/core/assets/email-templates/user-import-errored/html.pug create mode 100644 server/core/assets/email-templates/user-registered/html.hbs delete mode 100644 server/core/assets/email-templates/user-registered/html.pug create mode 100644 server/core/assets/email-templates/user-registration-request-accepted/html.hbs delete mode 100644 server/core/assets/email-templates/user-registration-request-accepted/html.pug create mode 100644 server/core/assets/email-templates/user-registration-request-rejected/html.hbs delete mode 100644 server/core/assets/email-templates/user-registration-request-rejected/html.pug create mode 100644 server/core/assets/email-templates/user-registration-request/html.hbs delete mode 100644 server/core/assets/email-templates/user-registration-request/html.pug create mode 100644 server/core/assets/email-templates/verify-registration-email/html.hbs delete mode 100644 server/core/assets/email-templates/verify-registration-email/html.pug create mode 100644 server/core/assets/email-templates/verify-user-change-email/html.hbs delete mode 100644 server/core/assets/email-templates/verify-user-change-email/html.pug create mode 100644 server/core/assets/email-templates/video-abuse-new/html.hbs delete mode 100644 server/core/assets/email-templates/video-abuse-new/html.pug create mode 100644 server/core/assets/email-templates/video-auto-blacklist-new/html.hbs delete mode 100644 server/core/assets/email-templates/video-auto-blacklist-new/html.pug create mode 100644 server/core/assets/email-templates/video-comment-abuse-new/html.hbs delete mode 100644 server/core/assets/email-templates/video-comment-abuse-new/html.pug create mode 100644 server/core/assets/email-templates/video-comment-mention/html.hbs delete mode 100644 server/core/assets/email-templates/video-comment-mention/html.pug create mode 100644 server/core/assets/email-templates/video-comment-new/html.hbs delete mode 100644 server/core/assets/email-templates/video-comment-new/html.pug create mode 100644 server/core/assets/email-templates/video-owner-blacklist-new/html.hbs create mode 100644 server/core/assets/email-templates/video-owner-unblacklist/html.hbs create mode 100644 server/core/controllers/api/client-config.ts create mode 100644 server/core/helpers/i18n.ts create mode 100644 server/core/initializers/migrations/0910-user-language.ts create mode 100644 server/core/lib/client-urls.ts create mode 100644 server/locales/ar/translation.json create mode 100644 server/locales/ca-ES/translation.json create mode 100644 server/locales/cs-CZ/translation.json create mode 100644 server/locales/de-DE/translation.json create mode 100644 server/locales/el-GR/translation.json create mode 100644 server/locales/en-US/translation.json create mode 100644 server/locales/eo/translation.json create mode 100644 server/locales/es-ES/translation.json create mode 100644 server/locales/eu-ES/translation.json create mode 100644 server/locales/fa-IR/translation.json create mode 100644 server/locales/fi-FI/translation.json create mode 100644 server/locales/fr-FR/translation.json create mode 100644 server/locales/gd/translation.json create mode 100644 server/locales/gl-ES/translation.json create mode 100644 server/locales/hr/translation.json create mode 100644 server/locales/hu-HU/translation.json create mode 100644 server/locales/is/translation.json create mode 100644 server/locales/it-IT/translation.json create mode 100644 server/locales/ja-JP/translation.json create mode 100644 server/locales/kab/translation.json create mode 100644 server/locales/nb-NO/translation.json create mode 100644 server/locales/nl-NL/translation.json create mode 100644 server/locales/nn/translation.json create mode 100644 server/locales/oc/translation.json create mode 100644 server/locales/pl-PL/translation.json create mode 100644 server/locales/pt-BR/translation.json create mode 100644 server/locales/pt-PT/translation.json create mode 100644 server/locales/ru-RU/translation.json create mode 100644 server/locales/sk-SK/translation.json create mode 100644 server/locales/sq/translation.json create mode 100644 server/locales/sv-SE/translation.json create mode 100644 server/locales/th-TH/translation.json create mode 100644 server/locales/tok/translation.json create mode 100644 server/locales/tr-TR/translation.json create mode 100644 server/locales/uk-UA/translation.json create mode 100644 server/locales/vi-VN/translation.json create mode 100644 server/locales/zh-Hans-CN/translation.json create mode 100644 server/locales/zh-Hant-TW/translation.json diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 566d8c3f7..447a5feb3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -223,8 +223,19 @@ Instance configurations are in `config/test-{1,2,3}.yaml`. To test emails with PeerTube: - * Run [mailslurper](http://mailslurper.com/) - * Run PeerTube using mailslurper SMTP port: `NODE_CONFIG='{ "smtp": { "hostname": "localhost", "port": 2500, "tls": false } }' NODE_ENV=dev node dist/server` + * Run [MailDev](https://github.com/maildev/maildev) using Docker + * Run PeerTube using MailDev SMTP port: `NODE_CONFIG='{ "smtp": { "hostname": "localhost", "port": 2500, "tls": false } }' NODE_ENV=dev node dist/server` + +To test all emails without having to run actions manually on the web interface, you can run notification unit tests with environment variables to relay emails to your MailDev instance. For example: + +```sh +MAILDEV_RELAY_HOST=localhost MAILDEV_RELAY_PORT=2500 mocha --exit --bail packages/tests/src/api/notifications/comments-notifications.ts +``` + +You can then go to the MailDev web interface and see how emails look like. + +The admin web interface also have a button to send some email templates to a specific email address. + ### Environment variables diff --git a/client/src/app/+admin/config/pages/admin-config-information.component.html b/client/src/app/+admin/config/pages/admin-config-information.component.html index fea520521..7aadb0125 100644 --- a/client/src/app/+admin/config/pages/admin-config-information.component.html +++ b/client/src/app/+admin/config/pages/admin-config-information.component.html @@ -73,6 +73,18 @@ > +
+ +
+
Default language used for users, in emails for example.
+
The web interface still uses the web browser preferred language if not overridden by user preference
+
+ +
+ +
+
+
diff --git a/client/src/app/+admin/config/pages/admin-config-information.component.ts b/client/src/app/+admin/config/pages/admin-config-information.component.ts index 42670b73d..6d11cac2a 100644 --- a/client/src/app/+admin/config/pages/admin-config-information.component.ts +++ b/client/src/app/+admin/config/pages/admin-config-information.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common' -import { Component, OnDestroy, OnInit, inject } from '@angular/core' +import { Component, inject, OnDestroy, OnInit } from '@angular/core' import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' import { ActivatedRoute, RouterLink } from '@angular/router' import { CanComponentDeactivate, ServerService } from '@app/core' @@ -17,8 +17,11 @@ import { } from '@app/shared/form-validators/form-validator.model' import { CustomMarkupService } from '@app/shared/shared-custom-markup/custom-markup.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' +import { SelectOptionsComponent } from '@app/shared/shared-forms/select/select-options.component' import { SelectRadioComponent } from '@app/shared/shared-forms/select/select-radio.component' +import { getCompleteLocale, I18N_LOCALES } from '@peertube/peertube-core-utils' import { ActorImage, CustomConfig, NSFWPolicyType, VideoConstant } from '@peertube/peertube-models' +import merge from 'lodash-es/merge' import { Subscription } from 'rxjs' import { SelectOptionsItem } from 'src/types/select-options-item.model' import { AdminConfigService } from '../../../shared/shared-admin/admin-config.service' @@ -44,6 +47,7 @@ type Form = { shortDescription: FormControl description: FormControl categories: FormControl + defaultLanguage: FormControl languages: FormControl serverCountry: FormControl @@ -87,7 +91,8 @@ type Form = { PeertubeCheckboxComponent, PeerTubeTemplateDirective, HelpComponent, - AdminSaveBarComponent + AdminSaveBarComponent, + SelectOptionsComponent ] }) export class AdminConfigInformationComponent implements OnInit, OnDestroy, CanComponentDeactivate { @@ -126,6 +131,8 @@ export class AdminConfigInformationComponent implements OnInit, OnDestroy, CanCo } ] + defaultLanguageItems: SelectOptionsItem[] = [] + private customConfig: CustomConfig private customConfigSub: Subscription @@ -143,6 +150,7 @@ export class AdminConfigInformationComponent implements OnInit, OnDestroy, CanCo this.languageItems = data.languages.map(l => ({ label: l.label, id: l.id })) this.categoryItems = data.categories.map(l => ({ label: l.label, id: l.id })) + this.defaultLanguageItems = Object.entries(I18N_LOCALES).map(([ id, label ]) => ({ label, id })) this.buildForm() @@ -185,6 +193,8 @@ export class AdminConfigInformationComponent implements OnInit, OnDestroy, CanCo hardwareInformation: null, + defaultLanguage: null, + categories: null, languages: null, @@ -200,7 +210,14 @@ export class AdminConfigInformationComponent implements OnInit, OnDestroy, CanCo } } - const defaultValues: FormDefaultTyped
= this.customConfig + const defaultValues: FormDefaultTyped = merge( + this.customConfig, + { + instance: { + defaultLanguage: getCompleteLocale(this.customConfig.instance.defaultLanguage) + } + } satisfies FormDefaultTyped + ) const { form, diff --git a/client/src/app/+admin/system/debug/debug.component.html b/client/src/app/+admin/system/debug/debug.component.html index c43f5e88f..0a512f9c4 100644 --- a/client/src/app/+admin/system/debug/debug.component.html +++ b/client/src/app/+admin/system/debug/debug.component.html @@ -1,15 +1,33 @@ -

IP address

+
+
+

IP address

-

PeerTube thinks your web browser public IP is {{ debug?.ip }}.

+

PeerTube thinks your web browser public IP is {{ debug?.ip }}.

-

If this is not your correct public IP, please consider fixing it because:

-
    -
  • Views may not be counted correctly (reduced compared to what they should be)
  • -
  • Anti brute force system could be overzealous
  • -
  • P2P system could not work correctly
  • -
+

If this is not your correct public IP, please consider fixing it because:

+
    +
  • Views may not be counted correctly (reduced compared to what they should be)
  • +
  • Anti brute force system could be overzealous
  • +
  • P2P system could not work correctly
  • +
-

To fix it:

-

    -
  • Check the trust_proxy configuration key
  • -
+

To fix it:

+

    +
  • Check the trust_proxy configuration key
  • +
+
+ +
+

Emails

+ + +
+ +
PeerTube can send all available email templates to the following email address
+ +
+ + + +
+
diff --git a/client/src/app/+admin/system/debug/debug.component.scss b/client/src/app/+admin/system/debug/debug.component.scss index bcbc3fc7c..8864c675a 100644 --- a/client/src/app/+admin/system/debug/debug.component.scss +++ b/client/src/app/+admin/system/debug/debug.component.scss @@ -1,7 +1,11 @@ -@use '_variables' as *; -@use '_mixins' as *; +@use "_variables" as *; +@use "_mixins" as *; code { font-size: 14px; font-weight: $font-semibold; } + +.root { + max-width: 500px; +} diff --git a/client/src/app/+admin/system/debug/debug.component.ts b/client/src/app/+admin/system/debug/debug.component.ts index 44d1c833e..adb3d9e22 100644 --- a/client/src/app/+admin/system/debug/debug.component.ts +++ b/client/src/app/+admin/system/debug/debug.component.ts @@ -1,23 +1,31 @@ +import { CommonModule } from '@angular/common' import { Component, OnInit, inject } from '@angular/core' -import { Notifier } from '@app/core' +import { FormsModule } from '@angular/forms' +import { Notifier, ServerService } from '@app/core' import { Debug } from '@peertube/peertube-models' import { DebugService } from './debug.service' @Component({ templateUrl: './debug.component.html', styleUrls: [ './debug.component.scss' ], - imports: [] + imports: [ CommonModule, FormsModule ] }) export class DebugComponent implements OnInit { private debugService = inject(DebugService) private notifier = inject(Notifier) + private server = inject(ServerService) debug: Debug + testEmail: string ngOnInit (): void { this.load() } + isEmailDisabled () { + return this.server.getHTMLConfig().email.enabled === false + } + load () { this.debugService.getDebug() .subscribe({ @@ -26,4 +34,17 @@ export class DebugComponent implements OnInit { error: err => this.notifier.error(err.message) }) } + + sendTestEmails () { + this.debugService.testEmails(this.testEmail) + .subscribe({ + next: () => { + this.testEmail = '' + + this.notifier.success($localize`Emails will be sent!`) + }, + + error: err => this.notifier.error(err.message) + }) + } } diff --git a/client/src/app/+admin/system/debug/debug.service.ts b/client/src/app/+admin/system/debug/debug.service.ts index 5e67d10c9..6799d0ee9 100644 --- a/client/src/app/+admin/system/debug/debug.service.ts +++ b/client/src/app/+admin/system/debug/debug.service.ts @@ -3,7 +3,7 @@ import { catchError } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' import { Injectable, inject } from '@angular/core' import { RestExtractor } from '@app/core' -import { Debug } from '@peertube/peertube-models' +import { Debug, SendDebugCommand } from '@peertube/peertube-models' import { environment } from '../../../../environments/environment' @Injectable() @@ -19,4 +19,16 @@ export class DebugService { catchError(err => this.restExtractor.handleError(err)) ) } + + testEmails (email: string) { + const body: SendDebugCommand = { + command: 'test-emails', + email + } + + return this.authHttp.post(DebugService.BASE_DEBUG_URL + '/run-command', body) + .pipe( + catchError(err => this.restExtractor.handleError(err)) + ) + } } diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index 66c52c7f1..be3625966 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html @@ -21,6 +21,7 @@
+

INTERFACE

diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index e8cb6dae9..97dfd6296 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,7 +1,7 @@ import { DOCUMENT, getLocaleDirection, NgClass, NgIf, PlatformLocation } from '@angular/common' import { AfterViewInit, Component, inject, LOCALE_ID, OnDestroy, OnInit, viewChild } from '@angular/core' import { DomSanitizer, SafeHtml } from '@angular/platform-browser' -import { ActivatedRoute, Event, GuardsCheckStart, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouterOutlet } from '@angular/router' +import { Event, GuardsCheckStart, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouterOutlet } from '@angular/router' import { AuthService, Hotkey, @@ -83,7 +83,6 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy { private scrollService = inject(ScrollService) private userLocalStorage = inject(UserLocalStorageService) private peertubeModal = inject(PeertubeModalService) - private route = inject(ActivatedRoute) menu = inject(MenuService) diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts index 08c11bdb9..b546e043f 100644 --- a/client/src/app/app.routes.ts +++ b/client/src/app/app.routes.ts @@ -1,5 +1,5 @@ import { Routes, UrlMatchResult, UrlSegment } from '@angular/router' -import { POSSIBLE_LOCALES } from '@peertube/peertube-core-utils' +import { AVAILABLE_LOCALES } from '@peertube/peertube-core-utils' import { MetaGuard } from './core' import { EmptyComponent } from './empty.component' import { HomepageRedirectComponent } from './homepage-redirect.component' @@ -241,7 +241,7 @@ const routes: Routes = [ ] // Avoid 404 when changing language -for (const locale of POSSIBLE_LOCALES) { +for (const locale of AVAILABLE_LOCALES) { routes.push({ path: locale, component: HomepageRedirectComponent diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts index 79b45349c..8fc423bcb 100644 --- a/client/src/app/core/users/user.model.ts +++ b/client/src/app/core/users/user.model.ts @@ -76,6 +76,8 @@ export class User implements UserServerModel { twoFactorEnabled: boolean + language: string + createdAt: Date constructor (hash: Partial) { diff --git a/client/src/app/core/users/user.service.ts b/client/src/app/core/users/user.service.ts index 81cd37c03..14a469a1e 100644 --- a/client/src/app/core/users/user.service.ts +++ b/client/src/app/core/users/user.service.ts @@ -1,9 +1,10 @@ +import { HttpClient, HttpParams } from '@angular/common/http' +import { Injectable, LOCALE_ID, inject } from '@angular/core' +import { AuthService } from '@app/core/auth' +import { getCompleteLocale } from '@peertube/peertube-core-utils' +import { ActorImage, User as UserServerModel, UserUpdateMe, UserVideoQuota } from '@peertube/peertube-models' import { Observable, of } from 'rxjs' import { catchError, first, map, shareReplay } from 'rxjs/operators' -import { HttpClient, HttpParams } from '@angular/common/http' -import { Injectable, inject } from '@angular/core' -import { AuthService } from '@app/core/auth' -import { ActorImage, User as UserServerModel, UserUpdateMe, UserVideoQuota } from '@peertube/peertube-models' import { environment } from '../../../environments/environment' import { RestExtractor } from '../rest' import { UserLocalStorageService } from './user-local-storage.service' @@ -14,9 +15,11 @@ export class UserService { private authHttp = inject(HttpClient) private authService = inject(AuthService) private restExtractor = inject(RestExtractor) + private localeId = inject(LOCALE_ID) private userLocalStorageService = inject(UserLocalStorageService) static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/' + static BASE_CLIENT_CONFIG_URL = environment.apiUrl + '/api/v1/client-config/' private userCache: { [id: number]: Observable } = {} private signupInThisSession = false @@ -60,7 +63,11 @@ export class UserService { } getAnonymousUser () { - return new User(this.userLocalStorageService.getUserInfo()) + return new User({ + ...this.userLocalStorageService.getUserInfo(), + + language: getCompleteLocale(this.localeId) + }) } getAnonymousOrLoggedUser () { @@ -188,4 +195,12 @@ export class UserService { .get(url, { params }) .pipe(catchError(res => this.restExtractor.handleError(res))) } + + updateInterfaceLanguage (language: string) { + const url = UserService.BASE_CLIENT_CONFIG_URL + 'update-interface-language' + const body = { language } + + return this.authHttp.post(url, body) + .pipe(catchError(err => this.restExtractor.handleError(err))) + } } diff --git a/client/src/app/header/header.component.html b/client/src/app/header/header.component.html index 8730dd3ba..83fc3f2ea 100644 --- a/client/src/app/header/header.component.html +++ b/client/src/app/header/header.component.html @@ -65,23 +65,20 @@ - + Manage my account - +
- - + diff --git a/client/src/app/header/header.component.ts b/client/src/app/header/header.component.ts index ff191b26d..86acdfdef 100644 --- a/client/src/app/header/header.component.ts +++ b/client/src/app/header/header.component.ts @@ -1,9 +1,8 @@ import { CommonModule } from '@angular/common' -import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core' +import { Component, inject, LOCALE_ID, OnDestroy, OnInit, viewChild } from '@angular/core' import { NavigationEnd, Router, RouterLink } from '@angular/router' import { AuthService, AuthStatus, AuthUser, HotkeysService, MenuService, RedirectService, ScreenService, ServerService } from '@app/core' import { NotificationDropdownComponent } from '@app/header/notification-dropdown.component' -import { LanguageChooserComponent } from '@app/menu/language-chooser.component' import { QuickSettingsModalComponent } from '@app/menu/quick-settings-modal.component' import { ActorAvatarComponent } from '@app/shared/shared-actor-image/actor-avatar.component' import { PeertubeModalService } from '@app/shared/shared-main/peertube-modal/peertube-modal.service' @@ -11,15 +10,16 @@ import { PluginSelectorDirective } from '@app/shared/shared-main/plugins/plugin- import { LoginLinkComponent } from '@app/shared/shared-main/users/login-link.component' import { SignupLabelComponent } from '@app/shared/shared-main/users/signup-label.component' import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap' +import { findAppropriateImage, getCompleteLocale, I18N_LOCALES } from '@peertube/peertube-core-utils' import { HTMLServerConfig, ServerConfig } from '@peertube/peertube-models' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { isAndroid, isIOS, isIphone } from '@root-helpers/web-browser' import { Subscription } from 'rxjs' import { GlobalIconComponent } from '../shared/shared-icons/global-icon.component' import { ButtonComponent } from '../shared/shared-main/buttons/button.component' -import { SearchTypeaheadComponent } from './search-typeahead.component' import { HeaderService } from './header.service' -import { findAppropriateImage } from '@peertube/peertube-core-utils' +import { SearchTypeaheadComponent } from './search-typeahead.component' +import { getDevLocale, isOnDevLocale } from '@app/helpers' @Component({ selector: 'my-header', @@ -32,7 +32,6 @@ import { findAppropriateImage } from '@peertube/peertube-core-utils' PluginSelectorDirective, SignupLabelComponent, LoginLinkComponent, - LanguageChooserComponent, QuickSettingsModalComponent, GlobalIconComponent, RouterLink, @@ -53,10 +52,10 @@ export class HeaderComponent implements OnInit, OnDestroy { private router = inject(Router) private menu = inject(MenuService) private headerService = inject(HeaderService) + private localeId = inject(LOCALE_ID) private static LS_HIDE_MOBILE_MSG = 'hide-mobile-msg' - readonly languageChooserModal = viewChild('languageChooserModal') readonly quickSettingsModal = viewChild('quickSettingsModal') readonly dropdown = viewChild('dropdown') @@ -65,8 +64,6 @@ export class HeaderComponent implements OnInit, OnDestroy { hotkeysHelpVisible = false - currentInterfaceLanguage: string - mobileMsg = false androidAppUrl = '' iosAppUrl = '' @@ -81,8 +78,15 @@ export class HeaderComponent implements OnInit, OnDestroy { private hotkeysSub: Subscription private authSub: Subscription - get language () { - return this.languageChooserModal().getCurrentLanguage() + get currentInterfaceLanguage () { + const english = 'English' + const locale = isOnDevLocale() + ? getDevLocale() + : getCompleteLocale(this.localeId) + + if (locale) return I18N_LOCALES[locale as keyof typeof I18N_LOCALES] || english + + return english } get requiresApproval () { @@ -121,7 +125,6 @@ export class HeaderComponent implements OnInit, OnDestroy { ngOnInit () { this.htmlConfig = this.serverService.getHTMLConfig() - this.currentInterfaceLanguage = this.languageChooserModal().getCurrentLanguage() this.loggedIn = this.authService.isLoggedIn() this.updateUserState() @@ -273,10 +276,6 @@ export class HeaderComponent implements OnInit, OnDestroy { this.redirectService.redirectToHomepage() } - openLanguageChooser () { - this.languageChooserModal().show() - } - openQuickSettings () { this.quickSettingsModal().show() } diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html deleted file mode 100644 index 6a4079507..000000000 --- a/client/src/app/menu/language-chooser.component.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Help to translate PeerTube! - - - - diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss deleted file mode 100644 index 447f6b250..000000000 --- a/client/src/app/menu/language-chooser.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -@use '_variables' as *; -@use '_mixins' as *; - -.modal-body { - text-align: center; - - a { - display: block; - margin: 15px; - } -} diff --git a/client/src/app/menu/language-chooser.component.ts b/client/src/app/menu/language-chooser.component.ts deleted file mode 100644 index 58d245e75..000000000 --- a/client/src/app/menu/language-chooser.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { CommonModule } from '@angular/common' -import { Component, ElementRef, LOCALE_ID, inject, viewChild } from '@angular/core' -import { getDevLocale, isOnDevLocale } from '@app/helpers' -import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component' -import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { getCompleteLocale, getShortLocale, I18N_LOCALES, objectKeysTyped, sortBy } from '@peertube/peertube-core-utils' - -@Component({ - selector: 'my-language-chooser', - templateUrl: './language-chooser.component.html', - styleUrls: [ './language-chooser.component.scss' ], - imports: [ CommonModule, GlobalIconComponent ] -}) -export class LanguageChooserComponent { - private modalService = inject(NgbModal) - private localeId = inject(LOCALE_ID) - - readonly modal = viewChild('modal') - - languages: { id: string, label: string, iso: string }[] = [] - - constructor () { - const l = objectKeysTyped(I18N_LOCALES) - .map(k => ({ id: k, label: I18N_LOCALES[k], iso: getShortLocale(k) })) - - this.languages = sortBy(l, 'label') - } - - show () { - this.modalService.open(this.modal(), { centered: true }) - } - - buildLanguageLink (lang: { id: string }) { - return window.location.origin + '/' + lang.id - } - - getCurrentLanguage () { - const english = 'English' - const locale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) - - if (locale) return I18N_LOCALES[locale as keyof typeof I18N_LOCALES] || english - return english - } -} diff --git a/client/src/app/menu/quick-settings-modal.component.html b/client/src/app/menu/quick-settings-modal.component.html index 947e96091..79175142c 100644 --- a/client/src/app/menu/quick-settings-modal.component.html +++ b/client/src/app/menu/quick-settings-modal.component.html @@ -9,21 +9,20 @@ diff --git a/client/src/app/menu/quick-settings-modal.component.ts b/client/src/app/menu/quick-settings-modal.component.ts index a97d05f72..d825af44e 100644 --- a/client/src/app/menu/quick-settings-modal.component.ts +++ b/client/src/app/menu/quick-settings-modal.component.ts @@ -1,9 +1,8 @@ import { CommonModule } from '@angular/common' -import { Component, OnDestroy, OnInit, inject, output, viewChild } from '@angular/core' +import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core' import { ActivatedRoute } from '@angular/router' import { AuthService, AuthStatus, LocalStorageService, PeerTubeRouterService, User, UserService } from '@app/core' import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component' -import { ButtonComponent } from '@app/shared/shared-main/buttons/button.component' import { AlertComponent } from '@app/shared/shared-main/common/alert.component' import { UserInterfaceSettingsComponent } from '@app/shared/shared-user-settings/user-interface-settings.component' import { UserVideoSettingsComponent } from '@app/shared/shared-user-settings/user-video-settings.component' @@ -15,13 +14,17 @@ import { filter } from 'rxjs/operators' @Component({ selector: 'my-quick-settings', templateUrl: './quick-settings-modal.component.html', + styles: [ + `h5 { + font-size: 1rem; + }` + ], imports: [ CommonModule, GlobalIconComponent, UserVideoSettingsComponent, UserInterfaceSettingsComponent, - AlertComponent, - ButtonComponent + AlertComponent ] }) export class QuickSettingsModalComponent implements OnInit, OnDestroy { @@ -36,8 +39,6 @@ export class QuickSettingsModalComponent implements OnInit, OnDestroy { readonly modal = viewChild('modal') - readonly openLanguageModal = output() - user: User userInformationLoaded = new ReplaySubject(1) @@ -89,11 +90,6 @@ export class QuickSettingsModalComponent implements OnInit, OnDestroy { this.setModalQuery('add') } - changeLanguage () { - this.openedModal.close() - this.openLanguageModal.emit() - } - private setModalQuery (type: 'add' | 'remove') { const modal = type === 'add' ? QuickSettingsModalComponent.QUERY_MODAL_NAME diff --git a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts b/client/src/app/shared/shared-main/http/auth-interceptor.service.ts similarity index 100% rename from client/src/app/shared/shared-main/auth/auth-interceptor.service.ts rename to client/src/app/shared/shared-main/http/auth-interceptor.service.ts diff --git a/client/src/app/shared/shared-main/http/language-interceptor.service.ts b/client/src/app/shared/shared-main/http/language-interceptor.service.ts new file mode 100644 index 000000000..ecddc5c3e --- /dev/null +++ b/client/src/app/shared/shared-main/http/language-interceptor.service.ts @@ -0,0 +1,10 @@ +import { HttpHandlerFn, HttpRequest } from '@angular/common/http' +import { inject, LOCALE_ID } from '@angular/core' + +export function languageInterceptor (req: HttpRequest, next: HttpHandlerFn) { + const localeId = inject(LOCALE_ID) + + const newReq = req.clone({ headers: req.headers.append('x-peertube-language', localeId) }) + + return next(newReq) +} diff --git a/client/src/app/shared/shared-main/main-providers.ts b/client/src/app/shared/shared-main/main-providers.ts index 78e63c851..8ba0f0866 100644 --- a/client/src/app/shared/shared-main/main-providers.ts +++ b/client/src/app/shared/shared-main/main-providers.ts @@ -1,10 +1,10 @@ import { DatePipe } from '@angular/common' import { AccountService } from './account/account.service' -import { AUTH_INTERCEPTOR_PROVIDER } from './auth/auth-interceptor.service' import { VideoChannelSyncService } from './channel/video-channel-sync.service' import { VideoChannelService } from './channel/video-channel.service' import { CustomPageService } from './custom-page/custom-page.service' import { FromNowPipe } from './date/from-now.pipe' +import { AUTH_INTERCEPTOR_PROVIDER } from './http/auth-interceptor.service' import { InstanceService } from './instance/instance.service' import { ActorRedirectGuard } from './router/actor-redirect-guard.service' import { UserHistoryService } from './users/user-history.service' diff --git a/client/src/app/shared/shared-user-settings/user-interface-settings.component.html b/client/src/app/shared/shared-user-settings/user-interface-settings.component.html index 3c454df5d..3570690e9 100644 --- a/client/src/app/shared/shared-user-settings/user-interface-settings.component.html +++ b/client/src/app/shared/shared-user-settings/user-interface-settings.component.html @@ -1,4 +1,21 @@
+
+ +
+
Preferred language for the web interface and for emails
+ +
+ You can help us to translate the platform by consulting this guide +
+
+ + +
@@ -6,5 +23,5 @@
- +
diff --git a/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts b/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts index 135c9f6f7..614c8d40d 100644 --- a/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts +++ b/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts @@ -1,37 +1,56 @@ -import { Subject, Subscription } from 'rxjs' -import { Component, OnDestroy, OnInit, inject, input } from '@angular/core' -import { AuthService, Notifier, ServerService, ThemeService, UserService } from '@app/core' -import { FormReactive } from '@app/shared/shared-forms/form-reactive' -import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' -import { HTMLServerConfig, User, UserUpdateMe } from '@peertube/peertube-models' -import { SelectOptionsItem } from 'src/types' import { NgIf } from '@angular/common' -import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { booleanAttribute, Component, inject, input, OnDestroy, OnInit } from '@angular/core' +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' +import { AuthService, Notifier, ServerService, ThemeService, UserService } from '@app/core' +import { + BuildFormArgumentTyped, + FormReactiveErrorsTyped, + FormReactiveMessagesTyped, + FormReactiveService +} from '@app/shared/shared-forms/form-reactive.service' +import { I18N_LOCALES } from '@peertube/peertube-core-utils' +import { HTMLServerConfig, User, UserUpdateMe } from '@peertube/peertube-models' +import { of, Subject, Subscription, switchMap } from 'rxjs' +import { SelectOptionsItem } from 'src/types' import { SelectOptionsComponent } from '../shared-forms/select/select-options.component' +type Form = { + theme: FormControl + language: FormControl +} + @Component({ selector: 'my-user-interface-settings', templateUrl: './user-interface-settings.component.html', styleUrls: [ './user-interface-settings.component.scss' ], imports: [ FormsModule, ReactiveFormsModule, NgIf, SelectOptionsComponent ] }) -export class UserInterfaceSettingsComponent extends FormReactive implements OnInit, OnDestroy { - protected formReactiveService = inject(FormReactiveService) +export class UserInterfaceSettingsComponent implements OnInit, OnDestroy { + private formReactiveService = inject(FormReactiveService) + private authService = inject(AuthService) private notifier = inject(Notifier) private userService = inject(UserService) private themeService = inject(ThemeService) private serverService = inject(ServerService) - readonly user = input(undefined) - readonly reactiveUpdate = input(false) - readonly notifyOnUpdate = input(true) + readonly user = input>(undefined) + readonly reactiveUpdate = input(false, { transform: booleanAttribute }) + readonly notifyOnUpdate = input(true, { transform: booleanAttribute }) readonly userInformationLoaded = input>(undefined) + form: FormGroup
+ formErrors: FormReactiveErrorsTyped = {} + validationMessages: FormReactiveMessagesTyped = {} + availableThemes: SelectOptionsItem[] + availableLanguages: SelectOptionsItem[] + formValuesWatcher: Subscription private serverConfig: HTMLServerConfig + private initialUserLanguage: string + private updating = false get instanceName () { return this.serverConfig.instance.name @@ -39,6 +58,7 @@ export class UserInterfaceSettingsComponent extends FormReactive implements OnIn ngOnInit () { this.serverConfig = this.serverService.getHTMLConfig() + this.initialUserLanguage = this.user().language this.availableThemes = [ { id: 'instance-default', label: $localize`${this.instanceName} theme`, description: this.getDefaultInstanceThemeLabel() }, @@ -48,14 +68,15 @@ export class UserInterfaceSettingsComponent extends FormReactive implements OnIn ...this.themeService.buildAvailableThemes() ] - this.buildForm({ - theme: null - }) + this.availableLanguages = Object.entries(I18N_LOCALES).map(([ id, label ]) => ({ label, id })) + + this.buildForm() this.userInformationLoaded() .subscribe(() => { this.form.patchValue({ - theme: this.user().theme + theme: this.user().theme, + language: this.user().language }) if (this.reactiveUpdate()) { @@ -63,23 +84,57 @@ export class UserInterfaceSettingsComponent extends FormReactive implements OnIn } }) } + private buildForm () { + const obj: BuildFormArgumentTyped = { + theme: null, + language: null + } + + const { + form, + formErrors, + validationMessages + } = this.formReactiveService.buildForm(obj) + + this.form = form + this.formErrors = formErrors + this.validationMessages = validationMessages + } ngOnDestroy () { this.formValuesWatcher?.unsubscribe() } + // --------------------------------------------------------------------------- + updateInterfaceSettings () { - const theme = this.form.value['theme'] + if (this.updating) return + this.updating = true + + const { theme, language } = this.form.value const details: UserUpdateMe = { - theme + theme, + language } + const changedLanguage = language !== this.initialUserLanguage + + const changeLanguageObs = changedLanguage + ? this.userService.updateInterfaceLanguage(details.language) + : of(true) if (this.authService.isLoggedIn()) { this.userService.updateMyProfile(details) + .pipe(switchMap(() => changeLanguageObs)) .subscribe({ next: () => { + if (changedLanguage) { + window.location.reload() + return + } + this.authService.refreshUserInformation() + this.updating = false if (this.notifyOnUpdate()) this.notifier.success($localize`Interface settings updated.`) }, @@ -91,7 +146,26 @@ export class UserInterfaceSettingsComponent extends FormReactive implements OnIn } this.userService.updateMyAnonymousProfile(details) + if (changedLanguage) { + changeLanguageObs.subscribe({ + next: () => { + window.location.reload() + }, + + error: err => this.notifier.error(err.message) + }) + + return + } + if (this.notifyOnUpdate()) this.notifier.success($localize`Interface settings updated.`) + this.updating = false + } + + getSubmitValue () { + return $localize`Save interface settings` + + // return $localize`Save and reload the interface` } private getDefaultInstanceThemeLabel () { diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts index 6550dda22..b43225733 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts @@ -1,8 +1,8 @@ import { NgIf } from '@angular/common' -import { Component, OnDestroy, OnInit, inject, input } from '@angular/core' +import { Component, OnDestroy, OnInit, booleanAttribute, inject, input } from '@angular/core' import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' import { AuthService, Notifier, ServerService, User, UserService } from '@app/core' -import { FormReactiveErrors, FormReactiveService, FormReactiveMessages } from '@app/shared/shared-forms/form-reactive.service' +import { FormReactiveErrors, FormReactiveMessages, FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { NSFWFlag, NSFWFlagType, NSFWPolicyType, UserUpdateMe } from '@peertube/peertube-models' import { pick } from 'lodash-es' import { Subject, Subscription } from 'rxjs' @@ -49,8 +49,8 @@ export class UserVideoSettingsComponent implements OnInit, OnDestroy { private serverService = inject(ServerService) readonly user = input(null) - readonly reactiveUpdate = input(false) - readonly notifyOnUpdate = input(true) + readonly reactiveUpdate = input(false, { transform: booleanAttribute }) + readonly notifyOnUpdate = input(true, { transform: booleanAttribute }) readonly userInformationLoaded = input>(undefined) form: FormGroup diff --git a/client/src/main.ts b/client/src/main.ts index 83d1290ba..6bdedb6e5 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -1,5 +1,5 @@ import { APP_BASE_HREF, registerLocaleData } from '@angular/common' -import { provideHttpClient } from '@angular/common/http' +import { provideHttpClient, withInterceptors } from '@angular/common/http' import { ApplicationRef, enableProdMode, @@ -15,6 +15,7 @@ import { ServiceWorkerModule } from '@angular/service-worker' import { PTPrimeTheme } from '@app/core/theme/primeng/primeng-theme' import localeOc from '@app/helpers/locales/oc' import { getFormProviders } from '@app/shared/shared-forms/shared-form-providers' +import { languageInterceptor } from '@app/shared/shared-main/http/language-interceptor.service' import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap' import { LoadingBarModule } from '@ngx-loading-bar/core' import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' @@ -76,7 +77,9 @@ const bootstrap = () => ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }) ), - provideHttpClient(), + provideHttpClient( + withInterceptors([ languageInterceptor ]) + ), importProvidersFrom( LoadingBarHttpClientModule, diff --git a/client/src/sass/class-helpers/_common.scss b/client/src/sass/class-helpers/_common.scss index 5cdecb717..638df391c 100644 --- a/client/src/sass/class-helpers/_common.scss +++ b/client/src/sass/class-helpers/_common.scss @@ -1,7 +1,7 @@ -@use '_icons' as *; -@use '_variables' as *; -@use '_mixins' as *; -@use '_button-mixins' as *; +@use "_icons" as *; +@use "_variables" as *; +@use "_mixins" as *; +@use "_button-mixins" as *; .no-results { height: 40vh; @@ -68,13 +68,12 @@ .anchor { position: relative; - top: -calc(#{pvar(--header-height)} + 20px); + top: calc((#{pvar(--header-height)} + 20px) * -1); } // --------------------------------------------------------------------------- .alert { - &.pt-alert-primary { color: pvar(--alert-primary-fg); background-color: pvar(--alert-primary-bg); diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 1be25f282..3bcf034bf 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -62,7 +62,7 @@ export class PeerTubeEmbed { constructor (videoWrapperId: string) { logger.registerServerSending(getBackendUrl()) - this.http = new AuthHTTP(getBackendUrl()) + this.http = new AuthHTTP(getBackendUrl(), navigator.language) this.videoFetcher = new VideoFetcher(this.http) this.playlistFetcher = new PlaylistFetcher(this.http) diff --git a/client/src/standalone/videos/shared/auth-http.ts b/client/src/standalone/videos/shared/auth-http.ts index 9dc450781..4e056395e 100644 --- a/client/src/standalone/videos/shared/auth-http.ts +++ b/client/src/standalone/videos/shared/auth-http.ts @@ -12,7 +12,7 @@ export class AuthHTTP { private headers = new Headers() - constructor (private readonly serverUrl: string) { + constructor (private readonly serverUrl: string, private readonly language: string) { this.userOAuthTokens = OAuthUserTokens.getUserTokens(peertubeLocalStorage) if (this.userOAuthTokens) this.setHeadersFromTokens() @@ -22,6 +22,8 @@ export class AuthHTTP { let refreshFetchOptions: { headers?: Headers } = {} if (isSameOrigin(this.serverUrl, url)) { + if (this.language) this.headers.set('x-peertube-language', this.language) + if (videoPassword) this.headers.set('x-peertube-video-password', videoPassword) if (videoPassword || optionalAuth) refreshFetchOptions = { headers: this.headers } diff --git a/config/default.yaml b/config/default.yaml index 97abcf289..48e575a93 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -893,6 +893,10 @@ instance: # Example: '2 vCore, 2GB RAM...' hardware_information: '' # Supports Markdown + # Default language of your instance, used in emails for example + # The web interface still uses the web browser preferred language + default_language: 'en' + # Describe the languages spoken on your instance, to interact with your users for example # Uncomment or add the languages you want # List of supported languages: https://peertube.cpy.re/api/v1/videos/languages diff --git a/config/production.yaml.example b/config/production.yaml.example index 89091a7c8..eb7fc48d1 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example @@ -557,7 +557,7 @@ signup: user: history: videos: - # Enable or disable video history by default for new users. + # Enable or disable video history by default for new users enabled: true # Default value of maximum video bytes the user can upload @@ -903,6 +903,10 @@ instance: # Example: '2 vCore, 2GB RAM...' hardware_information: '' # Supports Markdown + # Default language of your instance, used in emails for example + # The web interface still uses the web browser preferred language + default_language: 'en' + # Describe the languages spoken on your instance, to interact with your users for example # Uncomment or add the languages you want # List of supported languages: https://peertube.cpy.re/api/v1/videos/languages diff --git a/eslint.config.mjs b/eslint.config.mjs index dcb42c0f0..ed4d3a200 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -13,7 +13,8 @@ export default defineConfig([ 'packages/types-generator', '*.js', 'client', - 'dist' + 'dist', + 'server/.i18next-parser.config.ts' ]), { diff --git a/package.json b/package.json index 54bf760ce..fb53edb5f 100644 --- a/package.json +++ b/package.json @@ -146,6 +146,9 @@ "got-ssrf": "^3.0.0", "helmet": "^8.0.0", "http-problem-details": "^0.1.5", + "i18next": "^25.3.2", + "i18next-icu": "^2.3.0", + "intl-messageformat": "^10.7.16", "ioredis": "^5.2.3", "ip-anonymize": "^0.1.0", "ipaddr.js": "2.2.0", @@ -240,8 +243,11 @@ "eslint": "^9.26.0", "eslint-config-love": "^119.0.0", "fast-xml-parser": "^5.2.2", + "handlebars": "^4.7.8", + "i18next-parser": "^9.3.0", "jpeg-js": "^0.4.4", "jszip": "^3.10.1", + "maildev": "^2.2.1", "mocha": "^11.1.0", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", diff --git a/packages/core-utils/src/i18n/i18n.ts b/packages/core-utils/src/i18n/i18n.ts index 62c9d7169..c935e0c09 100644 --- a/packages/core-utils/src/i18n/i18n.ts +++ b/packages/core-utils/src/i18n/i18n.ts @@ -79,7 +79,7 @@ const I18N_LOCALE_ALIAS = { 'zh': 'zh-Hans-CN' } -export const POSSIBLE_LOCALES = Object.keys(I18N_LOCALES).concat(Object.keys(I18N_LOCALE_ALIAS)) +export const AVAILABLE_LOCALES = Object.keys(I18N_LOCALES).concat(Object.keys(I18N_LOCALE_ALIAS)) export function getDefaultLocale () { return 'en-US' @@ -95,13 +95,13 @@ export function peertubeTranslate (str: string, translations?: { [id: string]: s return translations[str] } -const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) +const possiblePaths = AVAILABLE_LOCALES.map(l => '/' + l) export function is18nPath (path: string) { return possiblePaths.includes(path) } export function is18nLocale (locale: string) { - return POSSIBLE_LOCALES.includes(locale) + return AVAILABLE_LOCALES.includes(locale) } export function getCompleteLocale (locale: string) { diff --git a/packages/core-utils/src/renderer/html.ts b/packages/core-utils/src/renderer/html.ts index a034bfcf5..b2c1d2bac 100644 --- a/packages/core-utils/src/renderer/html.ts +++ b/packages/core-utils/src/renderer/html.ts @@ -42,6 +42,16 @@ export function getDefaultSanitizeOptions () { } } +export function getMailHtmlSanitizeOptions () { + return { + allowedTags: [ 'a', 'strong' ], + allowedSchemes: getDefaultSanitizedSchemes(), + allowedAttributes: { + a: [ 'href', 'title' ] + } + } +} + export function getTextOnlySanitizeOptions () { return { allowedTags: [] as string[] @@ -56,7 +66,7 @@ export function getTextOnlySanitizeOptions () { export function escapeHTML (stringParam: string) { if (!stringParam) return '' - const entityMap: { [id: string ]: string } = { + const entityMap: { [id: string]: string } = { '&': '&', '<': '<', '>': '>', diff --git a/packages/models/src/import-export/peertube-export-format/user-settings-export.model.ts b/packages/models/src/import-export/peertube-export-format/user-settings-export.model.ts index 0eb3b6e98..52ef25946 100644 --- a/packages/models/src/import-export/peertube-export-format/user-settings-export.model.ts +++ b/packages/models/src/import-export/peertube-export-format/user-settings-export.model.ts @@ -15,6 +15,7 @@ export interface UserSettingsExportJSON { videosHistoryEnabled: boolean videoLanguages: string[] + language: string theme: string diff --git a/packages/models/src/server/custom-config.model.ts b/packages/models/src/server/custom-config.model.ts index 21f0b1fef..05efb74f2 100644 --- a/packages/models/src/server/custom-config.model.ts +++ b/packages/models/src/server/custom-config.model.ts @@ -29,6 +29,8 @@ export interface CustomConfig { businessModel: string hardwareInformation: string + defaultLanguage: string + languages: string[] categories: number[] diff --git a/packages/models/src/server/debug.model.ts b/packages/models/src/server/debug.model.ts index 067e53c41..ea43d4faa 100644 --- a/packages/models/src/server/debug.model.ts +++ b/packages/models/src/server/debug.model.ts @@ -3,11 +3,17 @@ export interface Debug { activityPubMessagesWaiting: number } -export interface SendDebugCommand { - command: 'remove-dandling-resumable-uploads' - | 'process-video-views-buffer' - | 'process-video-viewers' - | 'process-video-channel-sync-latest' - | 'process-update-videos-scheduler' - | 'remove-expired-user-exports' +export type SendDebugCommand = { + command: + | 'remove-dandling-resumable-uploads' + | 'process-video-views-buffer' + | 'process-video-viewers' + | 'process-video-channel-sync-latest' + | 'process-update-videos-scheduler' + | 'remove-expired-user-exports' +} | SendDebugTestEmails + +export type SendDebugTestEmails = { + command: 'test-emails' + email: string } diff --git a/packages/models/src/server/emailer.model.ts b/packages/models/src/server/emailer.model.ts index a69686780..c7108c524 100644 --- a/packages/models/src/server/emailer.model.ts +++ b/packages/models/src/server/emailer.model.ts @@ -1,7 +1,12 @@ +export type To = { email: string, language: string } type From = string | { name?: string, address: string } -interface Base extends Partial { - to: string[] | string +interface Base { + to: To[] | To + + from?: From + subject?: string + replyTo?: string } interface MailTemplate extends Base { @@ -30,6 +35,8 @@ interface SendEmailDefaultLocalsOptions { fg: string bg: string primary: string + language: string + logoUrl: string } interface SendEmailDefaultMessageOptions { diff --git a/packages/models/src/server/server-config.model.ts b/packages/models/src/server/server-config.model.ts index e1e9352f3..aabcf706a 100644 --- a/packages/models/src/server/server-config.model.ts +++ b/packages/models/src/server/server-config.model.ts @@ -137,6 +137,8 @@ export interface ServerConfig { avatars: ActorImage[] banners: ActorImage[] + defaultLanguage: string + logo: { type: LogoType width: number diff --git a/packages/models/src/users/user-update-me.model.ts b/packages/models/src/users/user-update-me.model.ts index fd7080604..a250b9d04 100644 --- a/packages/models/src/users/user-update-me.model.ts +++ b/packages/models/src/users/user-update-me.model.ts @@ -17,6 +17,7 @@ export interface UserUpdateMe { autoPlayNextVideoPlaylist?: boolean videosHistoryEnabled?: boolean videoLanguages?: string[] + language?: string email?: string emailPublic?: boolean diff --git a/packages/models/src/users/user.model.ts b/packages/models/src/users/user.model.ts index 6ae5a9d8c..c9e865856 100644 --- a/packages/models/src/users/user.model.ts +++ b/packages/models/src/users/user.model.ts @@ -31,6 +31,7 @@ export interface User { videosHistoryEnabled: boolean videoLanguages: string[] + language: string role: { id: UserRoleType diff --git a/packages/server-commands/src/users/users-command.ts b/packages/server-commands/src/users/users-command.ts index 62abd1136..1a8b3a044 100644 --- a/packages/server-commands/src/users/users-command.ts +++ b/packages/server-commands/src/users/users-command.ts @@ -18,10 +18,11 @@ import { unwrapBody } from '../requests/index.js' import { AbstractCommand, OverrideCommandOptions } from '../shared/index.js' export class UsersCommand extends AbstractCommand { - - askResetPassword (options: OverrideCommandOptions & { - email: string - }) { + askResetPassword ( + options: OverrideCommandOptions & { + email: string + } + ) { const { email } = options const path = '/api/v1/users/ask-reset-password' @@ -35,11 +36,13 @@ export class UsersCommand extends AbstractCommand { }) } - resetPassword (options: OverrideCommandOptions & { - userId: number - verificationString: string - password: string - }) { + resetPassword ( + options: OverrideCommandOptions & { + userId: number + verificationString: string + password: string + } + ) { const { userId, verificationString, password } = options const path = '/api/v1/users/' + userId + '/reset-password' @@ -55,9 +58,11 @@ export class UsersCommand extends AbstractCommand { // --------------------------------------------------------------------------- - askSendVerifyEmail (options: OverrideCommandOptions & { - email: string - }) { + askSendVerifyEmail ( + options: OverrideCommandOptions & { + email: string + } + ) { const { email } = options const path = '/api/v1/users/ask-send-verify-email' @@ -71,11 +76,13 @@ export class UsersCommand extends AbstractCommand { }) } - verifyEmail (options: OverrideCommandOptions & { - userId: number - verificationString: string - isPendingEmail?: boolean // default false - }) { + verifyEmail ( + options: OverrideCommandOptions & { + userId: number + verificationString: string + isPendingEmail?: boolean // default false + } + ) { const { userId, verificationString, isPendingEmail = false } = options const path = '/api/v1/users/' + userId + '/verify-email' @@ -94,10 +101,12 @@ export class UsersCommand extends AbstractCommand { // --------------------------------------------------------------------------- - banUser (options: OverrideCommandOptions & { - userId: number - reason?: string - }) { + banUser ( + options: OverrideCommandOptions & { + userId: number + reason?: string + } + ) { const { userId, reason } = options const path = '/api/v1/users' + '/' + userId + '/block' @@ -111,9 +120,11 @@ export class UsersCommand extends AbstractCommand { }) } - unbanUser (options: OverrideCommandOptions & { - userId: number - }) { + unbanUser ( + options: OverrideCommandOptions & { + userId: number + } + ) { const { userId } = options const path = '/api/v1/users' + '/' + userId + '/unblock' @@ -154,15 +165,17 @@ export class UsersCommand extends AbstractCommand { // --------------------------------------------------------------------------- - create (options: OverrideCommandOptions & { - username: string - password?: string - videoQuota?: number - videoQuotaDaily?: number - role?: UserRoleType - adminFlags?: UserAdminFlagType - email?: string - }) { + create ( + options: OverrideCommandOptions & { + username: string + password?: string + videoQuota?: number + videoQuotaDaily?: number + role?: UserRoleType + adminFlags?: UserAdminFlagType + email?: string + } + ) { const { username, adminFlags, @@ -243,9 +256,11 @@ export class UsersCommand extends AbstractCommand { }) } - getMyRating (options: OverrideCommandOptions & { - videoId: number | string - }) { + getMyRating ( + options: OverrideCommandOptions & { + videoId: number | string + } + ) { const { videoId } = options const path = '/api/v1/users/me/videos/' + videoId + '/rating' @@ -285,9 +300,11 @@ export class UsersCommand extends AbstractCommand { }) } - updateMyAvatar (options: OverrideCommandOptions & { - fixture: string - }) { + updateMyAvatar ( + options: OverrideCommandOptions & { + fixture: string + } + ) { const { fixture } = options const path = '/api/v1/users/me/avatar/pick' @@ -305,10 +322,12 @@ export class UsersCommand extends AbstractCommand { // --------------------------------------------------------------------------- - get (options: OverrideCommandOptions & { - userId: number - withStats?: boolean // default false - }) { + get ( + options: OverrideCommandOptions & { + userId: number + withStats?: boolean // default false + } + ) { const { userId, withStats } = options const path = '/api/v1/users/' + userId @@ -341,9 +360,11 @@ export class UsersCommand extends AbstractCommand { }) } - remove (options: OverrideCommandOptions & { - userId: number - }) { + remove ( + options: OverrideCommandOptions & { + userId: number + } + ) { const { userId } = options const path = '/api/v1/users/' + userId @@ -356,17 +377,19 @@ export class UsersCommand extends AbstractCommand { }) } - update (options: OverrideCommandOptions & { - userId: number - email?: string - emailVerified?: boolean - videoQuota?: number - videoQuotaDaily?: number - password?: string - adminFlags?: UserAdminFlagType - pluginAuth?: string - role?: UserRoleType - }) { + update ( + options: OverrideCommandOptions & { + userId: number + email?: string + emailVerified?: boolean + videoQuota?: number + videoQuotaDaily?: number + password?: string + adminFlags?: UserAdminFlagType + pluginAuth?: string + role?: UserRoleType + } + ) { const path = '/api/v1/users/' + options.userId const toSend: UserUpdate = {} @@ -388,4 +411,24 @@ export class UsersCommand extends AbstractCommand { defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } + + // --------------------------------------------------------------------------- + + updateInterfaceLanguage ( + options: OverrideCommandOptions & { + language: string + } + ) { + const { language } = options + const path = '/api/v1/client-config/update-interface-language' + + return this.postBodyRequest({ + ...options, + + path, + fields: { language }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } } diff --git a/packages/tests/src/api/check-params/contact-form.ts b/packages/tests/src/api/check-params/contact-form.ts index 009cb2ad9..c3a215e5a 100644 --- a/packages/tests/src/api/check-params/contact-form.ts +++ b/packages/tests/src/api/check-params/contact-form.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { MockSmtpServer } from '@tests/shared/mock-servers/index.js' import { HttpStatusCode } from '@peertube/peertube-models' import { cleanupTests, @@ -10,6 +9,7 @@ import { killallServers, PeerTubeServer } from '@peertube/peertube-server-commands' +import { MockSmtpServer } from '@tests/shared/mock-servers/index.js' describe('Test contact form API validators', function () { let server: PeerTubeServer @@ -79,7 +79,7 @@ describe('Test contact form API validators', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/check-params/my-user.ts b/packages/tests/src/api/check-params/my-user.ts index 84e12fad9..3cbb0457d 100644 --- a/packages/tests/src/api/check-params/my-user.ts +++ b/packages/tests/src/api/check-params/my-user.ts @@ -253,6 +253,12 @@ describe('Test my user API validators', function () { } }) + it('Should fail with an invalid language attribute', async function () { + const fields = { language: 'toto' } + + await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) + }) + it('Should fail with an invalid theme', async function () { const fields = { theme: 'invalid' } await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) @@ -293,7 +299,8 @@ describe('Test my user API validators', function () { theme: 'default', noInstanceConfigWarningModal: true, noWelcomeModal: true, - noAccountSetupWarningModal: true + noAccountSetupWarningModal: true, + language: 'fr' } await makePutBodyRequest({ @@ -545,6 +552,22 @@ describe('Test my user API validators', function () { }) }) + describe('Client config', function () { + it('Should fail with an invalid language', async function () { + await server.users.updateInterfaceLanguage({ + language: 'hello', + expectedStatus: HttpStatusCode.BAD_REQUEST_400 + }) + }) + + it('Should succeed to update language with the correct params', async function () { + await server.users.updateInterfaceLanguage({ + language: 'fr', + expectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + }) + }) + describe('When deleting our account', function () { it('Should fail with with the root account', async function () { await server.users.deleteMe({ expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) @@ -552,7 +575,7 @@ describe('Test my user API validators', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/check-params/users-admin.ts b/packages/tests/src/api/check-params/users-admin.ts index b52cf12ec..97398bc4e 100644 --- a/packages/tests/src/api/check-params/users-admin.ts +++ b/packages/tests/src/api/check-params/users-admin.ts @@ -479,7 +479,7 @@ describe('Test users admin API validators', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/notifications/admin-notifications.ts b/packages/tests/src/api/notifications/admin-notifications.ts index e183caf95..b9d35b280 100644 --- a/packages/tests/src/api/notifications/admin-notifications.ts +++ b/packages/tests/src/api/notifications/admin-notifications.ts @@ -60,7 +60,6 @@ describe('Test admin notifications', function () { }) describe('Latest PeerTube version notification', function () { - it('Should not send a notification to admins if there is no new version', async function () { this.timeout(30000) @@ -104,7 +103,6 @@ describe('Test admin notifications', function () { }) describe('Latest plugin version notification', function () { - it('Should not send a notification to admins if there is no new plugin version', async function () { this.timeout(30000) @@ -146,7 +144,7 @@ describe('Test admin notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await sqlCommand.cleanup() await cleanupTests([ server ]) diff --git a/packages/tests/src/api/notifications/caption-notifications.ts b/packages/tests/src/api/notifications/caption-notifications.ts index 4d584ec0b..56c6f99d0 100644 --- a/packages/tests/src/api/notifications/caption-notifications.ts +++ b/packages/tests/src/api/notifications/caption-notifications.ts @@ -3,11 +3,7 @@ import { UserNotification } from '@peertube/peertube-models' import { PeerTubeServer, cleanupTests, waitJobs } from '@peertube/peertube-server-commands' import { MockSmtpServer } from '@tests/shared/mock-servers/mock-email.js' -import { - CheckerBaseParams, - checkMyVideoTranscriptionGenerated, - prepareNotificationsTest -} from '@tests/shared/notifications.js' +import { CheckerBaseParams, checkMyVideoTranscriptionGenerated, prepareNotificationsTest } from '@tests/shared/notifications.js' import { join } from 'path' describe('Test caption notifications', function () { @@ -74,7 +70,7 @@ describe('Test caption notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests(servers) }) diff --git a/packages/tests/src/api/notifications/comments-notifications.ts b/packages/tests/src/api/notifications/comments-notifications.ts index 5defc3234..a1976fe53 100644 --- a/packages/tests/src/api/notifications/comments-notifications.ts +++ b/packages/tests/src/api/notifications/comments-notifications.ts @@ -15,7 +15,7 @@ describe('Test comments notifications', function () { const commentText = '**hello** world,

what do you think about peertube?

' const expectedHtml = 'hello world' + - ',

what do you think about peertube?' + ',

what do you think about peertube?' before(async function () { this.timeout(120000) @@ -392,7 +392,7 @@ describe('Test comments notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests(servers) }) diff --git a/packages/tests/src/api/notifications/index.ts b/packages/tests/src/api/notifications/index.ts index 977c4159f..3975eb317 100644 --- a/packages/tests/src/api/notifications/index.ts +++ b/packages/tests/src/api/notifications/index.ts @@ -1,5 +1,5 @@ import './admin-notifications.js' -import './captions-notifications.js' +import './caption-notifications.js' import './comments-notifications.js' import './moderation-notifications.js' import './notifications-api.js' diff --git a/packages/tests/src/api/notifications/moderation-notifications.ts b/packages/tests/src/api/notifications/moderation-notifications.ts index fe2d443cd..c16f394f2 100644 --- a/packages/tests/src/api/notifications/moderation-notifications.ts +++ b/packages/tests/src/api/notifications/moderation-notifications.ts @@ -427,7 +427,6 @@ describe('Test moderation notifications', function () { let videoName: string before(async function () { - adminBaseParamsServer1 = { server: servers[0], emails, @@ -583,7 +582,7 @@ describe('Test moderation notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests(servers) }) diff --git a/packages/tests/src/api/notifications/notifications-api.ts b/packages/tests/src/api/notifications/notifications-api.ts index 7c880bfed..9530d1fe7 100644 --- a/packages/tests/src/api/notifications/notifications-api.ts +++ b/packages/tests/src/api/notifications/notifications-api.ts @@ -36,7 +36,6 @@ describe('Test notifications API', function () { }) describe('Notification list & count', function () { - it('Should correctly list notifications', async function () { const { data, total } = await server.notifications.list({ token: userToken, start: 0, count: 2 }) @@ -74,7 +73,6 @@ describe('Test notifications API', function () { }) describe('Mark as read', function () { - it('Should mark as read some notifications', async function () { const { data } = await server.notifications.list({ token: userToken, start: 2, count: 3 }) const ids = data.map(n => n.id) @@ -227,7 +225,7 @@ describe('Test notifications API', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/notifications/registrations-notifications.ts b/packages/tests/src/api/notifications/registrations-notifications.ts index 1f166cb36..f96c197e5 100644 --- a/packages/tests/src/api/notifications/registrations-notifications.ts +++ b/packages/tests/src/api/notifications/registrations-notifications.ts @@ -35,7 +35,6 @@ describe('Test registrations notifications', function () { }) describe('New direct registration for moderators', function () { - before(async function () { await server.config.enableSignup(false) }) @@ -55,7 +54,6 @@ describe('Test registrations notifications', function () { }) describe('New registration request for moderators', function () { - before(async function () { await server.config.enableSignup(true) }) @@ -76,7 +74,7 @@ describe('Test registrations notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/notifications/user-notifications.ts b/packages/tests/src/api/notifications/user-notifications.ts index cadf3fa5a..1be70802d 100644 --- a/packages/tests/src/api/notifications/user-notifications.ts +++ b/packages/tests/src/api/notifications/user-notifications.ts @@ -396,7 +396,6 @@ describe('Test user notifications', function () { }) describe('My live replay is published', function () { - let baseParams: CheckerBaseParams before(() => { @@ -640,7 +639,7 @@ describe('Test user notifications', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests(servers) }) diff --git a/packages/tests/src/api/server/config.ts b/packages/tests/src/api/server/config.ts index 0c6d870e6..ddccde22a 100644 --- a/packages/tests/src/api/server/config.ts +++ b/packages/tests/src/api/server/config.ts @@ -32,6 +32,7 @@ function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) { expect(data.instance.hardwareInformation).to.be.empty expect(data.instance.serverCountry).to.be.empty expect(data.instance.support.text).to.be.empty + expect(data.instance.defaultLanguage).to.equal('en') expect(data.instance.social.externalLink).to.be.empty expect(data.instance.social.blueskyLink).to.be.empty expect(data.instance.social.mastodonLink).to.be.empty @@ -189,6 +190,7 @@ function buildNewCustomConfig (server: PeerTubeServer): CustomConfig { support: { text: 'My support text' }, + defaultLanguage: 'fr', social: { externalLink: 'https://joinpeertube.org/', mastodonLink: 'https://framapiaf.org/@peertube', @@ -984,9 +986,9 @@ describe('Test config', function () { expect(body.short_name).to.equal(body.name) expect(body.description).to.equal('description manifest') - const icon = body.icons.find(f => f.sizes === '36x36') + const icon = body.icons.find(f => f.sizes === '192x192') expect(icon).to.exist - expect(icon.src).to.equal('/client/assets/images/icons/icon-36x36.png') + expect(icon.src).to.equal('/client/assets/images/icons/icon-192x192.png') }) it('Should generate the manifest with avatar', async function () { diff --git a/packages/tests/src/api/server/contact-form.ts b/packages/tests/src/api/server/contact-form.ts index 03389aa64..9f8906f69 100644 --- a/packages/tests/src/api/server/contact-form.ts +++ b/packages/tests/src/api/server/contact-form.ts @@ -94,7 +94,7 @@ describe('Test contact form', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/server/email.ts b/packages/tests/src/api/server/email.ts index 4dec79707..55d384c0f 100644 --- a/packages/tests/src/api/server/email.ts +++ b/packages/tests/src/api/server/email.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { HttpStatusCode } from '@peertube/peertube-models' +import { HttpStatusCode, VideoCreateResult } from '@peertube/peertube-models' import { cleanupTests, ConfigCommand, @@ -12,7 +12,9 @@ import { import { expectStartWith } from '@tests/shared/checks.js' import { MockSmtpServer } from '@tests/shared/mock-servers/index.js' import { SQLCommand } from '@tests/shared/sql-command.js' -import { expect } from 'chai' +import { config, expect } from 'chai' + +config.truncateThreshold = 0 describe('Test emails', function () { let server: PeerTubeServer @@ -256,7 +258,7 @@ describe('Test emails', function () { expect(email['from'][0]['name']).equal('PeerTube') expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' blacklisted') + expect(email['subject']).contains(' blocked') expect(email['text']).contains('my super user video') expect(email['text']).contains('my super reason') }) @@ -272,7 +274,7 @@ describe('Test emails', function () { expect(email['from'][0]['name']).equal('PeerTube') expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' unblacklisted') + expect(email['subject']).contains(' unblocked') expect(email['text']).contains('my super user video') }) @@ -412,8 +414,71 @@ describe('Test emails', function () { }) }) + describe('Email translations', function () { + let video: VideoCreateResult + + before(async function () { + video = await server.videos.quickUpload({ name: 'video' }) + + await server.config.updateExistingConfig({ + newConfig: { + instance: { + defaultLanguage: 'fr' + } + } + }) + }) + + it('Should translate emails according to the instance language', async function () { + await server.contactForm.send({ + fromEmail: 'toto@example.com', + body: 'my super message', + subject: 'my subject', + fromName: 'Super toto' + }) + + await waitJobs(server) + + const email = emails[emails.length - 1] + + expect(email['subject']).to.contain('Formulaire de contact') + expect(email['text']).to.contain('Super toto vous a envoyé un message') + }) + + it('Should translate emails according to the instance language if not provided by the user', async function () { + await server.blacklist.add({ videoId: video.uuid }) + await waitJobs(server) + + const email = emails[emails.length - 1] + expect(email['subject']).to.contain('été bloquée') + expect(email['text']).to.contain('été bloquée') + }) + + it('Should translate emails according to the user language if provided', async function () { + await server.users.updateMe({ language: 'en' }) + + await server.blacklist.remove({ videoId: video.uuid }) + await waitJobs(server) + + const email = emails[emails.length - 1] + expect(email['subject']).to.contain('has been unblocked') + expect(email['text']).to.contain('has been unblocked') + }) + + it('Should update user language and translate emails accordingly', async function () { + await server.users.updateMe({ language: 'fr' }) + + await server.blacklist.add({ videoId: video.uuid }) + await waitJobs(server) + + const email = emails[emails.length - 1] + expect(email['subject']).to.contain('été bloquée') + expect(email['text']).to.contain('été bloquée') + }) + }) + after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/users/registrations.ts b/packages/tests/src/api/users/registrations.ts index dcf09cade..d6fabb9b7 100644 --- a/packages/tests/src/api/users/registrations.ts +++ b/packages/tests/src/api/users/registrations.ts @@ -27,6 +27,13 @@ describe('Test registrations', function () { await setAccessTokensToServers([ server ]) await server.config.enableSignup(false) + await server.config.updateExistingConfig({ + newConfig: { + instance: { + defaultLanguage: 'fr' + } + } + }) }) describe('Direct registrations of a new user', function () { @@ -210,8 +217,8 @@ describe('Test registrations', function () { const email = emails.find(e => e['to'][0]['address'] === 'user4@example.com') expect(email).to.exist - expect(email['subject']).to.contain('been rejected') - expect(email['text']).to.contain('been rejected') + expect(email['subject']).to.contain('été rejetée') + expect(email['text']).to.contain('été rejetée') expect(email['text']).to.contain('I do not want id 4 on this instance') }) @@ -229,8 +236,8 @@ describe('Test registrations', function () { const email = emails.find(e => e['to'][0]['address'] === 'user2@example.com') expect(email).to.exist - expect(email['subject']).to.contain('been accepted') - expect(email['text']).to.contain('been accepted') + expect(email['subject']).to.contain('été acceptée') + expect(email['text']).to.contain('été acceptée') expect(email['text']).to.contain('Welcome id 2') } @@ -238,8 +245,8 @@ describe('Test registrations', function () { const email = emails.find(e => e['to'][0]['address'] === 'user3@example.com') expect(email).to.exist - expect(email['subject']).to.contain('been accepted') - expect(email['text']).to.contain('been accepted') + expect(email['subject']).to.contain('été acceptée') + expect(email['text']).to.contain('été acceptée') expect(email['text']).to.contain('Welcome id 3') } }) @@ -259,6 +266,7 @@ describe('Test registrations', function () { expect(me.videoChannels[0].displayName).to.equal('Main user2 channel') expect(me.role.id).to.equal(UserRole.USER) expect(me.email).to.equal('user2@example.com') + expect(me.language).to.equal('fr') }) it('Should have created the appropriate attributes for user 3', async function () { @@ -271,6 +279,7 @@ describe('Test registrations', function () { expect(me.videoChannels[0].displayName).to.equal('my user 3 channel') expect(me.role.id).to.equal(UserRole.USER) expect(me.email).to.equal('user3@example.com') + expect(me.language).to.equal('fr') }) it('Should list these accepted/rejected registration requests', async function () { @@ -408,7 +417,7 @@ describe('Test registrations', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/users/user-export.ts b/packages/tests/src/api/users/user-export.ts index e63244323..f5107f920 100644 --- a/packages/tests/src/api/users/user-export.ts +++ b/packages/tests/src/api/users/user-export.ts @@ -86,7 +86,6 @@ function runTest (withObjectStorage: boolean) { objectStorage = withObjectStorage ? new ObjectStorageCommand() : undefined - ;({ rootId, noahId, @@ -906,7 +905,7 @@ function runTest (withObjectStorage: boolean) { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server, remoteServer ]) }) diff --git a/packages/tests/src/api/users/user-import.ts b/packages/tests/src/api/users/user-import.ts index 56f1b25a5..921fd3191 100644 --- a/packages/tests/src/api/users/user-import.ts +++ b/packages/tests/src/api/users/user-import.ts @@ -170,6 +170,7 @@ function runTest (withObjectStorage: boolean) { const me = await remoteServer.users.getMyInfo({ token: remoteNoahToken }) expect(me.p2pEnabled).to.be.false + expect(me.language).to.equal('fr') const settings = me.notificationSettings @@ -593,11 +594,11 @@ function runTest (withObjectStorage: boolean) { it('Should have received an email on finished import', async function () { const email = emails.reverse().find(e => { return e['to'][0]['address'] === 'noah_remote@example.com' && - e['subject'].includes('archive import has finished') + e['subject'].includes('importation de votre archive est terminée') }) expect(email).to.exist - expect(email['text']).to.contain('as considered duplicate: 5') // 5 videos are considered as duplicates + expect(email['text']).to.contain('considéré comme doublon : 5') // 5 videos are considered as duplicates }) it('Should auto blacklist imported videos if enabled by the administrator', async function () { @@ -715,7 +716,7 @@ function runTest (withObjectStorage: boolean) { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server, remoteServer, blockedServer ]) }) diff --git a/packages/tests/src/api/users/users-email-verification.ts b/packages/tests/src/api/users/users-email-verification.ts index ed87fb0da..9f3863db2 100644 --- a/packages/tests/src/api/users/users-email-verification.ts +++ b/packages/tests/src/api/users/users-email-verification.ts @@ -158,7 +158,7 @@ describe('Test users email verification', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests([ server ]) }) diff --git a/packages/tests/src/api/users/users.ts b/packages/tests/src/api/users/users.ts index 0705f19da..594ab5584 100644 --- a/packages/tests/src/api/users/users.ts +++ b/packages/tests/src/api/users/users.ts @@ -1,14 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { testAvatarSize } from '@tests/shared/checks.js' import { AbuseState, HttpStatusCode, UserAdminFlag, UserRole, VideoPlaylistType } from '@peertube/peertube-models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers -} from '@peertube/peertube-server-commands' +import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@peertube/peertube-server-commands' +import { testAvatarSize } from '@tests/shared/checks.js' +import { expect } from 'chai' describe('Test users', function () { let server: PeerTubeServer @@ -60,6 +55,7 @@ describe('Test users', function () { expect(user.id).to.be.a('number') expect(user.account.displayName).to.equal('user_1') expect(user.account.description).to.be.null + expect(user.language).to.equal('en') } expect(userMe.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST) @@ -334,6 +330,43 @@ describe('Test users', function () { expect(user.noInstanceConfigWarningModal).to.be.true expect(user.noAccountSetupWarningModal).to.be.true }) + + it('Should update instance config and automatically update user language', async function () { + { + const user = await server.users.getMyInfo({ token: userToken }) + expect(user.videoLanguages).to.be.null + expect(user.language).to.equal('en') + } + + { + await server.config.updateExistingConfig({ + newConfig: { + instance: { + defaultLanguage: 'es' + } + } + }) + } + + { + const user = await server.users.getMyInfo({ token: userToken }) + expect(user.language).to.equal('es') + } + }) + + it('Should be able to update my languages', async function () { + await server.users.updateMe({ + token: userToken, + language: 'fr', + videoLanguages: [ 'fr', 'en' ] + }) + + { + const user = await server.users.getMyInfo({ token: userToken }) + expect(user.language).to.equal('fr') + expect(user.videoLanguages).to.deep.equal([ 'fr', 'en' ]) + } + }) }) describe('Updating another user', function () { @@ -527,6 +560,32 @@ describe('Test users', function () { }) }) + describe('Client config', function () { + it('Send a cookie on interface language change', async function () { + const res = await server.users.updateInterfaceLanguage({ + language: 'fr', + expectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + + const setCookie = res.headers['set-cookie'] + + expect(setCookie).to.exist + expect(setCookie[0]).to.include('clientLanguage=fr;') + }) + + it('Should clear cookies if language is null', async function () { + const res = await server.users.updateInterfaceLanguage({ + language: null, + expectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + + const setCookie = res.headers['set-cookie'] + + expect(setCookie).to.exist + expect(setCookie[0]).to.include('clientLanguage=;') + }) + }) + after(async function () { await cleanupTests([ server ]) }) diff --git a/packages/tests/src/plugins/filter-hooks.ts b/packages/tests/src/plugins/filter-hooks.ts index 71a84dda3..c6c3b5d23 100644 --- a/packages/tests/src/plugins/filter-hooks.ts +++ b/packages/tests/src/plugins/filter-hooks.ts @@ -956,7 +956,7 @@ describe('Test plugin filter hooks', function () { }) after(async function () { - MockSmtpServer.Instance.kill() + await MockSmtpServer.Instance.kill() await cleanupTests(servers) }) diff --git a/packages/tests/src/shared/import-export.ts b/packages/tests/src/shared/import-export.ts index 2fd46f6ad..3df868b6f 100644 --- a/packages/tests/src/shared/import-export.ts +++ b/packages/tests/src/shared/import-export.ts @@ -262,7 +262,7 @@ export async function prepareImportExportTests (options: { }) // My settings - await server.users.updateMe({ token: noahToken, description: 'super noah description', p2pEnabled: false }) + await server.users.updateMe({ token: noahToken, description: 'super noah description', p2pEnabled: false, language: 'fr' }) // My notification settings await server.notifications.updateMySettings({ diff --git a/packages/tests/src/shared/mock-servers/mock-email.ts b/packages/tests/src/shared/mock-servers/mock-email.ts index 7c618e57f..4093637b9 100644 --- a/packages/tests/src/shared/mock-servers/mock-email.ts +++ b/packages/tests/src/shared/mock-servers/mock-email.ts @@ -1,17 +1,24 @@ -import MailDev from '@peertube/maildev' import { randomInt } from '@peertube/peertube-core-utils' import { parallelTests } from '@peertube/peertube-node-utils' +import MailDev from 'maildev' class MockSmtpServer { - private static instance: MockSmtpServer private started = false private maildev: any private emails: object[] + private relayingEmail: Promise - private constructor () { } + private + + private constructor () {} collectEmails (emailsCollection: object[]) { + const outgoingHost = process.env.MAILDEV_RELAY_HOST + const outgoingPort = process.env.MAILDEV_RELAY_PORT + ? parseInt(process.env.MAILDEV_RELAY_PORT) + : undefined + return new Promise((res, rej) => { const port = parallelTests() ? randomInt(1025, 2000) : 1025 this.emails = emailsCollection @@ -24,11 +31,26 @@ class MockSmtpServer { ip: '127.0.0.1', smtp: port, disableWeb: true, - silent: true + silent: true, + outgoingHost, + outgoingPort }) this.maildev.on('new', email => { this.emails.push(email) + + if (outgoingHost || outgoingPort) { + this.relayingEmail = new Promise(resolve => { + this.maildev.relayMail(email, function (err) { + if (err) return console.log(err) + + console.log('Email has been relayed!') + + this.relayingEmail = undefined + resolve() + }) + }) + } }) this.maildev.listen(err => { @@ -41,9 +63,13 @@ class MockSmtpServer { }) } - kill () { + async kill () { if (!this.maildev) return + if (this.relayingEmail) { + await this.relayingEmail + } + this.maildev.close() this.maildev = null diff --git a/packages/tests/src/shared/notifications.ts b/packages/tests/src/shared/notifications.ts index 72abc9b9b..39fa4169c 100644 --- a/packages/tests/src/shared/notifications.ts +++ b/packages/tests/src/shared/notifications.ts @@ -77,11 +77,13 @@ async function waitUntilNotification (options: { await waitJobs([ server ]) } -async function checkNewVideoFromSubscription (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { +async function checkNewVideoFromSubscription ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + checkType: CheckerType + } +) { const { videoName, shortUUID } = options const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION @@ -107,11 +109,13 @@ async function checkNewVideoFromSubscription (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewLiveFromSubscription (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { +async function checkNewLiveFromSubscription ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + checkType: CheckerType + } +) { const { videoName, shortUUID } = options const notificationType = UserNotificationType.NEW_LIVE_FROM_SUBSCRIPTION @@ -137,11 +141,13 @@ async function checkNewLiveFromSubscription (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkMyVideoIsPublished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { +async function checkMyVideoIsPublished ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + checkType: CheckerType + } +) { const { videoName, shortUUID } = options const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED @@ -165,11 +171,13 @@ async function checkMyVideoIsPublished (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkVideoStudioEditionIsFinished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { +async function checkVideoStudioEditionIsFinished ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + checkType: CheckerType + } +) { const { videoName, shortUUID } = options const notificationType = UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED @@ -193,13 +201,15 @@ async function checkVideoStudioEditionIsFinished (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - url: string - success: boolean - checkType: CheckerType -}) { +async function checkMyVideoImportIsFinished ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + url: string + success: boolean + checkType: CheckerType + } +) { const { videoName, shortUUID, url, success } = options const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR @@ -219,9 +229,11 @@ async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { function emailNotificationFinder (email: object) { const text: string = email['text'] - const toFind = success ? ' finished' : ' error' + const toFind = success + ? /\bfinished\b/ + : /\berror\b/ - return text.includes(url) && text.includes(toFind) + return text.includes(url) && !!text.match(toFind) } await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) @@ -229,10 +241,12 @@ async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { // --------------------------------------------------------------------------- -async function checkUserRegistered (options: CheckerBaseParams & { - username: string - checkType: CheckerType -}) { +async function checkUserRegistered ( + options: CheckerBaseParams & { + username: string + checkType: CheckerType + } +) { const { username } = options const notificationType = UserNotificationType.NEW_USER_REGISTRATION @@ -257,11 +271,13 @@ async function checkUserRegistered (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkRegistrationRequest (options: CheckerBaseParams & { - username: string - registrationReason: string - checkType: CheckerType -}) { +async function checkRegistrationRequest ( + options: CheckerBaseParams & { + username: string + registrationReason: string + checkType: CheckerType + } +) { const { username, registrationReason } = options const notificationType = UserNotificationType.NEW_USER_REGISTRATION_REQUEST @@ -287,13 +303,15 @@ async function checkRegistrationRequest (options: CheckerBaseParams & { // --------------------------------------------------------------------------- -async function checkNewActorFollow (options: CheckerBaseParams & { - followType: 'channel' | 'account' - followerName: string - followerDisplayName: string - followingDisplayName: string - checkType: CheckerType -}) { +async function checkNewActorFollow ( + options: CheckerBaseParams & { + followType: 'channel' | 'account' + followerName: string + followerDisplayName: string + followingDisplayName: string + checkType: CheckerType + } +) { const { followType, followerName, followerDisplayName, followingDisplayName } = options const notificationType = UserNotificationType.NEW_FOLLOW @@ -327,10 +345,12 @@ async function checkNewActorFollow (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewInstanceFollower (options: CheckerBaseParams & { - followerHost: string - checkType: CheckerType -}) { +async function checkNewInstanceFollower ( + options: CheckerBaseParams & { + followerHost: string + checkType: CheckerType + } +) { const { followerHost } = options const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER @@ -354,17 +374,19 @@ async function checkNewInstanceFollower (options: CheckerBaseParams & { function emailNotificationFinder (email: object) { const text: string = email['text'] - return text.includes('instance has a new follower') && text.includes(followerHost) + return text.includes('PeerTube has a new follower') && text.includes(followerHost) } await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkAutoInstanceFollowing (options: CheckerBaseParams & { - followerHost: string - followingHost: string - checkType: CheckerType -}) { +async function checkAutoInstanceFollowing ( + options: CheckerBaseParams & { + followerHost: string + followingHost: string + checkType: CheckerType + } +) { const { followerHost, followingHost } = options const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING @@ -391,19 +413,21 @@ async function checkAutoInstanceFollowing (options: CheckerBaseParams & { function emailNotificationFinder (email: object) { const text: string = email['text'] - return text.includes(' automatically followed a new instance') && text.includes(followingHost) + return text.match(/\bautomatically followed\b/) && text.includes(followingHost) } await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkCommentMention (options: CheckerBaseParams & { - shortUUID: string - commentId: number - threadId: number - byAccountDisplayName: string - checkType: CheckerType -}) { +async function checkCommentMention ( + options: CheckerBaseParams & { + shortUUID: string + commentId: number + threadId: number + byAccountDisplayName: string + checkType: CheckerType + } +) { const { shortUUID, commentId, threadId, byAccountDisplayName } = options const notificationType = UserNotificationType.COMMENT_MENTION @@ -425,7 +449,7 @@ async function checkCommentMention (options: CheckerBaseParams & { function emailNotificationFinder (email: object) { const text: string = email['text'] - return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName) + return text.match(/\bmentioned\b/) && text.includes(shortUUID) && text.includes(byAccountDisplayName) } await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) @@ -433,13 +457,15 @@ async function checkCommentMention (options: CheckerBaseParams & { let lastEmailCount = 0 -async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { - shortUUID: string - commentId: number - threadId: number - checkType: CheckerType - approval?: boolean // default false -}) { +async function checkNewCommentOnMyVideo ( + options: CheckerBaseParams & { + shortUUID: string + commentId: number + threadId: number + checkType: CheckerType + approval?: boolean // default false + } +) { const { server, shortUUID, commentId, threadId, checkType, emails, approval = false } = options const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO @@ -468,7 +494,7 @@ async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { const text = email['text'] return text.includes(commentUrl) && - (approval && text.includes('requires approval')) || + (approval && text.includes('requires approval')) || (!approval && !text.includes('requires approval')) } @@ -481,11 +507,13 @@ async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { } } -async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { +async function checkNewVideoAbuseForModerators ( + options: CheckerBaseParams & { + shortUUID: string + videoName: string + checkType: CheckerType + } +) { const { shortUUID, videoName } = options const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS @@ -511,12 +539,14 @@ async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewAbuseMessage (options: CheckerBaseParams & { - abuseId: number - message: string - toEmail: string - checkType: CheckerType -}) { +async function checkNewAbuseMessage ( + options: CheckerBaseParams & { + abuseId: number + message: string + toEmail: string + checkType: CheckerType + } +) { const { abuseId, message, toEmail } = options const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE @@ -543,11 +573,13 @@ async function checkNewAbuseMessage (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkAbuseStateChange (options: CheckerBaseParams & { - abuseId: number - state: AbuseStateType - checkType: CheckerType -}) { +async function checkAbuseStateChange ( + options: CheckerBaseParams & { + abuseId: number + state: AbuseStateType + checkType: CheckerType + } +) { const { abuseId, state } = options const notificationType = UserNotificationType.ABUSE_STATE_CHANGE @@ -578,11 +610,13 @@ async function checkAbuseStateChange (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { +async function checkNewCommentAbuseForModerators ( + options: CheckerBaseParams & { + shortUUID: string + videoName: string + checkType: CheckerType + } +) { const { shortUUID, videoName } = options const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS @@ -608,10 +642,12 @@ async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & { - displayName: string - checkType: CheckerType -}) { +async function checkNewAccountAbuseForModerators ( + options: CheckerBaseParams & { + displayName: string + checkType: CheckerType + } +) { const { displayName } = options const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS @@ -637,11 +673,13 @@ async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { +async function checkVideoAutoBlacklistForModerators ( + options: CheckerBaseParams & { + shortUUID: string + videoName: string + checkType: CheckerType + } +) { const { shortUUID, videoName } = options const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS @@ -667,11 +705,13 @@ async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & { - shortUUID: string - videoName: string - blacklistType: 'blacklist' | 'unblacklist' -}) { +async function checkNewBlacklistOnMyVideo ( + options: CheckerBaseParams & { + shortUUID: string + videoName: string + blacklistType: 'blacklist' | 'unblacklist' + } +) { const { videoName, shortUUID, blacklistType } = options const notificationType = blacklistType === 'blacklist' ? UserNotificationType.BLACKLIST_ON_MY_VIDEO @@ -687,21 +727,24 @@ async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & { } function emailNotificationFinder (email: object) { - const text = email['text'] - const blacklistText = blacklistType === 'blacklist' - ? 'blacklisted' - : 'unblacklisted' + const text: string = email['text'] - return text.includes(shortUUID) && text.includes(blacklistText) + const blacklistReg = blacklistType === 'blacklist' + ? /\bblocked\b/ + : /\bunblocked\b/ + + return text.includes(shortUUID) && !!text.match(blacklistReg) } await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' }) } -async function checkNewPeerTubeVersion (options: CheckerBaseParams & { - latestVersion: string - checkType: CheckerType -}) { +async function checkNewPeerTubeVersion ( + options: CheckerBaseParams & { + latestVersion: string + checkType: CheckerType + } +) { const { latestVersion } = options const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION @@ -728,11 +771,13 @@ async function checkNewPeerTubeVersion (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkNewPluginVersion (options: CheckerBaseParams & { - pluginType: PluginType_Type - pluginName: string - checkType: CheckerType -}) { +async function checkNewPluginVersion ( + options: CheckerBaseParams & { + pluginType: PluginType_Type + pluginName: string + checkType: CheckerType + } +) { const { pluginName, pluginType } = options const notificationType = UserNotificationType.NEW_PLUGIN_VERSION @@ -759,15 +804,17 @@ async function checkNewPluginVersion (options: CheckerBaseParams & { await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) } -async function checkMyVideoTranscriptionGenerated (options: CheckerBaseParams & { - videoName: string - shortUUID: string - language: { - id: string - label: string +async function checkMyVideoTranscriptionGenerated ( + options: CheckerBaseParams & { + videoName: string + shortUUID: string + language: { + id: string + label: string + } + checkType: CheckerType } - checkType: CheckerType -}) { +) { const { videoName, shortUUID, language } = options const notificationType = UserNotificationType.MY_VIDEO_TRANSCRIPTION_GENERATED @@ -872,11 +919,8 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an export { type CheckerType, type CheckerBaseParams, - getAllNotificationsSettings, - waitUntilNotification, - checkMyVideoImportIsFinished, checkUserRegistered, checkAutoInstanceFollowing, @@ -904,11 +948,13 @@ export { // --------------------------------------------------------------------------- -async function checkNotification (options: CheckerBaseParams & { - notificationChecker: (notification: UserNotification, checkType: CheckerType) => void - emailNotificationFinder: (email: object) => boolean - checkType: CheckerType -}) { +async function checkNotification ( + options: CheckerBaseParams & { + notificationChecker: (notification: UserNotification, checkType: CheckerType) => void + emailNotificationFinder: (email: object) => boolean + checkType: CheckerType + } +) { const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options const check = options.check || { web: true, mail: true } diff --git a/scripts/build/server.sh b/scripts/build/server.sh index 7d0acd1ac..e605164de 100755 --- a/scripts/build/server.sh +++ b/scripts/build/server.sh @@ -10,6 +10,7 @@ npm run tsc -- -b --verbose server/tsconfig.json npm run resolve-tspaths:server cp -r "./server/core/static" "./server/core/assets" ./dist/core +cp -r "./server/locales" ./dist cp "./server/scripts/upgrade.sh" "./dist/scripts" mkdir -p ./client/dist && cp -r ./client/src/assets ./client/dist diff --git a/scripts/dev/server.sh b/scripts/dev/server.sh index 569f3c4c9..d6f89e0dc 100755 --- a/scripts/dev/server.sh +++ b/scripts/dev/server.sh @@ -19,6 +19,7 @@ mkdir -p "./dist/core/lib" npm run tsc -- -b -v --incremental server/tsconfig.json npm run resolve-tspaths:server -cp -r ./server/core/static ./server/core/assets ./dist/core +cp -r "./server/core/static" "./server/core/assets" ./dist/core +cp -r "./server/locales" ./dist ./node_modules/.bin/tsc-watch --build --preserveWatchOutput --verbose --onSuccess 'sh -c "npm run resolve-tspaths:server && NODE_ENV=dev node dist/server"' server/tsconfig.json diff --git a/scripts/i18n/update.sh b/scripts/i18n/update.sh index aaabf76dd..64b9776e5 100755 --- a/scripts/i18n/update.sh +++ b/scripts/i18n/update.sh @@ -25,3 +25,7 @@ node ./node_modules/.bin/xliffmerge -p ./.xliffmerge.json $locales # Add our strings too cd ../ npm run i18n:create-custom-files + +# Generate server translations +node ./node_modules/.bin/i18next -c server/.i18next-parser.config.ts server/core/**/*.{ts,hbs} + diff --git a/server/.i18next-parser.config.ts b/server/.i18next-parser.config.ts new file mode 100644 index 000000000..844dd282f --- /dev/null +++ b/server/.i18next-parser.config.ts @@ -0,0 +1,145 @@ +import { I18N_LOCALES } from '../packages/core-utils/dist/i18n/i18n.js' +import { UserConfig } from 'i18next-parser' + +export default { + contextSeparator: '_', + // Key separator used in your translation keys + + createOldCatalogs: false, + // Save the \_old files + + defaultNamespace: 'translation', + // Default namespace used in your i18next config + + defaultValue: (_locale, _namespace, key, _value) => { + return key as string + }, + // Default value to give to keys with no value + // You may also specify a function accepting the locale, namespace, key, and value as arguments + + indentation: 2, + // Indentation of the catalog files + + keepRemoved: false, + // Keep keys from the catalog that are no longer in code + // You may either specify a boolean to keep or discard all removed keys. + // You may also specify an array of patterns: the keys from the catalog that are no long in the code but match one of the patterns will be kept. + // The patterns are applied to the full key including the namespace, the parent keys and the separators. + + keySeparator: false, + // Key separator used in your translation keys + // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance. + + // see below for more details + lexers: { + hbs: [ + { + lexer: 'HandlebarsLexer', + functions: [ 't' ] + } + ], + handlebars: [ 'HandlebarsLexer' ], + + htm: [ 'HTMLLexer' ], + html: [ 'HTMLLexer' ], + + mjs: [ 'JavascriptLexer' ], + js: [ 'JavascriptLexer' ], // if you're writing jsx inside .js files, change this to JsxLexer + ts: [ + { + lexer: 'JavascriptLexer', + functions: [ 't', 'tu' ] + } + ], + jsx: [ 'JsxLexer' ], + tsx: [ 'JsxLexer' ], + + default: [ 'JavascriptLexer' ] + }, + + lineEnding: 'auto', + // Control the line ending. See options at https://github.com/ryanve/eol + + locales: Object.keys(I18N_LOCALES), + // An array of the locales in your applications + + namespaceSeparator: false, + // Namespace separator used in your translation keys + // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance. + + output: 'server/locales/$LOCALE/$NAMESPACE.json', + // Supports $LOCALE and $NAMESPACE injection + // Supports JSON (.json) and YAML (.yml) file formats + // Where to write the locale files relative to process.cwd() + + pluralSeparator: '_', + // Plural separator used in your translation keys + // If you want to use plain english keys, separators such as `_` might conflict. You might want to set `pluralSeparator` to a different string that does not occur in your keys. + // If you don't want to generate keys for plurals (for example, in case you are using ICU format), set `pluralSeparator: false`. + + input: undefined, + // An array of globs that describe where to look for source files + // relative to the location of the configuration file + + sort: false, + // Whether or not to sort the catalog. Can also be a [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters) + + verbose: false, + // Display info about the parsing including some stats + + failOnWarnings: false, + // Exit with an exit code of 1 on warnings + + failOnUpdate: false, + // Exit with an exit code of 1 when translations are updated (for CI purpose) + + customValueTemplate: null, + // If you wish to customize the value output the value as an object, you can set your own format. + // + // - ${defaultValue} is the default value you set in your translation function. + // - ${filePaths} will be expanded to an array that contains the absolute + // file paths where the translations originated in, in case e.g., you need + // to provide translators with context + // + // Any other custom property will be automatically extracted from the 2nd + // argument of your `t()` function or tOptions in + // + // Example: + // For `t('my-key', {maxLength: 150, defaultValue: 'Hello'})` in + // /path/to/your/file.js, + // + // Using the following customValueTemplate: + // + // customValueTemplate: { + // message: "${defaultValue}", + // description: "${maxLength}", + // paths: "${filePaths}", + // } + // + // Will result in the following item being extracted: + // + // "my-key": { + // "message": "Hello", + // "description": 150, + // "paths": ["/path/to/your/file.js"] + // } + + resetDefaultValueLocale: null, + // The locale to compare with default values to determine whether a default value has been changed. + // If this is set and a default value differs from a translation in the specified locale, all entries + // for that key across locales are reset to the default value, and existing translations are moved to + // the `_old` file. + + i18nextOptions: null, + // If you wish to customize options in internally used i18next instance, you can define an object with any + // configuration property supported by i18next (https://www.i18next.com/overview/configuration-options). + // { compatibilityJSON: 'v3' } can be used to generate v3 compatible plurals. + + yamlOptions: null + // If you wish to customize options for yaml output, you can define an object here. + // Configuration options are here (https://github.com/nodeca/js-yaml#dump-object---options-). + // Example: + // { + // lineWidth: -1, + // } +} satisfies UserConfig diff --git a/server/core/assets/email-templates/abuse-new-message/html.hbs b/server/core/assets/email-templates/abuse-new-message/html.hbs new file mode 100644 index 000000000..7d03c24e3 --- /dev/null +++ b/server/core/assets/email-templates/abuse-new-message/html.hbs @@ -0,0 +1,10 @@ +{{! New message on abuse report }} +{{#> base title=(t "New message on abuse report")}} +

+ {{{t "A new message by {messageAccountName} was posted on abuse report #{abuseId}" messageAccountName=messageAccountName abuseUrl=abuseUrl abuseId=abuseId}}} +

+ +
{{messageText}}
+ +
+{{/base}} diff --git a/server/core/assets/email-templates/abuse-new-message/html.pug b/server/core/assets/email-templates/abuse-new-message/html.pug deleted file mode 100644 index c1d452e7d..000000000 --- a/server/core/assets/email-templates/abuse-new-message/html.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | New message on abuse report - -block content - p - | A new message by #{messageAccountName} was posted on #[a(href=abuseUrl) abuse report ##{abuseId}] on #{instanceName} - blockquote #{messageText} - br(style="display: none;") diff --git a/server/core/assets/email-templates/abuse-state-change/html.hbs b/server/core/assets/email-templates/abuse-state-change/html.hbs new file mode 100644 index 000000000..91145092a --- /dev/null +++ b/server/core/assets/email-templates/abuse-state-change/html.hbs @@ -0,0 +1,10 @@ +{{! Abuse report state changed }} +{{#> base title=(t "Abuse report state changed")}} +

+ {{#if isAccepted}} + {{{t "Your abuse report #{abuseId} on {instanceName} has been accepted." abuseUrl=abuseUrl abuseId=abuseId instanceName=instanceName}}} + {{else}} + {{{t "Your abuse report #{abuseId} on {instanceName} has been rejected." abuseUrl=abuseUrl abuseId=abuseId instanceName=instanceName}}} + {{/if}} +

+{{/base}} diff --git a/server/core/assets/email-templates/abuse-state-change/html.pug b/server/core/assets/email-templates/abuse-state-change/html.pug deleted file mode 100644 index bb243e729..000000000 --- a/server/core/assets/email-templates/abuse-state-change/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | Abuse report state changed - -block content - p - | #[a(href=abuseUrl) Your abuse report ##{abuseId}] on #{instanceName} has been #{isAccepted ? 'accepted' : 'rejected'} diff --git a/server/core/assets/email-templates/account-abuse-new/html.hbs b/server/core/assets/email-templates/account-abuse-new/html.hbs new file mode 100644 index 000000000..231dc3cef --- /dev/null +++ b/server/core/assets/email-templates/account-abuse-new/html.hbs @@ -0,0 +1,18 @@ +{{! An account is pending moderation }} +{{#> base title=(t "An account is pending moderation")}} +

+ {{#if isLocal}} + {{{t "{instanceName} received an abuse report for the account: {accountDisplayName}" accountUrl=accountUrl accountDisplayName=accountDisplayName instanceName=instanceName}}} + {{else}} + {{{t "{instanceName} received an abuse report for the remote account: {accountDisplayName}" accountUrl=accountUrl accountDisplayName=accountDisplayName instanceName=instanceName}}} + {{/if}} +

+ +

+ {{t "The reporter, {reporter}, cited the following reason(s):" reporter=reporter}} +

+ +
{{reason}}
+ +
+{{/base}} diff --git a/server/core/assets/email-templates/account-abuse-new/html.pug b/server/core/assets/email-templates/account-abuse-new/html.pug deleted file mode 100644 index e4c0366fb..000000000 --- a/server/core/assets/email-templates/account-abuse-new/html.pug +++ /dev/null @@ -1,14 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | An account is pending moderation - -block content - p - | #[a(href=WEBSERVER.URL) #{instanceName}] received an abuse report for the #{isLocal ? '' : 'remote '}account - a(href=accountUrl) #{accountDisplayName} - - p The reporter, #{reporter}, cited the following reason(s): - blockquote #{reason} - br(style="display: none;") diff --git a/server/core/assets/email-templates/common/base.pug b/server/core/assets/email-templates/common/base.pug deleted file mode 100644 index 8f15f2703..000000000 --- a/server/core/assets/email-templates/common/base.pug +++ /dev/null @@ -1,219 +0,0 @@ -//- - The email background color is defined in three places: - 1. body tag: for most email clients - 2. center tag: for Gmail and Inbox mobile apps and web versions of Gmail, GSuite, Inbox, Yahoo, AOL, Libero, Comcast, freenet, Mail.ru, Orange.fr - 3. mso conditional: For Windows 10 Mail -doctype html -head - // This template is heavily adapted from the Cerberus Fluid template. Kudos to them! - meta(charset='utf-8') - //- utf-8 works for most cases - meta(name='viewport' content='width=device-width') - //- Forcing initial-scale shouldn't be necessary - meta(http-equiv='X-UA-Compatible' content='IE=edge') - //- Use the latest (edge) version of IE rendering engine - meta(name='x-apple-disable-message-reformatting') - //- Disable auto-scale in iOS 10 Mail entirely - meta(name='format-detection' content='telephone=no,address=no,email=no,date=no,url=no') - //- Tell iOS not to automatically link certain text strings. - meta(name='color-scheme' content='light') - meta(name='supported-color-schemes' content='light') - //- The title tag shows in email notifications, like Android 4.4. - title #{subject} - //- What it does: Makes background images in 72ppi Outlook render at correct size. - //if gte mso 9 - xml - o:officedocumentsettings - o:allowpng - o:pixelsperinch 96 - //- CSS Reset : BEGIN - style. - /* What it does: Tells the email client that only light styles are provided but the client can transform them to dark. A duplicate of meta color-scheme meta tag above. */ - :root { - color-scheme: light; - supported-color-schemes: light; - } - /* What it does: Remove spaces around the email design added by some email clients. */ - /* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */ - html, - body { - margin: 0 auto !important; - padding: 0 !important; - height: 100% !important; - width: 100% !important; - } - /* What it does: Stops email clients resizing small text. */ - * { - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - } - /* What it does: Centers email on Android 4.4 */ - div[style*="margin: 16px 0"] { - margin: 0 !important; - } - /* What it does: forces Samsung Android mail clients to use the entire viewport */ - #MessageViewBody, #MessageWebViewDiv{ - width: 100% !important; - } - /* What it does: Stops Outlook from adding extra spacing to tables. */ - table, - td { - mso-table-lspace: 0pt !important; - mso-table-rspace: 0pt !important; - } - /* What it does: Fixes webkit padding issue. */ - table { - border-spacing: 0 !important; - border-collapse: collapse !important; - table-layout: fixed !important; - margin: 0 auto !important; - } - /* What it does: Uses a better rendering method when resizing images in IE. */ - img { - -ms-interpolation-mode:bicubic; - } - a { - color: #{fg}; - } - a:not(.no-color) { - font-weight: 600; - text-decoration: underline; - text-decoration-color: #{primary}; - text-underline-offset: 0.25em; - text-decoration-thickness: 0.15em; - } - /* What it does: A work-around for email clients meddling in triggered links. */ - a[x-apple-data-detectors], /* iOS */ - .unstyle-auto-detected-links a, - .aBn { - border-bottom: 0 !important; - cursor: default !important; - color: inherit !important; - text-decoration: none !important; - font-size: inherit !important; - font-family: inherit !important; - font-weight: inherit !important; - line-height: inherit !important; - } - /* What it does: Prevents Gmail from displaying a download button on large, non-linked images. */ - .a6S { - display: none !important; - opacity: 0.01 !important; - } - /* What it does: Prevents Gmail from changing the text color in conversation threads. */ - .im { - color: inherit !important; - } - /* If the above doesn't work, add a .g-img class to any image in question. */ - img.g-img + div { - display: none !important; - } - /* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */ - /* Create one of these media queries for each additional viewport size you'd like to fix */ - /* iPhone 4, 4S, 5, 5S, 5C, and 5SE */ - @media only screen and (min-device-width: 320px) and (max-device-width: 374px) { - u ~ div .email-container { - min-width: 320px !important; - } - } - /* iPhone 6, 6S, 7, 8, and X */ - @media only screen and (min-device-width: 375px) and (max-device-width: 413px) { - u ~ div .email-container { - min-width: 375px !important; - } - } - /* iPhone 6+, 7+, and 8+ */ - @media only screen and (min-device-width: 414px) { - u ~ div .email-container { - min-width: 414px !important; - } - } - //- CSS Reset : END - //- CSS for PeerTube : START - style. - blockquote { - margin-left: 0; - padding-left: 10px; - border-left: 2px solid #{primary}; - } - //- CSS for PeerTube : END - -body(width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; color: #{fg}; background-color: #{bg};") - center(role='article' aria-roledescription='email' lang='en' style='width: 100%; background-color: #{bg};') - //if mso | IE - table(role='presentation' border='0' cellpadding='0' cellspacing='0' width='100%' style='background-color: #fff;') - tr - td - //- Visually Hidden Preheader Text : BEGIN - div(style='max-height:0; overflow:hidden; mso-hide:all;' aria-hidden='true') - block preheader - //- Visually Hidden Preheader Text : END - - //- Create white space after the desired preview text so email clients don’t pull other distracting text into the inbox preview. Extend as necessary. - //- Preview Text Spacing Hack : BEGIN - div(style='display: none; font-size: 1px; line-height: 1px; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;') - | ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ - //- Preview Text Spacing Hack : END - - //- - Set the email width. Defined in two places: - 1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 600px. - 2. MSO tags for Desktop Windows Outlook enforce a 600px width. - .email-container(style='max-width: 600px; margin: 0 auto;') - //if mso - table(align='center' role='presentation' cellspacing='0' cellpadding='0' border='0' width='600') - tr - td - //- Email Body : BEGIN - table(align='center' role='presentation' cellspacing='0' cellpadding='0' border='0' width='100%' style='margin: auto;') - //- 1 Column Text + Button : BEGIN - tr - td - table(role='presentation' cellspacing='0' cellpadding='0' border='0' width='100%') - tr - td(style='padding: 20px; font-family: sans-serif; font-size: 15px; line-height: 1.5') - table(role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%") - tr - td(width="40px") - img(src=`${WEBSERVER.URL}/client/assets/images/icons/icon-192x192.png` width="auto" height="30px" alt="" border="0" style="height: 30px; font-family: sans-serif; font-size: 15px; line-height: 15px;") - td - h1(style='margin: 10px 0 10px 0; font-family: sans-serif; font-size: 25px; line-height: 30px; font-weight: normal;') - block title - if title - | #{title} - else - | Something requires your attention - p(style='margin: 0;') - block body - if action - tr - td(style='padding: 0 20px;') - //- Button : BEGIN - table(align='center' role='presentation' cellspacing='0' cellpadding='0' border='0' style='margin: auto;') - tr - td(style=`border-radius: 4px; background: ${primary};`) - a.no-color(href=action.url style=`background: ${primary}; font-family: sans-serif; font-size: 15px; line-height: 15px; text-decoration: none; padding: 13px 17px; display: block; border-radius: 4px; font-weight: bold;`) #{action.text} - //- Button : END - //- 1 Column Text + Button : END - //- Clear Spacer : BEGIN - tr - td(aria-hidden='true' height='20' style='font-size: 0px; line-height: 0px;') - br - //- Clear Spacer : END - //- Email Body : END - //- Email Footer : BEGIN - unless hideNotificationPreferencesLink - table(align='center' role='presentation' cellspacing='0' cellpadding='0' border='0' width='100%' style='margin: auto;') - tr - td(style='padding: 20px; padding-bottom: 0px; font-family: sans-serif; font-size: 12px; text-align: center;') - webversion - a.no-color(href=`${WEBSERVER.URL}/my-account/notifications` style='font-weight: bold;') View in your notifications - br - tr - td(style='padding: 20px; padding-top: 10px; font-family: sans-serif; font-size: 12px; text-align: center;') - unsubscribe - a.no-color(href=`${WEBSERVER.URL}/my-account/settings#notifications`) Manage your notification preferences in your profile - br - //- Email Footer : END - //if mso - //if mso | IE diff --git a/server/core/assets/email-templates/common/greetings.pug b/server/core/assets/email-templates/common/greetings.pug deleted file mode 100644 index 2170d3814..000000000 --- a/server/core/assets/email-templates/common/greetings.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends base - -block body - if username - p Hi #{username}, - - block content - - if signature - p - | #{signature} diff --git a/server/core/assets/email-templates/common/html.hbs b/server/core/assets/email-templates/common/html.hbs new file mode 100644 index 000000000..f6acb6098 --- /dev/null +++ b/server/core/assets/email-templates/common/html.hbs @@ -0,0 +1,5 @@ +{{#> base}} +

+ {{text}} +

+{{/base}} diff --git a/server/core/assets/email-templates/common/html.pug b/server/core/assets/email-templates/common/html.pug deleted file mode 100644 index d76168b85..000000000 --- a/server/core/assets/email-templates/common/html.pug +++ /dev/null @@ -1,4 +0,0 @@ -extends greetings - -block content - p !{text} \ No newline at end of file diff --git a/server/core/assets/email-templates/common/mixins.pug b/server/core/assets/email-templates/common/mixins.pug deleted file mode 100644 index 831211864..000000000 --- a/server/core/assets/email-templates/common/mixins.pug +++ /dev/null @@ -1,7 +0,0 @@ -mixin channel(channel) - - var handle = `${channel.name}@${channel.host}` - | #[a(href=`${WEBSERVER.URL}/video-channels/${handle}` title=handle) #{channel.displayName}] - -mixin account(account) - - var handle = `${account.name}@${account.host}` - | #[a(href=`${WEBSERVER.URL}/accounts/${handle}` title=handle) #{account.displayName}] diff --git a/server/core/assets/email-templates/contact-form/html.hbs b/server/core/assets/email-templates/contact-form/html.hbs new file mode 100644 index 000000000..54df5e190 --- /dev/null +++ b/server/core/assets/email-templates/contact-form/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "Someone just used the contact form")}} +

+ {{{t "{fromName} sent you a message via the contact form on {instanceName}: " fromName=fromName webserverUrl=WEBSERVER.URL instanceName=instanceName}}} +

+ +
{{body}}
+ +

+ {{{t "You can contact them at {fromEmail}, or simply reply to this email to get in touch." fromEmail=fromEmail}}} +

+{{/base}} diff --git a/server/core/assets/email-templates/contact-form/html.pug b/server/core/assets/email-templates/contact-form/html.pug deleted file mode 100644 index 5a24fa6f1..000000000 --- a/server/core/assets/email-templates/contact-form/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | Someone just used the contact form - -block content - p #{fromName} sent you a message via the contact form on #[a(href=WEBSERVER.URL) #{instanceName}]: - blockquote(style='white-space: pre-wrap') #{body} - p You can contact them at #[a(href=`mailto:${fromEmail}`) #{fromEmail}], or simply reply to this email to get in touch. \ No newline at end of file diff --git a/server/core/assets/email-templates/follower-on-channel/html.hbs b/server/core/assets/email-templates/follower-on-channel/html.hbs new file mode 100644 index 000000000..77d58d83e --- /dev/null +++ b/server/core/assets/email-templates/follower-on-channel/html.hbs @@ -0,0 +1,9 @@ +{{#> base title=(t "New follower on your channel")}} +

+ {{#if accountFollowType}} + {{{t "Your account {followingName} has a new subscriber: {followerName}." followingUrl=followingUrl followingName=followingName followerUrl=followerUrl followerName=followerName}}} + {{else}} + {{{t "Your channel {followingName} has a new subscriber: {followerName}." followingUrl=followingUrl followingName=followingName followerUrl=followerUrl followerName=followerName}}} + {{/if}} +

+{{/base}} diff --git a/server/core/assets/email-templates/follower-on-channel/html.pug b/server/core/assets/email-templates/follower-on-channel/html.pug deleted file mode 100644 index 8a352e90f..000000000 --- a/server/core/assets/email-templates/follower-on-channel/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | New follower on your channel - -block content - p. - Your #{followType} #[a(href=followingUrl) #{followingName}] has a new subscriber: - #[a(href=followerUrl) #{followerName}]. \ No newline at end of file diff --git a/server/core/assets/email-templates/my-user-block-new/html.hbs b/server/core/assets/email-templates/my-user-block-new/html.hbs new file mode 100644 index 000000000..e3067351b --- /dev/null +++ b/server/core/assets/email-templates/my-user-block-new/html.hbs @@ -0,0 +1,15 @@ +{{#> base title=(t "Your account has been blocked")}} +

+ {{#if reason}} + {{{t "Your account {username} has been blocked by {instanceName} moderators for the following reason:" username=username instanceName=instanceName}}} + {{else}} + {{{t "Your account {username} has been blocked by {instanceName} moderators." username=username instanceName=instanceName}}} + {{/if}} +

+ + {{#if reason}} +
{{reason}}
+ {{/if}} + +
+{{/base}} diff --git a/server/core/assets/email-templates/my-user-unblocked/html.hbs b/server/core/assets/email-templates/my-user-unblocked/html.hbs new file mode 100644 index 000000000..4e12e94d3 --- /dev/null +++ b/server/core/assets/email-templates/my-user-unblocked/html.hbs @@ -0,0 +1,5 @@ +{{#> base title=(t "Your account has been unblocked")}} +

+ {{{t "Your account {username} has been unblocked by {instanceName} moderators." username=username instanceName=instanceName}}} +

+{{/base}} diff --git a/server/core/assets/email-templates/partials/base.hbs b/server/core/assets/email-templates/partials/base.hbs new file mode 100644 index 000000000..999d7200b --- /dev/null +++ b/server/core/assets/email-templates/partials/base.hbs @@ -0,0 +1,268 @@ +{{! + The email background color is defined in three places: + 1. body tag: for most email clients + 2. center tag: for Gmail and Inbox mobile apps and web versions of Gmail, GSuite, Inbox, Yahoo, AOL, Libero, Comcast, freenet, Mail.ru, Orange.fr + 3. mso conditional: For Windows 10 Mail +}} + + + + + + + + + + + + + + + + + + {{subject}} + + + + + + + + + + + +
+ + + + +
+ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ +
+ + + + + +
+ + diff --git a/server/core/assets/email-templates/partials/button.hbs b/server/core/assets/email-templates/partials/button.hbs new file mode 100644 index 000000000..177a1ab46 --- /dev/null +++ b/server/core/assets/email-templates/partials/button.hbs @@ -0,0 +1,7 @@ + + + + +
+ {{actionText}} +
diff --git a/server/core/assets/email-templates/password-create/html.hbs b/server/core/assets/email-templates/password-create/html.hbs new file mode 100644 index 000000000..d17f180ac --- /dev/null +++ b/server/core/assets/email-templates/password-create/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "Password creation for your account")}} +

+ {{{t "Welcome to {instanceName}!" webserverUrl=WEBSERVER.URL instanceName=instanceName}}} +

+ +

{{t "Your username is: {username}." username=username}}

+ +

{{t "Please click on the link below to set your password (this link will expire within seven days):"}}

+ + {{> button actionUrl=createPasswordUrl actionText=(t "Create my password")}} +{{/base}} diff --git a/server/core/assets/email-templates/password-create/html.pug b/server/core/assets/email-templates/password-create/html.pug deleted file mode 100644 index d36179208..000000000 --- a/server/core/assets/email-templates/password-create/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extends ../common/greetings - -block title - | Password creation for your account - -block content - p. - Welcome to #[a(href=WEBSERVER.URL) #{instanceName}]. Your username is: #{username}. - Please set your password by following #[a(href=createPasswordUrl) this link]: #[a(href=createPasswordUrl) #{createPasswordUrl}] - (this link will expire within seven days). diff --git a/server/core/assets/email-templates/password-reset/html.hbs b/server/core/assets/email-templates/password-reset/html.hbs new file mode 100644 index 000000000..acfdef448 --- /dev/null +++ b/server/core/assets/email-templates/password-reset/html.hbs @@ -0,0 +1,15 @@ +{{#> base title=(t "Password reset for your account")}} +

+ {{t "A reset password procedure for your account has been requested on {instanceName}." username=username instanceName=instanceName}} +

+ +

+ {{t "Please click on the link below to reset it (the link will expire within 1 hour):"}} +

+ + {{> button actionUrl=resetPasswordUrl actionText=(t "Reset my password")}} + +

+ {{t "If you are not the person who initiated this request, please let us know by replying to this email."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/password-reset/html.pug b/server/core/assets/email-templates/password-reset/html.pug deleted file mode 100644 index 2af2885bc..000000000 --- a/server/core/assets/email-templates/password-reset/html.pug +++ /dev/null @@ -1,12 +0,0 @@ -extends ../common/greetings - -block title - | Password reset for your account - -block content - p. - A reset password procedure for your account #{username} has been requested on #[a(href=WEBSERVER.URL) #{instanceName}]. - Please follow #[a(href=resetPasswordUrl) this link] to reset it: #[a(href=resetPasswordUrl) #{resetPasswordUrl}] - (the link will expire within 1 hour). - p. - If you are not the person who initiated this request, please ignore this email. diff --git a/server/core/assets/email-templates/peertube-version-new/html.hbs b/server/core/assets/email-templates/peertube-version-new/html.hbs new file mode 100644 index 000000000..930542ae8 --- /dev/null +++ b/server/core/assets/email-templates/peertube-version-new/html.hbs @@ -0,0 +1,7 @@ +{{#> base title=(t "New PeerTube version available")}} +

+ {{t "A new version of PeerTube is available: {latestVersion}." latestVersion=latestVersion}} + + {{{t "You can check the latest news on JoinPeerTube."}}} +

+{{/base}} diff --git a/server/core/assets/email-templates/peertube-version-new/html.pug b/server/core/assets/email-templates/peertube-version-new/html.pug deleted file mode 100644 index 2f4d9399d..000000000 --- a/server/core/assets/email-templates/peertube-version-new/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | New PeerTube version available - -block content - p - | A new version of PeerTube is available: #{latestVersion}. - | You can check the latest news on #[a(href="https://joinpeertube.org/news") JoinPeerTube]. diff --git a/server/core/assets/email-templates/plugin-version-new/html.hbs b/server/core/assets/email-templates/plugin-version-new/html.hbs new file mode 100644 index 000000000..8c2352254 --- /dev/null +++ b/server/core/assets/email-templates/plugin-version-new/html.hbs @@ -0,0 +1,14 @@ +{{! New plugin version available }} +{{#> base title=(t "New plugin version available")}} +

+ {{#if isPlugin}} + {{t "A new version of the plugin {pluginName} is available: {latestVersion}." pluginName=pluginName latestVersion=latestVersion}} + {{else}} + {{t "A new version of the theme {pluginName} is available: {latestVersion}." pluginName=pluginName latestVersion=latestVersion}} + {{/if}} +

+ +

+ {{{t "You might want to upgrade it on your admin interface." pluginUrl=pluginUrl}}} +

+{{/base}} diff --git a/server/core/assets/email-templates/plugin-version-new/html.pug b/server/core/assets/email-templates/plugin-version-new/html.pug deleted file mode 100644 index 86d3d87e8..000000000 --- a/server/core/assets/email-templates/plugin-version-new/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | New plugin version available - -block content - p - | A new version of the plugin/theme #{pluginName} is available: #{latestVersion}. - | You might want to upgrade it on #[a(href=pluginUrl) the PeerTube admin interface]. diff --git a/server/core/assets/email-templates/user-export-completed/html.hbs b/server/core/assets/email-templates/user-export-completed/html.hbs new file mode 100644 index 000000000..714c022dc --- /dev/null +++ b/server/core/assets/email-templates/user-export-completed/html.hbs @@ -0,0 +1,10 @@ +{{! Your export archive has been created }} +{{#> base title=(t "Your export archive has been created")}} +

+ {{t "Your export archive has been created."}} +

+ +

+ {{{t "You can download it in your account export page." exportsUrl=exportsUrl}}} +

+{{/base}} diff --git a/server/core/assets/email-templates/user-export-completed/html.pug b/server/core/assets/email-templates/user-export-completed/html.pug deleted file mode 100644 index 00cf64211..000000000 --- a/server/core/assets/email-templates/user-export-completed/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | Your export archive has been created - -block content - p - | Your export archive has been created. You can download it in #[a(href=exportsUrl) your account export page]. diff --git a/server/core/assets/email-templates/user-export-errored/html.hbs b/server/core/assets/email-templates/user-export-errored/html.hbs new file mode 100644 index 000000000..08490033d --- /dev/null +++ b/server/core/assets/email-templates/user-export-errored/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "Failed to create your export archive")}} +

+ {{t "We are sorry but the generation of your export archive has failed:"}} +

+ +
{{errorMessage}}
+ +

+ {{t "Please contact your administrator if the problem occurs again."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/user-export-errored/html.pug b/server/core/assets/email-templates/user-export-errored/html.pug deleted file mode 100644 index 7699a5dd4..000000000 --- a/server/core/assets/email-templates/user-export-errored/html.pug +++ /dev/null @@ -1,12 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | Failed to create your export archive - -block content - p - | We are sorry but the generation of your export archive has failed: - blockquote !{errorMessage} - p - | Please contact your administrator if the problem occurs again. diff --git a/server/core/assets/email-templates/user-import-completed/html.hbs b/server/core/assets/email-templates/user-import-completed/html.hbs new file mode 100644 index 000000000..2da267a41 --- /dev/null +++ b/server/core/assets/email-templates/user-import-completed/html.hbs @@ -0,0 +1,68 @@ +{{#> base title=(t "Your archive import has finished")}} + {{#* inline "displaySummary"}} +
    + {{#if stats.success}} +
  • {{t "Imported: {success}" success=stats.success}}
  • + {{/if}} + {{#if stats.duplicates}} +
  • {{t "Not imported as considered duplicate: {duplicates}" duplicates=stats.duplicates}}
  • + {{/if}} + {{#if stats.errors}} +
  • {{t "Not imported due to error: {errors}" errors=stats.errors}}
  • + {{/if}} +
+ {{/inline}} + +

{{t "Your archive import has finished. Here is the summary of imported objects:"}}

+ +
    +
  • + {{t "User settings:"}} + {{> displaySummary stats=resultStats.userSettings}} +
  • +
  • + {{t "Account (name, description, avatar...):"}} + {{> displaySummary stats=resultStats.account}} +
  • +
  • + {{t "Blocklist:"}} + {{> displaySummary stats=resultStats.blocklist}} +
  • +
  • + {{t "Channels:"}} + {{> displaySummary stats=resultStats.channels}} +
  • +
  • + {{t "Likes:"}} + {{> displaySummary stats=resultStats.likes}} +
  • +
  • + {{t "Dislikes:"}} + {{> displaySummary stats=resultStats.dislikes}} +
  • +
  • + {{t "Subscriptions:"}} + {{> displaySummary stats=resultStats.following}} +
  • +
  • + {{t "Video Playlists:"}} + {{> displaySummary stats=resultStats.videoPlaylists}} +
  • +
  • + {{t "Videos:"}} + {{> displaySummary stats=resultStats.videos}} +
  • +
  • + {{t "Video history:"}} + {{> displaySummary stats=resultStats.userVideoHistory}} +
  • +
  • + {{t "Watched Words Lists:"}} + {{> displaySummary stats=resultStats.watchedWordsLists}} +
  • +
  • + {{t "Comment auto tag policies:"}} + {{> displaySummary stats=resultStats.commentAutoTagPolicies}} +
  • +
+{{/base}} diff --git a/server/core/assets/email-templates/user-import-completed/html.pug b/server/core/assets/email-templates/user-import-completed/html.pug deleted file mode 100644 index ddd6f023d..000000000 --- a/server/core/assets/email-templates/user-import-completed/html.pug +++ /dev/null @@ -1,55 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -mixin displaySummary(stats) - ul - if stats.success - li Imported: #{stats.success} - if stats.duplicates - li Not imported as considered duplicate: #{stats.duplicates} - if stats.errors - li Not imported due to error: #{stats.errors} - -block title - | Your archive import has finished - -block content - p Your archive import has finished. Here is the summary of imported objects: - - ul - li - strong User settings: - +displaySummary(resultStats.userSettings) - li - strong Account (name, description, avatar...): - +displaySummary(resultStats.account) - li - strong Blocklist: - +displaySummary(resultStats.blocklist) - li - strong Channels: - +displaySummary(resultStats.channels) - li - strong Likes: - +displaySummary(resultStats.likes) - li - strong Dislikes: - +displaySummary(resultStats.dislikes) - li - strong Subscriptions: - +displaySummary(resultStats.following) - li - strong Video Playlists: - +displaySummary(resultStats.videoPlaylists) - li - strong Videos: - +displaySummary(resultStats.videos) - li - strong Video history: - +displaySummary(resultStats.userVideoHistory) - li - strong Watched Words Lists: - +displaySummary(resultStats.watchedWordsLists) - li - strong Comment auto tag policies: - +displaySummary(resultStats.commentAutoTagPolicies) diff --git a/server/core/assets/email-templates/user-import-errored/html.hbs b/server/core/assets/email-templates/user-import-errored/html.hbs new file mode 100644 index 000000000..78ab3e0fb --- /dev/null +++ b/server/core/assets/email-templates/user-import-errored/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "Failed to import your archive")}} +

+ {{t "We are sorry but the import of your archive has failed:"}} +

+ +
{{errorMessage}}
+ +

+ {{t "Please contact your administrator if the problem occurs again."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/user-import-errored/html.pug b/server/core/assets/email-templates/user-import-errored/html.pug deleted file mode 100644 index 8f5041d1e..000000000 --- a/server/core/assets/email-templates/user-import-errored/html.pug +++ /dev/null @@ -1,12 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | Failed to import your archive - -block content - p - | We are sorry but the import of your archive has failed: - blockquote !{errorMessage} - p - | Please contact your administrator if the problem occurs again. diff --git a/server/core/assets/email-templates/user-registered/html.hbs b/server/core/assets/email-templates/user-registered/html.hbs new file mode 100644 index 000000000..2493f1834 --- /dev/null +++ b/server/core/assets/email-templates/user-registered/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "A new user registered")}} +

+ {{{t "User {userUsername} just registered." accountUrl=accountUrl userUsername=user.username}}} + + {{#if userEmail}} + {{{t "You might want to contact them at {userEmail}." userEmail=userEmail}}} + {{else}} + {{{t "You might want to contact them at {userEmail} (the email has not been verified yet)." userEmail=userPendingEmail}}} + {{/if}} +

+{{/base}} diff --git a/server/core/assets/email-templates/user-registered/html.pug b/server/core/assets/email-templates/user-registered/html.pug deleted file mode 100644 index 20f62125e..000000000 --- a/server/core/assets/email-templates/user-registered/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extends ../common/greetings - -block title - | A new user registered - -block content - - var mail = user.email || user.pendingEmail; - p - | User #[a(href=`${WEBSERVER.URL}/accounts/${user.username}`) #{user.username}] just registered. - | You might want to contact them at #[a(href=`mailto:${mail}`) #{mail}]. \ No newline at end of file diff --git a/server/core/assets/email-templates/user-registration-request-accepted/html.hbs b/server/core/assets/email-templates/user-registration-request-accepted/html.hbs new file mode 100644 index 000000000..8141a6425 --- /dev/null +++ b/server/core/assets/email-templates/user-registration-request-accepted/html.hbs @@ -0,0 +1,11 @@ +{{#> base title=(t "Congratulation {username}, your registration request has been accepted!" username=username)}} +

+ {{t "Your registration request has been accepted."}} +

+ +

+ {{t "Moderators sent you the following message:"}} +

+ +
{{moderationResponse}}
+{{/base}} diff --git a/server/core/assets/email-templates/user-registration-request-accepted/html.pug b/server/core/assets/email-templates/user-registration-request-accepted/html.pug deleted file mode 100644 index 7a52c3fe1..000000000 --- a/server/core/assets/email-templates/user-registration-request-accepted/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extends ../common/greetings - -block title - | Congratulation #{username}, your registration request has been accepted! - -block content - p Your registration request has been accepted. - p Moderators sent you the following message: - blockquote(style='white-space: pre-wrap') #{moderationResponse} - p Your account has been created and you can login on #[a(href=loginLink) #{loginLink}] diff --git a/server/core/assets/email-templates/user-registration-request-rejected/html.hbs b/server/core/assets/email-templates/user-registration-request-rejected/html.hbs new file mode 100644 index 000000000..1b537ba9e --- /dev/null +++ b/server/core/assets/email-templates/user-registration-request-rejected/html.hbs @@ -0,0 +1,7 @@ +{{#> base title=(t "Registration request of your account {username} has rejected" username=username)}} +

{{t "Your registration request has been rejected." }}

+ +

{{t "Moderators sent you the following message:" }}

+ +
{{moderationResponse}}
+{{/base}} diff --git a/server/core/assets/email-templates/user-registration-request-rejected/html.pug b/server/core/assets/email-templates/user-registration-request-rejected/html.pug deleted file mode 100644 index ec0aa8dfe..000000000 --- a/server/core/assets/email-templates/user-registration-request-rejected/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | Registration request of your account #{username} has rejected - -block content - p Your registration request has been rejected. - p Moderators sent you the following message: - blockquote(style='white-space: pre-wrap') #{moderationResponse} diff --git a/server/core/assets/email-templates/user-registration-request/html.hbs b/server/core/assets/email-templates/user-registration-request/html.hbs new file mode 100644 index 000000000..610b4d45b --- /dev/null +++ b/server/core/assets/email-templates/user-registration-request/html.hbs @@ -0,0 +1,7 @@ +{{#> base title=(t "A new user wants to register")}} +

+ {{t "User {registrationUsername} wants to register on {instanceName} for the following reason:" registrationUsername=registration.username instanceName=instanceName}} +

+ +
{{registration.registrationReason}}
+{{/base}} diff --git a/server/core/assets/email-templates/user-registration-request/html.pug b/server/core/assets/email-templates/user-registration-request/html.pug deleted file mode 100644 index 64898f3f2..000000000 --- a/server/core/assets/email-templates/user-registration-request/html.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends ../common/greetings - -block title - | A new user wants to register - -block content - p User #{registration.username} wants to register on your PeerTube instance with the following reason: - blockquote(style='white-space: pre-wrap') #{registration.registrationReason} - p You can accept or reject the registration request in the #[a(href=`${WEBSERVER.URL}/admin/moderation/registrations/list`) administration]. diff --git a/server/core/assets/email-templates/verify-registration-email/html.hbs b/server/core/assets/email-templates/verify-registration-email/html.hbs new file mode 100644 index 000000000..9d811f4ca --- /dev/null +++ b/server/core/assets/email-templates/verify-registration-email/html.hbs @@ -0,0 +1,19 @@ +{{#> base title=(t "Email verification")}} + {{#if isRegistrationRequest}} +

{{{t "You requested an account on {instanceName}." webserverUrl=WEBSERVER.URL instanceName=instanceName}}}

+

{{t "To complete your registration request you must verify your email first!"}}

+ {{else}} +

{{{t "You created an account on {instanceName}." webserverUrl=WEBSERVER.URL instanceName=instanceName}}}

+

{{t "To start using your account you must verify your email first!"}}

+ {{/if}} + +

+ {{t "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):"}} +

+ + {{> button actionUrl=verifyEmailUrl actionText=(t "Verify my email")}} + +

+ {{t "If you are not the person who initiated this request, please let us know by replying to this email."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/verify-registration-email/html.pug b/server/core/assets/email-templates/verify-registration-email/html.pug deleted file mode 100644 index c5c2fa91f..000000000 --- a/server/core/assets/email-templates/verify-registration-email/html.pug +++ /dev/null @@ -1,16 +0,0 @@ -extends ../common/greetings - -block title - | Email verification - -block content - if isRegistrationRequest - p You requested an account on #[a(href=WEBSERVER.URL) #{instanceName}]. - p To complete your registration request you must verify your email first! - else - p You created an account on #[a(href=WEBSERVER.URL) #{instanceName}]. - p To start using your account you must verify your email first! - - p Please follow #[a(href=verifyEmailUrl) this link] to verify this email belongs to you. - p If you can't see the verification link above you can use the following link #[a(href=verifyEmailUrl) #{verifyEmailUrl}] - p If you are not the person who initiated this request, please ignore this email. diff --git a/server/core/assets/email-templates/verify-user-change-email/html.hbs b/server/core/assets/email-templates/verify-user-change-email/html.hbs new file mode 100644 index 000000000..8909fb1cb --- /dev/null +++ b/server/core/assets/email-templates/verify-user-change-email/html.hbs @@ -0,0 +1,13 @@ +{{#> base title=(t "Email verification")}} +

{{t "You requested to change your email."}}

+ +

+ {{t "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):"}} +

+ + {{> button actionUrl=verifyEmailUrl actionText=(t "Verify my email")}} + +

+ {{t "If you are not the person who initiated this request, please let us know by replying to this email."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/verify-user-change-email/html.pug b/server/core/assets/email-templates/verify-user-change-email/html.pug deleted file mode 100644 index c5b18662d..000000000 --- a/server/core/assets/email-templates/verify-user-change-email/html.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends ../common/greetings - -block title - | Email verification - -block content - p You requested to change your email. - - p Please follow #[a(href=verifyEmailUrl) this link] to verify this email belongs to you. - p If you can't see the verification link above you can use the following link #[a(href=verifyEmailUrl) #{verifyEmailUrl}] - p If you are not the person who initiated this request, please contact your administrator. diff --git a/server/core/assets/email-templates/video-abuse-new/html.hbs b/server/core/assets/email-templates/video-abuse-new/html.hbs new file mode 100644 index 000000000..bc203b36d --- /dev/null +++ b/server/core/assets/email-templates/video-abuse-new/html.hbs @@ -0,0 +1,27 @@ +{{#> base title=(t "A video is pending moderation")}} +

+ {{#if isLocal}} + {{{t "{instanceName} received an abuse report for the video {videoName}." instanceName=instanceName videoUrl=videoUrl videoName=videoName}}} + {{else}} + {{{t "{instanceName} received an abuse report for the remote video {videoName}." instanceName=instanceName videoUrl=videoUrl videoName=videoName}}} + {{/if}} +

+ +

+ {{{t "The video was uploaded by {channelDisplayName} channel." channelUrl=channelUrl channelDisplayName=channelDisplayName}}} +

+ +

+ {{#if videoPublishedAt}} + {{t "It was published on {videoPublishedAt}." videoPublishedAt=videoPublishedAt}} + {{else}} + {{t "It was uploaded on {videoCreatedAt} but not yet published." videoCreatedAt=videoCreatedAt}} + {{/if}} +

+ +

{{t "The reporter, {reporter}, cited the following reason(s):" reporter=reporter}}

+ +
{{reason}}
+ +
+{{/base}} diff --git a/server/core/assets/email-templates/video-abuse-new/html.pug b/server/core/assets/email-templates/video-abuse-new/html.pug deleted file mode 100644 index a085b4b38..000000000 --- a/server/core/assets/email-templates/video-abuse-new/html.pug +++ /dev/null @@ -1,18 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | A video is pending moderation - -block content - p - | #[a(href=WEBSERVER.URL) #{instanceName}] received an abuse report for the #{isLocal ? '' : 'remote '}video " - a(href=videoUrl) #{videoName} - | " by #[+channel(videoChannel)] - if videoPublishedAt - | , published the #{videoPublishedAt}. - else - | , uploaded the #{videoCreatedAt} but not yet published. - p The reporter, #{reporter}, cited the following reason(s): - blockquote #{reason} - br(style="display: none;") diff --git a/server/core/assets/email-templates/video-auto-blacklist-new/html.hbs b/server/core/assets/email-templates/video-auto-blacklist-new/html.hbs new file mode 100644 index 000000000..93fc88781 --- /dev/null +++ b/server/core/assets/email-templates/video-auto-blacklist-new/html.hbs @@ -0,0 +1,13 @@ +{{#> base title=(t "A video is pending moderation")}} +

+ {{{t "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}." videoUrl=videoUrl videoName=videoName channelUrl=channelUrl channelDisplayName=channelDisplayName}}} +

+ +

+ {{t "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it."}} +

+ +

+ {{t "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public."}} +

+{{/base}} diff --git a/server/core/assets/email-templates/video-auto-blacklist-new/html.pug b/server/core/assets/email-templates/video-auto-blacklist-new/html.pug deleted file mode 100644 index 07c8dfd16..000000000 --- a/server/core/assets/email-templates/video-auto-blacklist-new/html.pug +++ /dev/null @@ -1,17 +0,0 @@ -extends ../common/greetings -include ../common/mixins - -block title - | A video is pending moderation - -block content - p - | A recently added video was auto-blacklisted and requires moderator review before going public: - | - a(href=videoUrl) #{videoName} - | - | by #[+channel(channel)]. - p. - Apart from the publisher and the moderation team, no one will be able to see the video until you - unblacklist it. If you trust the publisher, any admin can whitelist the user for later videos so - that they don't require approval before going public. diff --git a/server/core/assets/email-templates/video-comment-abuse-new/html.hbs b/server/core/assets/email-templates/video-comment-abuse-new/html.hbs new file mode 100644 index 000000000..6841ba3c9 --- /dev/null +++ b/server/core/assets/email-templates/video-comment-abuse-new/html.hbs @@ -0,0 +1,21 @@ +{{#> base title=(t "A comment is pending moderation")}} +

+ {{#if isLocal}} + {{{t "{instanceName} received an abuse report for the comment on video {videoName}." instanceName=instanceName commentUrl=commentUrl videoName=videoName}}} + {{else}} + {{{t "{instanceName} received an abuse report for the remote comment on video {videoName}." instanceName=instanceName commentUrl=commentUrl videoName=videoName}}} + {{/if}} +

+ +

+ {{t "The comment was posted on {commentCreatedAt} by {flaggedAccount} ." commentCreatedAt=commentCreatedAt flaggedAccount=flaggedAccount}} +

+ +

+ {{t "The reporter, {reporter}, cited the following reason(s):" reporter=reporter}} +

+ +
{{reason}}
+ +
+{{/base}} diff --git a/server/core/assets/email-templates/video-comment-abuse-new/html.pug b/server/core/assets/email-templates/video-comment-abuse-new/html.pug deleted file mode 100644 index 752bf7c10..000000000 --- a/server/core/assets/email-templates/video-comment-abuse-new/html.pug +++ /dev/null @@ -1,16 +0,0 @@ -extends ../common/greetings -include ../common/mixins.pug - -block title - | A comment is pending moderation - -block content - p - | #[a(href=WEBSERVER.URL) #{instanceName}] received an abuse report for the #{isLocal ? '' : 'remote '} - a(href=commentUrl) comment on video "#{videoName}" - | of #{flaggedAccount} - | created on #{commentCreatedAt} - - p The reporter, #{reporter}, cited the following reason(s): - blockquote #{reason} - br(style="display: none;") diff --git a/server/core/assets/email-templates/video-comment-mention/html.hbs b/server/core/assets/email-templates/video-comment-mention/html.hbs new file mode 100644 index 000000000..215091356 --- /dev/null +++ b/server/core/assets/email-templates/video-comment-mention/html.hbs @@ -0,0 +1,9 @@ +{{#> base title=(t "Someone mentioned you")}} +

+ {{{t "{accountName} mentioned you in a comment on video {videoName}:" accountUrl=accountUrl handle=handle accountName=accountName videoUrl=videoUrl videoName=video.name}}} +

+ +
{{{commentHtml}}}
+ +
+{{/base}} diff --git a/server/core/assets/email-templates/video-comment-mention/html.pug b/server/core/assets/email-templates/video-comment-mention/html.pug deleted file mode 100644 index a34c6b090..000000000 --- a/server/core/assets/email-templates/video-comment-mention/html.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends ../common/greetings - -block title - | Someone mentioned you - -block content - p. - #[a(href=accountUrl title=handle) #{accountName}] mentioned you in a comment on video - "#[a(href=videoUrl) #{video.name}]": - blockquote !{commentHtml} - br(style="display: none;") diff --git a/server/core/assets/email-templates/video-comment-new/html.hbs b/server/core/assets/email-templates/video-comment-new/html.hbs new file mode 100644 index 000000000..af78d028e --- /dev/null +++ b/server/core/assets/email-templates/video-comment-new/html.hbs @@ -0,0 +1,13 @@ +{{#> base title=(t "Someone commented your video")}} +

+ {{{t "{accountName} added a comment on your video {videoName}:" accountUrl=accountUrl handle=handle accountName=accountName videoUrl=videoUrl videoName=video.name}}} +

+ +
{{{commentHtml}}}
+ + {{#if requiresApproval}} +

{{t "This comment requires approval."}}

+ {{/if}} + +
+{{/base}} diff --git a/server/core/assets/email-templates/video-comment-new/html.pug b/server/core/assets/email-templates/video-comment-new/html.pug deleted file mode 100644 index a11787026..000000000 --- a/server/core/assets/email-templates/video-comment-new/html.pug +++ /dev/null @@ -1,16 +0,0 @@ -extends ../common/greetings - -block title - | Someone commented your video - -block content - p. - #[a(href=accountUrl title=handle) #{accountName}] added a comment on your video - "#[a(href=videoUrl) #{video.name}]": - - blockquote !{commentHtml} - - if requiresApproval - | This comment requires approval. - - br(style="display: none;") diff --git a/server/core/assets/email-templates/video-owner-blacklist-new/html.hbs b/server/core/assets/email-templates/video-owner-blacklist-new/html.hbs new file mode 100644 index 000000000..f40d99209 --- /dev/null +++ b/server/core/assets/email-templates/video-owner-blacklist-new/html.hbs @@ -0,0 +1,15 @@ +{{#> base title=(t "Your video has been blocked")}} +

+ {{#if reason}} + {{{t "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:" videoName=videoName instanceName=instanceName}}} + {{else}} + {{{t "Your video {videoName} has been blocked by {instanceName} moderators." videoName=videoName instanceName=instanceName}}} + {{/if}} +

+ + {{#if reason}} +
{{reason}}
+ {{/if}} + +
+{{/base}} diff --git a/server/core/assets/email-templates/video-owner-unblacklist/html.hbs b/server/core/assets/email-templates/video-owner-unblacklist/html.hbs new file mode 100644 index 000000000..a75ce66e1 --- /dev/null +++ b/server/core/assets/email-templates/video-owner-unblacklist/html.hbs @@ -0,0 +1,5 @@ +{{#> base title=(t "Your video has been unblocked")}} +

+ {{{t "Your video {videoName} has been unblocked by {instanceName} moderators." videoName=videoName instanceName=instanceName}}} +

+{{/base}} diff --git a/server/core/controllers/api/client-config.ts b/server/core/controllers/api/client-config.ts new file mode 100644 index 000000000..14675a0a4 --- /dev/null +++ b/server/core/controllers/api/client-config.ts @@ -0,0 +1,36 @@ +import { is18nLocale } from '@peertube/peertube-core-utils' +import { HttpStatusCode } from '@peertube/peertube-models' +import { setClientLanguageCookie } from '@server/helpers/i18n.js' +import express from 'express' +import { apiRateLimiter } from '../../middlewares/index.js' + +const clientConfigRouter = express.Router() + +clientConfigRouter.use(apiRateLimiter) + +clientConfigRouter.post( + '/update-interface-language', + updateLanguage +) + +// --------------------------------------------------------------------------- + +export { + clientConfigRouter +} + +// --------------------------------------------------------------------------- + +function updateLanguage (req: express.Request, res: express.Response) { + const language = req.body.language + + if (language !== null && !is18nLocale(language)) { + return res.fail({ + message: req.t('{language} is not a valid language', { language }) + }) + } + + setClientLanguageCookie(res, language) + + return res.sendStatus(HttpStatusCode.NO_CONTENT_204) +} diff --git a/server/core/controllers/api/config.ts b/server/core/controllers/api/config.ts index f55540a5c..2656b023a 100644 --- a/server/core/controllers/api/config.ts +++ b/server/core/controllers/api/config.ts @@ -309,6 +309,8 @@ function customConfig (): CustomConfig { businessModel: CONFIG.INSTANCE.BUSINESS_MODEL, hardwareInformation: CONFIG.INSTANCE.HARDWARE_INFORMATION, + defaultLanguage: CONFIG.INSTANCE.DEFAULT_LANGUAGE, + languages: CONFIG.INSTANCE.LANGUAGES, categories: CONFIG.INSTANCE.CATEGORIES, diff --git a/server/core/controllers/api/index.ts b/server/core/controllers/api/index.ts index d5034c1de..437151f27 100644 --- a/server/core/controllers/api/index.ts +++ b/server/core/controllers/api/index.ts @@ -7,6 +7,7 @@ import { accountsRouter } from './accounts.js' import { automaticTagRouter } from './automatic-tags.js' import { blocklistRouter } from './blocklist.js' import { bulkRouter } from './bulk.js' +import { clientConfigRouter } from './client-config.js' import { configRouter } from './config.js' import { customPageRouter } from './custom-page.js' import { jobsRouter } from './jobs.js' @@ -53,6 +54,7 @@ apiRouter.use('/blocklist', blocklistRouter) apiRouter.use('/runners', runnersRouter) apiRouter.use('/watched-words', watchedWordsRouter) apiRouter.use('/automatic-tags', automaticTagRouter) +apiRouter.use('/client-config', clientConfigRouter) apiRouter.use('/ping', pong) apiRouter.use('/*', badRequest) diff --git a/server/core/controllers/api/server/contact.ts b/server/core/controllers/api/server/contact.ts index 53e73fa2b..29250193f 100644 --- a/server/core/controllers/api/server/contact.ts +++ b/server/core/controllers/api/server/contact.ts @@ -7,15 +7,12 @@ import { asyncMiddleware, contactAdministratorValidator } from '../../../middlew const contactRouter = express.Router() -contactRouter.post('/contact', - asyncMiddleware(contactAdministratorValidator), - asyncMiddleware(contactAdministrator) -) +contactRouter.post('/contact', asyncMiddleware(contactAdministratorValidator), asyncMiddleware(contactAdministrator)) async function contactAdministrator (req: express.Request, res: express.Response) { const data = req.body as ContactForm - Emailer.Instance.addContactFormJob(data.fromEmail, data.fromName, data.subject, data.body) + Emailer.Instance.addContactFormJob({ fromEmail: data.fromEmail, fromName: data.fromName, subject: data.subject, body: data.body }) try { await Redis.Instance.setContactFormIp(req.ip) diff --git a/server/core/controllers/api/server/debug.ts b/server/core/controllers/api/server/debug.ts index 5ecf21d6b..d49395238 100644 --- a/server/core/controllers/api/server/debug.ts +++ b/server/core/controllers/api/server/debug.ts @@ -1,26 +1,41 @@ -import express from 'express' -import { Debug, HttpStatusCode, SendDebugCommand, UserRight } from '@peertube/peertube-models' +import { + Debug, + HttpStatusCode, + SendDebugCommand, + SendDebugTestEmails, + UserExportState, + UserImportResultSummary, + UserRegistrationState, + UserRight +} from '@peertube/peertube-models' +import { logger } from '@server/helpers/logger.js' +import { CONFIG } from '@server/initializers/config.js' +import { WEBSERVER } from '@server/initializers/constants.js' import { InboxManager } from '@server/lib/activitypub/inbox-manager.js' +import { Emailer } from '@server/lib/emailer.js' import { RemoveDanglingResumableUploadsScheduler } from '@server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.js' +import { RemoveExpiredUserExportsScheduler } from '@server/lib/schedulers/remove-expired-user-exports-scheduler.js' import { UpdateVideosScheduler } from '@server/lib/schedulers/update-videos-scheduler.js' import { VideoChannelSyncLatestScheduler } from '@server/lib/schedulers/video-channel-sync-latest-scheduler.js' import { VideoViewsBufferScheduler } from '@server/lib/schedulers/video-views-buffer-scheduler.js' import { VideoViewsManager } from '@server/lib/views/video-views-manager.js' -import { authenticate, ensureUserHasRight } from '../../../middlewares/index.js' -import { RemoveExpiredUserExportsScheduler } from '@server/lib/schedulers/remove-expired-user-exports-scheduler.js' +import express from 'express' +import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares/index.js' const debugRouter = express.Router() -debugRouter.get('/debug', +debugRouter.get( + '/debug', authenticate, ensureUserHasRight(UserRight.MANAGE_DEBUG), getDebug ) -debugRouter.post('/debug/run-command', +debugRouter.post( + '/debug/run-command', authenticate, ensureUserHasRight(UserRight.MANAGE_DEBUG), - runCommand + asyncMiddleware(runCommand) ) // --------------------------------------------------------------------------- @@ -47,7 +62,8 @@ async function runCommand (req: express.Request, res: express.Response) { 'process-video-views-buffer': () => VideoViewsBufferScheduler.Instance.execute(), 'process-video-viewers': () => VideoViewsManager.Instance.processViewerStats(), 'process-update-videos-scheduler': () => UpdateVideosScheduler.Instance.execute(), - 'process-video-channel-sync-latest': () => VideoChannelSyncLatestScheduler.Instance.execute() + 'process-video-channel-sync-latest': () => VideoChannelSyncLatestScheduler.Instance.execute(), + 'test-emails': () => testEmails(req, res) } if (!processors[body.command]) { @@ -58,3 +74,114 @@ async function runCommand (req: express.Request, res: express.Response) { return res.status(HttpStatusCode.NO_CONTENT_204).end() } + +// --------------------------------------------------------------------------- +// Private +// --------------------------------------------------------------------------- + +async function testEmails (req: express.Request, res: express.Response) { + const email = (req.body as SendDebugTestEmails).email + + if (!email) { + return res.fail({ message: 'Email is required for test-emails command' }) + } + + if (!email.includes('@')) { + return res.fail({ message: 'Invalid email format for test-emails command' }) + } + + const fakeUrl = WEBSERVER.URL + '/test' + const language = CONFIG.INSTANCE.DEFAULT_LANGUAGE + const to = { email, language } + + Emailer.Instance.addPasswordResetEmailJob({ username: 'test-username', to: email, language, resetPasswordUrl: fakeUrl }) + Emailer.Instance.addPasswordCreateEmailJob({ username: 'test-username', to: email, language, createPasswordUrl: fakeUrl }) + Emailer.Instance.addUserVerifyChangeEmailJob({ username: 'test-username', to: email, language, verifyEmailUrl: fakeUrl }) + + { + Emailer.Instance.addRegistrationVerifyEmailJob({ + username: 'test-username', + isRegistrationRequest: true, + to: email, + language, + verifyEmailUrl: fakeUrl + }) + Emailer.Instance.addRegistrationVerifyEmailJob({ + username: 'test-username', + isRegistrationRequest: false, + to: email, + language, + verifyEmailUrl: fakeUrl + }) + } + + { + const user = { username: 'test-username', email, language } + + Emailer.Instance.addUserBlockJob({ ...user, blocked: true, reason: 'Test reason for blocking' }) + Emailer.Instance.addUserBlockJob({ ...user, blocked: false, reason: 'Test reason for blocking' }) + Emailer.Instance.addUserBlockJob({ ...user, blocked: true }) + Emailer.Instance.addUserBlockJob({ ...user, blocked: false }) + } + + Emailer.Instance.addContactFormJob({ body: 'test contact form', fromEmail: email, fromName: 'Test User', subject: 'Test Subject' }) + + { + Emailer.Instance.addUserRegistrationRequestProcessedJob({ + username: 'test-username', + state: UserRegistrationState.ACCEPTED, + email, + moderationResponse: 'Test moderation response' + }) + Emailer.Instance.addUserRegistrationRequestProcessedJob({ + username: 'test-username', + state: UserRegistrationState.REJECTED, + email, + moderationResponse: 'Test moderation response' + }) + } + + { + await Emailer.Instance.addUserExportCompletedOrErroredJob({ error: 'error', state: UserExportState.ERRORED, userId: 1 }, to) + await Emailer.Instance.addUserExportCompletedOrErroredJob({ error: null, state: UserExportState.COMPLETED, userId: 1 }, to) + } + + await Emailer.Instance.addUserImportErroredJob({ error: 'Test error', userId: 1 }, to) + + { + const summary = { + success: 1, + duplicates: 2, + errors: 3 + } + const resultSummary: UserImportResultSummary = { + stats: { + blocklist: summary, + channels: summary, + likes: summary, + dislikes: summary, + following: summary, + videoPlaylists: summary, + videos: summary, + account: summary, + userSettings: summary, + userVideoHistory: summary, + watchedWordsLists: summary, + commentAutoTagPolicies: summary + } + } + + await Emailer.Instance.addUserImportSuccessJob({ resultSummary, userId: 1 }, to) + } + + { + const user = { username: 'test-username', email, language } + + Emailer.Instance.addUserBlockJob({ ...user, blocked: true, reason: 'Test reason for blocking' }) + Emailer.Instance.addUserBlockJob({ ...user, blocked: false }) + } + + logger.info(`Sent test email to ${email}`) + + return res.sendStatus(HttpStatusCode.NO_CONTENT_204) +} diff --git a/server/core/controllers/api/users/index.ts b/server/core/controllers/api/users/index.ts index 045c093b1..c0bfad58c 100644 --- a/server/core/controllers/api/users/index.ts +++ b/server/core/controllers/api/users/index.ts @@ -1,6 +1,7 @@ import { pick } from '@peertube/peertube-core-utils' import { HttpStatusCode, UserCreate, UserCreateResult, UserRight, UserUpdate } from '@peertube/peertube-models' import { tokensRouter } from '@server/controllers/api/users/token.js' +import { getResetPasswordUrl } from '@server/lib/client-urls.js' import { Hooks } from '@server/lib/plugins/hooks.js' import { OAuthTokenModel } from '@server/models/oauth/oauth-token.js' import { MUserAccountDefault } from '@server/types/models/index.js' @@ -8,7 +9,6 @@ import express from 'express' import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger.js' import { logger, loggerTagsFactory } from '../../../helpers/logger.js' import { generateRandomString, getFormattedObjects } from '../../../helpers/utils.js' -import { WEBSERVER } from '../../../initializers/constants.js' import { sequelizeTypescript } from '../../../initializers/database.js' import { Emailer } from '../../../lib/emailer.js' import { Redis } from '../../../lib/redis.js' @@ -161,11 +161,17 @@ async function createUser (req: express.Request, res: express.Response) { logger.info('User %s with its channel and account created.', body.username, lTags(user.username)) if (createPassword) { - // this will send an email for newly created users, so then can set their first password. + // This will send an email for newly created users, so then can set their first password logger.info('Sending to user %s a create password email', body.username, lTags(user.username)) + const verificationString = await Redis.Instance.setCreatePasswordVerificationString(user.id) - const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString - Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url) + + Emailer.Instance.addPasswordCreateEmailJob({ + username: userToCreate.username, + to: user.email, + language: user.getLanguage(), + createPasswordUrl: getResetPasswordUrl(user, verificationString) + }) } Hooks.runAction('action:api.user.created', { body, user, account, videoChannel, req, res }) @@ -289,8 +295,12 @@ async function askResetUserPassword (req: express.Request, res: express.Response const user = res.locals.user const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id) - const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString - Emailer.Instance.addPasswordResetEmailJob(user.username, user.email, url) + Emailer.Instance.addPasswordResetEmailJob({ + username: user.username, + to: user.email, + language: user.getLanguage(), + resetPasswordUrl: getResetPasswordUrl(user, verificationString) + }) logger.info(`User ${user.username} asked password reset.`, lTags(user.username)) @@ -321,7 +331,7 @@ async function changeUserBlock (res: express.Response, user: MUserAccountDefault await user.save({ transaction: t }) }) - Emailer.Instance.addUserBlockJob(user, block, reason) + Emailer.Instance.addUserBlockJob({ username: user.username, email: user.email, language: user.getLanguage(), blocked: block, reason }) auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) } diff --git a/server/core/controllers/api/users/me.ts b/server/core/controllers/api/users/me.ts index fcf7e038b..4493e0cd1 100644 --- a/server/core/controllers/api/users/me.ts +++ b/server/core/controllers/api/users/me.ts @@ -278,6 +278,7 @@ async function updateMe (req: express.Request, res: express.Response) { 'autoPlayNextVideoPlaylist', 'videosHistoryEnabled', 'videoLanguages', + 'language', 'theme', 'noInstanceConfigWarningModal', 'noAccountSetupWarningModal', diff --git a/server/core/controllers/client.ts b/server/core/controllers/client.ts index 4105a0309..7fe5c10dd 100644 --- a/server/core/controllers/client.ts +++ b/server/core/controllers/client.ts @@ -208,10 +208,10 @@ async function generateActorHtmlPage (req: express.Request, res: express.Respons async function generateManifest (req: express.Request, res: express.Response) { const serverActor = await getServerActor() - const defaultIcons = [ 36, 48, 72, 96, 144, 192, 512 ].map(size => { + const defaultIcons = [ 192, 512 ].map(size => { return { src: `/client/assets/images/icons/icon-${size}x${size}.png`, - sizes: `36x36`, + sizes: `${size}x${size}`, type: 'image/png' } }) diff --git a/server/core/controllers/feeds/shared/common-feed-utils.ts b/server/core/controllers/feeds/shared/common-feed-utils.ts index 8866adb8a..31726c8d3 100644 --- a/server/core/controllers/feeds/shared/common-feed-utils.ts +++ b/server/core/controllers/feeds/shared/common-feed-utils.ts @@ -117,7 +117,7 @@ export async function buildFeedMetadata (options: { }) { const { video, videoChannel, account } = options - let imageUrl = WEBSERVER.URL + '/client/assets/images/icons/icon-96x96.png' + let imageUrl = ServerConfigManager.Instance.getLogoUrl(await getServerActor(), 512) let ownerImageUrl: string let name: string let description: string diff --git a/server/core/helpers/custom-validators/users.ts b/server/core/helpers/custom-validators/users.ts index 84c49ff66..e609e2f2b 100644 --- a/server/core/helpers/custom-validators/users.ts +++ b/server/core/helpers/custom-validators/users.ts @@ -1,125 +1,104 @@ -import validator from 'validator' +import { AVAILABLE_LOCALES } from '@peertube/peertube-core-utils' import { UserRole } from '@peertube/peertube-models' +import validator from 'validator' import { isEmailEnabled } from '../../initializers/config.js' import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers/constants.js' import { exists, isArray, isBooleanValid } from './misc.js' const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS -function isUserPasswordValid (value: string) { +export function isUserPasswordValid (value: string) { return validator.default.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD) } -function isUserPasswordValidOrEmpty (value: string) { +export function isUserPasswordValidOrEmpty (value: string) { // Empty password is only possible if emailing is enabled. if (value === '') return isEmailEnabled() return isUserPasswordValid(value) } -function isUserVideoQuotaValid (value: string) { +export function isUserVideoQuotaValid (value: string) { return exists(value) && validator.default.isInt(value + '', USERS_CONSTRAINTS_FIELDS.VIDEO_QUOTA) } -function isUserVideoQuotaDailyValid (value: string) { +export function isUserVideoQuotaDailyValid (value: string) { return exists(value) && validator.default.isInt(value + '', USERS_CONSTRAINTS_FIELDS.VIDEO_QUOTA_DAILY) } -function isUserUsernameValid (value: string) { +export function isUserUsernameValid (value: string) { return exists(value) && validator.default.matches(value, new RegExp(`^[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?$`)) && validator.default.isLength(value, USERS_CONSTRAINTS_FIELDS.USERNAME) } -function isUserDisplayNameValid (value: string) { +export function isUserDisplayNameValid (value: string) { return value === null || (exists(value) && validator.default.isLength(value, CONSTRAINTS_FIELDS.USERS.NAME)) } -function isUserDescriptionValid (value: string) { +export function isUserDescriptionValid (value: string) { return value === null || (exists(value) && validator.default.isLength(value, CONSTRAINTS_FIELDS.USERS.DESCRIPTION)) } -function isUserEmailVerifiedValid (value: any) { +export function isUserEmailVerifiedValid (value: any) { return isBooleanValid(value) } const nsfwPolicies = new Set(Object.values(NSFW_POLICY_TYPES)) -function isUserNSFWPolicyValid (value: any) { +export function isUserNSFWPolicyValid (value: any) { return exists(value) && nsfwPolicies.has(value) } -function isUserP2PEnabledValid (value: any) { +export function isUserP2PEnabledValid (value: any) { return isBooleanValid(value) } -function isUserVideosHistoryEnabledValid (value: any) { +export function isUserVideosHistoryEnabledValid (value: any) { return isBooleanValid(value) } -function isUserAutoPlayVideoValid (value: any) { +export function isUserAutoPlayVideoValid (value: any) { return isBooleanValid(value) } -function isUserVideoLanguages (value: any) { +export function isUserVideoLanguages (value: any) { return value === null || (isArray(value) && value.length < CONSTRAINTS_FIELDS.USERS.VIDEO_LANGUAGES.max) } -function isUserAdminFlagsValid (value: any) { +export function isUserLanguage (value: any) { + return value === null || AVAILABLE_LOCALES.includes(value) +} + +export function isUserAdminFlagsValid (value: any) { return exists(value) && validator.default.isInt('' + value) } -function isUserBlockedValid (value: any) { +export function isUserBlockedValid (value: any) { return isBooleanValid(value) } -function isUserAutoPlayNextVideoValid (value: any) { +export function isUserAutoPlayNextVideoValid (value: any) { return isBooleanValid(value) } -function isUserAutoPlayNextVideoPlaylistValid (value: any) { +export function isUserAutoPlayNextVideoPlaylistValid (value: any) { return isBooleanValid(value) } -function isUserEmailPublicValid (value: any) { +export function isUserEmailPublicValid (value: any) { return isBooleanValid(value) } -function isUserNoModal (value: any) { +export function isUserNoModal (value: any) { return isBooleanValid(value) } -function isUserBlockedReasonValid (value: any) { +export function isUserBlockedReasonValid (value: any) { return value === null || (exists(value) && validator.default.isLength(value, CONSTRAINTS_FIELDS.USERS.BLOCKED_REASON)) } -function isUserRoleValid (value: any) { +export function isUserRoleValid (value: any) { return exists(value) && validator.default.isInt('' + value) && [ UserRole.ADMINISTRATOR, UserRole.MODERATOR, UserRole.USER ].includes(value) } - -// --------------------------------------------------------------------------- - -export { - isUserVideosHistoryEnabledValid, - isUserBlockedValid, - isUserPasswordValid, - isUserPasswordValidOrEmpty, - isUserVideoLanguages, - isUserBlockedReasonValid, - isUserRoleValid, - isUserVideoQuotaValid, - isUserVideoQuotaDailyValid, - isUserUsernameValid, - isUserAdminFlagsValid, - isUserEmailVerifiedValid, - isUserNSFWPolicyValid, - isUserP2PEnabledValid, - isUserAutoPlayVideoValid, - isUserAutoPlayNextVideoValid, - isUserAutoPlayNextVideoPlaylistValid, - isUserDisplayNameValid, - isUserDescriptionValid, - isUserEmailPublicValid, - isUserNoModal -} diff --git a/server/core/helpers/i18n.ts b/server/core/helpers/i18n.ts new file mode 100644 index 000000000..e760c6957 --- /dev/null +++ b/server/core/helpers/i18n.ts @@ -0,0 +1,76 @@ +import { AVAILABLE_LOCALES, getCompleteLocale } from '@peertube/peertube-core-utils' +import { CONFIG } from '@server/initializers/config.js' +import { LANGUAGE_COOKIE_NAME, LANGUAGE_HEADER, SERVER_INTERNAL_LOCALES_BASE_PATH } from '@server/initializers/constants.js' +import { MUser } from '@server/types/models/index.js' +import Bluebird from 'bluebird' +import express from 'express' +import { readJson } from 'fs-extra/esm' +import { readdir } from 'fs/promises' +import i18next from 'i18next' +import ICU from 'i18next-icu' +import { join } from 'path' +import { logger } from './logger.js' + +export async function initI18n () { + const locales = await readdir(SERVER_INTERNAL_LOCALES_BASE_PATH) + const resources: Record> = {} + + await Bluebird.map(locales, async locale => { + const localePath = join(SERVER_INTERNAL_LOCALES_BASE_PATH, locale) + + const translation = await readJson(join(localePath, 'translation.json')) + resources[locale] = { translation } + }, { concurrency: 10 }) + + return i18next.use(ICU) + .init({ + resources, + nsSeparator: false, + keySeparator: false, + + // do not load a fallback + fallbackLng: false + }) + .then(() => logger.info('i18n initialized with locales: ' + Object.keys(resources).join(', '))) +} + +export function useI18n (req: express.Request, res: express.Response, next: express.NextFunction) { + req.t = (key: string, context: Record = {}) => { + // Use req special header language + // Or user language + // Or default language + const language = req.headers[LANGUAGE_HEADER] as string || + res.locals.oauth?.token?.User?.language || + req.acceptsLanguages(AVAILABLE_LOCALES) || + CONFIG.INSTANCE.DEFAULT_LANGUAGE + + return t(key, language, context) + } + + next() +} + +export function t (key: string, language: string, context: Record = {}) { + if (!language) throw new Error('Language is required for translation') + + return i18next.t(key, { lng: getCompleteLocale(language), ...context }) +} + +export function tu (key: string, user: Pick, context: Record = {}) { + return t(key, user.getLanguage(), context) +} + +// --------------------------------------------------------------------------- + +export function setClientLanguageCookie (res: express.Response, language: string) { + if (language === null) { + res.clearCookie(LANGUAGE_COOKIE_NAME) + return + } + + res.cookie(LANGUAGE_COOKIE_NAME, language, { + secure: true, + sameSite: 'none', + maxAge: 1000 * 3600 * 24 * 90 // 3 months + }) +} diff --git a/server/core/helpers/markdown.ts b/server/core/helpers/markdown.ts index ae67b4b44..15b2c0cf3 100644 --- a/server/core/helpers/markdown.ts +++ b/server/core/helpers/markdown.ts @@ -1,12 +1,18 @@ import MarkdownItClass from 'markdown-it' // FIXME: use direct import: import markdownItEmoji from 'markdown-it-emoji/lib/light.mjs' if it improves perf' // when https://github.com/privatenumber/tsx/issues/334 is fixed +import { + getDefaultSanitizeOptions, + getMailHtmlSanitizeOptions, + getTextOnlySanitizeOptions, + TEXT_WITH_HTML_RULES +} from '@peertube/peertube-core-utils' import { light as markdownItEmoji } from 'markdown-it-emoji' import sanitizeHtml from 'sanitize-html' -import { getDefaultSanitizeOptions, getTextOnlySanitizeOptions, TEXT_WITH_HTML_RULES } from '@peertube/peertube-core-utils' const defaultSanitizeOptions = getDefaultSanitizeOptions() const textOnlySanitizeOptions = getTextOnlySanitizeOptions() +const hrefOnlySanitizeOptions = getMailHtmlSanitizeOptions() const markdownItForSafeHtml = new MarkdownItClass('default', { linkify: true, breaks: true, html: true }) .enable(TEXT_WITH_HTML_RULES) @@ -16,7 +22,7 @@ const markdownItForPlainText = new MarkdownItClass('default', { linkify: false, .use(markdownItEmoji) .use(plainTextPlugin) -const toSafeHtml = (text: string) => { +export const toSafeHtml = (text: string) => { if (!text) return '' // Restore line feed @@ -29,7 +35,7 @@ const toSafeHtml = (text: string) => { return sanitizeHtml(html, defaultSanitizeOptions) } -const mdToPlainText = (text: string) => { +export const mdToPlainText = (text: string) => { if (!text) return '' markdownItForPlainText.render(text) @@ -38,13 +44,14 @@ const mdToPlainText = (text: string) => { return sanitizeHtml(markdownItForPlainText.plainText, textOnlySanitizeOptions) } -// --------------------------------------------------------------------------- +export const toSafeMailHtml = (text: string) => { + if (!text) return '' -export { - toSafeHtml, - mdToPlainText + return sanitizeHtml(text, hrefOnlySanitizeOptions) } +// --------------------------------------------------------------------------- +// Private // --------------------------------------------------------------------------- // Thanks: https://github.com/wavesheep/markdown-it-plain-text diff --git a/server/core/initializers/checker-before-init.ts b/server/core/initializers/checker-before-init.ts index 5f44468e3..a1505d187 100644 --- a/server/core/initializers/checker-before-init.ts +++ b/server/core/initializers/checker-before-init.ts @@ -133,6 +133,7 @@ export function checkMissedConfig () { 'defaults.player.auto_play', 'instance.name', 'instance.short_description', + 'instance.default_language', 'instance.description', 'instance.terms', 'instance.default_client_route', diff --git a/server/core/initializers/config.ts b/server/core/initializers/config.ts index 003214d7c..17491d2ac 100644 --- a/server/core/initializers/config.ts +++ b/server/core/initializers/config.ts @@ -910,6 +910,9 @@ const CONFIG = { return config.get('instance.hardware_information') }, + get DEFAULT_LANGUAGE () { + return config.get('instance.default_language') + }, get LANGUAGES () { return config.get('instance.languages') || [] }, diff --git a/server/core/initializers/constants.ts b/server/core/initializers/constants.ts index ca4a69ba0..6b62dc98e 100644 --- a/server/core/initializers/constants.ts +++ b/server/core/initializers/constants.ts @@ -48,7 +48,7 @@ import { CONFIG, registerConfigChangedHandler } from './config.js' // --------------------------------------------------------------------------- -export const LAST_MIGRATION_VERSION = 905 +export const LAST_MIGRATION_VERSION = 910 // --------------------------------------------------------------------------- @@ -1119,6 +1119,9 @@ export const REDUNDANCY = { } export const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) +export const LANGUAGE_COOKIE_NAME = 'clientLanguage' +export const LANGUAGE_HEADER = 'x-peertube-language' + export const OTP = { HEADER_NAME: 'x-peertube-otp', HEADER_REQUIRED_VALUE: 'required; app' @@ -1129,6 +1132,8 @@ export const ASSETS_PATH = { DEFAULT_LIVE_BACKGROUND: join(root(), 'dist', 'core', 'assets', 'default-live-background.jpg') } +export const SERVER_INTERNAL_LOCALES_BASE_PATH = join(root(), 'dist', 'locales') + // --------------------------------------------------------------------------- export const CUSTOM_HTML_TAG_COMMENTS = { diff --git a/server/core/initializers/migrations/0910-user-language.ts b/server/core/initializers/migrations/0910-user-language.ts new file mode 100644 index 000000000..3d80a6807 --- /dev/null +++ b/server/core/initializers/migrations/0910-user-language.ts @@ -0,0 +1,26 @@ +import * as Sequelize from 'sequelize' + +async function up (utils: { + transaction: Sequelize.Transaction + queryInterface: Sequelize.QueryInterface + sequelize: Sequelize.Sequelize +}): Promise { + const { transaction } = utils + + { + await utils.queryInterface.addColumn('user', 'language', { + type: Sequelize.STRING, + defaultValue: null, + allowNull: true + }, { transaction }) + } +} + +function down (options) { + throw new Error('Not implemented.') +} + +export { + down, + up +} diff --git a/server/core/lib/client-urls.ts b/server/core/lib/client-urls.ts new file mode 100644 index 000000000..100dfee35 --- /dev/null +++ b/server/core/lib/client-urls.ts @@ -0,0 +1,36 @@ +import { PluginType_Type } from '@peertube/peertube-models' +import { WEBSERVER } from '@server/initializers/constants.js' +import { MAbuseId, MUserId } from '@server/types/models/index.js' + +export const instanceFollowingUrl = `${WEBSERVER.URL}/admin/settings/follows/following-list` +export const instanceFollowersUrl = `${WEBSERVER.URL}/admin/follows/followers-list` +export const videoAutoBlacklistUrl = `${WEBSERVER.URL}/admin/moderation/video-blocks/list` +export const myAccountImportExportUrl = `${WEBSERVER.URL}/my-account/import-export` +export const loginUrl = `${WEBSERVER.URL}/login` +export const adminRegistrationsListUrl = `${WEBSERVER.URL}/admin/moderation/registrations/list` +export const adminUsersListUrl = `${WEBSERVER.URL}/admin/overview/users/list` +export const myVideoImportsUrl = `${WEBSERVER.URL}/my-library/video-imports` + +export function getAdminAbuseUrl (abuse: MAbuseId) { + const suffix = abuse + ? '?search=%23' + abuse.id + : '' + + return WEBSERVER.URL + 'admin/moderation/abuses/list' + suffix +} + +export function getUserAbuseUrl (abuse: MAbuseId) { + const suffix = abuse + ? '?search=%23' + abuse.id + : '' + + return WEBSERVER.URL + '/my-account/abuses' + suffix +} + +export function getResetPasswordUrl (user: MUserId, verificationString: string) { + return WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString +} + +export function getPluginUrl (pluginType: PluginType_Type) { + return WEBSERVER.URL + '/admin/settings/plugins/list-installed?pluginType=' + pluginType +} diff --git a/server/core/lib/emailer.ts b/server/core/lib/emailer.ts index 11411119d..dee37a274 100644 --- a/server/core/lib/emailer.ts +++ b/server/core/lib/emailer.ts @@ -1,24 +1,35 @@ import { arrayify } from '@peertube/peertube-core-utils' -import { EmailPayload, SendEmailDefaultOptions, UserExportState, UserRegistrationState } from '@peertube/peertube-models' -import { isTestOrDevInstance, root } from '@peertube/peertube-node-utils' +import { EmailPayload, SendEmailDefaultOptions, To, UserExportState, UserRegistrationState } from '@peertube/peertube-models' +import { getFilenameWithoutExt, isTestOrDevInstance, root } from '@peertube/peertube-node-utils' +import { t } from '@server/helpers/i18n.js' +import { toSafeMailHtml } from '@server/helpers/markdown.js' +import { getServerActor } from '@server/models/application/application.js' import { UserModel } from '@server/models/user/user.js' import { readFileSync } from 'fs' +import { readdir, readFile } from 'fs/promises' +import handlebars, { HelperOptions } from 'handlebars' import merge from 'lodash-es/merge.js' -import { Transporter, createTransport } from 'nodemailer' +import { createTransport, Transporter } from 'nodemailer' import { join } from 'path' -import pug from 'pug' import { bunyanLogger, logger } from '../helpers/logger.js' import { CONFIG, isEmailEnabled } from '../initializers/config.js' import { WEBSERVER } from '../initializers/constants.js' -import { MRegistration, MUser, MUserExport, MUserImport } from '../types/models/index.js' +import { MRegistration, MUserExport, MUserImport } from '../types/models/index.js' +import { loginUrl, myAccountImportExportUrl } from './client-urls.js' import { JobQueue } from './job-queue/index.js' import { Hooks } from './plugins/hooks.js' +import { ServerConfigManager } from './server-config-manager.js' export class Emailer { private static instance: Emailer + private initialized = false + private registeringHandlebars: Promise + private transporter: Transporter + private readonly compiledTemplates = new Map() + private constructor () { } @@ -56,11 +67,18 @@ export class Emailer { // --------------------------------------------------------------------------- - addPasswordResetEmailJob (username: string, to: string, resetPasswordUrl: string) { + addPasswordResetEmailJob (options: { + username: string + to: string + language: string + resetPasswordUrl: string + }) { + const { username, to, resetPasswordUrl, language } = options + const emailPayload: EmailPayload = { template: 'password-reset', - to: [ to ], - subject: 'Reset your account password', + to: { email: to, language }, + subject: t('Reset your account password', language), locals: { username, resetPasswordUrl, @@ -72,11 +90,18 @@ export class Emailer { return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - addPasswordCreateEmailJob (username: string, to: string, createPasswordUrl: string) { + addPasswordCreateEmailJob (options: { + username: string + to: string + language: string + createPasswordUrl: string + }) { + const { username, to, createPasswordUrl, language } = options + const emailPayload: EmailPayload = { template: 'password-create', - to: [ to ], - subject: 'Create your account password', + to: { email: to, language }, + subject: t('Create your account password', language), locals: { username, createPasswordUrl, @@ -91,14 +116,15 @@ export class Emailer { addUserVerifyChangeEmailJob (options: { username: string to: string + language: string verifyEmailUrl: string }) { - const { username, to, verifyEmailUrl } = options + const { username, to, verifyEmailUrl, language } = options const emailPayload: EmailPayload = { template: 'verify-user-change-email', - to: [ to ], - subject: `Verify your email on ${CONFIG.INSTANCE.NAME}`, + to: { email: to, language }, + subject: t('Verify your email on {instanceName}', language, { instanceName: CONFIG.INSTANCE.NAME }), locals: { username, verifyEmailUrl, @@ -114,14 +140,16 @@ export class Emailer { username: string isRegistrationRequest: boolean to: string + language: string verifyEmailUrl: string }) { - const { username, isRegistrationRequest, to, verifyEmailUrl } = options + const { username, isRegistrationRequest, to, verifyEmailUrl, language } = options const emailPayload: EmailPayload = { template: 'verify-registration-email', - to: [ to ], - subject: `Verify your email on ${CONFIG.INSTANCE.NAME}`, + to: { email: to, language }, + + subject: t('Verify your email on {instanceName}', language, { instanceName: CONFIG.INSTANCE.NAME }), locals: { username, verifyEmailUrl, @@ -134,26 +162,53 @@ export class Emailer { return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - addUserBlockJob (user: MUser, blocked: boolean, reason?: string) { - const reasonString = reason ? ` for the following reason: ${reason}` : '' - const blockedWord = blocked ? 'blocked' : 'unblocked' + addUserBlockJob (options: { + username: string + email: string + language: string + blocked: boolean + reason?: string + }) { + const { username, language, email, blocked, reason } = options - const to = user.email - const emailPayload: EmailPayload = { - to: [ to ], - subject: 'Account ' + blockedWord, - text: `Your account ${user.username} on ${CONFIG.INSTANCE.NAME} has been ${blockedWord}${reasonString}.` - } + const emailPayload = blocked + ? { + template: 'my-user-block-new', + to: { email, language }, + subject: t('Your account has been blocked', language), + locals: { + username, + instanceName: CONFIG.INSTANCE.NAME, + reason + } + } + : { + template: 'my-user-unblocked', + to: { email, language }, + subject: t('Your account has been unblocked', language), + locals: { + username, + instanceName: CONFIG.INSTANCE.NAME + } + } return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - addContactFormJob (fromEmail: string, fromName: string, subject: string, body: string) { + addContactFormJob (options: { + fromEmail: string + + fromName: string + subject: string + body: string + }) { + const { fromEmail, fromName, subject, body } = options + const emailPayload: EmailPayload = { template: 'contact-form', - to: [ CONFIG.ADMIN.EMAIL ], + to: { email: CONFIG.ADMIN.EMAIL, language: CONFIG.INSTANCE.DEFAULT_LANGUAGE }, replyTo: `"${fromName}" <${fromEmail}>`, - subject: `(contact form) ${subject}`, + subject: t('Contact form - {subject}', CONFIG.INSTANCE.DEFAULT_LANGUAGE, { subject }), locals: { fromName, fromEmail, @@ -167,26 +222,34 @@ export class Emailer { return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - addUserRegistrationRequestProcessedJob (registration: MRegistration) { + addUserRegistrationRequestProcessedJob ( + registration: Pick + ) { + const language = CONFIG.INSTANCE.DEFAULT_LANGUAGE + let template: string let subject: string + let action: { text: string, href: string } + if (registration.state === UserRegistrationState.ACCEPTED) { template = 'user-registration-request-accepted' - subject = `Your registration request for ${registration.username} has been accepted` + subject = t('Your registration request for {username} has been accepted', language, { username: registration.username }) + + action = { text: t('Login to your account', language), href: loginUrl } } else { template = 'user-registration-request-rejected' - subject = `Your registration request for ${registration.username} has been rejected` + subject = t('Your registration request for {username} has been rejected', language, { username: registration.username }) } const to = registration.email const emailPayload: EmailPayload = { - to: [ to ], + to: { email: to, language }, template, subject, locals: { username: registration.username, moderationResponse: registration.moderationResponse, - loginLink: WEBSERVER.URL + '/login', + action, hideNotificationPreferencesLink: true } @@ -197,26 +260,26 @@ export class Emailer { // --------------------------------------------------------------------------- - async addUserExportCompletedOrErroredJob (userExport: MUserExport) { + async addUserExportCompletedOrErroredJob (userExport: Pick, toOverride?: To) { let template: string let subject: string + const to = toOverride ?? await UserModel.loadForEmail(userExport.userId) + if (userExport.state === UserExportState.COMPLETED) { template = 'user-export-completed' - subject = `Your export archive has been created` + subject = t('Your export archive has been created', to.language) } else { template = 'user-export-errored' - subject = `Failed to create your export archive` + subject = t('Failed to create your export archive', to.language) } - const user = await UserModel.loadById(userExport.userId) - const emailPayload: EmailPayload = { - to: [ user.email ], + to, template, subject, locals: { - exportsUrl: WEBSERVER.URL + '/my-account/import-export', + exportsUrl: myAccountImportExportUrl, errorMessage: userExport.error, hideNotificationPreferencesLink: true @@ -226,13 +289,14 @@ export class Emailer { return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - async addUserImportErroredJob (userImport: MUserImport) { - const user = await UserModel.loadById(userImport.userId) + async addUserImportErroredJob (userImport: Pick, toOverride?: To) { + const to = toOverride ?? await UserModel.loadForEmail(userImport.userId) const emailPayload: EmailPayload = { - to: [ user.email ], + to, + template: 'user-import-errored', - subject: 'Failed to import your archive', + subject: t('Failed to import your archive', to.language), locals: { errorMessage: userImport.error, @@ -243,13 +307,14 @@ export class Emailer { return JobQueue.Instance.createJobAsync({ type: 'email', payload: emailPayload }) } - async addUserImportSuccessJob (userImport: MUserImport) { - const user = await UserModel.loadById(userImport.userId) + async addUserImportSuccessJob (userImport: Pick, toOverride?: To) { + const to = toOverride ?? await UserModel.loadForEmail(userImport.userId) const emailPayload: EmailPayload = { - to: [ user.email ], + to, + template: 'user-import-completed', - subject: 'Your archive import has finished', + subject: t('Your archive import has finished', to.language), locals: { resultStats: userImport.resultSummary.stats, @@ -286,12 +351,20 @@ export class Emailer { render: async (view: string, locals: Record) => { if (view.split('/').pop() !== 'html') return undefined + await this.initHandlebarsIfNeeded() + const templatePath = await Hooks.wrapObject( - join(root(), 'dist', 'core', 'assets', 'email-templates', view + '.pug'), + join(root(), 'dist', 'core', 'assets', 'email-templates', view + '.hbs'), 'filter:email.template-path.result', { view } ) - const compiledTemplate = pug.compileFile(templatePath) + + let compiledTemplate = this.compiledTemplates.get(templatePath) + + if (!compiledTemplate) { + compiledTemplate = handlebars.compile(await readFile(templatePath, 'utf-8')) + this.compiledTemplates.set(templatePath, compiledTemplate) + } return compiledTemplate(locals) }, @@ -307,15 +380,13 @@ export class Emailer { { template: 'template' in options ? options.template : undefined } ) - const toEmails = arrayify(options.to) - const errors: Error[] = [] - for (const to of toEmails) { + for (const to of arrayify(options.to)) { const baseOptions: SendEmailDefaultOptions = { template: 'common', message: { - to, + to: to.email, from: options.from, subject, replyTo: options.replyTo @@ -328,7 +399,9 @@ export class Emailer { signature: this.buildSignature(), fg: CONFIG.THEME.CUSTOMIZATION.FOREGROUND_COLOR || '#000', bg: CONFIG.THEME.CUSTOMIZATION.BACKGROUND_COLOR || '#fff', - primary: CONFIG.THEME.CUSTOMIZATION.PRIMARY_COLOR || '#FF8F37' + primary: CONFIG.THEME.CUSTOMIZATION.PRIMARY_COLOR || '#FF8F37', + language: to.language, + logoUrl: ServerConfigManager.Instance.getLogoUrl(await getServerActor(), 192) } } @@ -416,6 +489,29 @@ export class Emailer { return signature.replace(/{{instanceName}}/g, CONFIG.INSTANCE.NAME) } + private initHandlebarsIfNeeded () { + if (this.registeringHandlebars) return this.registeringHandlebars + + this.registeringHandlebars = this._initHandlebarsIfNeeded() + + return this.registeringHandlebars + } + + private async _initHandlebarsIfNeeded () { + const partialsPath = join(root(), 'server', 'core', 'assets', 'email-templates', 'partials') + const partialFiles = await readdir(partialsPath) + + for (const partialFile of partialFiles) { + handlebars.registerPartial(getFilenameWithoutExt(partialFile), await readFile(join(partialsPath, partialFile), 'utf-8')) + } + + handlebars.registerHelper('t', function (key: string, options: HelperOptions) { + const result = t(key, this.language, options.hash) + + return toSafeMailHtml(result) + }) + } + static get Instance () { return this.instance || (this.instance = new this()) } diff --git a/server/core/lib/html/shared/page-html.ts b/server/core/lib/html/shared/page-html.ts index cc8b95203..df3b9c11e 100644 --- a/server/core/lib/html/shared/page-html.ts +++ b/server/core/lib/html/shared/page-html.ts @@ -1,13 +1,14 @@ import { + AVAILABLE_LOCALES, buildFileLocale, escapeHTML, getDefaultLocale, getDefaultRSSFeeds, - is18nLocale, - POSSIBLE_LOCALES + is18nLocale } from '@peertube/peertube-core-utils' import { HTMLServerConfig } from '@peertube/peertube-models' import { isTestOrDevInstance, root, sha256 } from '@peertube/peertube-node-utils' +import { setClientLanguageCookie } from '@server/helpers/i18n.js' import { CONFIG } from '@server/initializers/config.js' import { getServerActor } from '@server/models/application/application.js' import express from 'express' @@ -125,15 +126,11 @@ export class PageHtml { lang = paramLang // Save locale in cookies - res.cookie('clientLanguage', lang, { - secure: true, - sameSite: 'none', - maxAge: 1000 * 3600 * 24 * 90 // 3 months - }) + setClientLanguageCookie(res, lang) } else if (req.cookies.clientLanguage && is18nLocale(req.cookies.clientLanguage)) { lang = req.cookies.clientLanguage } else { - lang = req.acceptsLanguages(POSSIBLE_LOCALES) || getDefaultLocale() + lang = req.acceptsLanguages(AVAILABLE_LOCALES) || getDefaultLocale() } logger.debug( diff --git a/server/core/lib/html/shared/tags-html.ts b/server/core/lib/html/shared/tags-html.ts index 622525033..53c239665 100644 --- a/server/core/lib/html/shared/tags-html.ts +++ b/server/core/lib/html/shared/tags-html.ts @@ -1,4 +1,4 @@ -import { escapeAttribute, escapeHTML, findAppropriateImage } from '@peertube/peertube-core-utils' +import { escapeAttribute, escapeHTML } from '@peertube/peertube-core-utils' import { mdToPlainText } from '@server/helpers/markdown.js' import { ServerConfigManager } from '@server/lib/server-config-manager.js' import { getServerActor } from '@server/models/application/application.js' @@ -148,10 +148,7 @@ export class TagsHtml { tagsStr += `` // Apple Touch Icon - const appleTouchIcon = findAppropriateImage(serverActor.Avatars, 192) - const iconHref = appleTouchIcon - ? WEBSERVER.URL + appleTouchIcon.getStaticPath() - : '/client/assets/images/icons/icon-192x192.png' + const iconHref = ServerConfigManager.Instance.getLogoUrl(serverActor, 192) tagsStr += `` diff --git a/server/core/lib/notifier/notifier.ts b/server/core/lib/notifier/notifier.ts index 59ab31331..a2cf1f396 100644 --- a/server/core/lib/notifier/notifier.ts +++ b/server/core/lib/notifier/notifier.ts @@ -1,5 +1,5 @@ import { UserNotificationSettingValue, UserNotificationSettingValueType } from '@peertube/peertube-models' -import { MRegistration, MUser, MUserDefault } from '@server/types/models/user/index.js' +import { MRegistration, MUser, MUserDefault, MUserWithNotificationSetting } from '@server/types/models/user/index.js' import { MVideoBlacklistLightVideo, MVideoBlacklistVideo } from '@server/types/models/video/video-blacklist.js' import { logger, loggerTagsFactory } from '../../helpers/logger.js' import { CONFIG } from '../../initializers/config.js' @@ -49,7 +49,6 @@ import { const lTags = loggerTagsFactory('notifier') class Notifier { - private readonly notificationModels = { newVideoOrLive: [ NewVideoOrLiveForSubscribers ], publicationAfterTranscoding: [ OwnedPublicationAfterTranscoding ], @@ -169,7 +168,7 @@ class Notifier { logger.debug('Notify on video unblacklist', { video: video.url, ...lTags() }) this.sendNotifications(models, video) - .catch(err => logger.error('Cannot notify video owner of unblacklist of %s.', video.url, { err })) + .catch(err => logger.error('Cannot notify video owner of unblacklist of %s.', video.url, { err })) } notifyOnFinishedVideoImport (payload: ImportFinishedForOwnerPayload): void { @@ -178,9 +177,9 @@ class Notifier { logger.debug('Notify on finished video import', { import: payload.videoImport.getTargetIdentifier(), ...lTags() }) this.sendNotifications(models, payload) - .catch(err => { - logger.error('Cannot notify owner that its video import %s is finished.', payload.videoImport.getTargetIdentifier(), { err }) - }) + .catch(err => { + logger.error('Cannot notify owner that its video import %s is finished.', payload.videoImport.getTargetIdentifier(), { err }) + }) } notifyOnNewDirectRegistration (user: MUserDefault): void { @@ -288,7 +287,7 @@ class Notifier { .catch(err => logger.error('Cannot notify on generated video transcription %s of video %s.', caption.language, video.url, { err })) } - private async notify (object: AbstractNotification) { + private async notify (object: AbstractNotification) { await object.prepare() const users = object.getTargetUsers() @@ -298,7 +297,7 @@ class Notifier { object.log() - const toEmails: string[] = [] + const toUsers: MUserWithNotificationSetting[] = [] for (const user of users) { const setting = object.getSetting(user) @@ -314,13 +313,13 @@ class Notifier { } if (emailNotificationEnabled) { - toEmails.push(user.email) + toUsers.push(user) } Hooks.runAction('action:notifier.notification.created', { webNotificationEnabled, emailNotificationEnabled, user, notification }) } - for (const to of toEmails) { + for (const to of toUsers) { const payload = await object.createEmail(to) JobQueue.Instance.createJobAsync({ type: 'email', payload }) } @@ -336,7 +335,7 @@ class Notifier { return (value & UserNotificationSettingValue.WEB) === UserNotificationSettingValue.WEB } - private async sendNotifications (models: (new (payload: T) => AbstractNotification)[], payload: T) { + private async sendNotifications (models: (new(payload: T) => AbstractNotification)[], payload: T) { for (const model of models) { // eslint-disable-next-line new-cap await this.notify(new model(payload)) diff --git a/server/core/lib/notifier/shared/abuse/abstract-new-abuse-message.ts b/server/core/lib/notifier/shared/abuse/abstract-new-abuse-message.ts index f9a940299..efbdb8194 100644 --- a/server/core/lib/notifier/shared/abuse/abstract-new-abuse-message.ts +++ b/server/core/lib/notifier/shared/abuse/abstract-new-abuse-message.ts @@ -1,5 +1,6 @@ -import { UserNotificationType } from '@peertube/peertube-models' -import { WEBSERVER } from '@server/initializers/constants.js' +import { To, UserNotificationType } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' +import { getAdminAbuseUrl, getUserAbuseUrl } from '@server/lib/client-urls.js' import { AccountModel } from '@server/models/account/account.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' import { @@ -16,7 +17,7 @@ type NewAbuseMessagePayload = { message: MAbuseMessage } -export abstract class AbstractNewAbuseMessage extends AbstractNotification { +export abstract class AbstractNewAbuseMessage extends AbstractNotification { protected messageAccount: MAccountDefault async loadMessageAccount () { @@ -38,14 +39,14 @@ export abstract class AbstractNewAbuseMessage extends AbstractNotification { - +export class AbuseStateChangeForReporter extends AbstractNotification { private user: MUserDefault async prepare () { @@ -43,15 +43,18 @@ export class AbuseStateChangeForReporter extends AbstractNotification , abuseInstance: MAbuseFull, reporter: string } -export class NewAbuseForModerators extends AbstractNotification { +export class NewAbuseForModerators extends AbstractNotification { private moderators: MUserDefault[] async prepare () { @@ -39,7 +41,9 @@ export class NewAbuseForModerators extends AbstractNotification { +export class NewAutoBlacklistForModerators extends AbstractNotification { private moderators: MUserDefault[] async prepare () { @@ -42,21 +44,21 @@ export class NewAutoBlacklistForModerators extends AbstractNotification { +export class NewBlacklistForOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -44,19 +45,24 @@ export class NewBlacklistForOwner extends AbstractNotification { +export class UnblacklistForOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -39,16 +40,23 @@ export class UnblacklistForOwner extends AbstractNotification return notification } - createEmail (to: string) { + createEmail (user: MUserWithNotificationSetting) { + const to = { email: user.email, language: user.getLanguage() } + const video = this.payload const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() return { + template: 'video-owner-unblacklist', to, - subject: `Video ${video.name} unblacklisted`, - text: `Your video "${video.name}" (${videoUrl}) on ${CONFIG.INSTANCE.NAME} has been unblacklisted.`, + subject: tu('Your video has been unblocked', user), locals: { - title: 'Your video was unblacklisted' + instanceName: CONFIG.INSTANCE.NAME, + videoName: video.name, + action: { + text: tu('View video', user), + url: videoUrl + } } } } diff --git a/server/core/lib/notifier/shared/caption/video-transcription-generated-for-owner.ts b/server/core/lib/notifier/shared/caption/video-transcription-generated-for-owner.ts index a77740736..2d0d4dd01 100644 --- a/server/core/lib/notifier/shared/caption/video-transcription-generated-for-owner.ts +++ b/server/core/lib/notifier/shared/caption/video-transcription-generated-for-owner.ts @@ -1,4 +1,5 @@ import { UserNotificationType } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' import { logger } from '@server/helpers/logger.js' import { VIDEO_LANGUAGES, WEBSERVER } from '@server/initializers/constants.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' @@ -6,7 +7,7 @@ import { UserModel } from '@server/models/user/user.js' import { MUserDefault, MUserWithNotificationSetting, MVideoCaptionVideo, UserNotificationModelForApi } from '@server/types/models/index.js' import { AbstractNotification } from '../common/abstract-notification.js' -export class VideoTranscriptionGeneratedForOwner extends AbstractNotification { +export class VideoTranscriptionGeneratedForOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -16,7 +17,9 @@ export class VideoTranscriptionGeneratedForOwner extends AbstractNotification { +export class CommentMention extends AbstractNotification { private users: MUserDefault[] private serverAccountId: number - private accountMutedHash: { [ id: number ]: boolean } - private instanceMutedHash: { [ id: number ]: boolean } + private accountMutedHash: { [id: number]: boolean } + private instanceMutedHash: { [id: number]: boolean } isDisabled () { return this.payload.heldForReview === true @@ -31,7 +32,9 @@ export class CommentMention extends AbstractNotification { +export class NewCommentForVideoOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -49,7 +50,9 @@ export class NewCommentForVideoOwner extends AbstractNotification { - +export abstract class AbstractNotification { constructor (protected readonly payload: T) { - } abstract prepare (): Promise @@ -14,10 +12,9 @@ export abstract class AbstractNotification abstract getTargetUsers (): U[] abstract createNotification (user: U): UserNotificationModelForApi - abstract createEmail (to: string): EmailPayload | Promise + abstract createEmail (to: U): EmailPayload | Promise isDisabled (): boolean | Promise { return false } - } diff --git a/server/core/lib/notifier/shared/follow/auto-follow-for-instance.ts b/server/core/lib/notifier/shared/follow/auto-follow-for-instance.ts index 027bf8eef..f6ea20f8e 100644 --- a/server/core/lib/notifier/shared/follow/auto-follow-for-instance.ts +++ b/server/core/lib/notifier/shared/follow/auto-follow-for-instance.ts @@ -1,11 +1,13 @@ -import { logger } from '@server/helpers/logger.js' -import { UserModel } from '@server/models/user/user.js' -import { UserNotificationModel } from '@server/models/user/user-notification.js' -import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' import { UserNotificationType, UserRight } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' +import { logger } from '@server/helpers/logger.js' +import { instanceFollowingUrl } from '@server/lib/client-urls.js' +import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' +import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' import { AbstractNotification } from '../common/abstract-notification.js' -export class AutoFollowForInstance extends AbstractNotification { +export class AutoFollowForInstance extends AbstractNotification { private admins: MUserDefault[] async prepare () { @@ -35,13 +37,21 @@ export class AutoFollowForInstance extends AbstractNotification ${instanceUrl}.` + subject: t('Auto platform follow', to.language), + text: `Your platform automatically followed ${subscription.getIdentifier()}`, + locals: { + action: { + text: t('View subscription', to.language), + url: instanceFollowingUrl + } + } } } diff --git a/server/core/lib/notifier/shared/follow/follow-for-instance.ts b/server/core/lib/notifier/shared/follow/follow-for-instance.ts index 76fa0332a..4e60b4974 100644 --- a/server/core/lib/notifier/shared/follow/follow-for-instance.ts +++ b/server/core/lib/notifier/shared/follow/follow-for-instance.ts @@ -1,13 +1,15 @@ +import { UserNotificationType, UserRight } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' import { logger } from '@server/helpers/logger.js' +import { CONFIG } from '@server/initializers/config.js' import { WEBSERVER } from '@server/initializers/constants.js' import { isBlockedByServerOrAccount } from '@server/lib/blocklist.js' -import { UserModel } from '@server/models/user/user.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' -import { UserNotificationType, UserRight } from '@peertube/peertube-models' import { AbstractNotification } from '../common/abstract-notification.js' -export class FollowForInstance extends AbstractNotification { +export class FollowForInstance extends AbstractNotification { private admins: MUserDefault[] async prepare () { @@ -43,19 +45,23 @@ export class FollowForInstance extends AbstractNotification { return notification } - createEmail (to: string) { - const awaitingApproval = this.actorFollow.state === 'pending' - ? ' awaiting manual approval.' - : '' + createEmail (user: MUserWithNotificationSetting) { + const to = { email: user.email, language: user.getLanguage() } + const language = user.getLanguage() + + const context = { instanceName: CONFIG.INSTANCE.NAME, handle: this.actorFollow.ActorFollower.getIdentifier() } + + const text = this.actorFollow.state === 'pending' + ? t('{instanceName} has a new follower, {handle}, awaiting manual approval.', language, context) + : t('{instanceName} has a new follower: {handle}.', language, context) return { to, - subject: 'New instance follower', - text: `Your instance has a new follower: ${this.actorFollow.ActorFollower.url}${awaitingApproval}.`, + subject: t('New follower for {instanceName}', language, { instanceName: CONFIG.INSTANCE.NAME }), + text, locals: { - title: 'New instance follower', action: { - text: 'Review followers', + text: t('Review followers', language), url: WEBSERVER.URL + '/admin/follows/followers-list' } } diff --git a/server/core/lib/notifier/shared/follow/follow-for-user.ts b/server/core/lib/notifier/shared/follow/follow-for-user.ts index bf915dfeb..3e79a136c 100644 --- a/server/core/lib/notifier/shared/follow/follow-for-user.ts +++ b/server/core/lib/notifier/shared/follow/follow-for-user.ts @@ -1,12 +1,13 @@ +import { UserNotificationType } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' import { logger } from '@server/helpers/logger.js' import { isBlockedByServerOrAccount } from '@server/lib/blocklist.js' -import { UserModel } from '@server/models/user/user.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' -import { UserNotificationType } from '@peertube/peertube-models' import { AbstractNotification } from '../common/abstract-notification.js' -export class FollowForUser extends AbstractNotification { +export class FollowForUser extends AbstractNotification { private followType: 'account' | 'channel' private user: MUserDefault @@ -56,22 +57,30 @@ export class FollowForUser extends AbstractNotification { return notification } - createEmail (to: string) { + createEmail (user: MUserWithNotificationSetting) { + const to = { email: user.email, language: user.getLanguage() } + const following = this.actorFollow.ActorFollowing const follower = this.actorFollow.ActorFollower - const followingName = (following.VideoChannel || following.Account).getDisplayName() + const followingAccountOrChannel = Object.assign(following.VideoChannel || following.Account, { Actor: following }) + const followerAccountOrChannel = Object.assign(follower.VideoChannel || follower.Account, { Actor: follower }) + const followingName = followingAccountOrChannel.getDisplayName() return { template: 'follower-on-channel', to, - subject: `New follower on your channel ${followingName}`, + + subject: this.followType === 'account' + ? t('New follower on your account {followingName}', to.language, { followingName }) + : t('New follower on your channel {followingName}', to.language, { followingName }), + locals: { followerName: follower.Account.getDisplayName(), - followerUrl: follower.url, + followerUrl: followerAccountOrChannel.getClientUrl(), + followingUrl: followingAccountOrChannel.getClientUrl(), followingName, - followingUrl: following.url, - followType: this.followType + accountFollowType: this.followType === 'account' } } } diff --git a/server/core/lib/notifier/shared/instance/direct-registration-for-moderators.ts b/server/core/lib/notifier/shared/instance/direct-registration-for-moderators.ts index 42078ba24..f7bbf9443 100644 --- a/server/core/lib/notifier/shared/instance/direct-registration-for-moderators.ts +++ b/server/core/lib/notifier/shared/instance/direct-registration-for-moderators.ts @@ -1,12 +1,14 @@ +import { UserNotificationType, UserRight } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' import { logger } from '@server/helpers/logger.js' import { CONFIG } from '@server/initializers/config.js' -import { UserModel } from '@server/models/user/user.js' +import { adminUsersListUrl } from '@server/lib/client-urls.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' import { MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' -import { UserNotificationType, UserRight } from '@peertube/peertube-models' import { AbstractNotification } from '../common/abstract-notification.js' -export class DirectRegistrationForModerators extends AbstractNotification { +export class DirectRegistrationForModerators extends AbstractNotification { private moderators: MUserDefault[] async prepare () { @@ -36,13 +38,22 @@ export class DirectRegistrationForModerators extends AbstractNotification { +export class NewPeerTubeVersionForAdmins extends AbstractNotification { private admins: MUserDefault[] async prepare () { @@ -41,11 +42,13 @@ export class NewPeerTubeVersionForAdmins extends AbstractNotification { +export class NewPluginVersionForAdmins extends AbstractNotification { private admins: MUserDefault[] async prepare () { @@ -37,16 +38,25 @@ export class NewPluginVersionForAdmins extends AbstractNotification { return notification } - createEmail (to: string) { - const pluginUrl = WEBSERVER.URL + '/admin/settings/plugins/list-installed?pluginType=' + this.plugin.type + createEmail (user: MUserWithNotificationSetting) { + const to = { email: user.email, language: user.getLanguage() } + const language = user.getLanguage() + + const pluginUrl = getPluginUrl(this.plugin.type) + const context = { pluginName: this.plugin.name, latestVersion: this.plugin.latestVersion } return { to, template: 'plugin-version-new', - subject: `A new plugin/theme version is available: ${this.plugin.name}@${this.plugin.latestVersion}`, + + subject: this.plugin.type === PluginType.PLUGIN + ? t('A new version of the plugin {pluginName} is available: {latestVersion}', language, context) + : t('A new version of the theme {pluginName} is available: {latestVersion}', language, context), + locals: { pluginName: this.plugin.name, latestVersion: this.plugin.latestVersion, + isPlugin: this.plugin.type === PluginType.PLUGIN, pluginUrl } } diff --git a/server/core/lib/notifier/shared/instance/registration-request-for-moderators.ts b/server/core/lib/notifier/shared/instance/registration-request-for-moderators.ts index 29dda28be..e6281f7ea 100644 --- a/server/core/lib/notifier/shared/instance/registration-request-for-moderators.ts +++ b/server/core/lib/notifier/shared/instance/registration-request-for-moderators.ts @@ -1,11 +1,14 @@ -import { logger } from '@server/helpers/logger.js' -import { UserModel } from '@server/models/user/user.js' -import { UserNotificationModel } from '@server/models/user/user-notification.js' -import { MRegistration, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' import { UserNotificationType, UserRight } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' +import { logger } from '@server/helpers/logger.js' +import { CONFIG } from '@server/initializers/config.js' +import { adminRegistrationsListUrl } from '@server/lib/client-urls.js' +import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' +import { MRegistration, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js' import { AbstractNotification } from '../common/abstract-notification.js' -export class RegistrationRequestForModerators extends AbstractNotification { +export class RegistrationRequestForModerators extends AbstractNotification { private moderators: MUserDefault[] async prepare () { @@ -35,13 +38,21 @@ export class RegistrationRequestForModerators extends AbstractNotification { +export abstract class AbstractOwnedVideoPublication extends AbstractNotification { protected user: MUserDefault async prepare () { @@ -38,17 +39,20 @@ export abstract class AbstractOwnedVideoPublication extends AbstractNotification return notification } - createEmail (to: string) { + createEmail (user: MUserWithNotificationSetting) { + const to = { email: user.email, language: user.getLanguage() } + const language = user.getLanguage() + const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath() return { to, - subject: `Your video ${this.payload.name} has been published`, - text: `Your video "${this.payload.name}" has been published.`, + subject: t('Your video has been published', language), + text: t('Your video {videoName} has been published.', language, { videoName: this.payload.name }), locals: { - title: 'Your video is live', + title: t('Your video is live', language), action: { - text: 'View video', + text: t('View video', language), url: videoUrl } } diff --git a/server/core/lib/notifier/shared/video-publication/import-finished-for-owner.ts b/server/core/lib/notifier/shared/video-publication/import-finished-for-owner.ts index 38f12d8cf..f8fb50f81 100644 --- a/server/core/lib/notifier/shared/video-publication/import-finished-for-owner.ts +++ b/server/core/lib/notifier/shared/video-publication/import-finished-for-owner.ts @@ -1,9 +1,11 @@ +import { To, UserNotificationType } from '@peertube/peertube-models' +import { t } from '@server/helpers/i18n.js' import { logger } from '@server/helpers/logger.js' import { WEBSERVER } from '@server/initializers/constants.js' -import { UserModel } from '@server/models/user/user.js' +import { myVideoImportsUrl } from '@server/lib/client-urls.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' import { MUserDefault, MUserWithNotificationSetting, MVideoImportVideo, UserNotificationModelForApi } from '@server/types/models/index.js' -import { UserNotificationType } from '@peertube/peertube-models' import { AbstractNotification } from '../common/abstract-notification.js' export type ImportFinishedForOwnerPayload = { @@ -11,7 +13,7 @@ export type ImportFinishedForOwnerPayload = { success: boolean } -export class ImportFinishedForOwner extends AbstractNotification { +export class ImportFinishedForOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -46,46 +48,47 @@ export class ImportFinishedForOwner extends AbstractNotification ${importUrl}.` + const text = t('Your video import {targetId} encountered an error.', language, { targetId }) return { to, - subject: `Your video import "${this.videoImport.getTargetIdentifier()}" encountered an error`, + subject: t('Your video import encountered an error', language), text, locals: { - title: 'Import failed', + title: t('Import failed', language), action: { - text: 'Review imports', - url: importUrl + text: t('Review imports', language), + url: myVideoImportsUrl } } } diff --git a/server/core/lib/notifier/shared/video-publication/new-video-or-live-for-subscribers.ts b/server/core/lib/notifier/shared/video-publication/new-video-or-live-for-subscribers.ts index 1940a55d6..1b5905330 100644 --- a/server/core/lib/notifier/shared/video-publication/new-video-or-live-for-subscribers.ts +++ b/server/core/lib/notifier/shared/video-publication/new-video-or-live-for-subscribers.ts @@ -1,12 +1,13 @@ +import { To, UserNotificationType, VideoPrivacy, VideoState } from '@peertube/peertube-models' import { logger } from '@server/helpers/logger.js' import { WEBSERVER } from '@server/initializers/constants.js' -import { UserModel } from '@server/models/user/user.js' import { UserNotificationModel } from '@server/models/user/user-notification.js' +import { UserModel } from '@server/models/user/user.js' import { MUserWithNotificationSetting, MVideoAccountLight, UserNotificationModelForApi } from '@server/types/models/index.js' -import { UserNotificationType, VideoPrivacy, VideoState } from '@peertube/peertube-models' import { AbstractNotification } from '../common/abstract-notification.js' +import { t } from '@server/helpers/i18n.js' -export class NewVideoOrLiveForSubscribers extends AbstractNotification { +export class NewVideoOrLiveForSubscribers extends AbstractNotification { private users: MUserWithNotificationSetting[] async prepare () { @@ -50,7 +51,9 @@ export class NewVideoOrLiveForSubscribers extends AbstractNotification { +export class StudioEditionFinishedForOwner extends AbstractNotification { private user: MUserDefault async prepare () { @@ -38,17 +39,18 @@ export class StudioEditionFinishedForOwner extends AbstractNotification a.toFormattedJSON()), banners: serverActor.Banners.map(b => b.toFormattedJSON()), @@ -512,6 +514,24 @@ class ServerConfigManager { return maxBy(this.getOpenGraphLogos(serverActor), 'width') } + getLogoUrl (serverActor: MActorUploadImages, width: 192 | 512) { + const customLogo = this.getLogo(serverActor, width) + + if (customLogo) { + return WEBSERVER.URL + customLogo.getStaticPath() + } + + return `${WEBSERVER.URL}/client/assets/images/icons/icon-${width}x${width}.png` + } + + getLogo (serverActor: MActorUploadImages, width: 192 | 512) { + if (serverActor.Avatars.length > 0) { + return findAppropriateImage(serverActor.Avatars, width) + } + + return undefined + } + private getFaviconLogos (serverActor: MActorUploadImages) { return this.getLogoWithFallbacks({ serverActor, diff --git a/server/core/lib/user-import-export/exporters/user-settings-exporter.ts b/server/core/lib/user-import-export/exporters/user-settings-exporter.ts index f63590493..ff6d2d702 100644 --- a/server/core/lib/user-import-export/exporters/user-settings-exporter.ts +++ b/server/core/lib/user-import-export/exporters/user-settings-exporter.ts @@ -1,8 +1,7 @@ import { AbstractUserExporter } from './abstract-user-exporter.js' import { UserSettingsExportJSON } from '@peertube/peertube-models' -export class UserSettingsExporter extends AbstractUserExporter { - +export class UserSettingsExporter extends AbstractUserExporter { export () { return { json: { @@ -19,6 +18,7 @@ export class UserSettingsExporter extends AbstractUserExporter @@ -46,6 +48,7 @@ export class UserSettingsImporter extends AbstractUserImporter { @Column autoPlayNextVideoPlaylist: boolean + @AllowNull(true) + @Column(DataType.STRING) + language: string + @AllowNull(true) @Default(null) @Is('UserVideoLanguages', value => throwIfNotValid(value, isUserVideoLanguages, 'video languages')) @@ -872,6 +876,16 @@ export class UserModel extends SequelizeModel { return UserModel.unscoped().findOne(query) } + static async loadForEmail (id: number) { + const user = await UserModel.unscoped().findByPk(id) + + if (!user) return undefined + + return { email: user.email, language: user.getLanguage() } + } + + // --------------------------------------------------------------------------- + static generateUserQuotaBaseSQL (options: { daily: boolean whereUserId: '$userId' | '"UserModel"."id"' @@ -981,6 +995,10 @@ export class UserModel extends SequelizeModel { return comparePassword(password, this.password) } + getLanguage () { + return this.language || CONFIG.INSTANCE.DEFAULT_LANGUAGE + } + toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User { const videoQuotaUsed = this.get('videoQuotaUsed') const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily') @@ -1026,6 +1044,8 @@ export class UserModel extends SequelizeModel { autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist, videoLanguages: this.videoLanguages, + language: this.getLanguage(), + role: { id: this.role, label: USER_ROLE_LABELS[this.role] diff --git a/server/core/types/express.d.ts b/server/core/types/express.d.ts index 63f5248d3..91240eba4 100644 --- a/server/core/types/express.d.ts +++ b/server/core/types/express.d.ts @@ -56,6 +56,8 @@ declare module 'express' { query: any method: HttpMethodType rawBody: Buffer // Allow plugin routes to access the raw body + + t: (key: string, context?: Record) => string } // --------------------------------------------------------------------------- diff --git a/server/locales/ar/translation.json b/server/locales/ar/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/ar/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/ca-ES/translation.json b/server/locales/ca-ES/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/ca-ES/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/cs-CZ/translation.json b/server/locales/cs-CZ/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/cs-CZ/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/de-DE/translation.json b/server/locales/de-DE/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/de-DE/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/el-GR/translation.json b/server/locales/el-GR/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/el-GR/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/en-US/translation.json b/server/locales/en-US/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/en-US/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/eo/translation.json b/server/locales/eo/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/eo/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/es-ES/translation.json b/server/locales/es-ES/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/es-ES/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/eu-ES/translation.json b/server/locales/eu-ES/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/eu-ES/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/fa-IR/translation.json b/server/locales/fa-IR/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/fa-IR/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/fi-FI/translation.json b/server/locales/fi-FI/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/fi-FI/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/fr-FR/translation.json b/server/locales/fr-FR/translation.json new file mode 100644 index 000000000..1a5e12695 --- /dev/null +++ b/server/locales/fr-FR/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "Nouveau message sur le signalement", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "Un nouveau message de {messageAccountName} a été publié sur le signalement #{abuseId}", + "Abuse report state changed": "État du signalement modifié", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Votre signalement #{abuseId} sur {instanceName} a été accepté.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Votre signalement #{abuseId} sur {instanceName} a été rejeté.", + "An account is pending moderation": "Un compte est en attente de modération", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} a reçu un signalement pour le compte : {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} a reçu un signalement pour le compte distant : {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "Le signaleur, {reporter}, a cité la/les raison(s) suivante(s) :", + "Someone just used the contact form": "Quelqu'un a utilisé le formulaire de contact", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} vous a envoyé un message via le formulaire de contact de {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "Vous pouvez contacter la personne à l'adresse {fromEmail}, ou simplement répondre à cet e-mail.", + "New follower on your channel": "Nouvel abonné de votre chaîne", + "Your account {followingName} has a new subscriber: {followerName}.": "Votre compte {followingName} a un nouvel abonné : {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Votre chaîne {followingName} a un nouvel abonné : {followerName}.", + "Your account has been blocked": "Votre compte a été bloqué", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Votre compte {username} a été bloqué par les modérateurs de {instanceName} pour la raison suivante :", + "Your account {username} has been blocked by {instanceName} moderators.": "Votre compte {username} a été bloqué par les modérateurs de {instanceName}.", + "Your account has been unblocked": "Votre compte a été débloqué", + "Your account {username} has been unblocked by {instanceName} moderators.": "Votre compte {username} a été débloqué par les modérateurs de {instanceName}.", + "Hi {username},": "Bonjour {username},", + "View in your notifications": "Voir dans vos notifications", + "Manage your notification preferences in your profile": "Gérer vos préférences de notification dans votre profil", + "Password creation for your account": "Création de mot de passe pour votre compte", + "Welcome to {instanceName}!": "Bienvenue sur {instanceName} !", + "Your username is: {username}.": "Votre nom d'utilisateur est : {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Veuillez cliquer sur le lien ci-dessous pour définir votre mot de passe (ce lien expirera dans sept jours) :", + "Create my password": "Créer mon mot de passe", + "Password reset for your account": "Réinitialisation de mot de passe pour votre compte", + "A reset password procedure for your account has been requested on {instanceName}.": "Une procédure de réinitialisation de mot de passe pour votre compte a été demandée sur {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Veuillez cliquer sur le lien ci-dessous pour le réinitialiser (le lien expirera dans 1 heure) :", + "Reset my password": "Réinitialiser mon mot de passe", + "If you are not the person who initiated this request, please let us know by replying to this email.": "Si vous n'êtes pas la personne qui a initié cette demande, veuillez nous le faire savoir en répondant à cet e-mail.", + "New PeerTube version available": "Nouvelle version de PeerTube disponible", + "A new version of PeerTube is available: {latestVersion}.": "Une nouvelle version de PeerTube est disponible : {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "Vous pouvez consulter les dernières actualités sur JoinPeerTube.", + "New plugin version available": "Nouvelle version de plugin disponible", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "Une nouvelle version du plugin {pluginName} est disponible : {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "Une nouvelle version du thème {pluginName} est disponible : {latestVersion}.", + "You might want to upgrade it on your admin interface.": "Vous voudrez peut-être faire la mise à jour sur votre interface d'administration.", + "Your export archive has been created": "Votre archive d'exportation a été créée", + "Your export archive has been created.": "Votre archive d'exportation a été créée.", + "You can download it in your account export page.": "Vous pouvez la télécharger dans votre page d'exportation de compte.", + "Failed to create your export archive": "Échec de la création de votre archive d'exportation", + "We are sorry but the generation of your export archive has failed:": "Nous sommes désolés mais la génération de votre archive d'exportation a échouée :", + "Please contact your administrator if the problem occurs again.": "Veuillez contacter votre administrateur si le problème se reproduit.", + "Your archive import has finished": "L'importation de votre archive est terminée", + "Imported: {success}": "Importé : {success}", + "Not imported as considered duplicate: {duplicates}": "Non importé car considéré comme doublon : {duplicates}", + "Not imported due to error: {errors}": "Non importé en raison d'une erreur : {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "L'importation de votre archive est terminée. Voici le résumé des objets importés :", + "User settings:": "Paramètres utilisateur :", + "Account (name, description, avatar...):": "Compte (nom, description, avatar...) :", + "Blocklist:": "Liste de blocage :", + "Channels:": "Chaînes :", + "Likes:": "J'aime :", + "Dislikes:": "Je n'aime pas :", + "Subscriptions:": "Abonnements :", + "Video Playlists:": "Playlists vidéo :", + "Videos:": "Vidéos :", + "Video history:": "Historique vidéo :", + "Watched Words Lists:": "Listes de mots surveillés :", + "Comment auto tag policies:": "Politiques d'auto-étiquetage des commentaires :", + "Failed to import your archive": "Échec de l'importation de votre archive", + "We are sorry but the import of your archive has failed:": "Nous sommes désolés mais l'importation de votre archive a échoué :", + "A new user registered": "Un nouvel utilisateur s'est inscrit", + "User {userUsername} just registered.": "L'utilisateur {userUsername} vient de s'inscrire.", + "You might want to contact them at {userEmail}.": "Vous pourriez vouloir contacter l'utilisateur via {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "Vous pourriez vouloir contacter l'utilisateur via {userEmail} (l'e-mail n'a pas encore été vérifié).", + "Congratulation {username}, your registration request has been accepted!": "Félicitations {username}, votre demande d'inscription a été acceptée !", + "Your registration request has been accepted.": "Votre demande d'inscription a été acceptée.", + "Moderators sent you the following message:": "Les modérateurs vous ont envoyé le message suivant :", + "Registration request of your account {username} has rejected": "La demande d'inscription de votre compte {username} a été rejetée", + "Your registration request has been rejected.": "Votre demande d'inscription a été rejetée.", + "A new user wants to register": "Un nouvel utilisateur souhaite s'inscrire", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Vérification d'e-mail", + "You requested an account on {instanceName}.": "Vous avez demandé un compte sur {instanceName}.", + "To complete your registration request you must verify your email first!": "Pour compléter votre demande d'inscription, vous devez d'abord vérifier votre e-mail !", + "You created an account on {instanceName}.": "Vous avez créé un compte sur {instanceName}.", + "To start using your account you must verify your email first!": "Pour commencer à utiliser votre compte, vous devez d'abord vérifier votre e-mail !", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Veuillez cliquer sur le lien ci-dessous pour vérifier que cet e-mail vous appartient (le lien expirera dans 1 heure) :", + "Verify my email": "Vérifier mon e-mail", + "You requested to change your email.": "Vous avez demandé à changer votre e-mail.", + "A video is pending moderation": "Une vidéo est en attente de modération", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} a reçu un signalement pour la vidéo {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} a reçu un signalement pour la vidéo distante {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "La vidéo a été mise en ligne par la chaîne {channelDisplayName}.", + "It was published on {videoPublishedAt}.": "Elle a été publiée le {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "Elle a été mise en ligne le {videoCreatedAt} mais n'est pas encore publiée.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "Une vidéo récemment ajoutée a été automatiquement bloquée et nécessite une révision par un modérateur avant d'être rendue publique : {videoName} par {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "En dehors du propriétaire et de l'équipe de modération, personne ne pourra voir la vidéo tant que vous ne la débloquez pas.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "Si vous faites confiance au propriétaire, tout administrateur peut mettre l'utilisateur sur liste blanche pour les prochaines vidéos afin qu'elles ne nécessitent pas d'approbation avant d'être rendues publiques.", + "A comment is pending moderation": "Un commentaire est en attente de modération", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} a reçu un signalement pour le commentaire sur la vidéo {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} a reçu un signalement pour le commentaire distant sur la vidéo {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "Le commentaire a été publié le {commentCreatedAt} par {flaggedAccount} .", + "Someone mentioned you": "Quelqu'un vous a mentionné", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} vous a mentionné dans un commentaire de la vidéo {videoName} :", + "Someone commented your video": "Quelqu'un a commenté votre vidéo", + "{accountName} added a comment on your video {videoName}:": "{accountName} a ajouté un commentaire sur votre vidéo {videoName} :", + "This comment requires approval.": "Ce commentaire nécessite une approbation.", + "Your video has been blocked": "Votre vidéo a été bloquée", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Votre vidéo {videoName} a été bloquée par les modérateurs de {instanceName} pour la raison suivante :", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Votre vidéo {videoName} a été bloquée par les modérateurs de {instanceName}.", + "Your video has been unblocked": "Votre vidéo a été débloquée", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Votre vidéo {videoName} a été débloquée par les modérateurs de {instanceName}.", + "Reset your account password": "Réinitialiser le mot de passe de votre compte", + "Create your account password": "Créer le mot de passe de votre compte", + "Verify your email on {instanceName}": "Vérifiez votre e-mail sur {instanceName}", + "Contact form - {subject}": "Formulaire de contact - {subject}", + "Your registration request for {username} has been accepted": "Votre demande d'inscription pour {username} a été acceptée", + "Login to your account": "Connectez-vous à votre compte", + "Your registration request for {username} has been rejected": "Votre demande d'inscription pour {username} a été rejetée", + "New message on report #{id}": "Nouveau message sur le signalement #{id}", + "View report #{id}": "Voir le signalement #{id}", + "Report #{id} has been accepted": "Le signalement #{id} a été accepté", + "Report #{id} has been rejected": "Le signalement #{id} a été rejeté", + "New video abuse report from {reporter}": "Nouveau signalement vidéo de {reporter}", + "New comment abuse report from {reporter}": "Nouveau signalement de commentaire de {reporter}", + "New account abuse report from {reporter}": "Nouveau signalement de compte de {reporter}", + "A new video is pending moderation": "Une nouvelle vidéo est en attente de modération", + "Review video": "Examiner la vidéo", + "View video": "Voir la vidéo", + "Transcription of your video has been generated": "La transcription de votre vidéo a été générée", + "Transcription in {language} of your video {videoName} has been generated.": "La transcription en {language} de votre vidéo {videoName} a été générée.", + "Mention on video {videoName}": "Mention sur la vidéo {videoName}", + "View comment": "Voir le commentaire", + "New comment on your video": "Nouveau commentaire sur votre vidéo", + "Review comment": "Examiner le commentaire", + "Auto platform follow": "Abonnement de automatique de plateforme", + "View subscription": "Voir l'abonnement", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} a un nouvel abonné, {followerUrl}, en attente d'approbation.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} a un nouvel abonné : {followerUrl}.", + "New follower for {instanceName}": "Nouvel abonné pour {instanceName}", + "Review followers": "Examiner les abonnés", + "New follower on your account {followingName}": "Nouvel abonné sur votre compte {followingName}", + "New follower on your channel {followingName}": "Nouvel abonné sur votre chaîne {followingName}", + "A new user registered on {instanceName}": "Un nouvel utilisateur s'est inscrit sur {instanceName}", + "A new PeerTube version is available: {latestVersion}": "Une nouvelle version de PeerTube est disponible : {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "Une nouvelle version du plugin {pluginName} est disponible : {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "Une nouvelle version du thème {pluginName} est disponible : {latestVersion}", + "A new user wants to register: {username}": "Un nouvel utilisateur souhaite s'inscrire : {username}", + "View registration request": "Voir la demande d'inscription", + "Your video has been published": "Votre vidéo a été publiée", + "Your video {videoName} has been published.": "Votre vidéo {videoName} a été publiée.", + "Your video is live": "Votre vidéo est en ligne", + "Your video import is complete": "L'importation de votre vidéo est terminée", + "Your video {targetId} has just finished importing.": "Votre vidéo {targetId} vient de terminer son importation.", + "Your video import targetId encountered an error.": "L'importation de votre vidéo {targetId} a rencontré une erreur.", + "Your video import encountered an error": "L'importation de votre vidéo a rencontré une erreur", + "Import failed": "Échec de l'importation", + "Review imports": "Examiner les importations", + "{channelName} is live streaming": "{channelName} est en direct", + "Your subscription {channelName} is live streaming {videoName}": "Votre abonnement {channelName} diffuse en direct {videoName}", + "Edition of your video has finished": "L'édition de votre vidéo est terminée", + "Edition of your video {videoName} has finished.": "L'édition de votre vidéo {videoName} est terminée.", + "Video edition has finished": "L'édition de la vidéo est terminée" +} diff --git a/server/locales/gd/translation.json b/server/locales/gd/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/gd/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/gl-ES/translation.json b/server/locales/gl-ES/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/gl-ES/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/hr/translation.json b/server/locales/hr/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/hr/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/hu-HU/translation.json b/server/locales/hu-HU/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/hu-HU/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/is/translation.json b/server/locales/is/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/is/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/it-IT/translation.json b/server/locales/it-IT/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/it-IT/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/ja-JP/translation.json b/server/locales/ja-JP/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/ja-JP/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/kab/translation.json b/server/locales/kab/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/kab/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/nb-NO/translation.json b/server/locales/nb-NO/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/nb-NO/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/nl-NL/translation.json b/server/locales/nl-NL/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/nl-NL/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/nn/translation.json b/server/locales/nn/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/nn/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/oc/translation.json b/server/locales/oc/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/oc/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/pl-PL/translation.json b/server/locales/pl-PL/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/pl-PL/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/pt-BR/translation.json b/server/locales/pt-BR/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/pt-BR/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/pt-PT/translation.json b/server/locales/pt-PT/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/pt-PT/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/ru-RU/translation.json b/server/locales/ru-RU/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/ru-RU/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/sk-SK/translation.json b/server/locales/sk-SK/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/sk-SK/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/sq/translation.json b/server/locales/sq/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/sq/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/sv-SE/translation.json b/server/locales/sv-SE/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/sv-SE/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/th-TH/translation.json b/server/locales/th-TH/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/th-TH/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/tok/translation.json b/server/locales/tok/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/tok/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/tr-TR/translation.json b/server/locales/tr-TR/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/tr-TR/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/uk-UA/translation.json b/server/locales/uk-UA/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/uk-UA/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/vi-VN/translation.json b/server/locales/vi-VN/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/vi-VN/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/zh-Hans-CN/translation.json b/server/locales/zh-Hans-CN/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/zh-Hans-CN/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/locales/zh-Hant-TW/translation.json b/server/locales/zh-Hant-TW/translation.json new file mode 100644 index 000000000..dfdcef08b --- /dev/null +++ b/server/locales/zh-Hant-TW/translation.json @@ -0,0 +1,160 @@ +{ + "New message on abuse report": "New message on abuse report", + "A new message by {messageAccountName} was posted on abuse report #{abuseId}": "A new message by {messageAccountName} was posted on abuse report #{abuseId}", + "Abuse report state changed": "Abuse report state changed", + "Your abuse report #{abuseId} on {instanceName} has been accepted.": "Your abuse report #{abuseId} on {instanceName} has been accepted.", + "Your abuse report #{abuseId} on {instanceName} has been rejected.": "Your abuse report #{abuseId} on {instanceName} has been rejected.", + "An account is pending moderation": "An account is pending moderation", + "{instanceName} received an abuse report for the account: {accountDisplayName}": "{instanceName} received an abuse report for the account: {accountDisplayName}", + "{instanceName} received an abuse report for the remote account: {accountDisplayName}": "{instanceName} received an abuse report for the remote account: {accountDisplayName}", + "The reporter, {reporter}, cited the following reason(s):": "The reporter, {reporter}, cited the following reason(s):", + "Someone just used the contact form": "Someone just used the contact form", + "{fromName} sent you a message via the contact form on {instanceName}: ": "{fromName} sent you a message via the contact form on {instanceName}: ", + "You can contact them at {fromEmail}, or simply reply to this email to get in touch.": "You can contact them at {fromEmail}, or simply reply to this email to get in touch.", + "New follower on your channel": "New follower on your channel", + "Your account {followingName} has a new subscriber: {followerName}.": "Your account {followingName} has a new subscriber: {followerName}.", + "Your channel {followingName} has a new subscriber: {followerName}.": "Your channel {followingName} has a new subscriber: {followerName}.", + "Your account has been blocked": "Your account has been blocked", + "Your account {username} has been blocked by {instanceName} moderators for the following reason:": "Your account {username} has been blocked by {instanceName} moderators for the following reason:", + "Your account {username} has been blocked by {instanceName} moderators.": "Your account {username} has been blocked by {instanceName} moderators.", + "Your account has been unblocked": "Your account has been unblocked", + "Your account {username} has been unblocked by {instanceName} moderators.": "Your account {username} has been unblocked by {instanceName} moderators.", + "Hi {username},": "Hi {username},", + "View in your notifications": "View in your notifications", + "Manage your notification preferences in your profile": "Manage your notification preferences in your profile", + "Password creation for your account": "Password creation for your account", + "Welcome to {instanceName}!": "Welcome to {instanceName}!", + "Your username is: {username}.": "Your username is: {username}.", + "Please click on the link below to set your password (this link will expire within seven days):": "Please click on the link below to set your password (this link will expire within seven days):", + "Create my password": "Create my password", + "Password reset for your account": "Password reset for your account", + "A reset password procedure for your account has been requested on {instanceName}.": "A reset password procedure for your account has been requested on {instanceName}.", + "Please click on the link below to reset it (the link will expire within 1 hour):": "Please click on the link below to reset it (the link will expire within 1 hour):", + "Reset my password": "Reset my password", + "If you are not the person who initiated this request, please let us know by replying to this email.": "If you are not the person who initiated this request, please let us know by replying to this email.", + "New PeerTube version available": "New PeerTube version available", + "A new version of PeerTube is available: {latestVersion}.": "A new version of PeerTube is available: {latestVersion}.", + "You can check the latest news on JoinPeerTube.": "You can check the latest news on JoinPeerTube.", + "New plugin version available": "New plugin version available", + "A new version of the plugin {pluginName} is available: {latestVersion}.": "A new version of the plugin {pluginName} is available: {latestVersion}.", + "A new version of the theme {pluginName} is available: {latestVersion}.": "A new version of the theme {pluginName} is available: {latestVersion}.", + "You might want to upgrade it on your admin interface.": "You might want to upgrade it on your admin interface.", + "Your export archive has been created": "Your export archive has been created", + "Your export archive has been created.": "Your export archive has been created.", + "You can download it in your account export page.": "You can download it in your account export page.", + "Failed to create your export archive": "Failed to create your export archive", + "We are sorry but the generation of your export archive has failed:": "We are sorry but the generation of your export archive has failed:", + "Please contact your administrator if the problem occurs again.": "Please contact your administrator if the problem occurs again.", + "Your archive import has finished": "Your archive import has finished", + "Imported: {success}": "Imported: {success}", + "Not imported as considered duplicate: {duplicates}": "Not imported as considered duplicate: {duplicates}", + "Not imported due to error: {errors}": "Not imported due to error: {errors}", + "Your archive import has finished. Here is the summary of imported objects:": "Your archive import has finished. Here is the summary of imported objects:", + "User settings:": "User settings:", + "Account (name, description, avatar...):": "Account (name, description, avatar...):", + "Blocklist:": "Blocklist:", + "Channels:": "Channels:", + "Likes:": "Likes:", + "Dislikes:": "Dislikes:", + "Subscriptions:": "Subscriptions:", + "Video Playlists:": "Video Playlists:", + "Videos:": "Videos:", + "Video history:": "Video history:", + "Watched Words Lists:": "Watched Words Lists:", + "Comment auto tag policies:": "Comment auto tag policies:", + "Failed to import your archive": "Failed to import your archive", + "We are sorry but the import of your archive has failed:": "We are sorry but the import of your archive has failed:", + "A new user registered": "A new user registered", + "User {userUsername} just registered.": "User {userUsername} just registered.", + "You might want to contact them at {userEmail}.": "You might want to contact them at {userEmail}.", + "You might want to contact them at {userEmail} (the email has not been verified yet).": "You might want to contact them at {userEmail} (the email has not been verified yet).", + "Congratulation {username}, your registration request has been accepted!": "Congratulation {username}, your registration request has been accepted!", + "Your registration request has been accepted.": "Your registration request has been accepted.", + "Moderators sent you the following message:": "Moderators sent you the following message:", + "Registration request of your account {username} has rejected": "Registration request of your account {username} has rejected", + "Your registration request has been rejected.": "Your registration request has been rejected.", + "A new user wants to register": "A new user wants to register", + "User {registrationUsername} wants to register on {instanceName} for the following reason:": "User {registrationUsername} wants to register on {instanceName} for the following reason:", + "Email verification": "Email verification", + "You requested an account on {instanceName}.": "You requested an account on {instanceName}.", + "To complete your registration request you must verify your email first!": "To complete your registration request you must verify your email first!", + "You created an account on {instanceName}.": "You created an account on {instanceName}.", + "To start using your account you must verify your email first!": "To start using your account you must verify your email first!", + "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):": "Please click on the link below to verify this email belongs to you (the link will expire within 1 hour):", + "Verify my email": "Verify my email", + "You requested to change your email.": "You requested to change your email.", + "A video is pending moderation": "A video is pending moderation", + "{instanceName} received an abuse report for the video {videoName}.": "{instanceName} received an abuse report for the video {videoName}.", + "{instanceName} received an abuse report for the remote video {videoName}.": "{instanceName} received an abuse report for the remote video {videoName}.", + "The video was uploaded by {channelDisplayName} channel.": "The video was uploaded by {channelDisplayName} channel.", + "It was published on {videoPublishedAt}.": "It was published on {videoPublishedAt}.", + "It was uploaded on {videoCreatedAt} but not yet published.": "It was uploaded on {videoCreatedAt} but not yet published.", + "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.": "A recently added video was automatically blocked and requires moderator review before going public: {videoName} by {channelDisplayName}.", + "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.": "Apart from the publisher and the moderation team, no one will be able to see the video until you unblock it.", + "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.": "If you trust the publisher, any admin can whitelist the user for later videos so that they don't require approval before going public.", + "A comment is pending moderation": "A comment is pending moderation", + "{instanceName} received an abuse report for the comment on video {videoName}.": "{instanceName} received an abuse report for the comment on video {videoName}.", + "{instanceName} received an abuse report for the remote comment on video {videoName}.": "{instanceName} received an abuse report for the remote comment on video {videoName}.", + "The comment was posted on {commentCreatedAt} by {flaggedAccount} .": "The comment was posted on {commentCreatedAt} by {flaggedAccount} .", + "Someone mentioned you": "Someone mentioned you", + "{accountName} mentioned you in a comment on video {videoName}:": "{accountName} mentioned you in a comment on video {videoName}:", + "Someone commented your video": "Someone commented your video", + "{accountName} added a comment on your video {videoName}:": "{accountName} added a comment on your video {videoName}:", + "This comment requires approval.": "This comment requires approval.", + "Your video has been blocked": "Your video has been blocked", + "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:": "Your video {videoName} has been blocked by {instanceName} moderators for the following reason:", + "Your video {videoName} has been blocked by {instanceName} moderators.": "Your video {videoName} has been blocked by {instanceName} moderators.", + "Your video has been unblocked": "Your video has been unblocked", + "Your video {videoName} has been unblocked by {instanceName} moderators.": "Your video {videoName} has been unblocked by {instanceName} moderators.", + "Reset your account password": "Reset your account password", + "Create your account password": "Create your account password", + "Verify your email on {instanceName}": "Verify your email on {instanceName}", + "Contact form - {subject}": "Contact form - {subject}", + "Your registration request for {username} has been accepted": "Your registration request for {username} has been accepted", + "Login to your account": "Login to your account", + "Your registration request for {username} has been rejected": "Your registration request for {username} has been rejected", + "New message on report #{id}": "New message on report #{id}", + "View report #{id}": "View report #{id}", + "Report #{id} has been accepted": "Report #{id} has been accepted", + "Report #{id} has been rejected": "Report #{id} has been rejected", + "New video abuse report from {reporter}": "New video abuse report from {reporter}", + "New comment abuse report from {reporter}": "New comment abuse report from {reporter}", + "New account abuse report from {reporter}": "New account abuse report from {reporter}", + "A new video is pending moderation": "A new video is pending moderation", + "Review video": "Review video", + "View video": "View video", + "Transcription of your video has been generated": "Transcription of your video has been generated", + "Transcription in {language} of your video {videoName} has been generated.": "Transcription in {language} of your video {videoName} has been generated.", + "Mention on video {videoName}": "Mention on video {videoName}", + "View comment": "View comment", + "New comment on your video": "New comment on your video", + "Review comment": "Review comment", + "Auto platform follow": "Auto platform follow", + "View subscription": "View subscription", + "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.": "{instanceName} has a new follower, {followerUrl}, awaiting manual approval.", + "{instanceName} has a new follower: {followerUrl}.": "{instanceName} has a new follower: {followerUrl}.", + "New follower for {instanceName}": "New follower for {instanceName}", + "Review followers": "Review followers", + "New follower on your account {followingName}": "New follower on your account {followingName}", + "New follower on your channel {followingName}": "New follower on your channel {followingName}", + "A new user registered on {instanceName}": "A new user registered on {instanceName}", + "A new PeerTube version is available: {latestVersion}": "A new PeerTube version is available: {latestVersion}", + "A new version of the plugin {pluginName} is available: {latestVersion}": "A new version of the plugin {pluginName} is available: {latestVersion}", + "A new version of the theme {pluginName} is available: {latestVersion}": "A new version of the theme {pluginName} is available: {latestVersion}", + "A new user wants to register: {username}": "A new user wants to register: {username}", + "View registration request": "View registration request", + "Your video has been published": "Your video has been published", + "Your video {videoName} has been published.": "Your video {videoName} has been published.", + "Your video is live": "Your video is live", + "Your video import is complete": "Your video import is complete", + "Your video {targetId} has just finished importing.": "Your video {targetId} has just finished importing.", + "Your video import targetId encountered an error.": "Your video import targetId encountered an error.", + "Your video import encountered an error": "Your video import encountered an error", + "Import failed": "Import failed", + "Review imports": "Review imports", + "{channelName} is live streaming": "{channelName} is live streaming", + "Your subscription {channelName} is live streaming {videoName}": "Your subscription {channelName} is live streaming {videoName}", + "Edition of your video has finished": "Edition of your video has finished", + "Edition of your video {videoName} has finished.": "Edition of your video {videoName} has finished.", + "Video edition has finished": "Video edition has finished" +} diff --git a/server/server.ts b/server/server.ts index eca0dd13f..ebf8c3391 100644 --- a/server/server.ts +++ b/server/server.ts @@ -10,6 +10,7 @@ import { checkMissedConfig, checkFFmpeg, checkNodeVersion } from './core/initial import { CONFIG } from './core/initializers/config.js' import { API_VERSION, WEBSERVER, loadLanguages } from './core/initializers/constants.js' import { logger } from './core/helpers/logger.js' +import { initI18n, useI18n } from '@server/helpers/i18n.js' const missed = checkMissedConfig() if (missed.length !== 0) { @@ -55,8 +56,10 @@ migrate() }) // ----------- Initialize ----------- -loadLanguages() - .catch(err => logger.error('Cannot load languages', { err })) +Promise.all([ + initI18n(), + loadLanguages() +]).catch(err => logger.error('Cannot load i18n/languages', { err })) // Express configuration import express from 'express' @@ -83,6 +86,8 @@ app.use((_req, res, next) => { return next() }) +app.use(useI18n) + // Security middleware import { baseCSP } from './core/middlewares/csp.js' diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index d84d89306..b0b52652e 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml @@ -309,6 +309,8 @@ tags: Manage runner registration token - name: Video Passwords description: Operation on video passwords + - name: Client Config + description: Configuration of the web client x-tagGroups: - name: Static endpoints @@ -367,6 +369,7 @@ x-tagGroups: - name: Instance tags: - Config + - Client Config - Homepage - Instance Follows - Instance Redundancy @@ -7321,6 +7324,28 @@ paths: responses: '204': description: successful operation + /api/v1/client-config/update-language: + post: + tags: + - Client Config + summary: Update client language + description: Set a cookie so that, the next time the client refreshes the HTML of the web interface, PeerTube will use the next language + operationId: updateClientLanguage + requestBody: + content: + application/json: + schema: + type: object + properties: + language: + type: string + description: Language code to set + example: 'en-US' + required: + - language + responses: + '204': + description: successful operation servers: - url: 'https://peertube2.cpy.re' @@ -9491,6 +9516,8 @@ components: type: string serverCountry: type: string + defaultLanguage: + type: string support: type: object properties: @@ -10674,6 +10701,9 @@ components: items: type: string description: list of languages to filter videos down to + language: + type: string + description: default language for this user theme: type: string noInstanceConfigWarningModal: diff --git a/support/doc/translation.md b/support/doc/translation.md index 3852865cc..fa222fa7e 100644 --- a/support/doc/translation.md +++ b/support/doc/translation.md @@ -14,7 +14,7 @@ You can get a chance to see translations before the official release by going to * Create an account: https://weblate.framasoft.org/accounts/register/ * Validate your email and follow the link sent - * Create your password (keep the `Current password` field empty) and setup your account + * Create your password (keep the `Current password` field empty) and set up your account * To translate the PeerTube web, visit the PeerTube project page: https://weblate.framasoft.org/projects/peertube/ * To translate the PeerTube mobile application, visit the PeerTube App project page: https://weblate.framasoft.org/projects/peertube-app/ * Choose the file and the locale you want to translate @@ -26,8 +26,8 @@ There are 4 files: * **angular**: contains client strings * **player**: contains player strings. Most of the strings come from VideoJS, so you can help yourself by using [video.js JSON files](https://github.com/videojs/video.js/tree/master/lang) - * **server**: contains server strings (privacies, licences...) and iso639 (languages) strings used by PeerTube to describe the audio language of a particular video. - It's the reason why these strings should be translated too. There are many strings so do not hesitate to translate only main audio languages. + * **server**: contains server strings clients can fetch in JSON format so they don't have to translate common PeerTube strings themselves (iso639 languages, privacies, licences...) + * **server-internal**: contains internal server strings used in the REST API responses or emails ## Tips @@ -41,7 +41,7 @@ For example: - views ``` -should be in french +should be in French ``` - vues ``` @@ -57,7 +57,7 @@ For example: {VAR_PLURAL, plural, =0 {No videos} =1 {1 video} other { videos} } ``` -should be in french +should be in French ``` {VAR_PLURAL, plural, =0 {Aucune vidéo} =1 {1 vidéo} other { vidéos} } diff --git a/yarn.lock b/yarn.lock index f720db1b5..4b8b1abfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,6 +44,17 @@ ajv-draft-04 "^1.0.0" call-me-maybe "^1.0.2" +"@asamuzakjp/css-color@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-3.2.0.tgz#cc42f5b85c593f79f1fa4f25d2b9b321e61d1794" + integrity sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw== + dependencies: + "@csstools/css-calc" "^2.1.3" + "@csstools/css-color-parser" "^3.0.9" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + lru-cache "^10.4.3" + "@assemblyscript/loader@^0.19.21": version "0.19.23" resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.19.23.tgz#7fccae28d0a2692869f1d1219d36093bc24d5e72" @@ -679,6 +690,11 @@ dependencies: "@babel/types" "^7.27.1" +"@babel/runtime@^7.25.0", "@babel/runtime@^7.26.10", "@babel/runtime@^7.27.6": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== + "@babel/template@^7.27.1": version "7.27.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" @@ -724,6 +740,34 @@ resolved "https://registry.yarnpkg.com/@commander-js/extra-typings/-/extra-typings-13.1.0.tgz#026e29b04401c92fc4307223fbaadf1ff3e5551e" integrity sha512-q5P52BYb1hwVWE6dtID7VvuJWrlfbCv4klj7BjUUOqMz4jbSZD4C9fJ9lRjL2jnBGTg+gDDlaXN51rkWcLk4fg== +"@csstools/color-helpers@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.2.tgz#82592c9a7c2b83c293d9161894e2a6471feb97b8" + integrity sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA== + +"@csstools/css-calc@^2.1.3", "@csstools/css-calc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.4.tgz#8473f63e2fcd6e459838dd412401d5948f224c65" + integrity sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ== + +"@csstools/css-color-parser@^3.0.9": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz#79fc68864dd43c3b6782d2b3828bc0fa9d085c10" + integrity sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg== + dependencies: + "@csstools/color-helpers" "^5.0.2" + "@csstools/css-calc" "^2.1.4" + +"@csstools/css-parser-algorithms@^3.0.4": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz#5755370a9a29abaec5515b43c8b3f2cf9c2e3076" + integrity sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ== + +"@csstools/css-tokenizer@^3.0.3": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" + integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw== + "@dabh/diagnostics@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" @@ -747,126 +791,256 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz#830d6476cbbca0c005136af07303646b419f1162" integrity sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q== +"@esbuild/aix-ppc64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz#164b19122e2ed54f85469df9dea98ddb01d5e79e" + integrity sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw== + "@esbuild/android-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz#d11d4fc299224e729e2190cacadbcc00e7a9fd67" integrity sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A== +"@esbuild/android-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz#8f539e7def848f764f6432598e51cc3820fde3a5" + integrity sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA== + "@esbuild/android-arm@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.4.tgz#5660bd25080553dd2a28438f2a401a29959bd9b1" integrity sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ== +"@esbuild/android-arm@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.6.tgz#4ceb0f40113e9861169be83e2a670c260dd234ff" + integrity sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg== + "@esbuild/android-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.4.tgz#18ddde705bf984e8cd9efec54e199ac18bc7bee1" integrity sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ== +"@esbuild/android-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.6.tgz#ad4f280057622c25fe985c08999443a195dc63a8" + integrity sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A== + "@esbuild/darwin-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz#b0b7fb55db8fc6f5de5a0207ae986eb9c4766e67" integrity sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g== +"@esbuild/darwin-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz#d1f04027396b3d6afc96bacd0d13167dfd9f01f7" + integrity sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA== + "@esbuild/darwin-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz#e6813fdeba0bba356cb350a4b80543fbe66bf26f" integrity sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A== +"@esbuild/darwin-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz#2b4a6cedb799f635758d7832d75b23772c8ef68f" + integrity sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg== + "@esbuild/freebsd-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz#dc11a73d3ccdc308567b908b43c6698e850759be" integrity sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ== +"@esbuild/freebsd-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz#a26266cc97dd78dc3c3f3d6788b1b83697b1055d" + integrity sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg== + "@esbuild/freebsd-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz#91da08db8bd1bff5f31924c57a81dab26e93a143" integrity sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ== +"@esbuild/freebsd-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz#9feb8e826735c568ebfd94859b22a3fbb6a9bdd2" + integrity sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ== + "@esbuild/linux-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz#efc15e45c945a082708f9a9f73bfa8d4db49728a" integrity sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ== +"@esbuild/linux-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz#c07cbed8e249f4c28e7f32781d36fc4695293d28" + integrity sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ== + "@esbuild/linux-arm@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz#9b93c3e54ac49a2ede6f906e705d5d906f6db9e8" integrity sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ== +"@esbuild/linux-arm@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz#d6e2cd8ef3196468065d41f13fa2a61aaa72644a" + integrity sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw== + "@esbuild/linux-ia32@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz#be8ef2c3e1d99fca2d25c416b297d00360623596" integrity sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ== +"@esbuild/linux-ia32@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz#3e682bd47c4eddcc4b8f1393dfc8222482f17997" + integrity sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw== + "@esbuild/linux-loong64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz#b0840a2707c3fc02eec288d3f9defa3827cd7a87" integrity sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA== +"@esbuild/linux-loong64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz#473f5ea2e52399c08ad4cd6b12e6dbcddd630f05" + integrity sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg== + "@esbuild/linux-mips64el@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz#2a198e5a458c9f0e75881a4e63d26ba0cf9df39f" integrity sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg== +"@esbuild/linux-mips64el@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz#9960631c9fd61605b0939c19043acf4ef2b51718" + integrity sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw== + "@esbuild/linux-ppc64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz#64f4ae0b923d7dd72fb860b9b22edb42007cf8f5" integrity sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag== +"@esbuild/linux-ppc64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz#477cbf8bb04aa034b94f362c32c86b5c31db8d3e" + integrity sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw== + "@esbuild/linux-riscv64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz#fb2844b11fdddd39e29d291c7cf80f99b0d5158d" integrity sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA== +"@esbuild/linux-riscv64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz#bcdb46c8fb8e93aa779e9a0a62cd4ac00dcac626" + integrity sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w== + "@esbuild/linux-s390x@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz#1466876e0aa3560c7673e63fdebc8278707bc750" integrity sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g== +"@esbuild/linux-s390x@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz#f412cf5fdf0aea849ff51c73fd817c6c0234d46d" + integrity sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw== + "@esbuild/linux-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz#c10fde899455db7cba5f11b3bccfa0e41bf4d0cd" integrity sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA== +"@esbuild/linux-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz#d8233c09b5ebc0c855712dc5eeb835a3a3341108" + integrity sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig== + "@esbuild/netbsd-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz#02e483fbcbe3f18f0b02612a941b77be76c111a4" integrity sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ== +"@esbuild/netbsd-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz#f51ae8dd1474172e73cf9cbaf8a38d1c72dd8f1a" + integrity sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q== + "@esbuild/netbsd-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz#ec401fb0b1ed0ac01d978564c5fc8634ed1dc2ed" integrity sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw== +"@esbuild/netbsd-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz#a267538602c0e50a858cf41dcfe5d8036f8da8e7" + integrity sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g== + "@esbuild/openbsd-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz#f272c2f41cfea1d91b93d487a51b5c5ca7a8c8c4" integrity sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A== +"@esbuild/openbsd-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz#a51be60c425b85c216479b8c344ad0511635f2d2" + integrity sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg== + "@esbuild/openbsd-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz#2e25950bc10fa9db1e5c868e3d50c44f7c150fd7" integrity sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw== +"@esbuild/openbsd-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz#7e4a743c73f75562e29223ba69d0be6c9c9008da" + integrity sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw== + +"@esbuild/openharmony-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz#2087a5028f387879154ebf44bdedfafa17682e5b" + integrity sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA== + "@esbuild/sunos-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz#cd596fa65a67b3b7adc5ecd52d9f5733832e1abd" integrity sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q== +"@esbuild/sunos-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz#56531f861723ea0dc6283a2bb8837304223cb736" + integrity sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA== + "@esbuild/win32-arm64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz#b4dbcb57b21eeaf8331e424c3999b89d8951dc88" integrity sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ== +"@esbuild/win32-arm64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz#f4989f033deac6fae323acff58764fa8bc01436e" + integrity sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q== + "@esbuild/win32-ia32@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz#410842e5d66d4ece1757634e297a87635eb82f7a" integrity sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg== +"@esbuild/win32-ia32@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz#b260e9df71e3939eb33925076d39f63cec7d1525" + integrity sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ== + "@esbuild/win32-x64@0.25.4": version "0.25.4" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz#0b17ec8a70b2385827d52314c1253160a0b9bacc" integrity sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ== +"@esbuild/win32-x64@0.25.6": + version "0.25.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz#4276edd5c105bc28b11c6a1f76fb9d29d1bd25c1" + integrity sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA== + "@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.5.0", "@eslint-community/eslint-utils@^4.7.0": version "4.7.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" @@ -938,6 +1112,54 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== +"@formatjs/ecma402-abstract@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" + integrity sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA== + dependencies: + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.1" + decimal.js "^10.4.3" + tslib "^2.8.0" + +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== + dependencies: + tslib "^2.8.0" + +"@formatjs/icu-messageformat-parser@2.11.2": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz#85aea211bea40aa81ee1d44ac7accc3cf5500a73" + integrity sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/icu-skeleton-parser" "1.8.14" + tslib "^2.8.0" + +"@formatjs/icu-skeleton-parser@1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz#b9581d00363908efb29817fdffc32b79f41dabe5" + integrity sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + tslib "^2.8.0" + +"@formatjs/intl-localematcher@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== + dependencies: + tslib "^2.8.0" + +"@gulpjs/to-absolute-glob@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz#1fc2460d3953e1d9b9f2dfdb4bcc99da4710c021" + integrity sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA== + dependencies: + is-negated-glob "^1.0.0" + "@hapi/boom@^10.0.0": version "10.0.1" resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-10.0.1.tgz#ebb14688275ae150aa6af788dbe482e6a6062685" @@ -2949,11 +3171,21 @@ "@types/methods" "^1.1.4" "@types/superagent" "^8.1.0" +"@types/symlink-or-copy@^1.2.0": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/symlink-or-copy/-/symlink-or-copy-1.2.2.tgz#51b1c00b516a5774ada5d611e65eb123f988ef8d" + integrity sha512-MQ1AnmTLOncwEf9IVU+B2e4Hchrku5N67NkgcAHW0p3sdzPe0FNMANxEm6OJUzPniEQGkeT3OROLlCwZJLWFZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== +"@types/trusted-types@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + "@types/tv4@*": version "1.2.33" resolved "https://registry.yarnpkg.com/@types/tv4/-/tv4-1.2.33.tgz#f6ac0f85cabffde144a16bf7ef8c043e89d1854a" @@ -3185,7 +3417,7 @@ addr-to-ip-port@^2.0.0: resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-2.0.0.tgz#ab383c140392f3e99d5e9c34b88c259fa35274b1" integrity sha512-9bYbtjamtdLHZSqVIUXhilOryNPiL+x+Q5J/Unpg4VY3ZIkK3fT52UoErj1NdUeVm3J1t2iBEAur4Ywbl/bahw== -addressparser@^1.0.1: +addressparser@1.0.1, addressparser@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" integrity sha512-aQX7AISOMM7HFE0iZ3+YnD07oIeJqWGVnJ+ZIKaBZAk03ftmVYVqsGas/rbXKR21n4D/hKCSHypvcyOkds/xzg== @@ -3197,6 +3429,11 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.4" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" + integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== + ajv-draft-04@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" @@ -3274,6 +3511,14 @@ any-base@^1.1.0: resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== +anymatch@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + append-field@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" @@ -3766,6 +4011,15 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + block-iterator@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/block-iterator/-/block-iterator-1.1.1.tgz#3c8a94e083febf8da59d8baad1006ffee1a74694" @@ -3851,6 +4105,38 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" +broccoli-node-api@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/broccoli-node-api/-/broccoli-node-api-1.7.0.tgz#391aa6edecd2a42c63c111b4162956b2fa288cb6" + integrity sha512-QIqLSVJWJUVOhclmkmypJJH9u9s/aWH4+FH6Q6Ju5l+Io4dtwqdPUNmDfw40o6sxhbZHhqGujDJuHTML1wG8Yw== + +broccoli-node-info@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-2.2.0.tgz#feb01c13020792f429e01d7f7845dc5b3a7932b3" + integrity sha512-VabSGRpKIzpmC+r+tJueCE5h8k6vON7EIMMWu6d/FyPdtijwLQ7QvzShEw+m3mHoDzUaj/kiZsDYrS8X2adsBg== + +broccoli-output-wrapper@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/broccoli-output-wrapper/-/broccoli-output-wrapper-3.2.5.tgz#514b17801c92922a2c2f87fd145df2a25a11bc5f" + integrity sha512-bQAtwjSrF4Nu0CK0JOy5OZqw9t5U0zzv2555EA/cF8/a8SLDTIetk9UgrtMVw7qKLKdSpOZ2liZNeZZDaKgayw== + dependencies: + fs-extra "^8.1.0" + heimdalljs-logger "^0.1.10" + symlink-or-copy "^1.2.0" + +broccoli-plugin@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-4.0.7.tgz#dd176a85efe915ed557d913744b181abe05047db" + integrity sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg== + dependencies: + broccoli-node-api "^1.7.0" + broccoli-output-wrapper "^3.2.5" + fs-merger "^3.2.1" + promise-map-series "^0.3.0" + quick-temp "^0.1.8" + rimraf "^3.0.2" + symlink-or-copy "^1.3.1" + browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -4139,6 +4425,23 @@ cheerio@1.0.0-rc.12: parse5 "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0" +cheerio@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.1.0.tgz#87b9bec6dd3696e405ea79da7d2749d8308b0953" + integrity sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.2.2" + encoding-sniffer "^0.2.0" + htmlparser2 "^10.0.0" + parse5 "^7.3.0" + parse5-htmlparser2-tree-adapter "^7.1.0" + parse5-parser-stream "^7.1.2" + undici "^7.10.0" + whatwg-mimetype "^4.0.0" + chokidar@^4.0.1, chokidar@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" @@ -4231,6 +4534,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + cluster-key-slot@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" @@ -4286,6 +4594,11 @@ colors@1.0.x: resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== +colors@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + colorspace@1.1.x: version "1.1.4" resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" @@ -4306,6 +4619,11 @@ commander@11.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^13.1.0: version "13.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" @@ -4349,6 +4667,26 @@ compress-commons@^6.0.2: normalize-path "^3.0.0" readable-stream "^4.0.0" +compressible@~2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.8.1" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.1.tgz#4a45d909ac16509195a9a28bd91094889c180d79" + integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w== + dependencies: + bytes "3.1.2" + compressible "~2.0.18" + debug "2.6.9" + negotiator "~0.6.4" + on-headers "~1.1.0" + safe-buffer "5.2.1" + vary "~1.1.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4416,6 +4754,11 @@ content-type@^1.0.5, content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-parser@^1.4.3: version "1.4.7" resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.7.tgz#e2125635dfd766888ffe90d60c286404fa0e7b26" @@ -4570,6 +4913,14 @@ css-what@^6.1.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== +cssstyle@^4.0.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.6.0.tgz#ea18007024e3167f4f105315f3ec2d982bf48ed9" + integrity sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg== + dependencies: + "@asamuzakjp/css-color" "^3.2.0" + rrweb-cssom "^0.8.0" + cycle@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" @@ -4595,6 +4946,14 @@ data-uri-to-buffer@^4.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + data-view-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" @@ -4627,7 +4986,7 @@ dateformat@^4.6.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== -debug@2.6.9: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -4665,6 +5024,11 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decimal.js@^10.4.3: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -4903,6 +5267,13 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^3.1.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.6.tgz#ca040a6ad2b88e2a92dc45f38c79f84a714a1cad" + integrity sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + domutils@^2.4.2: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -4912,7 +5283,7 @@ domutils@^2.4.2: domelementtype "^2.2.0" domhandler "^4.2.0" -domutils@^3.0.1: +domutils@^3.0.1, domutils@^3.2.1, domutils@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78" integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== @@ -5020,6 +5391,14 @@ encoding-japanese@2.2.0: resolved "https://registry.yarnpkg.com/encoding-japanese/-/encoding-japanese-2.2.0.tgz#0ef2d2351250547f432a2dd155453555c16deb59" integrity sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A== +encoding-sniffer@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz#396ec97ac22ce5a037ba44af1992ac9d46a7b819" + integrity sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw== + dependencies: + iconv-lite "^0.6.3" + whatwg-encoding "^3.1.1" + end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -5066,6 +5445,11 @@ enhanced-resolve@^5.17.1: graceful-fs "^4.2.4" tapable "^2.2.0" +ensure-posix-path@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" + integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw== + entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -5081,6 +5465,11 @@ entities@^6.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.0.tgz#09c9e29cb79b0a6459a9b9db9efb418ac5bb8e51" integrity sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw== +eol@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/eol/-/eol-0.9.1.tgz#f701912f504074be35c6117a5c4ade49cd547acd" + integrity sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg== + err-code@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" @@ -5245,6 +5634,38 @@ es6-weak-map@^2.0.3: es6-iterator "^2.0.3" es6-symbol "^3.1.1" +esbuild@^0.25.0: + version "0.25.6" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.6.tgz#9b82a3db2fa131aec069ab040fd57ed0a880cdcd" + integrity sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.6" + "@esbuild/android-arm" "0.25.6" + "@esbuild/android-arm64" "0.25.6" + "@esbuild/android-x64" "0.25.6" + "@esbuild/darwin-arm64" "0.25.6" + "@esbuild/darwin-x64" "0.25.6" + "@esbuild/freebsd-arm64" "0.25.6" + "@esbuild/freebsd-x64" "0.25.6" + "@esbuild/linux-arm" "0.25.6" + "@esbuild/linux-arm64" "0.25.6" + "@esbuild/linux-ia32" "0.25.6" + "@esbuild/linux-loong64" "0.25.6" + "@esbuild/linux-mips64el" "0.25.6" + "@esbuild/linux-ppc64" "0.25.6" + "@esbuild/linux-riscv64" "0.25.6" + "@esbuild/linux-s390x" "0.25.6" + "@esbuild/linux-x64" "0.25.6" + "@esbuild/netbsd-arm64" "0.25.6" + "@esbuild/netbsd-x64" "0.25.6" + "@esbuild/openbsd-arm64" "0.25.6" + "@esbuild/openbsd-x64" "0.25.6" + "@esbuild/openharmony-arm64" "0.25.6" + "@esbuild/sunos-x64" "0.25.6" + "@esbuild/win32-arm64" "0.25.6" + "@esbuild/win32-ia32" "0.25.6" + "@esbuild/win32-x64" "0.25.6" + esbuild@^0.25.4, esbuild@~0.25.0: version "0.25.4" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.4.tgz#bb9a16334d4ef2c33c7301a924b8b863351a0854" @@ -5657,7 +6078,7 @@ express-validator@^7.0.1: lodash "^4.17.21" validator "~13.12.0" -express@^4.18.1, express@^4.21.1: +express@^4.18.1, express@^4.21.1, express@^4.21.2: version "4.21.2" resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== @@ -5835,7 +6256,7 @@ fast-xml-parser@^5.2.2: dependencies: strnum "^2.1.0" -fastq@^1.6.0: +fastq@^1.13.0, fastq@^1.6.0: version "1.19.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== @@ -6087,7 +6508,7 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^11.1.0: +fs-extra@^11.1.0, fs-extra@^11.2.0: version "11.3.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== @@ -6096,6 +6517,26 @@ fs-extra@^11.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^8.0.1, fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-merger@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/fs-merger/-/fs-merger-3.2.1.tgz#a225b11ae530426138294b8fbb19e82e3d4e0b3b" + integrity sha512-AN6sX12liy0JE7C2evclwoo0aCG3PFulLjrTLsJpWh/2mM+DinhpSGqYLbHBBbIW1PLRNcFhJG8Axtz8mQW3ug== + dependencies: + broccoli-node-api "^1.7.0" + broccoli-node-info "^2.1.0" + fs-extra "^8.0.1" + fs-tree-diff "^2.0.1" + walk-sync "^2.2.0" + fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -6103,6 +6544,14 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" +fs-mkdirp-stream@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz#1e82575c4023929ad35cf69269f84f1a8c973aa7" + integrity sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw== + dependencies: + graceful-fs "^4.2.8" + streamx "^2.12.0" + fs-native-extensions@^1.3.1: version "1.4.2" resolved "https://registry.yarnpkg.com/fs-native-extensions/-/fs-native-extensions-1.4.2.tgz#13b015e7a30e9555f68f504b57daef36d896ba73" @@ -6111,6 +6560,17 @@ fs-native-extensions@^1.3.1: require-addon "^1.1.0" which-runtime "^1.2.0" +fs-tree-diff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz#343e4745ab435ec39ebac5f9059ad919cd034afa" + integrity sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A== + dependencies: + "@types/symlink-or-copy" "^1.2.0" + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -6279,6 +6739,20 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-stream@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-8.0.3.tgz#87e63153aadf05bd0207cde1a253ee39d91458b9" + integrity sha512-fqZVj22LtFJkHODT+M4N1RJQ3TjnnQhfE9GwZI8qXscYarnhpip70poMldRnP8ipQ/w0B621kOhfc53/J9bd/A== + dependencies: + "@gulpjs/to-absolute-glob" "^4.0.0" + anymatch "^3.1.3" + fastq "^1.13.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + is-negated-glob "^1.0.0" + normalize-path "^3.0.0" + streamx "^2.12.5" + glob@7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -6396,7 +6870,7 @@ got@^14.4.5: responselike "^3.0.0" type-fest "^4.26.1" -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.8: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6406,6 +6880,25 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +gulp-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-sort/-/gulp-sort-2.0.0.tgz#c6762a2f1f0de0a3fc595a21599d3fac8dba1aca" + integrity sha512-MyTel3FXOdh1qhw1yKhpimQrAmur9q1X0ZigLmCOxouQD+BD3za9/89O+HfbgBQvvh4igEbp0/PUWO+VqGYG1g== + dependencies: + through2 "^2.0.1" + +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-async-hooks@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-async-hooks/-/has-async-hooks-1.0.0.tgz#3df965ade8cd2d9dbfdacfbca3e0a5152baaf204" @@ -6483,6 +6976,21 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +heimdalljs-logger@^0.1.10, heimdalljs-logger@^0.1.7: + version "0.1.10" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.10.tgz#90cad58aabb1590a3c7e640ddc6a4cd3a43faaf7" + integrity sha512-pO++cJbhIufVI/fmB/u2Yty3KJD0TqNPecehFae0/eps0hkZ3b4Zc/PezUMOpYuHFQbA7FxHZxa305EhmjLj4g== + dependencies: + debug "^2.2.0" + heimdalljs "^0.2.6" + +heimdalljs@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.6.tgz#b0eebabc412813aeb9542f9cc622cb58dbdcd9fe" + integrity sha512-o9bd30+5vLBvBtzCPwwGqpry2+n0Hi6H1+qwt6y+0kwRHGGF8TFIhJPmnuM0xO97zaKrDZMwO/V56fAnn8m/tA== + dependencies: + rsvp "~3.2.1" + helmet@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/helmet/-/helmet-8.1.0.tgz#f96d23fedc89e9476ecb5198181009c804b8b38c" @@ -6505,6 +7013,13 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + html-to-text@9.0.5, html-to-text@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-9.0.5.tgz#6149a0f618ae7a0db8085dca9bbf96d32bb8368d" @@ -6516,6 +7031,16 @@ html-to-text@9.0.5, html-to-text@^9.0.5: htmlparser2 "^8.0.2" selderee "^0.11.0" +htmlparser2@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-10.0.0.tgz#77ad249037b66bf8cc99c6e286ef73b83aeb621d" + integrity sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.2.1" + entities "^6.0.0" + htmlparser2@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-5.0.1.tgz#7daa6fc3e35d6107ac95a4fc08781f091664f6e7" @@ -6578,6 +7103,14 @@ http-problem-details@^0.1.5: resolved "https://registry.yarnpkg.com/http-problem-details/-/http-problem-details-0.1.7.tgz#223fda43d8ff7cc6634a592d4706b2c99e0be46d" integrity sha512-+ccES43ePQOnZDIkEuo4gNyT0R/Gkulk79oZ3a9FuQQFZYPcUx0OPBe5ztmehe6t79WN/me7APHX3yD6Ha5CHA== +http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http2-express@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/http2-express/-/http2-express-1.0.1.tgz#5865adc1637220eec55a6dafa2c8d495607751e8" @@ -6599,6 +7132,14 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^4.3.0: version "4.3.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" @@ -6637,6 +7178,48 @@ i18n@^0.15.0: math-interval-parser "^2.0.1" mustache "^4.2.0" +i18next-icu@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/i18next-icu/-/i18next-icu-2.3.0.tgz#eee6a15ef4c0639d5878aec4db6ec692eaed32bd" + integrity sha512-x+j7kd5nDJCfbU53uwsMfXD7ALPu5uv0bqjAMQ5nVvXRoj1L7gkmswKtM3XDWYo4YUHf1jznlhSdPyy0xEwU+Q== + +i18next-parser@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/i18next-parser/-/i18next-parser-9.3.0.tgz#65c226cac54cd2783b59715a366be1e3515dd8e6" + integrity sha512-VaQqk/6nLzTFx1MDiCZFtzZXKKyBV6Dv0cJMFM/hOt4/BWHWRgYafzYfVQRUzotwUwjqeNCprWnutzD/YAGczg== + dependencies: + "@babel/runtime" "^7.25.0" + broccoli-plugin "^4.0.7" + cheerio "^1.0.0" + colors "^1.4.0" + commander "^12.1.0" + eol "^0.9.1" + esbuild "^0.25.0" + fs-extra "^11.2.0" + gulp-sort "^2.0.0" + i18next "^23.5.1 || ^24.2.0" + js-yaml "^4.1.0" + lilconfig "^3.1.3" + rsvp "^4.8.5" + sort-keys "^5.0.0" + typescript "^5.0.4" + vinyl "^3.0.0" + vinyl-fs "^4.0.0" + +"i18next@^23.5.1 || ^24.2.0": + version "24.2.3" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-24.2.3.tgz#3a05f72615cbd7c00d7e348667e2aabef1df753b" + integrity sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A== + dependencies: + "@babel/runtime" "^7.26.10" + +i18next@^25.3.2: + version "25.3.2" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-25.3.2.tgz#3d6a7d1dc058caa1b9bdca47fd585483e2e7a637" + integrity sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA== + dependencies: + "@babel/runtime" "^7.27.6" + iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6644,6 +7227,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -6750,6 +7340,16 @@ internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" +intl-messageformat@^10.7.16: + version "10.7.16" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.16.tgz#d909f9f9f4ab857fbe681d559b958dd4dd9f665a" + integrity sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.2" + tslib "^2.8.0" + ioredis@^5.2.3, ioredis@^5.4.1: version "5.6.1" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.6.1.tgz#1ed7dc9131081e77342503425afceaf7357ae599" @@ -6941,6 +7541,11 @@ is-map@^2.0.3: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug== + is-number-object@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" @@ -6959,7 +7564,7 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-obj@^4.1.0: +is-plain-obj@^4.0.0, is-plain-obj@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== @@ -6969,6 +7574,11 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-promise@^2.0.0, is-promise@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" @@ -7060,6 +7670,11 @@ is-unicode-supported@^2.0.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== +is-valid-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" + integrity sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA== + is-weakmap@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" @@ -7205,6 +7820,33 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsdom@^24.1.1: + version "24.1.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.3.tgz#88e4a07cb9dd21067514a619e9f17b090a394a9f" + integrity sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ== + dependencies: + cssstyle "^4.0.1" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.5" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.12" + parse5 "^7.1.2" + rrweb-cssom "^0.7.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.4" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.18.0" + xml-name-validator "^5.0.0" + jsesc@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" @@ -7252,6 +7894,13 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -7421,6 +8070,11 @@ leac@^0.6.0: resolved "https://registry.yarnpkg.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912" integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg== +lead@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lead/-/lead-4.0.0.tgz#5317a49effb0e7ec3a0c8fb9c1b24fb716aab939" + integrity sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg== + leven@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" @@ -7461,6 +8115,11 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + limiter@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" @@ -7628,7 +8287,7 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^10.2.0: +lru-cache@^10.2.0, lru-cache@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== @@ -7688,6 +8347,27 @@ magnet-uri@^7.0.5, magnet-uri@^7.0.7: bep53-range "^2.0.0" uint8-util "^2.2.5" +maildev@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/maildev/-/maildev-2.2.1.tgz#0a7ea8188bc6d9fea6bd08dbc63ecf4872acc67c" + integrity sha512-uNSJ4LpiNfCMw5KpWAM5x1UgOyG3ngeNwzBqw4/Wl18ECkJDyXBYpTH44HCG8LqAOFLkUiLl/1Ah5lrQhv3GzQ== + dependencies: + addressparser "1.0.1" + async "^3.2.3" + commander "^12.1.0" + compression "^1.7.4" + cors "^2.8.5" + dompurify "^3.1.6" + express "^4.21.2" + iconv-lite "0.5.0" + jsdom "^24.1.1" + mime "2.4.4" + nodemailer "^6.9.14" + smtp-server "^3.13.4" + socket.io "^4.7.5" + uue "3.1.2" + wildstring "1.0.9" + mailparser-mit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mailparser-mit/-/mailparser-mit-1.0.0.tgz#19df8436c2a02e1d34a03ec518a2eb065e0a94a4" @@ -7762,6 +8442,14 @@ markdown-it@^14.0.0: punycode.js "^2.3.1" uc.micro "^2.1.0" +matcher-collection@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" + integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ== + dependencies: + "@types/minimatch" "^3.0.3" + minimatch "^3.0.2" + math-interval-parser@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/math-interval-parser/-/math-interval-parser-2.0.1.tgz#e22cd6d15a0a7f4c03aec560db76513da615bed4" @@ -7859,7 +8547,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-db@^1.54.0: +"mime-db@>= 1.43.0 < 2", mime-db@^1.54.0: version "1.54.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== @@ -7883,6 +8571,11 @@ mime@1.6.0, mime@^1.3.4, mime@^1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + mime@2.6.0, mime@^2.4.6: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" @@ -7915,7 +8608,7 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7943,7 +8636,7 @@ minimatch@^9.0.4, minimatch@^9.0.5: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8: +minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -7995,6 +8688,11 @@ mkdirp@^2.1.6: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== +mktemp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + integrity sha512-IXnMcJ6ZyTuhRmJSjzvHSRhlVPiN9Jwc6e59V0bEJ0ba6OBeX2L0E+mRN1QseeOF4mM+F1Rit6Nh7o+rl2Yn/A== + mmdb-lib@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/mmdb-lib/-/mmdb-lib-2.2.0.tgz#fbb08116e56d7b7874314dc680bb74693e5026ff" @@ -8178,6 +8876,16 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== +negotiator@~0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + netmask@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" @@ -8299,16 +9007,16 @@ nodemailer@6.9.16: resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.16.tgz#3ebdf6c6f477c571c0facb0727b33892635e0b8b" integrity sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ== +nodemailer@7.0.3, nodemailer@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.3.tgz#c098ce79ac60c7c111a86949eed2f99bd00cdac3" + integrity sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw== + nodemailer@^6.9.13, nodemailer@^6.9.14: version "6.10.1" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.10.1.tgz#cbc434c54238f83a51c07eabd04e2b3e832da623" integrity sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA== -nodemailer@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.3.tgz#c098ce79ac60c7c111a86949eed2f99bd00cdac3" - integrity sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw== - nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -8316,7 +9024,7 @@ nopt@^5.0.0: dependencies: abbrev "1" -normalize-path@^3.0.0: +normalize-path@3.0.0, normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -8326,6 +9034,13 @@ normalize-url@^8.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== +now-and-later@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-3.0.0.tgz#cdc045dc5b894b35793cf276cc3206077bb7302d" + integrity sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg== + dependencies: + once "^1.4.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -8365,7 +9080,12 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -object-assign@^4, object-assign@^4.1.1: +nwsapi@^2.2.12: + version "2.2.20" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.20.tgz#22e53253c61e7b0e7e93cef42c891154bcca11ef" + integrity sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA== + +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -8450,6 +9170,11 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== +on-headers@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.1.0.tgz#59da4f91c45f5f989c6e4bcedc5a3b0aed70ff65" + integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A== + on-net-listen@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/on-net-listen/-/on-net-listen-1.1.2.tgz#671e55a81c910fa7e5b1e4d506545e9ea0f2e11c" @@ -8680,7 +9405,7 @@ parse-torrent@^11.0.14, parse-torrent@^11.0.18: queue-microtask "^1.2.3" uint8-util "^2.2.5" -parse5-htmlparser2-tree-adapter@^7.0.0: +parse5-htmlparser2-tree-adapter@^7.0.0, parse5-htmlparser2-tree-adapter@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz#b5a806548ed893a43e24ccb42fbb78069311e81b" integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g== @@ -8688,7 +9413,14 @@ parse5-htmlparser2-tree-adapter@^7.0.0: domhandler "^5.0.3" parse5 "^7.0.0" -parse5@^7.0.0: +parse5-parser-stream@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz#d7c20eadc37968d272e2c02660fff92dd27e60e1" + integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow== + dependencies: + parse5 "^7.0.0" + +parse5@^7.0.0, parse5@^7.1.2, parse5@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== @@ -8743,6 +9475,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA== + path-scurry@^1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" @@ -8888,7 +9625,7 @@ picocolors@^1.1.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -9091,6 +9828,11 @@ progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +promise-map-series@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.3.0.tgz#41873ca3652bb7a042b387d538552da9b576f8a1" + integrity sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA== + promise@^7.0.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -9133,6 +9875,13 @@ ps-tree@^1.2.0: dependencies: event-stream "=3.3.4" +psl@^1.1.33: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + pug-attrs@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" @@ -9266,7 +10015,7 @@ punycode.js@2.3.1, punycode.js@^2.3.1: resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -9285,6 +10034,11 @@ qs@^6.11.0, qs@^6.14.0: dependencies: side-channel "^1.1.0" +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -9300,6 +10054,15 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +quick-temp@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + integrity sha512-YsmIFfD9j2zaFwJkzI6eMG7y0lQP7YeWzgtFgNl38pGWZBSXJooZbOWwkcRot7Vt0Fg9L23pX0tqWU3VvLDsiA== + dependencies: + mktemp "~0.4.0" + rimraf "^2.5.4" + underscore.string "~3.3.4" + railroad-diagrams@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" @@ -9549,6 +10312,16 @@ reinterval@^1.1.0: resolved "https://registry.yarnpkg.com/reinterval/-/reinterval-1.1.0.tgz#3361ecfa3ca6c18283380dd0bb9546f390f5ece7" integrity sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ== +remove-trailing-separator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== + +replace-ext@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-2.0.0.tgz#9471c213d22e1bcc26717cd6e50881d88f812b06" + integrity sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug== + require-addon@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/require-addon/-/require-addon-1.1.0.tgz#0a1ef0ba98b186a3aa304a1abda5208902e63e17" @@ -9586,6 +10359,11 @@ require-package-name@^2.0.1: resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" integrity sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + resolve-alpn@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" @@ -9609,6 +10387,13 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-options@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-2.0.0.tgz#a1a57a9949db549dd075de3f5550675f02f1e4c5" + integrity sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A== + dependencies: + value-or-function "^4.0.0" + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" @@ -9655,6 +10440,13 @@ revalidator@0.1.x: resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" integrity sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg== +rimraf@^2.5.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -9711,6 +10503,26 @@ router@^2.2.0: parseurl "^1.3.3" path-to-regexp "^8.0.0" +rrweb-cssom@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" + integrity sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg== + +rrweb-cssom@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz#3021d1b4352fbf3b614aaeed0bc0d5739abe0bc2" + integrity sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw== + +rsvp@^4.8.5: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + integrity sha512-Rf4YVNYpKjZ6ASAmibcwTNciQ5Co5Ztq6iZPEykHpkoflnD/K5ryE/rHehFsTm4NJj8nKDhbi3eKBWGogmNnkg== + run-applescript@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-3.2.0.tgz#73fb34ce85d3de8076d511ea767c30d4fdfc918b" @@ -9814,6 +10626,13 @@ sax@>=0.6.0, sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + selderee@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/selderee/-/selderee-0.11.0.tgz#6af0c7983e073ad3e35787ffe20cefd9daf0ec8a" @@ -10117,6 +10936,16 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +smtp-server@^3.13.4: + version "3.14.0" + resolved "https://registry.yarnpkg.com/smtp-server/-/smtp-server-3.14.0.tgz#2c2c9078d027fbd8d10c75f2bc62f2217fbf161a" + integrity sha512-cEw/hdIY+xw1pkbQbQ23hvnm9kNABAsgYB+jJYGkzAynZxJ2VB9aqC6JhB1vpdDnqan7C7AL3qHYRGwz5eD6BQ== + dependencies: + base32.js "0.1.0" + ipv6-normalize "1.0.1" + nodemailer "7.0.3" + punycode.js "2.3.1" + smtp-server@^3.9.0: version "3.13.6" resolved "https://registry.yarnpkg.com/smtp-server/-/smtp-server-3.13.6.tgz#779aa22fd3746bb8b94d25ab78447b6e4b7d5b78" @@ -10153,7 +10982,7 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io@^4.5.4: +socket.io@^4.5.4, socket.io@^4.7.5: version "4.8.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.1.tgz#fa0eaff965cc97fdf4245e8d4794618459f7558a" integrity sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg== @@ -10174,11 +11003,23 @@ socks@^2.8.3: ip-address "^9.0.5" smart-buffer "^4.2.0" +sort-keys@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-5.1.0.tgz#50a3f3d1ad3c5a76d043e0aeeba7299241e9aa5c" + integrity sha512-aSbHV0DaBcr7u0PVHXzM6NbZNAtrr9sF6+Qfs9UUVG7Ll3jQ6hHi8F/xqIIcn2rvIVbr0v/2zyjSdwSV47AgLQ== + dependencies: + is-plain-obj "^4.0.0" + source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + speed-limiter@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/speed-limiter/-/speed-limiter-1.0.2.tgz#e4632f476a1d25d32557aad7bd089b3a0d948116" @@ -10213,7 +11054,7 @@ split@^1.0.1: dependencies: through "2" -sprintf-js@^1.1.3: +sprintf-js@^1.1.1, sprintf-js@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== @@ -10293,6 +11134,13 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" +stream-composer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-composer/-/stream-composer-1.0.2.tgz#7ee61ca1587bf5f31b2e29aa2093cbf11442d152" + integrity sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w== + dependencies: + streamx "^2.13.2" + stream-shift@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" @@ -10325,6 +11173,16 @@ streamx@2.22.0, streamx@^2.10.3, streamx@^2.15.0, streamx@^2.15.1, streamx@^2.17 optionalDependencies: bare-events "^2.2.0" +streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.2, streamx@^2.14.0: + version "2.22.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.1.tgz#c97cbb0ce18da4f4db5a971dc9ab68ff5dc7f5a5" + integrity sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA== + dependencies: + fast-fifo "^1.3.2" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + string-argv@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" @@ -10546,6 +11404,16 @@ swagger-cli@^4.0.2: dependencies: "@apidevtools/swagger-cli" "4.0.4" +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" + integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== + tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -10593,6 +11461,13 @@ tar@^6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" +teex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/teex/-/teex-1.0.1.tgz#b8fa7245ef8e8effa8078281946c85ab780a0b12" + integrity sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg== + dependencies: + streamx "^2.12.5" + text-decoder@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65" @@ -10630,7 +11505,7 @@ through2@^1.0.0: readable-stream ">=1.1.13-1 <1.2.0-0" xtend ">=4.0.0 <4.1.0-0" -through2@^2.0.3: +through2@^2.0.1, through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -10708,6 +11583,13 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +to-through@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/to-through/-/to-through-3.0.0.tgz#bf4956eaca5a0476474850a53672bed6906ace54" + integrity sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw== + dependencies: + streamx "^2.12.5" + to-utf-8@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/to-utf-8/-/to-utf-8-1.3.0.tgz#b2af7be9e003f4c3817cc116d3baed2a054993c9" @@ -10760,6 +11642,23 @@ torrent-piece@^3.0.1: dependencies: uint8-util "^2.1.9" +tough-cookie@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.1.1.tgz#96ae867cddb8fdb64a49cc3059a8d428bcf238ca" + integrity sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw== + dependencies: + punycode "^2.3.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -10800,7 +11699,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -10930,7 +11829,7 @@ typescript-eslint@^8.26.0: "@typescript-eslint/parser" "8.32.0" "@typescript-eslint/utils" "8.32.0" -typescript@~5.8.3: +typescript@^5.0.4, typescript@~5.8.3: version "5.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== @@ -10956,6 +11855,11 @@ uc.micro@^2.0.0, uc.micro@^2.1.0: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + uid-safe@2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" @@ -10985,6 +11889,14 @@ underscore.deep@~0.5.1: resolved "https://registry.yarnpkg.com/underscore.deep/-/underscore.deep-0.5.3.tgz#210969d58025339cecabd2a2ad8c3e8925e5c095" integrity sha512-4OuSOlFNkiVFVc3khkeG112Pdu1gbitMj7t9B9ENb61uFmN70Jq7Iluhi3oflcSgexkKfDdJ5XAJET2gEq6ikA== +underscore.string@~3.3.4: + version "3.3.6" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.6.tgz#ad8cf23d7423cb3b53b898476117588f4e2f9159" + integrity sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ== + dependencies: + sprintf-js "^1.1.1" + util-deprecate "^1.0.2" + underscore@~1.13.1: version "1.13.7" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" @@ -11007,11 +11919,26 @@ undici@^5.21.2: dependencies: "@fastify/busboy" "^2.0.0" +undici@^7.10.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-7.11.0.tgz#8e13a54f62afa756666c0590c38b3866e286d0b3" + integrity sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg== + unicorn-magic@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104" integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA== +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -11039,6 +11966,14 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + ut_metadata@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/ut_metadata/-/ut_metadata-4.0.3.tgz#f5c38e89dfb2291f718cd4a1f7900b27144b62ac" @@ -11072,7 +12007,7 @@ utif2@^4.0.1: dependencies: pako "^1.0.11" -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -11093,7 +12028,7 @@ utp-native@^2.5.3: timeout-refresh "^1.0.0" unordered-set "^2.0.1" -uue@^3.1.0: +uue@3.1.2, uue@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.2.tgz#e99368414e87200012eb37de4dbaebaa1c742ad2" integrity sha512-axKLXVqwtdI/czrjG0X8hyV1KLgeWx8F4KvSbvVCnS+RUvsQMGRjx0kfuZDXXqj0LYvVJmx3B9kWlKtEdRrJLg== @@ -11136,6 +12071,11 @@ validator@~13.12.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== +value-or-function@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-4.0.0.tgz#70836b6a876a010dc3a2b884e7902e9db064378d" + integrity sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg== + vary@^1, vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -11150,11 +12090,78 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vinyl-contents@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-contents/-/vinyl-contents-2.0.0.tgz#cc2ba4db3a36658d069249e9e36d9e2b41935d89" + integrity sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q== + dependencies: + bl "^5.0.0" + vinyl "^3.0.0" + +vinyl-fs@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-4.0.2.tgz#d46557653e4a7109f29d626a9cf478680c7f8c70" + integrity sha512-XRFwBLLTl8lRAOYiBqxY279wY46tVxLaRhSwo3GzKEuLz1giffsOquWWboD/haGf5lx+JyTigCFfe7DWHoARIA== + dependencies: + fs-mkdirp-stream "^2.0.1" + glob-stream "^8.0.3" + graceful-fs "^4.2.11" + iconv-lite "^0.6.3" + is-valid-glob "^1.0.0" + lead "^4.0.0" + normalize-path "3.0.0" + resolve-options "^2.0.0" + stream-composer "^1.0.2" + streamx "^2.14.0" + to-through "^3.0.0" + value-or-function "^4.0.0" + vinyl "^3.0.1" + vinyl-sourcemap "^2.0.0" + +vinyl-sourcemap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz#422f410a0ea97cb54cebd698d56a06d7a22e0277" + integrity sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q== + dependencies: + convert-source-map "^2.0.0" + graceful-fs "^4.2.10" + now-and-later "^3.0.0" + streamx "^2.12.5" + vinyl "^3.0.0" + vinyl-contents "^2.0.0" + +vinyl@^3.0.0, vinyl@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-3.0.1.tgz#5f5ff85255bda2b5da25e4b3bd80b3fc077fb5a9" + integrity sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA== + dependencies: + clone "^2.1.2" + remove-trailing-separator "^1.1.0" + replace-ext "^2.0.0" + teex "^1.0.1" + void-elements@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + +walk-sync@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-2.2.0.tgz#80786b0657fcc8c0e1c0b1a042a09eae2966387a" + integrity sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg== + dependencies: + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^2.0.0" + minimatch "^3.0.4" + web-resource-inliner@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz#df0822f0a12028805fe80719ed52ab6526886e02" @@ -11184,6 +12191,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webrtc-polyfill@^1.1.10: version "1.1.10" resolved "https://registry.yarnpkg.com/webrtc-polyfill/-/webrtc-polyfill-1.1.10.tgz#1a140c42afd9bcd041a63174810795b35be5e26d" @@ -11239,11 +12251,31 @@ webtorrent@^2.5.17: optionalDependencies: utp-native "^2.5.3" +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + whatwg-fetch@^3.4.1: version "3.6.20" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^14.0.0: + version "14.2.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.2.0.tgz#4ee02d5d725155dae004f6ae95c73e7ef5d95663" + integrity sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw== + dependencies: + tr46 "^5.1.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -11401,6 +12433,11 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + workerpool@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" @@ -11479,6 +12516,11 @@ xml-js@^1.6.11: dependencies: sax "^1.2.4" +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" @@ -11505,6 +12547,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xmlhttprequest-ssl@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23"