- added @adonisjs/mail
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m2s

- mail_settings_controller for setting smtp settings
- added view ror rjecting dataset for editor
- added new model AppConfig for stroing appwide config values
- better validate_chesum.ts command with process chunking
- added vue3 apps 'BasicSettings' like email, profile settings
- started with 2 multilingual capabilities
- npm updates
This commit is contained in:
Kaimbacher 2024-09-16 17:59:46 +02:00
parent 010bead723
commit b06ccae603
67 changed files with 7820 additions and 1463 deletions

View File

@ -14,4 +14,7 @@ PG_DB_NAME=lucid
REDIS_CONNECTION=local REDIS_CONNECTION=local
REDIS_HOST=127.0.0.1 REDIS_HOST=127.0.0.1
REDIS_PORT=6379 REDIS_PORT=6379
REDIS_PASSWORD= REDIS_PASSWORD=
SMTP_HOST=
SMTP_PORT=
RESEND_API_KEY=

View File

@ -66,6 +66,7 @@ COPY --chown=node:node . .
################## Third Stage - Building Stage ##################### ################## Third Stage - Building Stage #####################
# In this stage, we will start building dependencies # In this stage, we will start building dependencies
FROM dependencies AS build FROM dependencies AS build
ENV NODE_ENV=production
# We run "node ace build" to build the app (dist folder) for production # We run "node ace build" to build the app (dist folder) for production
RUN node ace build --ignore-ts-errors RUN node ace build --ignore-ts-errors
# RUN node ace build --production # RUN node ace build --production

View File

@ -12,7 +12,8 @@ export default defineConfig({
*/ */
commands: [ commands: [
() => import('@adonisjs/core/commands'), () => import('@adonisjs/core/commands'),
() => import('@adonisjs/lucid/commands') () => import('@adonisjs/lucid/commands'),
() => import('@adonisjs/mail/commands')
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -68,7 +69,9 @@ export default defineConfig({
// () => import('#providers/validator_provider'), // () => import('#providers/validator_provider'),
() => import('#providers/drive/provider/drive_provider'), () => import('#providers/drive/provider/drive_provider'),
// () => import('@adonisjs/core/providers/vinejs_provider'), // () => import('@adonisjs/core/providers/vinejs_provider'),
() => import('#providers/vinejs_provider') () => import('#providers/vinejs_provider'),
() => import('@adonisjs/mail/mail_provider')
// () => import('#providers/mail_provider'),
], ],
metaFiles: [ metaFiles: [
{ {

View File

@ -0,0 +1,103 @@
import type { HttpContext } from '@adonisjs/core/http';
import vine from '@vinejs/vine';
import AppConfig from '#models/appconfig';
import mail from '@adonisjs/mail/services/main';
// import config from '@adonisjs/core/services/config';
// import { configProvider } from '@adonisjs/core';
// import app from '@adonisjs/core/services/app';
export default class MailSettingsController {
/**
* Save the email server settings
*/
public async setMailSettings({ request, response }: HttpContext) {
const settingsSchema = vine.compile(
vine.object({
mail_domain: vine.string(),
mail_from_address: vine.string(),
mail_smtp_mode: vine.string(),
mail_smtpsecure: vine.string().optional(),
mail_smtphost: vine.string(),
mail_smtpport: vine.string(),
mail_smtpauth: vine.boolean(),
// mail_sendmailmode: vine.string().optional(),
}),
);
const validatedData = await request.validateUsing(settingsSchema);
const configData: any = { ...validatedData };
if (!validatedData.mail_smtpauth) {
configData.mail_smtpname = null;
configData.mail_smtppassword = null;
}
// Prepare the settings to be saved
const settingsToSave = [
{ appid: 'settings', configkey: 'default', configvalue: validatedData.mail_smtp_mode, type: 1, lazy: 0 },
{ appid: 'settings', configkey: 'host', configvalue: validatedData.mail_smtphost, type: 1, lazy: 0 },
{ appid: 'settings', configkey: 'port', configvalue: validatedData.mail_smtpport, type: 1, lazy: 0 },
{
appid: 'settings',
configkey: 'from.address',
configvalue: `${validatedData.mail_from_address}@${validatedData.mail_domain}`,
type: 1,
lazy: 0,
},
];
// if (validatedData.mail_smtpauth) {
// settingsToSave.push(
// { appid: 'settings', configkey: 'smtp_user', configvalue: validatedData.mail_smtpname, type: 1, lazy: 0 },
// { appid: 'settings', configkey: 'smtp_password', configvalue: validatedData.mail_smtppassword, type: 1, lazy: 0 },
// );
// } else {
// settingsToSave.push(
// { appid: 'settings', configkey: 'smtp_user', configvalue: null, type: 1, lazy: 0 },
// { appid: 'settings', configkey: 'smtp_password', configvalue: null, type: 1, lazy: 0 },
// );
// }
// Save or update the settings in the database
for (const setting of settingsToSave) {
await AppConfig.updateOrCreate(
{ appid: setting.appid, configkey: setting.configkey },
{ configvalue: setting.configvalue, type: setting.type, lazy: setting.lazy },
);
}
return response.json({ success: true, message: 'Mail settings updated successfully' });
}
/**
* Send a test email to ensure settings work
*/
public async sendTestMail({ response, auth }: HttpContext) {
const user = auth.user!;
const userEmail = user.email;
// let mailManager = await app.container.make('mail.manager');
// let iwas = mailManager.use();
// let test = mail.config.mailers.smtp();
if (!userEmail) {
return response.badRequest({ message: 'User email is not set. Please update your profile.' });
}
try {
await mail.send((message) => {
message
// .from(Config.get('mail.from.address'))
.from('tethys@geosphere.at')
.to(userEmail)
.subject('Test Email')
.html('<p>If you received this email, the email configuration seems to be correct.</p>');
});
return response.json({ success: true, message: 'Test email sent successfully' });
// return response.flash('Test email sent successfully!', 'message').redirect().back();
} catch (error) {
return response.internalServerError({ message: `Error sending test email: ${error.message}` });
}
}
}

View File

@ -85,6 +85,7 @@ export default class DatasetsController {
can: { can: {
receive: await auth.user?.can(['dataset-receive']), receive: await auth.user?.can(['dataset-receive']),
approve: await auth.user?.can(['dataset-approve']), approve: await auth.user?.can(['dataset-approve']),
reject: await auth.user?.can(['dataset-editor-reject']),
edit: await auth.user?.can(['dataset-editor-update']), edit: await auth.user?.can(['dataset-editor-update']),
delete: await auth.user?.can(['dataset-editor-delete']), delete: await auth.user?.can(['dataset-editor-delete']),
publish: await auth.user?.can(['dataset-publish']), publish: await auth.user?.can(['dataset-publish']),
@ -223,6 +224,92 @@ export default class DatasetsController {
} }
} }
public async reject({ request, inertia, response }: HttpContext) {
const id = request.param('id');
const dataset = await Dataset.query()
.where('id', id)
// .preload('titles')
// .preload('descriptions')
.preload('user', (builder) => {
builder.select('id', 'login');
})
.firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
// session.flash('errors', 'Invalid server state!');
return response
.flash(
'warning',
`Invalid server state. Dataset with id ${id} cannot be rejected. Datset has server state ${dataset.server_state}.`,
)
.redirect()
.toRoute('editor.dataset.list');
}
return inertia.render('Editor/Dataset/Reject', {
dataset,
});
}
public async rejectUpdate({ request, response }: HttpContext) {
const id = request.param('id');
const dataset = await Dataset.query()
.where('id', id)
.preload('user', (builder) => {
builder.select('id', 'login');
})
.firstOrFail();
// const newSchema = schema.create({
// server_state: schema.string({ trim: true }),
// reject_reviewer_note: schema.string({ trim: true }, [rules.minLength(10), rules.maxLength(500)]),
// });
const newSchema = vine.object({
server_state: vine.string().trim(),
reject_editor_note: vine.string().trim().minLength(10).maxLength(500),
});
try {
// await request.validate({ schema: newSchema });
const validator = vine.compile(newSchema);
await request.validateUsing(validator);
} catch (error) {
// return response.badRequest(error.messages);
throw error;
}
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
// throw new Error('Invalid server state!');
// return response.flash('warning', 'Invalid server state. Dataset cannot be released to editor').redirect().back();
return response
.flash(
'warning',
`Invalid server state. Dataset with id ${id} cannot be rejected. Datset has server state ${dataset.server_state}.`,
)
.redirect()
.toRoute('reviewer.dataset.list');
}
// dataset.server_state = 'reviewed';
dataset.server_state = 'rejected_editor';
const rejectEditorNote = request.input('reject_editor_note', '');
dataset.reject_editor_note = rejectEditorNote;
try {
// await dataset.related('editor').associate(user); // speichert schon ab
await dataset.save();
return response
.toRoute('editor.dataset.list')
.flash('message', `You have rejected dataset ${dataset.id}! to submitter ${dataset.user.login}`);
} catch (error) {
// Handle any errors
console.error(error);
return response.status(500).json({ error: 'An error occurred while reviewing the data.' });
}
}
public async publish({ request, inertia, response }: HttpContext) { public async publish({ request, inertia, response }: HttpContext) {
const id = request.param('id'); const id = request.param('id');
@ -254,7 +341,7 @@ export default class DatasetsController {
public async publishUpdate({ request, response }: HttpContext) { public async publishUpdate({ request, response }: HttpContext) {
const publishDatasetSchema = vine.object({ const publishDatasetSchema = vine.object({
publisher_name: vine.string().alphaNumeric().trim(), publisher_name: vine.string().trim(),
}); });
try { try {
// await request.validate({ schema: publishDatasetSchema, messages: this.messages }); // await request.validate({ schema: publishDatasetSchema, messages: this.messages });

View File

@ -96,11 +96,11 @@ export default class DatasetController {
// builder.where('type', 'Main'); // builder.where('type', 'Main');
// }) // })
.paginate(page, 10); .paginate(page, 5);
return inertia.render('Submitter/Dataset/Index', { return inertia.render('Submitter/Dataset/Index', {
// testing: 'this is a test', // testing: 'this is a test',
datasets: myDatasets.serialize(), datasets: myDatasets.toJSON(),
filters: request.all(), filters: request.all(),
can: { can: {
// create: await auth.user?.can(['dataset-submit']), // create: await auth.user?.can(['dataset-submit']),

33
app/models/appconfig.ts Normal file
View File

@ -0,0 +1,33 @@
import BaseModel from './base_model.js';
import { column } from '@adonisjs/lucid/orm';
export default class AppConfig extends BaseModel {
public static table = 'appconfigs'; // Specify the table name if it differs from the model name
@column({ isPrimary: true })
public id: number;
@column()
public appid: string;
@column()
public configkey: string;
@column()
public configvalue: string | null;
@column()
public type: number;
@column()
public lazy: number;
// async function setConfig(key: string, value: string) {
// await this.updateOrCreate({ key }, { value })
// }
// async function getConfig(key: string) {
// const config = await this.findBy('key', key)
// return config ? config.value : null
// }
}

View File

@ -38,7 +38,7 @@ export const updateUserValidator = vine.withMetaData<{ objId: number }>().compil
.email() .email()
.normalizeEmail() .normalizeEmail()
.isUnique({ table: 'accounts', column: 'email', whereNot: (field) => field.meta.objId }), .isUnique({ table: 'accounts', column: 'email', whereNot: (field) => field.meta.objId }),
password: vine.string().confirmed().trim().minLength(3).maxLength(60), password: vine.string().confirmed().trim().minLength(3).maxLength(60).optional(),
roles: vine.array(vine.number()).minLength(1), // define at least one role for the new user roles: vine.array(vine.number()).minLength(1), // define at least one role for the new user
}), }),
); );

View File

@ -1,4 +1,6 @@
// import Logger from '@ioc:Adonis/Core/Logger'; // podman exec -it tethys_backend_1 node ace validate:checksum
// sudo crontab -u www-data -e
// */5 * * * * podman exec -u www-data tethys_backend_1 node ace validate:checksum
import { XMLBuilder } from 'xmlbuilder2/lib/interfaces.js'; import { XMLBuilder } from 'xmlbuilder2/lib/interfaces.js';
import { create } from 'xmlbuilder2'; import { create } from 'xmlbuilder2';
import Dataset from '#models/dataset'; import Dataset from '#models/dataset';
@ -12,6 +14,8 @@ import { CommandOptions } from '@adonisjs/core/types/ace';
import env from '#start/env'; import env from '#start/env';
// import db from '@adonisjs/lucid/services/db'; // import db from '@adonisjs/lucid/services/db';
// import { default as Dataset } from '#models/dataset'; // import { default as Dataset } from '#models/dataset';
import logger from '@adonisjs/core/services/logger';
const opensearchNode = env.get('OPENSEARCH_HOST', 'localhost'); const opensearchNode = env.get('OPENSEARCH_HOST', 'localhost');
const client = new Client({ node: `${opensearchNode}` }); // replace with your OpenSearch endpoint const client = new Client({ node: `${opensearchNode}` }); // replace with your OpenSearch endpoint
@ -32,7 +36,7 @@ export default class IndexDatasets extends BaseCommand {
async run() { async run() {
this.logger.info('Hello world!'); logger.debug('Hello world!');
// const { default: Dataset } = await import('#models/dataset'); // const { default: Dataset } = await import('#models/dataset');
// const datasets = await Dataset.query().where('server_state', 'published').exec(); //this.getDatasets(); // const datasets = await Dataset.query().where('server_state', 'published').exec(); //this.getDatasets();
const datasets = await this.getDatasets(); const datasets = await this.getDatasets();
@ -72,9 +76,9 @@ export default class IndexDatasets extends BaseCommand {
body: document, body: document,
refresh: true, refresh: true,
}); });
this.logger.info(`dataset with publish_id ${dataset.publish_id} successfully indexed`); logger.info(`dataset with publish_id ${dataset.publish_id} successfully indexed`);
} catch (error) { } catch (error) {
this.logger.error(`An error occurred while indexing dataset with publish_id ${dataset.publish_id}.`); logger.error(`An error occurred while indexing dataset with publish_id ${dataset.publish_id}.`);
} }
} }
@ -92,7 +96,7 @@ export default class IndexDatasets extends BaseCommand {
}); });
return result.principalResult; return result.principalResult;
} catch (error) { } catch (error) {
this.logger.error(`An error occurred while creating the user, error: ${error.message},`); logger.error(`An error occurred while creating the user, error: ${error.message},`);
return ''; return '';
} }
} }

View File

@ -1,70 +1,120 @@
import crypto from 'crypto'; import crypto from 'crypto';
import fs from 'fs'; import fs from 'fs/promises'; // Use fs/promises for async file operations
// import Config from '@ioc:Adonis/Core/Config';
import logger from '@adonisjs/core/services/logger'; import logger from '@adonisjs/core/services/logger';
import { BaseCommand } from "@adonisjs/core/ace"; import { BaseCommand } from '@adonisjs/core/ace';
import { CommandOptions } from "@adonisjs/core/types/ace"; import { CommandOptions } from '@adonisjs/core/types/ace';
import dayjs from 'dayjs';
import TethysFile from '#models/file';
import AppConfig from '#models/appconfig';
// import db from '@adonisjs/lucid/services/db'; // Import the DB service
export default class ValidateChecksum extends BaseCommand { export default class ValidateChecksum extends BaseCommand {
/** /**
* Command name is used to run the command * Command name used to run the command
*/ */
public static commandName = 'validate:checksum'; public static commandName = 'validate:checksum';
/** /**
* Command description is displayed in the "help" output * Command description displayed in the "help" output
*/ */
public static description = ''; public static description = '';
static options: CommandOptions = {
loadApp: true, public static options: CommandOptions = {
staysAlive: false, startApp: true,
}; staysAlive: false,
};
private chunkSize = 100; // Set chunk size for pagination
public async run() { public async run() {
// this.logger.info('Hello world!') let page = 1; // Start with the first page
const { default: File } = await import('#models/file'); let hasMoreFiles = true; // Flag to check if there are more files to process
// const { default: HashValue } = await (await (import ('App/Models/HashValue')));
// query all published files from database: // Loop to process files in chunks
const files = await File.query() while (hasMoreFiles) {
.whereHas('dataset', (dQuery) => { // Query a chunk of published files from the database with pagination
dQuery.where('server_state', 'published'); const files = await TethysFile.query()
}) .whereHas('dataset', (dQuery) => {
.preload('hashvalues'); dQuery.where('server_state', 'published'); // Only get published datasets
})
.orderBy('document_id', 'asc') // Order by document ID
.preload('hashvalues') // Preload hash values
.forPage(page, this.chunkSize); // Get files for the current page
// const logLevel = Config.get('app.logger.level', 'info'); // Check if there are no more files to process
// console.log(this.logger.) if (files.length === 0) {
hasMoreFiles = false; // No more files, exit the loop
for (var file of files) { break;
let hashValue = await file.related('hashvalues').query().pluck('value', 'type');
const filePath = '/storage/app/public/' + file.pathName;
let calculatedMd5FileHash;
try {
calculatedMd5FileHash = await this.checksumFile(filePath, 'md5');
} catch (exception) {
// this.logger.error(exception.message);
logger.error(exception.message);
continue;
} }
if (hashValue['md5'] === calculatedMd5FileHash) { // Process the current chunk of files
logger.info(`File id ${file.id} OK: stored md5 checksum: ${calculatedMd5FileHash}, same control md5 checksum: ${hashValue['md5']}`); await this.processChunk(files);
// Move to the next page
page += 1; // Increment page number
}
// Write the current timestamp into the database
const timestamp = dayjs().unix(); // Get Unix timestamp
// Update the timestamp in the appconfigs table
// await db.from('appconfigs')
// .where('appid', 'backgroundjob')
// .where('configkey', 'lastjob')
// .update({ configvalue: timestamp });
await AppConfig.updateOrCreate({ appid: 'backgroundjob', configkey: 'lastjob' }, { configvalue: timestamp });
// Log the updated timestamp
logger.info(`Updated last job timestamp to: ${timestamp}`);
logger.info(`Cron job executed at: ${dayjs.unix(timestamp).format('YYYY-MM-DD HH:mm:ss')}`);
}
private async processChunk(filesArray: TethysFile[]) {
// Process all files in parallel using Promise.all
await Promise.all(
filesArray.map((file) => this.fetchData(file)), // Fetch data for each file
);
}
private async fetchData(file: TethysFile): Promise<void> {
// Create a hashValues object to store hash values
const hashValues = file.hashvalues.reduce(
(acc, h) => {
acc[h.type] = h.value; // Map hash type to its value
return acc;
},
{} as { [key: string]: string },
);
// Construct the file path
const filePath = '/storage/app/public/' + file.pathName;
try {
// Calculate the MD5 checksum of the file
const calculatedMd5FileHash = await this.checksumFile(filePath, 'md5');
// Compare the calculated hash with the stored hash
if (hashValues['md5'] === calculatedMd5FileHash) {
logger.info(
`File id ${file.id} OK: stored md5 checksum: ${calculatedMd5FileHash}, same control md5 checksum: ${hashValues['md5']}`,
);
} else { } else {
// Log an error if checksums do not match
logger.error( logger.error(
`File id ${file.id}: stored md5 checksum: ${calculatedMd5FileHash}, control md5 checksum: ${hashValue['md5']}`, `File id ${file.id}: stored md5 checksum: ${calculatedMd5FileHash}, control md5 checksum: ${hashValues['md5']}`,
); );
} }
} catch (error) {
// Log any error encountered during processing
logger.error(`File id ${file.id} error: ${error.message}`);
} }
} }
private async checksumFile(path: string, hashName = 'md5'): Promise<string> { private async checksumFile(path: string, hashName = 'md5'): Promise<string> {
return new Promise((resolve, reject) => { const hash = crypto.createHash(hashName); // Create a hash object
const hash = crypto.createHash(hashName); const data = await fs.readFile(path); // Read file asynchronously
const stream = fs.createReadStream(path); hash.update(data); // Update hash with file data
stream.on('error', (err) => reject(err)); return hash.digest('hex'); // Return the hash in hexadecimal format
stream.on('data', (chunk) => hash.update(chunk));
stream.on('end', () => resolve(hash.digest('hex')));
});
} }
} }

View File

@ -13,7 +13,7 @@ const loggerConfig = defineConfig({
app: { app: {
enabled: true, enabled: true,
name: env.get('APP_NAME'), name: env.get('APP_NAME'),
level: env.get('LOG_LEVEL'), level: env.get('LOG_LEVEL', 'info'),
transport: { transport: {
targets: targets() targets: targets()
.pushIf(!app.inProduction, targets.pretty()) .pushIf(!app.inProduction, targets.pretty())

76
config/mail.ts Normal file
View File

@ -0,0 +1,76 @@
import env from '#start/env'
import { defineConfig, transports } from '@adonisjs/mail'
const mailConfig = defineConfig({
default: 'smtp',
/**
* The mailers object can be used to configure multiple mailers
* each using a different transport or same transport with different
* options.
*/
mailers: {
smtp: transports.smtp({
host: env.get('SMTP_HOST', ''),
port: env.get('SMTP_PORT'),
secure: false,
// ignoreTLS: true,
requireTLS: false,
/**
* Uncomment the auth block if your SMTP
* server needs authentication
*/
/* auth: {
type: 'login',
user: env.get('SMTP_USERNAME'),
pass: env.get('SMTP_PASSWORD'),
}, */
}),
resend: transports.resend({
key: env.get('RESEND_API_KEY'),
baseUrl: 'https://api.resend.com',
}),
},
})
export default mailConfig
declare module '@adonisjs/mail/types' {
export interface MailersList extends InferMailers<typeof mailConfig> {}
}
// const mailConfig = defineConfig({
// default: 'smtp',
// /**
// * The mailers object can be used to configure multiple mailers
// * each using a different transport or same transport with different
// * options.
// */
// mailers: {
// smtp: transports.smtp({
// host: env.get('SMTP_HOST', ''),
// port: env.get('SMTP_PORT'),
// /**
// * Uncomment the auth block if your SMTP
// * server needs authentication
// */
// /* auth: {
// type: 'login',
// user: env.get('SMTP_USERNAME'),
// pass: env.get('SMTP_PASSWORD'),
// }, */
// }),
// resend: transports.resend({
// key: env.get('RESEND_API_KEY'),
// baseUrl: 'https://api.resend.com',
// }),
// },
// })

View File

@ -87,7 +87,7 @@ const sessionConfig = defineConfig({
cookie: { cookie: {
path: '/', path: '/',
httpOnly: true, httpOnly: true,
secure: app.inProduction, secure: false, //app.inProduction,
sameSite: false, sameSite: false,
}, },

View File

@ -0,0 +1,22 @@
// node ace make:migration appconfig
import { BaseSchema } from '@adonisjs/lucid/schema';
export default class extends BaseSchema {
protected tableName = 'appconfigs';
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id');
table.string('appid', 32).notNullable();
table.string('configkey', 64).notNullable();
table.text('configvalue');
table.bigInteger('type');
table.smallint('lazy');
table.unique(['appid', 'configkey']) // Unique constraint on the combination
});
}
async down() {
this.schema.dropTable(this.tableName);
}
}

4294
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
"compress:xslt": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/datasetxml2oai-pmh.xslt -export:public/assets2/datasetxml2oai.sef.json -t -nogo '-ns:##html5'", "compress:xslt": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/datasetxml2oai-pmh.xslt -export:public/assets2/datasetxml2oai.sef.json -t -nogo '-ns:##html5'",
"compress:solr": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/solr.xslt -export:public/assets2/solr.sef.json -t -nogo '-ns:##html5'", "compress:solr": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/solr.xslt -export:public/assets2/solr.sef.json -t -nogo '-ns:##html5'",
"compress:doi": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/doi_datacite.xslt -export:public/assets2/doi_datacite.sef.json -t -nogo '-ns:##html5'", "compress:doi": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/doi_datacite.xslt -export:public/assets2/doi_datacite.sef.json -t -nogo '-ns:##html5'",
"build": "node ace build", "build": "node ace build --ignore-ts-errors",
"start": "node server.js", "start": "node server.js",
"lint": "eslint . --ext=.ts", "lint": "eslint . --ext=.ts",
"format": "prettier --write .", "format": "prettier --write .",
@ -41,6 +41,7 @@
"@tailwindcss/forms": "^0.5.2", "@tailwindcss/forms": "^0.5.2",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/clamscan": "^2.0.4", "@types/clamscan": "^2.0.4",
"@types/escape-html": "^1.0.4",
"@types/leaflet": "^1.9.3", "@types/leaflet": "^1.9.3",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@types/node": "^20.1.1", "@types/node": "^20.1.1",
@ -59,7 +60,7 @@
"eslint-plugin-prettier": "^5.0.0-alpha.2", "eslint-plugin-prettier": "^5.0.0-alpha.2",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"pinia": "^2.0.30", "pinia": "^2.0.30",
"pino-pretty": "^11.0.0", "pino-pretty": "^11.2.2",
"postcss-loader": "^7.3.4", "postcss-loader": "^7.3.4",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"supertest": "^6.3.3", "supertest": "^6.3.3",
@ -80,6 +81,7 @@
"@adonisjs/encore": "^1.0.0", "@adonisjs/encore": "^1.0.0",
"@adonisjs/inertia": "^1.0.0-7", "@adonisjs/inertia": "^1.0.0-7",
"@adonisjs/lucid": "^21.1.0", "@adonisjs/lucid": "^21.1.0",
"@adonisjs/mail": "^9.2.2",
"@adonisjs/redis": "^9.1.0", "@adonisjs/redis": "^9.1.0",
"@adonisjs/session": "^7.1.1", "@adonisjs/session": "^7.1.1",
"@adonisjs/shield": "^8.1.1", "@adonisjs/shield": "^8.1.1",
@ -98,6 +100,7 @@
"crypto": "^1.0.1", "crypto": "^1.0.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"edge.js": "^6.0.1", "edge.js": "^6.0.1",
"escape-html": "^1.0.3",
"focus-trap": "^7.5.4", "focus-trap": "^7.5.4",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"http-status-codes": "^2.2.0", "http-status-codes": "^2.2.0",
@ -112,7 +115,6 @@
"reflect-metadata": "^0.2.1", "reflect-metadata": "^0.2.1",
"saxon-js": "^2.5.0", "saxon-js": "^2.5.0",
"toastify-js": "^1.12.0", "toastify-js": "^1.12.0",
"vue-i18n": "^9.13.1",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"xmlbuilder2": "^3.1.1" "xmlbuilder2": "^3.1.1"
}, },

View File

@ -8,18 +8,18 @@ export default class AppProvider {
public register() { public register() {
// Register your own bindings // Register your own bindings
} }
public async boot() { public async boot() {
// IoC container is ready // IoC container is ready
await import('../src/extensions.js'); await import('../src/extensions.js');
// const hashInstance: typeof hash = this.app.container.make('@adonisjs/core/services/hash'); // const hashInstance: typeof hash = this.app.container.make('@adonisjs/core/services/hash');
// hashInstance.extend('bcrypt', () => { // hashInstance.extend('bcrypt', () => {
// return new LaravelHash(); // return new LaravelHash();
// }); // });
// this.app.container.resolving('validator', (validator) => { // this.app.container.resolving('validator', (validator) => {
// validator.rule('foo', () => {}) // validator.rule('foo', () => {})
@ -45,7 +45,7 @@ export default class AppProvider {
} }
public async ready() { public async ready() {
// App is ready // App is ready
} }
public async shutdown() { public async shutdown() {

108
providers/mail_provider.ts Normal file
View File

@ -0,0 +1,108 @@
/*
* @adonisjs/mail
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { configProvider } from '@adonisjs/core';
import { RuntimeException } from '@poppinss/utils';
import type { ApplicationService } from '@adonisjs/core/types';
// import { MailManager, Mailer, Message } from '../index.js'
import { MailManager, Mailer, Message } from '@adonisjs/mail';
// import type { MailEvents, MailService } from '../src/types.js'
import type { MailEvents, MailService } from '@adonisjs/mail/types';
import env from '#start/env';
// import { mailPluginEdge } from '@adonisjs/mail';
/**
* Extended types
*/
declare module '@adonisjs/core/types' {
export interface ContainerBindings {
'mail.manager': MailService;
}
export interface EventsList extends MailEvents {}
}
/**
* Mail provider to register mail manager with the container
*/
export default class MailProvider {
constructor(protected app: ApplicationService) {}
/**
* Defines the template engine on the message class to
* render templates
*/
protected async defineTemplateEngine() {
if (this.app.usingEdgeJS) {
const edge = await import('edge.js');
Message.templateEngine = {
render(templatePath, helpers, data) {
return edge.default.share(helpers).render(templatePath, data);
},
};
const { mailPluginEdge } = await import('@adonisjs/mail/plugins/edge');
edge.default.use(mailPluginEdge);
}
}
/**
* Registering bindings to container
*/
register() {
// process.env.SMTP_HOST = 'xhost';
env.set("SMTP_HOST", 'xhost');
// this.app.config.set('mail.mailers.smtp.host', 'xhost');
this.app.container.singleton('mail.manager', async (resolver) => {
const emitter = await resolver.make('emitter');
this.app.config.set('mail.mailers.smtp.host', 'xhost');
// env.set("SMTP_HOST", 'xhost');
// env.set("SMTP_PORT", '333');
// Reset or modify environment variables here
const mailConfigProvider = this.app.config.get('mail');
const config = await configProvider.resolve<any>(this.app, mailConfigProvider);
const iwas = await config.mailers.smtp();
// iwas.config.host = 'hhhost';
// this.app.config.set('mail.mailers.smtp.host', 'xhost');
// const iwas = await config.mailers.smtp();
// const smtpConfigProvider = await this.app.config.get('mail.mailers.smtp');
// const smtpConfig = await configProvider.resolve<any>(this.app, smtpConfigProvider);
// let test = config.get('mailers.smtp');
if (!config) {
throw new RuntimeException('Invalid "config/mail.ts" file. Make sure you are using the "defineConfig" method');
}
return new MailManager(emitter, config);
});
this.app.container.bind(Mailer, async (resolver) => {
const mailManager = await resolver.make('mail.manager');
return mailManager.use();
});
}
/**
* Invoked automatically when the app is booting
*/
async boot() {
await this.defineTemplateEngine();
}
/**
* Cleanup hook
*/
async shutdown() {
const mail = await this.app.container.make('mail.manager');
await mail.closeAll();
}
}

View File

@ -1,6 +1,8 @@
{ {
"assets/app.css": "http://localhost:8080/assets/app.css", "assets/app.css": "http://localhost:8080/assets/app.css",
"assets/app.js": "http://localhost:8080/assets/app.js", "assets/app.js": "http://localhost:8080/assets/app.js",
"assets/resources_js_apps_settings_l18n_de_js.js": "http://localhost:8080/assets/resources_js_apps_settings_l18n_de_js.js",
"assets/resources_js_apps_settings_l18n_en_js.js": "http://localhost:8080/assets/resources_js_apps_settings_l18n_en_js.js",
"assets/resources_js_Pages_Admin_License_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_License_Index_vue.js", "assets/resources_js_Pages_Admin_License_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_License_Index_vue.js",
"assets/resources_js_Pages_Admin_Mimetype_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Mimetype_Index_vue.js", "assets/resources_js_Pages_Admin_Mimetype_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Mimetype_Index_vue.js",
"assets/resources_js_Pages_Admin_Permission_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Create_vue.js", "assets/resources_js_Pages_Admin_Permission_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Create_vue.js",
@ -11,8 +13,10 @@
"assets/resources_js_Pages_Admin_Role_Edit_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Edit_vue.js", "assets/resources_js_Pages_Admin_Role_Edit_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Edit_vue.js",
"assets/resources_js_Pages_Admin_Role_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Index_vue.js", "assets/resources_js_Pages_Admin_Role_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Index_vue.js",
"assets/resources_js_Pages_Admin_Role_Show_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Show_vue.js", "assets/resources_js_Pages_Admin_Role_Show_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Show_vue.js",
"assets/resources_js_Pages_Admin_Settings_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Settings_vue.js", "assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.css": "http://localhost:8080/assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.css",
"assets/resources_js_Pages_Admin_User_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue.js", "assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.js",
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css",
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js",
"assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css", "assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css",
"assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js", "assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js",
"assets/resources_js_Pages_Admin_User_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Index_vue.js", "assets/resources_js_Pages_Admin_User_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Index_vue.js",
@ -28,6 +32,7 @@
"assets/resources_js_Pages_Editor_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Index_vue.js", "assets/resources_js_Pages_Editor_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Index_vue.js",
"assets/resources_js_Pages_Editor_Dataset_Publish_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Publish_vue.js", "assets/resources_js_Pages_Editor_Dataset_Publish_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Publish_vue.js",
"assets/resources_js_Pages_Editor_Dataset_Receive_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Receive_vue.js", "assets/resources_js_Pages_Editor_Dataset_Receive_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Receive_vue.js",
"assets/resources_js_Pages_Editor_Dataset_Reject_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Reject_vue.js",
"assets/resources_js_Pages_Error_vue.js": "http://localhost:8080/assets/resources_js_Pages_Error_vue.js", "assets/resources_js_Pages_Error_vue.js": "http://localhost:8080/assets/resources_js_Pages_Error_vue.js",
"assets/resources_js_Pages_Errors_ServerError_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError_vue.js", "assets/resources_js_Pages_Errors_ServerError_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError_vue.js",
"assets/resources_js_Pages_Errors_not_found_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_not_found_vue.js", "assets/resources_js_Pages_Errors_not_found_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_not_found_vue.js",
@ -42,7 +47,6 @@
"assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js", "assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js",
"assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.css", "assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.css",
"assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.js", "assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-b6a1eb.js",
"assets/resources_js_Pages_Submitter_Dataset_Index_vue.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Index_vue.css",
"assets/resources_js_Pages_Submitter_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Index_vue.js", "assets/resources_js_Pages_Submitter_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Index_vue.js",
"assets/resources_js_Pages_Submitter_Dataset_Release_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Release_vue.js", "assets/resources_js_Pages_Submitter_Dataset_Release_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Release_vue.js",
"assets/resources_js_Pages_Submitter_Person_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Person_Index_vue.js", "assets/resources_js_Pages_Submitter_Person_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Person_Index_vue.js",
@ -50,45 +54,43 @@
"assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js": "http://localhost:8080/assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js", "assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js": "http://localhost:8080/assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js",
"assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js": "http://localhost:8080/assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js", "assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js": "http://localhost:8080/assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js",
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js", "assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js",
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js",
"assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js", "assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js",
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js",
"assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js": "http://localhost:8080/assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js", "assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js": "http://localhost:8080/assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js",
"assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js", "assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js",
"assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js", "assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js",
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js", "assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js",
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css", "assets/resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Layouts_LayoutAuthenticated_vue.css",
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js", "assets/resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Layouts_LayoutAuthenticated_vue.js",
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js", "assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js",
"assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-8134e7.js": "http://localhost:8080/assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-8134e7.js", "assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-6f3a70.js": "http://localhost:8080/assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-6f3a70.js",
"assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-196747.js": "http://localhost:8080/assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-196747.js", "assets/resources_js_utils_toast_ts-resources_js_Components_NotificationBar_vue.js": "http://localhost:8080/assets/resources_js_utils_toast_ts-resources_js_Components_NotificationBar_vue.js",
"assets/resources_js_utils_toast_ts-resources_js_Components_FormValidationErrors_vue-resources_js_Com-a6b99f.js": "http://localhost:8080/assets/resources_js_utils_toast_ts-resources_js_Components_FormValidationErrors_vue-resources_js_Com-a6b99f.js", "assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-058bcc.js": "http://localhost:8080/assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-058bcc.js",
"assets/resources_js_Components_SectionMain_vue-resources_js_Components_SectionTitleLineWithButton_vu-764dfe.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Components_SectionTitleLineWithButton_vu-764dfe.js",
"assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js": "http://localhost:8080/assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js", "assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js": "http://localhost:8080/assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js",
"assets/resources_js_Components_CardBoxModal_vue.js": "http://localhost:8080/assets/resources_js_Components_CardBoxModal_vue.js", "assets/resources_js_Components_CardBoxModal_vue.js": "http://localhost:8080/assets/resources_js_Components_CardBoxModal_vue.js",
"assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-bdf2f9.js": "http://localhost:8080/assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-bdf2f9.js", "assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-25e686.js": "http://localhost:8080/assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-25e686.js",
"assets/resources_js_Components_SectionTitleLineWithButton_vue-resources_js_Components_SimplePassword-945989.js": "http://localhost:8080/assets/resources_js_Components_SectionTitleLineWithButton_vue-resources_js_Components_SimplePassword-945989.js", "assets/resources_js_Components_BaseButtons_vue-resources_js_Components_NotificationBar_vue-resources-7e06d8.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_NotificationBar_vue-resources-7e06d8.js",
"assets/fonts/inter-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.40b3b0d5.woff", "assets/fonts/inter-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.1c20f7dc.woff",
"assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.0f9e8d4e.woff2", "assets/fonts/inter-latin-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-400-normal.b0c8fe9d.woff",
"assets/fonts/inter-latin-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-400-normal.08a02fd2.woff", "assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.3d10c85f.woff2",
"assets/fonts/inter-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-400-normal.f1535355.woff2", "assets/fonts/inter-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-400-normal.9698cc7d.woff2",
"assets/fonts/archivo-black-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.fc847a1f.woff2", "assets/fonts/archivo-black-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.fc847a1f.woff2",
"assets/fonts/archivo-black-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.21761451.woff2", "assets/fonts/archivo-black-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.21761451.woff2",
"assets/fonts/inter-cyrillic-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.cd2ad378.woff", "assets/fonts/inter-cyrillic-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.e8945162.woff",
"assets/fonts/archivo-black-latin-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.58a301a6.woff", "assets/fonts/archivo-black-latin-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.58a301a6.woff",
"assets/fonts/inter-greek-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-400-normal.1eeaf1d0.woff", "assets/fonts/inter-cyrillic-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.fd1478dc.woff2",
"assets/fonts/inter-cyrillic-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.ac62c8eb.woff2", "assets/fonts/inter-cyrillic-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.e2841352.woff",
"assets/fonts/inter-cyrillic-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.fa67b2dd.woff", "assets/fonts/inter-greek-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-400-normal.a42da273.woff",
"assets/fonts/archivo-black-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.5ab5ba92.woff", "assets/fonts/archivo-black-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.5ab5ba92.woff",
"assets/fonts/inter-greek-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-400-normal.be0e76b3.woff2", "assets/fonts/inter-greek-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-400-normal.a8de720a.woff2",
"assets/fonts/inter-greek-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.708f2f74.woff", "assets/fonts/inter-cyrillic-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.cb04b2ee.woff2",
"assets/fonts/inter-cyrillic-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.fa78d8d6.woff2", "assets/fonts/inter-greek-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.b9e1e894.woff",
"assets/fonts/inter-vietnamese-400-normal.woff": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.6eab7f5e.woff", "assets/fonts/inter-vietnamese-400-normal.woff": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.96f8adc7.woff",
"assets/fonts/inter-greek-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.1e2b9039.woff2", "assets/fonts/inter-greek-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.f2fa0d9e.woff2",
"assets/fonts/inter-vietnamese-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.5952d3d3.woff2", "assets/fonts/inter-vietnamese-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.44c9df13.woff2",
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png", "assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png", "assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png", "assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg", "assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg"
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js",
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css",
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js"
} }

View File

@ -1,8 +1,6 @@
<!-- <!--
- @copyright Copyright (c) 2023 Arno Kaimbacher <arno.kaimbacher@outlook.at> - @copyright Copyright (c) 2023 Arno Kaimbacher <arno.kaimbacher@outlook.at>
- - -
- @author Marco Ambrosini <arno.kaimbacher@outlook.at>
-
- @license GNU AGPL version 3 or any later version - @license GNU AGPL version 3 or any later version
- -
- This program is free software: you can redistribute it and/or modify - This program is free software: you can redistribute it and/or modify
@ -46,7 +44,8 @@ import Card from './Card.vue';
// import { generateUrl } from '@nextcloud/router'; // import { generateUrl } from '@nextcloud/router';
import { loadState } from '@/utils/initialState'; import { loadState } from '@/utils/initialState';
const desktop = loadState('firstrunwizard', 'desktop'); const desktop = loadState('firstrunwizard', 'desktop'); //'https://gitea.geologie.ac.at/geolba/tethys.backend'
// const profileEnabledByDefault = loadState('settings', 'profileEnabledByDefault'); //true
export default { export default {
name: 'Page2', name: 'Page2',

View File

@ -51,6 +51,10 @@ const props = defineProps({
type: Number, type: Number,
default: null, default: null,
}, },
extraHigh: {
type: Boolean,
default: false,
},
required: Boolean, required: Boolean,
borderless: Boolean, borderless: Boolean,
transparent: Boolean, transparent: Boolean,
@ -67,7 +71,7 @@ const inputElClass = computed(() => {
const base = [ const base = [
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full', 'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
'dark:placeholder-gray-400', 'dark:placeholder-gray-400',
computedType.value === 'textarea' ? 'h-44' : 'h-12', props.extraHigh ? 'h-80' : (computedType.value === 'textarea' ? 'h-44' : 'h-12'),
props.borderless ? 'border-0' : 'border', props.borderless ? 'border-0' : 'border',
// props.transparent && !props.isReadOnly ? 'bg-transparent' : 'bg-white dark:bg-slate-800', // props.transparent && !props.isReadOnly ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800', props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800',

View File

@ -0,0 +1,30 @@
<template>
<span v-bind="$attrs" :aria-hidden="title ? null : true" :aria-label="title" class="material-design-icon alert-icon"
role="img" @click="$emit('click', $event)">
<svg :fill="fillColor" class="material-design-icon__svg" :width="size" :height="size" viewBox="0 0 24 24">
<path d="M13 14H11V9H13M13 18H11V16H13M1 21H23L12 2L1 21Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: "AlertIcon",
emits: ['click'],
props: {
title: {
type: String,
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<span v-bind="$attrs" :aria-hidden="title ? null : true" :aria-label="title"
class="material-design-icon alert-decagram-icon" role="img" @click="$emit('click', $event)">
<svg :fill="fillColor" class="material-design-icon__svg" :width="size" :height="size" viewBox="0 0 24 24">
<path
d="M23,12L20.56,9.22L20.9,5.54L17.29,4.72L15.4,1.54L12,3L8.6,1.54L6.71,4.72L3.1,5.53L3.44,9.21L1,12L3.44,14.78L3.1,18.47L6.71,19.29L8.6,22.47L12,21L15.4,22.46L17.29,19.28L20.9,18.46L20.56,14.78L23,12M13,17H11V15H13V17M13,13H11V7H13V13Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: "AlertDecagramIcon",
emits: ['click'],
props: {
title: {
type: String,
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
}
</script>

View File

@ -0,0 +1,38 @@
<template>
<span v-bind="$attrs"
:aria-hidden="title ? null : true"
:aria-label="title"
class="material-design-icon checkbox-marked-circle-icon"
role="img"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 24 24">
<path d="M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: "CheckboxMarkedCircleIcon",
emits: ['click'],
props: {
title: {
type: String,
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
}
</script>

View File

@ -0,0 +1,38 @@
<template>
<span v-bind="$attrs"
:aria-hidden="title ? null : true"
:aria-label="title"
class="material-design-icon help-circle-icon"
role="img"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 24 24">
<path d="M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: "HelpCircleIcon",
emits: ['click'],
props: {
title: {
type: String,
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<span v-bind="$attrs" :aria-hidden="title ? null : true" :aria-label="title"
class="material-design-icon information-icon" role="img" @click="$emit('click', $event)">
<svg :fill="fillColor" class="material-design-icon__svg" :width="size" :height="size" viewBox="0 0 24 24">
<path
d="M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: "InformationIcon",
emits: ['click'],
props: {
title: {
type: String,
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
}
</script>

View File

@ -8,7 +8,7 @@ import { svg } from 'leaflet/src/layer/vector/SVG';
import axios from 'axios'; import axios from 'axios';
import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds'; import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds';
import { tileLayerWMS } from 'leaflet/src/layer/tile/TileLayer.WMS'; import { tileLayerWMS } from 'leaflet/src/layer/tile/TileLayer.WMS';
import { TileLayer } from 'leaflet/src/layer/tile/TileLayer'; // import { TileLayer } from 'leaflet/src/layer/tile/TileLayer';
import { Attribution } from 'leaflet/src/control/Control.Attribution'; import { Attribution } from 'leaflet/src/control/Control.Attribution';
import DrawControlComponent from '@/Components/Map/draw.component.vue'; import DrawControlComponent from '@/Components/Map/draw.component.vue';
import ZoomControlComponent from '@/Components/Map/zoom.component.vue'; import ZoomControlComponent from '@/Components/Map/zoom.component.vue';
@ -59,8 +59,8 @@ Map.include({
}); });
const DEFAULT_BASE_LAYER_NAME = 'BaseLayer'; const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors'; const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors';
// const OPENSEARCH_HOST = 'http://localhost:9200'; const OPENSEARCH_HOST = 'https://catalog.geosphere.at';
const OPENSEARCH_HOST = `${process.env.OPENSEARCH_HOST}`; // const OPENSEARCH_HOST = `${process.env.OPENSEARCH_HOST}`;
// const OPENSEARCH_HOST = `http://${process.env.OPENSEARCH_PUBLIC_HOST}`; // const OPENSEARCH_HOST = `http://${process.env.OPENSEARCH_PUBLIC_HOST}`;
let map: Map; let map: Map;

View File

@ -0,0 +1,163 @@
<template>
<!-- <div class="notecard" :class="`notecard--${color}`" :role="shouldShowAlert ? 'alert' : 'note'"> -->
<div class="notecard" :class="colorsBgLight[type]" :role="shouldShowAlert ? 'alert' : 'note'">
<!-- @slot Manually provide icon -->
<slot name="icon">
<component :is="icon" class="notecard__icon" :class="{ 'notecard__icon--heading': heading }" :fill-color="color"
:size="20" />
</slot>
<div>
<p v-if="heading" class="font-bold">
{{ heading }}
</p>
<!-- @slot The main content (overwrites the `text` prop) -->
<slot>
<p class="notecard__text">
{{ text }}
</p>
</slot>
</div>
</div>
</template>
<!-- <div v-if="flash && flash.message" class="flex flex-col mt-6 animate-fade-in">
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
<p class="font-bold">Be Warned</p>
<p>{{ flash.message }}</p>
</div>
</div> -->
<script lang="ts">
import CheckboxMarkedCircle from './Icons/CheckboxMarkedCircle.vue';
import AlertDecagram from './Icons/AlertDecagram.vue';
import Alert from './Icons/Alert.vue';
import Information from './Icons/Information.vue';
import { colorsBgLight } from '@/colors';
export default {
name: 'NcNoteCard',
data() {
return {
colorsBgLight: colorsBgLight,
};
},
props: {
/**
* Type or severity of the message
*/
type: {
type: String,
default: 'warning',
validator: (type: string) => ['success', 'info', 'warning', 'danger'].includes(type),
},
/**
* Enforce the `alert` role on the note card.
*
* The [`alert` role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role)
* should only be used for information that requires the user's immediate attention.
*/
showAlert: {
type: Boolean,
default: false,
},
/**
* Optional text to show as a heading of the note card
*/
heading: {
type: String,
default: '',
},
/**
* The message text of the note card
*/
text: {
type: String,
default: '',
},
},
computed: {
shouldShowAlert() {
return this.showAlert || this.type === 'error';
},
icon() {
switch (this.type) {
case 'error':
return AlertDecagram;
case 'success':
return CheckboxMarkedCircle;
case 'info':
return Information;
case 'warning':
return Alert;
default:
return Alert;
}
},
color() {
switch (this.type) {
case 'error':
return 'var(--color-error)';
case 'success':
return 'var(--color-success)';
case 'info':
return 'var(--color-info)';
case 'warning':
return 'var(--color-warning)';
default:
return 'var(--color-warning)';
}
},
},
};
</script>
<style lang="css" scoped>
.notecard {
--note-card-icon-size: 20px;
--note-card-padding: calc(2 * var(--default-grid-baseline));
/* color: var(--color-main-text) !important; */
/* background-color: var(--note-background) !important;
border-inline-start: var(--default-grid-baseline) solid var(--note-theme);
border-radius: var(--border-radius); */
margin: 1rem 0;
padding: var(--note-card-padding);
display: flex;
flex-direction: row;
gap: var(--note-card-padding);
&__heading {
font-size: var(--note-card-icon-size);
font-weight: 600;
}
&__icon {
&--heading {
font-size: 20px;
margin-block: calc((1lh - 1em) / 2) auto;
}
}
/* &--success {
--note-background: rgba(var(--color-success-rgb), 0.1);
--note-theme: var(--color-success);
}
&--info {
--note-background: rgba(var(--color-info-rgb), 0.1);
--note-theme: var(--color-info);
}
&--error {
--note-background: rgba(var(--color-error-rgb), 0.1);
--note-theme: var(--color-error);
}
&--warning {
--note-background: rgba(var(--color-warning-rgb), 0.1);
--note-theme: var(--color-warning);
} */
}
</style>

View File

@ -0,0 +1,147 @@
<template>
<!-- <div class="settings-section" :class="{'settings-section--limit-width': forceLimitWidth}"> -->
<div class="settings-section" v-bind:class="containerMaxW">
<h2 class="settings-section__name">
{{ name }}
<a v-if="hasDocUrl"
:href="docUrl"
class="settings-section__info"
:title="docNameTranslated"
:aria-label="docNameTranslated"
target="_blank"
rel="noreferrer nofollow">
<HelpCircle :size="20" />
</a>
</h2>
<p v-if="hasDescription"
class="settings-section__desc">
{{ description }}
</p>
<slot />
</div>
</template>
<script lang="ts">
// import { t } from '../../l10n.js'
// import { translate as t } from '@nextcloud/l10n'
import { translate as t } from '@/utils/tethyscloud-l10n';
import HelpCircle from './Icons/HelpCircle.vue';
import { containerMaxW } from '@/config';
export default {
name: 'NcSettingsSection',
components: {
HelpCircle,
},
props: {
name: {
type: String,
required: true,
},
description: {
type: String,
default: '',
},
docUrl: {
type: String,
default: '',
},
/**
* Limit the width of the setting's content
*
* Setting this to false allows unrestricted (width) settings content.
* Note that the name and description have always a width limit.
* @deprecated Will be removed with next version and will not be used on Nextcloud 30+ (always forced to true)
*/
limitWidth: {
type: Boolean,
default: true,
},
},
data() {
return {
docNameTranslated: t('External documentation for {name}', {
name: this.name,
}),
containerMaxW: containerMaxW,
}
},
computed: {
forceLimitWidth() {
// if (this.limitWidth) {
// return true
// }
// // Overwrite this on Nextcloud 30+ to always limit the width
// const [major] = window._oc_config?.version.split('.', 2) ?? []
// return major && Number.parseInt(major) >= 30
return true;
},
hasDescription() {
return this.description.length > 0
},
hasDocUrl() {
return this.docUrl.length > 0
},
},
}
</script>
<style lang="css" scoped>
/* $maxWidth: 900px; */
.settings-section {
display: block;
margin-bottom: auto;
padding: 30px;
&:not(:last-child) {
border-bottom: 1px solid var(--color-border);
}
&--limit-width > * {
max-width: 900px;
}
&__name {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: bold;
max-width: 900px;
margin-top: 0;
}
&__info {
display: flex;
align-items: center;
justify-content: center;
width: var(--default-clickable-area);
height: var(--default-clickable-area);
/* margin: calc($icon-margin * -1); */
margin-left: 0;
color: var(--color-text-maxcontrast);
&:hover, &:focus, &:active {
color: var(--color-main-text);
}
}
&__desc {
margin-top: -.2em;
margin-bottom: 1em;
color: var(--color-text-maxcontrast);
max-width: 900px;
}
}
</style>

View File

@ -0,0 +1,159 @@
<script lang="ts" setup>
import { Link } from '@inertiajs/vue3';
import { computed } from 'vue';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
});
// meta:
// {total: 19, perPage: 5, currentPage: 1, lastPage: 4, firstPage: 1, }
// currentPage:
// 1
// firstPage:
// 1
// firstPageUrl:
// '/?page=1'
// lastPage:
// 4
// lastPageUrl:
// '/?page=4'
// nextPageUrl:
// '/?page=2'
// perPage:
// 5
// previousPageUrl:
// null
// total:
// 19
const calculateNextPageLink = computed(() => {
let url = new URL(document.location.href);
url.searchParams.set('page', String(props.data.current_page + 1));
return url.href;
});
const calculatePrevPageLink = computed(() => {
let url = new URL(document.location.href);
url.searchParams.set('page', String(props.data.current_page - 1));
return url.href;
});
const toPage = computed(() => {
let currentPage = props.data.current_page;
let perPage = props.data.per_page;
if (props.data.current_page == props.data.last_page) {
return props.data.total;
} else {
return currentPage * perPage;
}
});
const fromPage = computed(() => {
let currentPage = props.data.current_page;
let perPage = props.data.per_page;
return currentPage * perPage - (perPage - 1);
});
</script>
<template>
<!-- <nav v-if="data.links.length > 3" -->
<nav v-if="data.total > 3" role="navigation" aria-label="Pagination Navigation"
class="flex items-center justify-between">
<div class="flex justify-between flex-1 sm:hidden">
<span v-if="data.current_page <= 1"
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md">
Previous
</span>
<Link v-else :href="data.previous_page_url"
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Previous
</Link>
<Link v-if="data.current_page < data.last_page" :href="data.next_page_url"
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Next
</Link>
<span v-else
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md">
Next
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700 leading-5">
Showing
<span class="font-medium">{{ fromPage }}</span>
to
<span class="font-medium">{{ toPage }}</span>
of
<span class="font-medium">{{ data.total }}</span>
results
</p>
</div>
<div>
<span class="relative z-0 inline-flex shadow-sm rounded-md">
<span v-if="props.data.current_page <= 1" aria-disabled="true" aria-label="Previous">
<span
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5 opacity-50"
aria-hidden="true">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
</span>
</span>
<!-- <Link v-else :href="data.previousPageUrl" rel="prev" -->
<Link v-else :href="calculatePrevPageLink" rel="prev"
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
aria-label="Previous">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
</Link>
<!-- <template v-for="(link, key) in data.links">
<template v-if="key > 0 && key < data.last_page + 1">
<span v-if="!link.active && link.url === null" :key="key" aria-disabled="true">
<span class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 cursor-default leading-5">{{ link.label }}</span>
</span>
<span v-else-if="link.active" :key="`current-${key}`" aria-current="page">
<span class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5">{{ link.label }}</span>
</span>
<Link v-else :key="`link-${key}`" :href="link.url" v-html="link.label" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150" aria-label="`Go to page ${link.label}`" />
</template>
</template> -->
<Link v-if="props.data.current_page < props.data.last_page" :href="calculateNextPageLink" rel="next"
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
aria-label="Next">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
</Link>
<!-- else disabled link -->
<span v-else aria-disabled="true" aria-label="Next">
<span
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-r-md leading-5 opacity-50"
aria-hidden="true">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
</span>
</span>
</span>
</div>
</div>
</nav>
</template>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
// import { MainService } from '@/Stores/main'; // import { MainService } from '@/Stores/main';
import { StyleService } from '@/Stores/style.service'; // import { StyleService } from '@/Stores/style.service';
import { mdiTrashCan } from '@mdi/js'; import { mdiTrashCan } from '@mdi/js';
import { mdiDragVariant } from '@mdi/js'; import { mdiDragVariant } from '@mdi/js';
import BaseIcon from '@/Components/BaseIcon.vue'; import BaseIcon from '@/Components/BaseIcon.vue';
@ -10,9 +10,9 @@ import BaseIcon from '@/Components/BaseIcon.vue';
// import BaseLevel from '@/Components/BaseLevel.vue'; // import BaseLevel from '@/Components/BaseLevel.vue';
import BaseButtons from '@/Components/BaseButtons.vue'; import BaseButtons from '@/Components/BaseButtons.vue';
import BaseButton from '@/Components/BaseButton.vue'; import BaseButton from '@/Components/BaseButton.vue';
import UserAvatar from '@/Components/UserAvatar.vue'; // import UserAvatar from '@/Components/UserAvatar.vue';
// import Person from 'App/Models/Person'; // import Person from 'App/Models/Person';
import { Person } from '@/Stores/main'; import { Person } from '@/Dataset';
import Draggable from 'vuedraggable'; import Draggable from 'vuedraggable';
import FormControl from '@/Components/FormControl.vue'; import FormControl from '@/Components/FormControl.vue';
@ -36,7 +36,7 @@ const props = defineProps({
}, },
}); });
const styleService = StyleService(); // const styleService = StyleService();
// const mainService = MainService(); // const mainService = MainService();
// const items = computed(() => props.persons); // const items = computed(() => props.persons);

View File

@ -133,8 +133,8 @@ export interface Person {
id?: number; id?: number;
name?: string; name?: string;
email: string; email: string;
name_type: string; name_type?: string;
identifier_orcid: string; identifier_orcid?: string;
datasetCount?: string; datasetCount?: string;
created_at?: string; created_at?: string;
status: boolean; status: boolean;

View File

@ -1,18 +1,18 @@
<script setup> <script lang="ts" setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { StyleService } from '@/Stores/style.service'; import { StyleService } from '@/Stores/style.service';
import { // import {
mdiContrastCircle, // mdiContrastCircle,
mdiInformation, // mdiInformation,
mdiCheckCircle, // mdiCheckCircle,
mdiAlert, // mdiAlert,
mdiAlertCircle, // mdiAlertCircle,
mdiOpenInNew, // mdiOpenInNew,
mdiClose, // mdiClose,
mdiReload, // mdiReload,
mdiTrendingUp, // mdiTrendingUp,
} from '@mdi/js'; // } from '@mdi/js';
import SectionMain from '@/Components/SectionMain.vue'; import SectionMain from '@/Components/SectionMain.vue';
import CardBox from '@/Components/CardBox.vue'; import CardBox from '@/Components/CardBox.vue';
// import BaseButtons from '@/Components/BaseButtons.vue'; // import BaseButtons from '@/Components/BaseButtons.vue';
@ -28,18 +28,22 @@ import LayoutAuthenticated from "@/Layouts/LayoutAuthenticated.vue";
// import CardBoxComponentEmpty from "@/components/CardBoxComponentEmpty.vue"; // import CardBoxComponentEmpty from "@/components/CardBoxComponentEmpty.vue";
// import CardBoxComponentTitle from "@/components/CardBoxComponentTitle.vue"; // import CardBoxComponentTitle from "@/components/CardBoxComponentTitle.vue";
// import PillTag from "@/components/PillTag.vue"; // import PillTag from "@/components/PillTag.vue";
import BackgroundJob from '@/apps/settings/basic_settings/BackgroundJob.vue';
import MailSettings from '@/apps/settings/basic_settings/MailSettings.vue';
// const modalOneActive = ref(false); // const modalOneActive = ref(false);
// const modalTwoActive = ref(false); // const modalTwoActive = ref(false);
// const modalThreeActive = ref(false); // const modalThreeActive = ref(false);
// const notificationSettingsModel = ref([]); // const notificationSettingsModel = ref([]);
const styleService = StyleService(); const styleService = StyleService();
</script> </script>
<template> <template>
<LayoutAuthenticated> <LayoutAuthenticated>
<SectionTitle first>Dark mode</SectionTitle> <!-- <SectionTitle first>Dark mode</SectionTitle> -->
<!--
<SectionMain> <SectionMain>
<CardBox class="md:w-7/12 lg:w-5/12 xl:w-4/12 shadow-2xl md:mx-auto"> <CardBox class="md:w-7/12 lg:w-5/12 xl:w-4/12 shadow-2xl md:mx-auto">
@ -47,6 +51,9 @@ const styleService = StyleService();
<BaseButton label="Toggle" color="contrast" @click="styleService.setDarkMode()" /> <BaseButton label="Toggle" color="contrast" @click="styleService.setDarkMode()" />
</div> </div>
</CardBox> </CardBox>
</SectionMain> </SectionMain> -->
<BackgroundJob></BackgroundJob>
<MailSettings></MailSettings>
</LayoutAuthenticated> </LayoutAuthenticated>
</template> </template>

View File

@ -55,8 +55,6 @@ const handleScore = (score: number) => {
} else { } else {
enabled.value = false; enabled.value = false;
} }
// strengthLabel.value = scoreLabel;
// score.value = scoreValue;
}; };
</script> </script>
@ -135,7 +133,7 @@ const handleScore = (score: number) => {
color="info" color="info"
label="Submit" label="Submit"
:class="{ 'opacity-25': form.processing }" :class="{ 'opacity-25': form.processing }"
:disabled="form.processing == true || enabled == false" :disabled="form.processing == true|| (form.password != '' && enabled == false)"
/> />
</BaseButtons> </BaseButtons>
</template> </template>

View File

@ -2,7 +2,7 @@
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3'; // import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
import { Head, usePage } from '@inertiajs/vue3'; import { Head, usePage } from '@inertiajs/vue3';
import { ComputedRef } from 'vue'; import { ComputedRef } from 'vue';
import { mdiSquareEditOutline, mdiAlertBoxOutline, mdiShareVariant, mdiBookEdit } from '@mdi/js'; import { mdiSquareEditOutline, mdiAlertBoxOutline, mdiShareVariant, mdiBookEdit, mdiUndo } from '@mdi/js';
import { computed } from 'vue'; import { computed } from 'vue';
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue'; import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
import SectionMain from '@/Components/SectionMain.vue'; import SectionMain from '@/Components/SectionMain.vue';
@ -10,7 +10,7 @@ import BaseButton from '@/Components/BaseButton.vue';
import CardBox from '@/Components/CardBox.vue'; import CardBox from '@/Components/CardBox.vue';
import BaseButtons from '@/Components/BaseButtons.vue'; import BaseButtons from '@/Components/BaseButtons.vue';
import NotificationBar from '@/Components/NotificationBar.vue'; import NotificationBar from '@/Components/NotificationBar.vue';
import Pagination from '@/Components/Admin/Pagination.vue'; import Pagination from '@/Components/Pagination.vue';
import { stardust } from '@eidellev/adonis-stardust/client'; import { stardust } from '@eidellev/adonis-stardust/client';
const props = defineProps({ const props = defineProps({
@ -39,17 +39,33 @@ const flash: ComputedRef<any> = computed(() => {
}); });
// const getRowClass = (dataset) => {
// // (props.options ? 'select' : props.type)
// let rowclass = '';
// if (dataset.server_state == 'accepted') {
// rowclass = 'bg-accepted';
// } else if (dataset.server_state == 'rejected_reviewer') {
// rowclass = 'bg-rejected-reviewer';
// } else if (dataset.server_state == 'reviewed') {
// rowclass = 'bg-reviewed';
// } else if (dataset.server_state == 'released') {
// rowclass = 'bg-released';
// } else if (dataset.server_state == 'published') {
// rowclass = 'bg-published';
// } else {
// rowclass = '';
// }
// return rowclass;
// };
const getRowClass = (dataset) => { const getRowClass = (dataset) => {
// (props.options ? 'select' : props.type) // (props.options ? 'select' : props.type)
let rowclass = ''; let rowclass = '';
if (dataset.server_state == 'accepted') { if (dataset.server_state == 'released') {
rowclass = 'bg-accepted'; rowclass = 'bg-released';
} else if (dataset.server_state == 'rejected_reviewer') { } else if (dataset.server_state == 'editor_accepted' || dataset.server_state == 'rejected_reviewer') {
rowclass = 'bg-rejected-reviewer'; rowclass = 'bg-editor-accepted';
} else if (dataset.server_state == 'reviewed') { } else if (dataset.server_state == 'reviewed') {
rowclass = 'bg-reviewed'; rowclass = 'bg-reviewed';
} else if (dataset.server_state == 'released') {
rowclass = 'bg-released';
} else if (dataset.server_state == 'published') { } else if (dataset.server_state == 'published') {
rowclass = 'bg-published'; rowclass = 'bg-published';
} else { } else {
@ -58,6 +74,20 @@ const getRowClass = (dataset) => {
return rowclass; return rowclass;
}; };
// New method to format server state
const formatServerState = (state: string) => {
if (state === 'inprogress') {
return 'draft';
} else if (state === 'released') {
return 'submitted';
} else if (state === 'approved') {
return 'ready for review';
} else if (state === 'reviewer_accepted') {
return 'in review';
}
return state; // Return the original state for other cases
};
</script> </script>
@ -105,7 +135,8 @@ const getRowClass = (dataset) => {
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody class="bg-white divide-y divide-gray-200">
<tr v-for="dataset in props.datasets.data" :key="dataset.id" :class="[getRowClass(dataset)]"> <tr v-for="dataset in props.datasets.data" :key="dataset.id"
:class="[getRowClass(dataset)]">
<td data-label="Login" class="py-4 whitespace-nowrap text-gray-700 dark:text-white"> <td data-label="Login" class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
<!-- <Link v-bind:href="stardust.route('user.show', [user.id])" <!-- <Link v-bind:href="stardust.route('user.show', [user.id])"
class="no-underline hover:underline text-cyan-600 dark:text-cyan-400"> class="no-underline hover:underline text-cyan-600 dark:text-cyan-400">
@ -117,7 +148,7 @@ const getRowClass = (dataset) => {
<div class="text-sm">{{ dataset.user.login }}</div> <div class="text-sm">{{ dataset.user.login }}</div>
</td> </td>
<td class="py-4 whitespace-nowrap text-gray-700 dark:text-white"> <td class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
<div class="text-sm">{{ dataset.server_state }}</div> <div class="text-sm"> {{ formatServerState(dataset.server_state) }}</div>
</td> </td>
<td class="py-4 whitespace-nowrap text-gray-700 dark:text-white" <td class="py-4 whitespace-nowrap text-gray-700 dark:text-white"
@ -146,17 +177,23 @@ const getRowClass = (dataset) => {
<BaseButtons type="justify-start lg:justify-end" no-wrap> <BaseButtons type="justify-start lg:justify-end" no-wrap>
<BaseButton v-if="can.receive && (dataset.server_state == 'released')" <BaseButton v-if="can.receive && (dataset.server_state == 'released')"
:route-name="stardust.route('editor.dataset.receive', [dataset.id])" :route-name="stardust.route('editor.dataset.receive', [dataset.id])"
color="info" :icon="mdiSquareEditOutline" :label="'Receive edit task'" small /> color="info" :icon="mdiSquareEditOutline" :label="'Receive edit task'"
small />
<BaseButton <BaseButton
v-if="can.approve && (dataset.server_state == 'editor_accepted' || dataset.server_state == 'rejected_reviewer')" v-if="can.approve && (dataset.server_state == 'editor_accepted' || dataset.server_state == 'rejected_reviewer')"
:route-name="stardust.route('editor.dataset.approve', [dataset.id])" :route-name="stardust.route('editor.dataset.approve', [dataset.id])"
color="info" :icon="mdiShareVariant" :label="'Approve'" small /> color="info" :icon="mdiShareVariant" :label="'Approve'" small />
<BaseButton <BaseButton
v-if="can.publish && (dataset.server_state == 'reviewed')" v-if="can.approve && (dataset.server_state == 'editor_accepted' || dataset.server_state == 'rejected_reviewer')"
:route-name="stardust.route('editor.dataset.reject', [dataset.id])"
color="info" :icon="mdiUndo" label="Reject" small>
</BaseButton>
<BaseButton v-if="can.publish && (dataset.server_state == 'reviewed')"
:route-name="stardust.route('editor.dataset.publish', [dataset.id])" :route-name="stardust.route('editor.dataset.publish', [dataset.id])"
color="info" :icon="mdiBookEdit" :label="'Publish'" small /> color="info" :icon="mdiBookEdit" :label="'Publish'" small />
<BaseButton <BaseButton
v-if="can.publish && (dataset.server_state == 'published' && !dataset.identifier)" v-if="can.publish && (dataset.server_state == 'published' && !dataset.identifier)"

View File

@ -0,0 +1,99 @@
<script setup lang="ts">
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
import SectionMain from '@/Components/SectionMain.vue';
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
import { useForm, Head, usePage } from '@inertiajs/vue3';
import { computed, Ref } from 'vue';
import CardBox from '@/Components/CardBox.vue';
import FormField from '@/Components/FormField.vue';
import FormControl from '@/Components/FormControl.vue';
import BaseButton from '@/Components/BaseButton.vue';
import BaseButtons from '@/Components/BaseButtons.vue';
import { stardust } from '@eidellev/adonis-stardust/client';
import { mdiArrowLeftBoldOutline, mdiReiterate } from '@mdi/js';
import FormValidationErrors from '@/Components/FormValidationErrors.vue';
const props = defineProps({
dataset: {
type: Object,
default: () => ({}),
},
});
// Define the computed property for the label
const computedLabel = computed(() => {
return `Reject to ${props.dataset.user?.login || 'Unknown User'}`;
});
const flash: Ref<any> = computed(() => {
return usePage().props.flash;
});
const errors: Ref<any> = computed(() => {
return usePage().props.errors;
});
const form = useForm({
server_state: 'rejected_editor',
reject_editor_note: '',
});
const handleSubmit = async (e: SubmitEvent) => {
e.preventDefault();
await form.put(stardust.route('editor.dataset.rejectUpdate', [props.dataset.id]));
// await form.put(stardust.route('editor.dataset.update', [props.dataset.id]));
};
</script>
<template>
<LayoutAuthenticated>
<Head title="Reject submitted dataset" />
<SectionMain>
<SectionTitleLineWithButton :icon="mdiReiterate" title="Reject submitted dataset" main>
<BaseButton :route-name="stardust.route('editor.dataset.list')" :icon="mdiArrowLeftBoldOutline"
label="Back" color="white" rounded-full small />
</SectionTitleLineWithButton>
<CardBox form @submit.prevent="handleSubmit">
<FormValidationErrors v-bind:errors="errors" />
<FormField label="server state" :class="{ 'text-red-400': form.errors.server_state }">
<FormControl v-model="form.server_state" type="text" placeholder="-- server state --"
:is-read-only="true" :error="form.errors.server_state">
<div class="text-red-400 text-sm" v-if="form.errors.server_state">
{{ form.errors.server_state }}
</div>
</FormControl>
</FormField>
<FormField label="reject note" :class="{ 'text-red-400': form.errors.reject_editor_note }">
<FormControl v-model="form.reject_editor_note" type="textarea"
placeholder="-- reject note for submitter --" :error="form.errors.reject_editor_note">
<div class="text-red-400 text-sm" v-if="form.errors.reject_editor_note">
{{ form.errors.reject_editor_note }}
</div>
</FormControl>
</FormField>
<!-- <NotificationBar v-if="flash && flash.message" color="warning" :icon="mdiAlertBoxOutline">
{{ flash.message }}
class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"
</NotificationBar> -->
<div v-if="flash && flash.warning" class="flex flex-col mt-6 animate-fade-in">
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
<p class="font-bold">Be Warned</p>
<p>{{ flash.warning }}</p>
</div>
</div>
<template #footer>
<BaseButtons>
<BaseButton type="submit" color="info" :label="computedLabel"
:class="{ 'opacity-25': form.processing }" :disabled="form.processing" />
</BaseButtons>
</template>
</CardBox>
</SectionMain>
</LayoutAuthenticated>
</template>

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
import { Head, usePage } from '@inertiajs/vue3'; import { Head, usePage } from '@inertiajs/vue3';
import { ComputedRef } from 'vue'; import { ComputedRef } from 'vue';
import { mdiAlertBoxOutline, mdiGlasses, mdiReiterate } from '@mdi/js'; import { mdiAlertBoxOutline, mdiGlasses, mdiReiterate } from '@mdi/js';
@ -58,6 +57,20 @@ const getRowClass = (dataset) => {
return rowclass; return rowclass;
}; };
// New method to format server state
const formatServerState = (state: string) => {
if (state === 'inprogress') {
return 'draft';
} else if (state === 'released') {
return 'submitted';
} else if (state === 'approved') {
return 'ready for review';
} else if (state === 'reviewer_accepted') {
return 'in review';
}
return state; // Return the original state for other cases
};
</script> </script>
@ -117,7 +130,7 @@ const getRowClass = (dataset) => {
<div class="text-sm">{{ dataset.id }}</div> <div class="text-sm">{{ dataset.id }}</div>
</td> </td>
<td class="py-4 whitespace-nowrap text-gray-700 dark:text-white"> <td class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
<div class="text-sm">{{ dataset.server_state }}</div> <div class="text-sm">{{ formatServerState(dataset.server_state) }}</div>
</td> </td>

View File

@ -2,7 +2,7 @@
import { Head, useForm, usePage } from '@inertiajs/vue3'; import { Head, useForm, usePage } from '@inertiajs/vue3';
import { ref, watch, computed, ComputedRef } from 'vue'; import { ref, watch, computed, ComputedRef } from 'vue';
import FormValidationErrors from '@/Components/FormValidationErrors.vue'; import FormValidationErrors from '@/Components/FormValidationErrors.vue';
import { Dataset, Description, Title, Subject } from '@/Dataset'; import { Dataset, Title, Subject } from '@/Dataset';
import { import {
mdiDatabasePlus, mdiDatabasePlus,
mdiMinusCircle, mdiMinusCircle,
@ -44,6 +44,7 @@ import { LayerOptions } from '@/Components/Map/LayerOptions';
import TableKeywords from '@/Components/TableKeywords.vue'; import TableKeywords from '@/Components/TableKeywords.vue';
import NotificationBar from '@/Components/NotificationBar.vue'; import NotificationBar from '@/Components/NotificationBar.vue';
import FileUploadComponent from '@/Components/FileUpload.vue'; import FileUploadComponent from '@/Components/FileUpload.vue';
import Person from '#models/person';
const props = defineProps({ const props = defineProps({
licenses: { licenses: {
@ -276,7 +277,7 @@ const mapId = 'test';
// }; // };
const nextStep = async () => { const nextStep = async () => {
let route; let route ="";
if (formStep.value == 1) { if (formStep.value == 1) {
route = stardust.route('dataset.first.step'); route = stardust.route('dataset.first.step');
} else if (formStep.value == 2) { } else if (formStep.value == 2) {
@ -381,7 +382,7 @@ const addTitle = () => {
//this.dataset.files.push(uploadedFiles[i]); //this.dataset.files.push(uploadedFiles[i]);
form.titles.push(newTitle); form.titles.push(newTitle);
}; };
const removeTitle = (key) => { const removeTitle = (key: number) => {
form.titles.splice(key, 1); form.titles.splice(key, 1);
}; };
@ -390,11 +391,11 @@ const addDescription = () => {
//this.dataset.files.push(uploadedFiles[i]); //this.dataset.files.push(uploadedFiles[i]);
form.descriptions.push(newDescription); form.descriptions.push(newDescription);
}; };
const removeDescription = (key) => { const removeDescription = (key: number) => {
form.descriptions.splice(key, 1); form.descriptions.splice(key, 1);
}; };
const onAddAuthor = (person) => { const onAddAuthor = (person: Person) => {
if (form.authors.filter((e) => e.id === person.id).length > 0) { if (form.authors.filter((e) => e.id === person.id).length > 0) {
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as author' }, 4000); notify({ type: 'warning', title: 'Warning', text: 'person is already defined as author' }, 4000);
} else if (form.contributors.filter((e) => e.id === person.id).length > 0) { } else if (form.contributors.filter((e) => e.id === person.id).length > 0) {
@ -404,7 +405,7 @@ const onAddAuthor = (person) => {
notify({ type: 'info', text: 'person has been successfully added as author' }); notify({ type: 'info', text: 'person has been successfully added as author' });
} }
}; };
const onAddContributor = (person) => { const onAddContributor = (person: Person) => {
if (form.contributors.filter((e) => e.id === person.id).length > 0) { if (form.contributors.filter((e) => e.id === person.id).length > 0) {
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as contributor' }, 4000); notify({ type: 'warning', title: 'Warning', text: 'person is already defined as contributor' }, 4000);
} else if (form.authors.filter((e) => e.id === person.id).length > 0) { } else if (form.authors.filter((e) => e.id === person.id).length > 0) {
@ -417,7 +418,7 @@ const onAddContributor = (person) => {
} }
}; };
// const onMapInitializedEvent = "onMapInitializedEvent"; // const onMapInitializedEvent = "onMapInitializedEvent";
const onMapInitialized = (newItem) => { const onMapInitialized = (newItem: any) => {
// notify({ type: 'info', text: message }); // notify({ type: 'info', text: message });
console.log(newItem); console.log(newItem);
}; };
@ -439,7 +440,7 @@ const addReference = () => {
/* /*
Removes a selected reference Removes a selected reference
*/ */
const removeReference = (key) => { const removeReference = (key: number) => {
form.references.splice(key, 1); form.references.splice(key, 1);
}; };
/* /*
@ -593,8 +594,8 @@ Removes a selected keyword
<FormField label="Main Title *" help="required: main title" <FormField label="Main Title *" help="required: main title"
:class="{ 'text-red-400': form.errors['titles.0.value'] }" :class="{ 'text-red-400': form.errors['titles.0.value'] }"
class="w-full mx-2 flex-1"> class="w-full mx-2 flex-1">
<FormControl required v-model="form.titles[0].value" type="text" <FormControl required v-model="form.titles[0].value" type="textarea"
placeholder="[enter main title]"> placeholder="[enter main title]" :show-char-count="true" :max-input-length="255">
<div class="text-red-400 text-sm" <div class="text-red-400 text-sm"
v-if="form.errors['titles.0.value'] && Array.isArray(form.errors['titles.0.value'])"> v-if="form.errors['titles.0.value'] && Array.isArray(form.errors['titles.0.value'])">
{{ form.errors['titles.0.value'].join(', ') }} {{ form.errors['titles.0.value'].join(', ') }}
@ -739,7 +740,7 @@ Removes a selected keyword
</CardBox> </CardBox>
<!-- authors --> <!-- authors -->
<CardBox class="mb-6 shadow" has-table title="Authors" :icon="mdiBookOpenPageVariant"> <CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant">
<SearchAutocomplete source="/api/persons" :response-property="'first_name'" <SearchAutocomplete source="/api/persons" :response-property="'first_name'"
placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete> placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete>

View File

@ -239,11 +239,11 @@
</CardBox> </CardBox>
<!-- (7) authors --> <!-- (7) authors -->
<CardBox class="mb-6 shadow" has-table title="Authors" :icon="mdiBookOpenPageVariant"> <CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant">
<SearchAutocomplete source="/api/persons" :response-property="'first_name'" <SearchAutocomplete source="/api/persons" :response-property="'first_name'"
placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete> placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete>
<TablePersons :persons="form.authors" v-if="form.authors.length > 0" /> <TablePersons :persons="form.authors" v-if="form.authors.length > 0" :relation="'authors'"/>
<div class="text-red-400 text-sm" v-if="form.errors.authors && Array.isArray(form.errors.authors)"> <div class="text-red-400 text-sm" v-if="form.errors.authors && Array.isArray(form.errors.authors)">
{{ form.errors.authors.join(', ') }} {{ form.errors.authors.join(', ') }}
</div> </div>
@ -257,7 +257,7 @@
</SearchAutocomplete> </SearchAutocomplete>
<TablePersons :persons="form.contributors" v-if="form.contributors.length > 0" <TablePersons :persons="form.contributors" v-if="form.contributors.length > 0"
:contributortypes="contributorTypes" :errors="form.errors" /> :contributortypes="contributorTypes" :errors="form.errors" :relation="'contributors'" />
<div class="text-red-400 text-sm" <div class="text-red-400 text-sm"
v-if="form.errors.contributors && Array.isArray(form.errors.contributors)"> v-if="form.errors.contributors && Array.isArray(form.errors.contributors)">
{{ form.errors.contributors.join(', ') }} {{ form.errors.contributors.join(', ') }}

View File

@ -10,7 +10,7 @@ import BaseButton from '@/Components/BaseButton.vue';
import CardBox from '@/Components/CardBox.vue'; import CardBox from '@/Components/CardBox.vue';
import BaseButtons from '@/Components/BaseButtons.vue'; import BaseButtons from '@/Components/BaseButtons.vue';
import NotificationBar from '@/Components/NotificationBar.vue'; import NotificationBar from '@/Components/NotificationBar.vue';
import Pagination from '@/Components/Admin/Pagination.vue'; import Pagination from '@/Components/Pagination.vue';
import { stardust } from '@eidellev/adonis-stardust/client'; import { stardust } from '@eidellev/adonis-stardust/client';
const props = defineProps({ const props = defineProps({
@ -61,6 +61,20 @@ const getRowClass = (dataset) => {
return rowclass; return rowclass;
}; };
// New method to format server state
const formatServerState = (state: string) => {
if (state === 'inprogress') {
return 'draft';
} else if (state === 'released') {
return 'submitted';
} else if (state === 'approved') {
return 'ready for review';
} else if (state === 'reviewer_accepted') {
return 'in review';
}
return state; // Return the original state for other cases
};
</script> </script>
<template> <template>
@ -109,7 +123,7 @@ const getRowClass = (dataset) => {
{{ dataset.main_title }} {{ dataset.main_title }}
</td> </td>
<td class="py-4 whitespace-nowrap text-gray-700 dark:text-white"> <td class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
{{ dataset.server_state }} {{ formatServerState(dataset.server_state) }}
</td> </td>
<td data-label="modified" class="py-4 whitespace-nowrap text-gray-700 dark:text-white"> <td data-label="modified" class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
@ -135,42 +149,26 @@ const getRowClass = (dataset) => {
</tbody> </tbody>
</table> </table>
<div class="py-4"> <div class="py-4">
<Pagination v-bind:data="datasets.meta" /> <Pagination v-bind:data="datasets.meta" />
<!-- <ul>
<li>
<a href="{{ users.page == 1 ? '#' : '?page=' + (users.page - 1) }}">Previous</a>
</li>
@each(page in ???)
<li>
<a href="?page={{ page }}">{{ page }}</a>
</li>
@endeach
<li>
<a href="{{ users.lastPage == users.page ? '#' : '?page=' + (users.page + 1) }}">Next</a>
</li>
</ul> -->
</div> </div>
</CardBox> </CardBox>
</SectionMain> </SectionMain>
</LayoutAuthenticated> </LayoutAuthenticated>
</template> </template>
<style scoped lang="css"> <!-- <style scoped lang="css">
.pure-table tr.released { .pure-table tr.released {
/* background-color: greenyellow; */
background-color: rgb(52 211 153); background-color: rgb(52 211 153);
color: gray; color: gray;
} }
.pure-table tr.inprogress { .pure-table tr.inprogress {
padding: 0.8em; padding: 0.8em;
/* bg-teal-300 */
background-color: rgb(94 234 212); background-color: rgb(94 234 212);
color: gray; color: gray;
} }
.pure-table tr.editor_accepted { .pure-table tr.editor_accepted {
/* background-color: lightblue; */
background-color: rgb(125 211 252); background-color: rgb(125 211 252);
color: gray; color: gray;
} }
@ -181,24 +179,21 @@ const getRowClass = (dataset) => {
color: gray; color: gray;
} }
.pure-table tr.rejected_editor { .pure-table tr.rejected_editor {
/* padding: 0.8em; */
background-color: orange; background-color: orange;
color: gray; color: gray;
} }
.pure-table tr.reviewed { .pure-table tr.reviewed {
/* padding: 0.8em; */
background-color: yellow; background-color: yellow;
color: gray; color: gray;
} }
.pure-table tr.approved { .pure-table tr.approved {
/* padding: 0.8em; */
background-color: rgb(86, 86, 241); background-color: rgb(86, 86, 241);
color: whitesmoke; color: whitesmoke;
} }
</style> </style> -->

View File

@ -108,13 +108,13 @@ const flash: ComputedRef<any> = computed(() => {
class="no-underline hover:underline text-cyan-600 dark:text-cyan-400"> class="no-underline hover:underline text-cyan-600 dark:text-cyan-400">
{{ user.login }} {{ user.login }}
</Link> --> </Link> -->
<td class="p-4 flex items-center whitespace-nowrap space-x-6 mr-12 lg:mr-0"> <div class="p-4 flex items-center whitespace-nowrap space-x-6 mr-12 lg:mr-0">
<!-- <img class="h-10 w-10 rounded-full" src="/images/users/{{ .avatar }}" alt="{{ .name }} avatar"> --> <!-- <img class="h-10 w-10 rounded-full" src="/images/users/{{ .avatar }}" alt="{{ .name }} avatar"> -->
<div class="text-sm font-normal"> <div class="text-sm font-normal">
<div class="text-base font-semibold">{{ person.name }}</div> <div class="text-base font-semibold">{{ person.name }}</div>
<div class="text-sm font-normal">{{ person.email }}</div> <div class="text-sm font-normal">{{ person.email }}</div>
</div> </div>
</td> </div>
</td> </td>
<td class="p-4 whitespace-nowrap text-base font-medium">{{ person.identifier_orcid ? <td class="p-4 whitespace-nowrap text-base font-medium">{{ person.identifier_orcid ?
person.identifier_orcid : '#' }}</td> person.identifier_orcid : '#' }}</td>

View File

@ -0,0 +1,41 @@
// src/stores/locale.ts
import { defineStore } from 'pinia';
import dayjs from '@/utils/dayjs';
import { getBrowserLocale } from '@/utils/tethyscloud-l10n';
export const LocaleStore = defineStore('locale', {
state: () => ({
locale: 'en',
}),
actions: {
setLocale(locale: string) {
if (typeof localStorage !== 'undefined') {
localStorage.setItem('app-locale', locale);
}
this.locale = locale;
dayjs.locale(locale); // Update dayjs locale
},
initializeLocale() {
let locale = 'en';
// Check if localStorage is available and has a saved locale
if (typeof localStorage !== 'undefined') {
const savedLocale = localStorage.getItem('app-locale');
if (savedLocale) {
locale = savedLocale;
} else {
// Get locale from the browser if not saved in localStorage
locale = getBrowserLocale({ languageCodeOnly: true });
}
} else {
// Fallback to the browser locale if localStorage is not available
locale = getBrowserLocale({ languageCodeOnly: true });
}
this.setLocale(locale);
},
},
});

View File

@ -28,7 +28,7 @@ export enum State {
STATE_ENABLED = 2, STATE_ENABLED = 2,
} }
export const saveState = async (data) => { export const saveState = async (data: any) => {
const url = '/api/twofactor_totp/settings/enable'; const url = '/api/twofactor_totp/settings/enable';
const resp = await axios.post(url, data); const resp = await axios.post(url, data);
@ -122,7 +122,7 @@ export const MainService = defineStore('main', {
this.dataset = null; this.dataset = null;
}, },
fetch(sampleDataKey: any) { fetch(sampleDataKey: string) {
// sampleDataKey= clients or history // sampleDataKey= clients or history
axios axios
.get(`/data-sources/${sampleDataKey}.json`) .get(`/data-sources/${sampleDataKey}.json`)
@ -136,7 +136,7 @@ export const MainService = defineStore('main', {
}); });
}, },
fetchApi(sampleDataKey) { fetchApi(sampleDataKey: string) {
// sampleDataKey= authors or datasets // sampleDataKey= authors or datasets
axios axios
.get(`/api/${sampleDataKey}`) .get(`/api/${sampleDataKey}`)
@ -150,7 +150,7 @@ export const MainService = defineStore('main', {
}); });
}, },
setState(state) { setState(state: any) {
this.totpState = state; this.totpState = state;
}, },

View File

@ -61,5 +61,17 @@ export const StyleService = defineStore('style', {
document.documentElement.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars-compat'); document.documentElement.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars-compat');
} }
}, },
// Toggle dark mode
setLocale(payload?: boolean) {
this.darkMode = payload !== undefined ? payload : !this.darkMode;
if (typeof localStorage !== 'undefined') {
localStorage.setItem(darkModeKey, this.darkMode ? '1' : '0');
}
if (typeof document !== 'undefined') {
document.body.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars');
document.documentElement.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars-compat');
}
},
}, },
}); });

View File

@ -0,0 +1,10 @@
export const coreApps = ['settings', 'admin', 'log', 'core/search', 'core', '3rdparty']
export const menuSpeed = 50
export const PERMISSION_NONE = 0
export const PERMISSION_CREATE = 4
export const PERMISSION_READ = 1
export const PERMISSION_UPDATE = 2
export const PERMISSION_DELETE = 8
export const PERMISSION_SHARE = 16
export const PERMISSION_ALL = 31
export const TAG_FAVORITE = '_$!<Favorite>!$_'

38
resources/js/TC/index.js Normal file
View File

@ -0,0 +1,38 @@
import L10N from './l10n.js'
// import {
// getCanonicalLocale,
// getLanguage,
// getLocale,
// } from './l10n';
import {
coreApps,
menuSpeed,
PERMISSION_ALL,
PERMISSION_CREATE,
PERMISSION_DELETE,
PERMISSION_NONE,
PERMISSION_READ,
PERMISSION_SHARE,
PERMISSION_UPDATE,
TAG_FAVORITE,
} from './constants.js'
export default {
/*
* Constants
*/
coreApps,
menuSpeed,
PERMISSION_ALL,
PERMISSION_CREATE,
PERMISSION_DELETE,
PERMISSION_NONE,
PERMISSION_READ,
PERMISSION_SHARE,
PERMISSION_UPDATE,
TAG_FAVORITE,
L10N,
}

View File

@ -7,6 +7,7 @@ import { createInertiaApp } from '@inertiajs/vue3';
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';
import { StyleService } from '@/Stores/style.service'; import { StyleService } from '@/Stores/style.service';
import { LayoutService } from '@/Stores/layout'; import { LayoutService } from '@/Stores/layout';
import { LocaleStore } from '@/Stores/locale';
import { darkModeKey, styleKey } from '@/config'; import { darkModeKey, styleKey } from '@/config';
// import type { DefineComponent } from 'vue'; // import type { DefineComponent } from 'vue';
// import { resolvePageComponent } from '@adonisjs/inertia/helpers'; // import { resolvePageComponent } from '@adonisjs/inertia/helpers';
@ -17,6 +18,10 @@ import { EmitterPlugin } from '@/EmitterDirective';
import { initRoutes } from '@eidellev/adonis-stardust/client/index.js'; import { initRoutes } from '@eidellev/adonis-stardust/client/index.js';
initRoutes(); initRoutes();
// import { loadTranslations } from './utils/tethyscloud-l10n';
import asyncPlugin from '@/apps/settings/asyncPlugin';
// const translation = await asyncPlugin.install('settings');
// interface SetupOptions { // interface SetupOptions {
// el: Element; // el: Element;
// App: App; // App: App;
@ -59,19 +64,26 @@ createInertiaApp({
// ) // )
// }, // },
setup({ el, App, props, plugin}) { setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) }) const app = createApp({ render: () => h(App, props) })
.use(plugin) .use(plugin)
.use(pinia) .use(pinia)
// .use(i18n) // .use(i18n)
.use(EmitterPlugin) .use(EmitterPlugin);
// .component('inertia-link', Link) // .component('inertia-link', Link)
.mount(el);
asyncPlugin.install('settings').then(() => {
app.mount(el);
});
}, },
}); });
const styleService = StyleService(pinia); const styleService = StyleService(pinia);
const layoutService = LayoutService(pinia); const layoutService = LayoutService(pinia);
const localeService = LocaleStore(pinia);
localeService.initializeLocale();
// const mainService = MainService(pinia); // const mainService = MainService(pinia);
// mainService.setUser(user); // mainService.setUser(user);
@ -83,7 +95,6 @@ if ((!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dar
styleService.setDarkMode(true); styleService.setDarkMode(true);
} }
/* Collapse mobile aside menu on route change */ /* Collapse mobile aside menu on route change */
Inertia.on('navigate', () => { Inertia.on('navigate', () => {
layoutService.isAsideMobileExpanded = false; layoutService.isAsideMobileExpanded = false;

View File

@ -0,0 +1,13 @@
import { loadTranslations } from '@/utils/tethyscloud-l10n';
// export const register = async () => {
// await loadTranslations('settings');
// };
// asyncPlugin.js
export default {
async install(app: string) {
// Perform your async setup logic here
await loadTranslations(app);
}
};

View File

@ -0,0 +1,191 @@
<template>
<NcSettingsSection :name="t('settings', 'Background jobs')" :description="t(
'settings',
`For the server to work properly, it\'s important to configure background jobs correctly. Cron is the recommended setting. Please see the documentation for more information.`,
)" :doc-url="backgroundJobsDocUrl">
<template v-if="lastCron !== 0">
<NcNoteCard v-if="oldExecution" type="danger">
{{ t('settings', `Last job execution ran {time}. Something seems wrong.`, {
time: relativeTime,
timestamp: lastCron
}) }}
</NcNoteCard>
<!-- <NcNoteCard v-else-if="longExecutionCron" type="warning">
{{ t('settings', `Some jobs have not been executed since {maxAgeRelativeTime}. Please consider increasing the execution frequency.`, {maxAgeRelativeTime}) }}
</NcNoteCard> -->
<NcNoteCard v-else type="success">
{{ t('settings', 'Last job ran {relativeTime}.', { relativeTime }) }}
</NcNoteCard>
</template>
<NcNoteCard v-else type="danger">
'Background job did not run yet!'
</NcNoteCard>
</NcSettingsSection>
</template>
<script lang="ts">
import { usePage } from '@inertiajs/vue3';
import { loadState } from '@/utils/initialState';
import { showError } from '@/utils/toast';
// import { generateOcsUrl } from '@nextcloud/router';
// import { confirmPassword } from '@nextcloud/password-confirmation';
import axios from 'axios';
import dayjs from '@/utils/dayjs';
import NcNoteCard from '@/Components/NCNoteCard.vue';
import NcSettingsSection from '@/Components/NcSettingsSection.vue';
import { translate as t } from '@/utils/tethyscloud-l10n';
// import { useLocaleStore } from '@/Stores/locale';
// import '@nextcloud/password-confirmation/dist/style.css';
// const lastCron: number = 1723807502; //loadState('settings', 'lastCron'); //1723788607
const cronMaxAge: number = 1724046901;//loadState('settings', 'cronMaxAge', 0); //''
const backgroundJobsMode: string = loadState('settings', 'backgroundJobsMode', 'cron'); //cron
const cliBasedCronPossible = loadState('settings', 'cliBasedCronPossible', true); //true
const cliBasedCronUser = loadState('settings', 'cliBasedCronUser', 'www-data'); //www-data
const backgroundJobsDocUrl: string = loadState('settings', 'backgroundJobsDocUrl'); //https://docs.nextcloud.com/server/29/go.php?to=admin-background-jobs
// await loadTranslations('settings');
export default {
name: 'BackgroundJob',
components: {
NcSettingsSection,
NcNoteCard,
},
data() {
return {
// lastCron: 0,
cronMaxAge: cronMaxAge,
backgroundJobsMode: backgroundJobsMode,
cliBasedCronPossible: cliBasedCronPossible,
cliBasedCronUser: cliBasedCronUser,
backgroundJobsDocUrl: backgroundJobsDocUrl,
// relativeTime: dayjs(this.lastCron * 1000).fromNow(),
// maxAgeRelativeTime: dayjs(cronMaxAge * 1000).fromNow(),
t: t,
};
},
computed: {
lastCron(): number {
return usePage().props.lastCron as number;
},
relativeTime() {
return dayjs.unix(this.lastCron).fromNow(); // Calculate relative time for lastCron
},
maxAgeRelativeTime() {
return dayjs.unix(this.cronMaxAge).fromNow(); // Calculate relative time for cronMaxAge
},
cronLabel() {
let desc = 'Use system cron service to call the cron.php file every 5 minutes.';
if (this.cliBasedCronPossible) {
desc +=
'<br>' +
'The cron.php needs to be executed by the system account "{user}".', { user: this.cliBasedCronUser };
} else {
desc +=
'<br>' +
'The PHP POSIX extension is required. See {linkstart}PHP documentation{linkend} for more details.',
{
linkstart:
'<a target="_blank" rel="noreferrer nofollow" class="external" href="https://www.php.net/manual/en/book.posix.php">',
linkend: '</a>',
}
}
return desc;
},
oldExecution() {
return (dayjs().unix() - this.lastCron) > 600; // older than 10 minutes
},
longExecutionCron() {
//type of cron job and greater than 24h
// let test = dayjs.unix(this.cronMaxAge).format('YYYY-MM-DD HH:mm:ss');
return (dayjs().unix() - this.cronMaxAge) > 24 * 3600 && this.backgroundJobsMode === 'cron';
},
},
methods: {
async onBackgroundJobModeChanged(backgroundJobsMode: string) {
const url = generateOcsUrl('/apps/provisioning_api/api/v1/config/apps/{appId}/{key}', {
appId: 'core',
key: 'backgroundjobs_mode',
});
// await confirmPassword();
try {
const { data } = await axios.post(url, {
value: backgroundJobsMode,
});
this.handleResponse({
status: data.ocs?.meta?.status,
});
} catch (e) {
this.handleResponse({
errorMessage: t('settings', 'Unable to update background job mode'),
error: e,
});
}
},
async handleResponse({ status, errorMessage, error }) {
if (status === 'ok') {
await this.deleteError();
} else {
showError(errorMessage);
console.error(errorMessage, error);
}
},
async deleteError() {
// clear cron errors on background job mode change
const url = generateOcsUrl('/apps/provisioning_api/api/v1/config/apps/{appId}/{key}', {
appId: 'core',
key: 'cronErrors',
});
// await confirmPassword();
try {
await axios.delete(url);
} catch (error) {
console.error(error);
}
},
},
};
</script>
<style lang="css" scoped>
.error {
margin-top: 8px;
padding: 5px;
border-radius: var(--border-radius);
color: var(--color-primary-element-text);
background-color: var(--color-error);
width: initial;
}
.warning {
margin-top: 8px;
padding: 5px;
border-radius: var(--border-radius);
color: var(--color-primary-element-text);
background-color: var(--color-warning);
width: initial;
}
.ajaxSwitch {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,198 @@
<template>
<NcSettingsSection :name="t('settings', 'Email server')" :description="t(
'settings',
`It is important to set up this server to be able to send emails, like for password reset and notifications.`,
)" :doc-url="linkToDocs('admin-email')">
<NotificationBar v-if="flash.message" color="success" :icon="mdiAlertBoxOutline">
{{ flash.message }}
</NotificationBar>
<!-- from address for sendmail -->
<!-- <div v-show="form.mail_smtp_mode === 'sendmail'" class="flex flex-col space-y-2">
<label for="mail_sendmailmode" class="font-medium">{{ t('settings', 'Sendmail mode') }}</label>
<FormControl name="mail_sendmailmode" id="mail_sendmailmode" v-model="form.mailSendmailmode"
:options="mailSendmailmodeOptions">
</FormControl>
</div> -->
<!-- <form id="mail_general_settings_form" @submit.prevent="saveMailSettingsForm" class="space-y-6">
<p>
<span id="mail_settings_msg" class="text-red-500">{{ message }}</span>
</p>
<div class="flex flex-col space-y-2">
<label for="mail_smtpmode" class="font-medium">{{ t('settings', 'Send mode') }}</label>
<FormControl type="select" name="mail_smtpmode" id="mail_smtpmode" v-model="form.mail_smtp_mode"
@change="handleModeChange" :options="mailSmtpmodeOptions">
</FormControl>
</div>
<div v-show="form.mail_smtp_mode === 'smtp'" class="flex flex-col space-y-2">
<label for="mail_smtpsecure" class="font-medium">{{ t('settings', 'Encryption') }}</label>
<FormControl type="select" name="mail_smtpsecure" id="mail_smtpsecure" v-model="form.mail_smtpsecure"
:options="mailSmtpsecureOptions">
</FormControl>
</div>
<div class="flex flex-col space-y-2">
<label for="mail_from_address" class="font-medium">{{ t('settings', 'From address') }}</label>
<div class="flex space-x-2">
<FormControl type="text" name="mail_from_address" id="mail_from_address"
v-model="form.mail_from_address" :placeholder="t('settings', 'Email')" class="flex-grow" />
<span class="text-gray-600">@</span>
<FormControl type="text" name="mail_domain" id="mail_domain" placeholder="example.com"
v-model="form.mail_domain" class="flex-grow" />
</div>
</div>
<div v-show="form.mail_smtp_mode === 'smtp'" class="flex flex-col space-y-2">
<label for="mail_smtphost" class="font-medium">{{ t('settings', 'Server address') }}</label>
<div class="flex space-x-2">
<FormControl type="text" name="mail_smtphost" id="mail_smtphost" placeholder="smtp.example.com"
v-model="form.mail_smtphost" class="flex-grow" />
<span class="text-gray-600">:</span>
<FormControl type="text" inputmode="numeric" name="mail_smtpport" id="mail_smtpport"
:placeholder="t('settings', 'Port')" v-model="form.mail_smtpport" class="flex-shrink" />
</div>
</div>
<div v-show="form.mail_smtp_mode === 'smtp'" class="flex flex-col space-y-2">
<label for="mail_smtpauthtype" class="font-medium">{{ t('settings', 'Authentication') }}</label>
<div class="flex items-center space-x-2">
<input type="checkbox" name="mail_smtpauth" id="mail_smtpauth" v-model="form.mail_smtpauth"
class="form-checkbox" />
<label for="mail_smtpauth" class="font-medium">{{ t('settings', 'Authentication required') }}
</label>
</div>
</div>
<BaseButtons>
<BaseButton type="submit" color="info" label="Submit" :class="{ 'opacity-25': form.processing }"
:disabled="form.processing == true" />
</BaseButtons>
</form> -->
<!-- <form id="mail_credentials_settings" class="mt-6">
<div v-show="form.mail_smtpauth && form.mail_smtp_mode === 'smtp'" class="flex flex-col space-y-2">
<label for="mail_smtpname" class="font-medium">{{ t('settings', 'Credentials') }}</label>
<FormControl type="text" name="mail_smtpname" id="mail_smtpname"
:placeholder="t('settings', 'SMTP Login')" v-model="mail_smtpname" />
<FormControl type="password" name="mail_smtppassword" id="mail_smtppassword"
placeholder="t('settings', 'SMTP Password')" v-model="mail_smtppassword" />
<input id="mail_credentials_settings_submit" type="button" :value="t('settings', 'Save')"
@click="storeCredentialsForm" class="mt-2 btn btn-primary" />
</div>
</form> -->
<div class="mt-6">
<em>{{ t('settings', 'Test and verify email settings') }}</em>
<BaseButtons>
<BaseButton type="submit" color="info" name="testemail" id="testemail"
:label="t('settings', 'Test email')" @click="sendTestEmail" :small="true" />
</BaseButtons>
<span id="sendtestmail_msg" class="text-blue-500 ml-4">{{ testMailMessage }}</span>
</div>
</NcSettingsSection>
</template>
<script setup lang="ts">
import axios from 'axios';
import { ref, ComputedRef, computed } from 'vue';
import { useForm, usePage } from '@inertiajs/vue3';
import NcSettingsSection from '@/Components/NcSettingsSection.vue';
import { translate as t } from '@/utils/tethyscloud-l10n';
import BaseButton from '@/Components/BaseButton.vue';
import BaseButtons from '@/Components/BaseButtons.vue';
// import FormControl from '@/Components/FormControl.vue';
import { stardust } from '@eidellev/adonis-stardust/client';
import NotificationBar from '@/Components/NotificationBar.vue';
import { mdiAlertBoxOutline } from '@mdi/js';
import Notification from '@/utils/toast';
const flash: ComputedRef<any> = computed(() => {
// let test = usePage();
// console.log(test);
return usePage().props.flash;
});
const message = ref('');
const testMailMessage = ref('');
const form = useForm({
mail_smtp_mode: 'smtp',
mail_smtpsecure: '',
mailSendmailmode: 'smtp',
mail_from_address: '',
mail_domain: '',
mail_smtphost: '',
mail_smtpport: '',
mail_smtpauthtype: 'LOGIN',
mail_smtpauth: false,
});
const mail_smtpname = ref('');
const mail_smtppassword = ref('');
const mailSmtpmodeOptions = ref({
'smtp': 'SMTP',
'sendmail': 'Sendmail',
});
const mailSmtpsecureOptions = ref({
'': 'None/STARTTLS',
ssl: 'SSL',
});
// const mailSendmailmodeOptions = ref({
// smtp: 'smtp (-bs)',
// pipe: 'pipe (-t -i)',
// });
const handleModeChange = () => {
// Logic to update visibility based on selected mailSmtpmode
};
const saveMailSettingsForm = async () => {
// Logic to save the email server settings
await form.post(stardust.route('settings.mail.store'));
};
const storeCredentialsForm = () => {
// Logic to save the email credentials
};
const sendTestEmail = async () => {
// Logic to send a test email
try {
const response = await axios.post(stardust.route('settings.mail.send'));
if (response.data && response.data.success) {
Notification.showSuccess(response.data.message);
}
} catch (error) {
Notification.showError(error.message)
}
// ;
// if (response.data.success) {
// // responseMessage.value = response.data.message;
// Notification.showSuccess(response.data.message);
// } else {
// // responseMessage.value = 'An error occurred.';
// Notification.showError('An error occurred.')
// }
};
const linkToDocs = (page: string) => {
return `https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/${page}.html`;
};
</script>
<style lang="css" scoped>
.hidden {
display: none;
}
</style>

View File

@ -0,0 +1,78 @@
<template>
<div id="profile-settings" class="section">
<h2 class="inlineblock">
{{ t('settings', 'Profile') }}
</h2>
<p class="settings-hint">
{{ t('settings', 'Enable or disable profile by default for new accounts.') }}
</p>
<NcCheckboxRadioSwitch type="switch" :checked.sync="initialProfileEnabledByDefault"
@update:checked="onProfileDefaultChange">
{{ t('settings', 'Enable') }}
</NcCheckboxRadioSwitch>
</div>
</template>
<script lang="ts">
// import { loadState } from '@nextcloud/initial-state'
import { loadState } from '@/utils/initialState';
import { showError } from '@/utils/toast.js';
import { saveProfileDefault } from '../../service/ProfileService.js'
import { validateBoolean } from '../../utils/validate.js'
import logger from '../../logger.ts'
// import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
const profileEnabledByDefault = loadState('settings', 'profileEnabledByDefault', true)
export default {
name: 'ProfileSettings',
components: {
NcCheckboxRadioSwitch,
},
data() {
return {
initialProfileEnabledByDefault: profileEnabledByDefault,
}
},
methods: {
async onProfileDefaultChange(isEnabled: boolean) {
if (validateBoolean(isEnabled)) {
await this.updateProfileDefault(isEnabled)
}
},
async updateProfileDefault(isEnabled: boolean) {
try {
const responseData = await saveProfileDefault(isEnabled)
this.handleResponse({
isEnabled,
status: responseData.ocs?.meta?.status,
})
} catch (e) {
this.handleResponse({
errorMessage: t('settings', 'Unable to update profile default setting'),
error: e,
})
}
},
handleResponse({ isEnabled, status, errorMessage, error }) {
if (status === 'ok') {
this.initialProfileEnabledByDefault = isEnabled
} else {
showError(errorMessage)
logger.error(errorMessage, error)
}
},
},
}
</script>
<style lang="css" scoped></style>

View File

@ -0,0 +1,902 @@
export default {
"translations": {
"Private": "Privat",
"Only visible to people matched via phone number integration through Talk on mobile": "Nur sichtbar für Personen, die über die Rufnummernintegration von Talk auf dem Smartphone abgeglichen wurden.",
"Local": "Lokal",
"Only visible to people on this instance and guests": "Nur für Personen dieser Instanz und Gäste sichtbar",
"Federated": "Federated",
"Only synchronize to trusted servers": "Nur mit vertrauenswürdigen Servern synchronisieren",
"Published": "Veröffentlicht",
"Synchronize to trusted servers and the global and public address book": "Mit vertrauenswürdigen Servern und dem globalen und öffentlichen Adressbuch synchronisieren",
"Verify": "Überprüfen",
"Verifying …": "Überprüfe …",
"Unable to change password": "Passwort konnte nicht geändert werden",
"Very weak password": "Sehr schwaches Passwort",
"Weak password": "Schwaches Passwort",
"So-so password": "Akzeptables Passwort",
"Good password": "Gutes Passwort",
"Strong password": "Starkes Passwort",
"Groups": "Gruppen",
"Group list is empty": "Gruppenliste ist leer",
"Unable to retrieve the group list": "Gruppenliste konnte nicht abgerufen werden",
"{actor} added you to group {group}": "{actor} hat dich zur Gruppe {group} hinzugefügt",
"You added {user} to group {group}": "Du hast {user} zur Gruppe {group} hinzugefügt",
"{actor} added {user} to group {group}": "{actor} hat {user} zur Gruppe {group} hinzugefügt",
"An administrator added you to group {group}": "Ein Administrator hat dich zur Gruppe {group} hinzugefügt",
"An administrator added {user} to group {group}": "Ein Administrator hat {user} zur Gruppe {group} hinzugefügt",
"{actor} removed you from group {group}": "{actor} hat dich von der Gruppe {group} entfernt",
"You removed {user} from group {group}": "Du hast {user} von der Gruppe {group} entfernt",
"{actor} removed {user} from group {group}": "{actor} hat {user} von der Gruppe {group} entfernt",
"An administrator removed you from group {group}": "Ein Administrator hat dich von der Gruppe {group} entfernt",
"An administrator removed {user} from group {group}": "Ein Administrator hat {user} von der Gruppe {group} entfernt",
"Your <strong>group memberships</strong> were modified": "Deine <strong>Gruppenmitgliedschaft</strong> wurde geändert",
"{actor} changed your password": "{actor} hat dein Passwort geändert",
"You changed your password": "Du hast dein Passwort geändert",
"Your password was reset by an administrator": "Dein Passwort wurde vom Administrator zurückgesetzt",
"Your password was reset": "Dein Passwort wurde zurückgesetzt",
"{actor} changed your email address": "{actor} hat deine E-Mail-Adresse geändert",
"You changed your email address": "Du hast deine E-Mail-Adresse geändert",
"Your email address was changed by an administrator": "Deine E-Mail-Adresse wurde von einem Administrator geändert",
"You created an app password for a session named \"{token}\"": "Du hast ein App-Passwort für eine Sitzung mit dem Namen \"{token}\" erstellt.",
"An administrator created an app password for a session named \"{token}\"": "Die Administration hat ein App-Passwort für eine Sitzung mit dem Namen \"{token}“ erstellt",
"You deleted app password \"{token}\"": "Du hast das App-Passwort \"{token}\" entfernt",
"You renamed app password \"{token}\" to \"{newToken}\"": "Du hast App-Passwort \"{token}\" in \"{newToken}\" umbenannt",
"You granted filesystem access to app password \"{token}\"": "Du hast Dateisystemzugriff für App-Passwort \"{token}\" erlaubt",
"You revoked filesystem access from app password \"{token}\"": "Du hast Dateisystemzugriff für App-Passwort \"{token}\" widerrufen",
"Security": "Sicherheit",
"You successfully logged in using two-factor authentication (%1$s)": "Du hast dich erfolgreich mittels Zwei-Faktor-Authentifizierung angemeldet (%1$s)",
"A login attempt using two-factor authentication failed (%1$s)": "Ein Anmeldeversuch mittels Zwei-Faktor-Authentifizierung schlug fehl (%1$s)",
"Remote wipe was started on %1$s": "Fernlöschung wurde am %1$s gestartet",
"Remote wipe has finished on %1$s": "Fernlöschung wurde am %1$s abgeschlossen",
"Your <strong>password</strong> or <strong>email</strong> was modified": "Dein <strong>Passwort</strong> oder deine <strong>E-Mail-Adresse</strong> wurde geändert",
"Settings": "Einstellungen",
"Could not remove app.": "App konnte nicht entfernt werden",
"Could not update app.": "App konnte nicht aktualisiert werden",
"Wrong password": "Falsches Passwort",
"Unable to change personal password": "Das persönliche Passwort konnte nicht geändert werden",
"Saved": "Gespeichert",
"No Login supplied": "Keine Anmeldename eingegeben",
"Unable to change password. Password too long.": "Passwort konnte nicht geändert werden. Passwort ist zu lang.",
"Authentication error": "Authentifizierungsfehler",
"Please provide an admin recovery password; otherwise, all account data will be lost.": "Bitte gib ein Wiederherstellungspasswort für das Administrationskonto an, da sonst alle Kontodaten verlorengehen.",
"Wrong admin recovery password. Please check the password and try again.": "Falsches Wiederherstellungspasswort für das Admin-Konto. Bitte überprüfe das Passwort und versuche es erneut.",
"Backend does not support password change, but the encryption of the account key was updated.": "Das Backend unterstützt keine Passwortänderung, aber die Verschlüsselung des Kontoschlüssels wurde aktualisiert.",
"Administrator documentation": "Dokumentation für Administratoren",
"User documentation": "Dokumentation für Benutzer",
"Nextcloud help overview": "Übersicht über die Nextcloud-Hilfe",
"Invalid SMTP password.": "Ungültiges SMTP-Passwort",
"Email setting test": "Test der E-Mail-Einstellungen",
"Well done, %s!": "Gut gemacht, %s!",
"If you received this email, the email configuration seems to be correct.": "Wenn du diese E-Mail empfangen hast, sind die E-Mail-Einstellungen korrekt.",
"Email could not be sent. Check your mail server log": "E-Mail konnte nicht versandt werden. Prüfe dein E-Mail-Server-Protokoll",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)": "Beim Senden der E-Mail ist ein Problem aufgetreten. Bitte überprüfe deine Einstellungen. (Fehler: %s)",
"You need to set your account email before being able to send test emails. Go to %s for that.": "Du musst deine Konto-E-Mail-Adresse festlegen, bevor du Test-E-Mails senden kannst. Gehe dazu zu %s.",
"Recently active": "Kürzlich aktiv",
"Disabled accounts": "Deaktivierte Konten",
"Invalid account": "Ungültiges Benutzerkonto",
"Invalid mail address": "Ungültige E-Mail-Adresse",
"Settings saved": "Einstellungen gespeichert",
"Unable to change full name": "Der vollständige Name konnte nicht geändert werden",
"Unable to change email address": "E-Mail-Adresse konnte nicht geändert werden",
"Unable to set invalid phone number": "Ungültige Telefonnummer konnte nicht festgelegt werden",
"Unable to set invalid website": "Ungültige Webseite konnte nicht eingestellt werden",
"Some account data was invalid": "Einige Kontodaten waren ungültig",
"In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):": "Um dein X-Konto zu überprüfen, veröffentliche bitte den folgenden Tweet auf X (Bitte stelle sicher, dass der Tweet keinen Zeilenumbruch enthält):",
"In order to verify your Website, store the following content in your web-root at '.well-known/CloudIdVerificationCode.txt' (please make sure that the complete text is in one line):": "Um deine Webseite zu überprüfen, speichere bitte den folgenden Inhalt im Web-Wurzelverzeichnist in der Datei '.well-known/CloudIdVerificationCode.txt' (bitte stelle sicher, das sich der gesamte Text in einer Zeile befindet):",
"%1$s changed your password on %2$s.": "%1$s hat dein Passwort auf %2$s geändert.",
"Your password on %s was changed.": "Dein Passwort auf %s wurde geändert.",
"Your password on %s was reset by an administrator.": "Dein Passwort auf %s wurde vom Administrator zurückgesetzt.",
"Your password on %s was reset.": "Dein Passwort auf %s wurde zurückgesetzt",
"Password for %1$s changed on %2$s": "Passwort für %1$s geändert auf %2$s",
"Password changed for %s": "Passwort geändert für %s",
"If you did not request this, please contact an administrator.": "Wenn du das nicht angefordert haben solltest, wende dich bitte an den Administrator.",
"Your email address on %s was changed.": "Deine E-Mail-Adresse auf %s wurde geändert.",
"Your email address on %s was changed by an administrator.": "Deine E-Mail-Adresse auf %s wurde von einem Administrator geändert.",
"Email address for %1$s changed on %2$s": "E-Mail-Adresse für %1$s geändert auf %2$s",
"Email address changed for %s": "Die E-Mail-Adresse für %s wurde geändert",
"The new email address is %s": "Die neue E-Mail-Adresse lautet %s",
"Your %s account was created": "Dein %s-Konto wurde erstellt",
"Welcome aboard": "Willkommen an Bord",
"Welcome aboard %s": "Willkommen an Bord %s",
"Welcome to your %s account, you can add, protect, and share your data.": "Willkommen zu deinem %s-Konto. Du kannst deine Daten hinzufügen, schützen und teilen.",
"Your Login is: %s": "Dein Anmeldename lautet: %s",
"Set your password": "Setze dein Passwort",
"Go to %s": "%s aufrufen",
"Install Client": "Installiere den Client",
"Logged in account must be a subadmin": "Das angemeldete Konto muss eine Subadministration sein.",
"Apps": "Apps",
"Personal": "Persönlich",
"Administration": "Verwaltung",
"Users": "Benutzer",
"Additional settings": "Zusätzliche Einstellungen",
"Artificial Intelligence": "Künstliche Intelligenz",
"Administration privileges": "Administratorrechte",
"Groupware": "Groupware",
"Overview": "Übersicht",
"Basic settings": "Grundeinstellungen",
"Sharing": "Teilen",
"Availability": "Verfügbarkeit",
"Calendar": "Kalender",
"Personal info": "Persönliche Informationen",
"Mobile & desktop": "Mobil & Desktop",
"Email server": "E-Mail-Server",
"Security & setup warnings": "Sicherheits- & Einrichtungswarnungen",
"Background jobs": "Hintergrund-Jobs",
"Unlimited": "Unbegrenzt",
"Verifying": "Überprüfe",
"Allowed admin IP ranges": "Zulässige Administrations-IP-Bereiche",
"Admin IP filtering isnt applied.": "Administrations-IP-Filterung ist nicht aktiv.",
"Configuration key \"%1$s\" expects an array (%2$s found). Admin IP range validation will not be applied.": "Der Konfigurationsschlüssel \"%1$s\" erwartet ein Array (%2$s gefunden). Die Validierung des Administrations-IP-Bereichs wird nicht angewendet.",
"Configuration key \"%1$s\" contains invalid IP range(s): \"%2$s\"": "Konfigurationsschlüssel \"%1$s\" enthält ungültige IP-Bereiche: \"%2$s\"",
"Admin IP filtering is correctly configured.": "Administrations-IP-Filterung ist richtig konfiguriert.",
"App directories owner": "Besitzende der App-Ordner",
"Some app directories are owned by a different user than the web server one. This may be the case if apps have been installed manually. Check the permissions of the following app directories:\n%s": "Einige App-Ordner werden von einem anderen Konto als dem des Web-Servers besessen. Dies kann der Fall sein, wenn Apps manuell installiert wurden. Überprüfe die Berechtigungen der folgenden App-Ordner:\n%s",
"App directories have the correct owner \"%s\"": "App-Ordner haben den richtigen Besitzenden \"%s\"",
"Brute-force Throttle": "Brute-Force-Drosselung",
"Your remote address could not be determined.": "Ihre Remote-Adresse konnte nicht ermittelt werden.",
"Your remote address was identified as \"%s\" and is brute-force throttled at the moment slowing down the performance of various requests. If the remote address is not your address this can be an indication that a proxy is not configured correctly.": "Ihre Remote-Adresse wurde als \"%s\" erkannt und wird derzeit durch die Brute-Force-Erkennung gedrosselt, was die Leistung verschiedener Anfragen verlangsamt. Wenn die Remote-Adresse nicht Ihre Adresse ist, kann dies ein Hinweis darauf sein, dass ein Proxy nicht richtig konfiguriert ist.",
"Your remote address \"%s\" is not brute-force throttled.": "Ihre Remote-Adresse \"%s\" ist nicht durch die Brute-Force-Erkennung gedrosselt.",
"To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule.": "Damit diese Prüfung ausgeführt werden kann, musst du sicherstellen, dass dein Webserver eine Verbindung zu sich selbst herstellen kann. Daher muss er in der Lage sein, mindestens eine seiner `trusted_domains` oder `overwrite.cli.url` aufzulösen und eine Verbindung zu ihnen herzustellen. Dieser Fehler kann das Ergebnis einer serverseitigen DNS-Nichtübereinstimmung oder einer ausgehenden Firewall-Regel sein.",
"Old administration imported certificates": "Alte, von der Adminstration importierte Zertifikate",
"A background job is pending that checks for administration imported SSL certificates. Please check back later.": "Eine Hintergrundaufgabe, die nach, von der Adminstration importierten SSL-Zertifikaten sucht, läuft noch. Bitte später erneut versuchen.",
"There are some administration imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.": "Es sind einige, von der Administration importierte SSL-Zertifikate vorhanden, die von Nextcloud 21 nicht mehr verwendet werden. Du kannst diese über den Befehl \"occ security:certificates:import\" in der Befehlszeile importieren. Ihre Pfade innerhalb des Datenverzeichnisses werden unten angezeigt.",
"Code integrity": "Codeintegrität",
"Integrity checker has been disabled. Integrity cannot be verified.": "Die Integritätsprüfung wurde deaktiviert. Die Integrität kann nicht überprüft werden.",
"No altered files": "Keine veränderten Dateien",
"Some files have not passed the integrity check. {link1} {link2}": "Einige Dateien haben die Integritätsprüfung nicht bestanden. {link1} {link2}",
"Cron errors": "Cron-Fehler",
"It was not possible to execute the cron job via CLI. The following technical errors have appeared:\n%s": "Es war nicht möglich, den Cron-Job über die CLI auszuführen. Es sind folgende technische Fehler aufgetreten:\n%s",
"The last cron job ran without errors.": "Der letzte Cron-Job wurde ohne Fehler ausgeführt.",
"Cron last run": "Cron zuletzt ausgeführt",
"Last background job execution ran %s. Something seems wrong. {link}.": "Letzte Hintergrund-Jobausführung lief %s. Etwas scheint nicht in Ordnung zu sein. {link}.",
"Last background job execution ran %s.": "Letzte Hintergrund-Jobausführung lief %s.",
"Data directory protected": "Datenverzeichnis geschützt",
"Your data directory and files are probably accessible from the internet. The .htaccess file is not working. It is strongly recommended that you configure your web server so that the data directory is no longer accessible, or move the data directory outside the web server document root.": "Dein Datenverzeichnis und deine Dateien sind wahrscheinlich vom Internet aus erreichbar. Die .htaccess-Datei funktioniert nicht. Es wird dringend empfohlen, deinen Webserver dahingehend zu konfigurieren, dass das Datenverzeichnis nicht mehr vom Internet aus erreichbar ist oder dass du es aus dem Document-Root-Verzeichnis des Webservers herausverschiebst.",
"Could not check that the data directory is protected. Please check manually that your server does not allow access to the data directory.": "Konnte nicht überprüfen, ob das Datenverzeichnis geschützt ist. Bitte überprüfe manuell, ob dein Server keinen Zugriff auf das Datenverzeichnis erlaubt.",
"Database missing columns": "In der Datenbank fehlen Spalten",
"Missing optional column \"%s\" in table \"%s\".": "Fehlende optionale Spalte \"%s\" in der Tabelle \"%s\".",
"The database is missing some optional columns. Due to the fact that adding columns on big tables could take some time they were not added automatically when they can be optional. By running \"occ db:add-missing-columns\" those missing columns could be added manually while the instance keeps running. Once the columns are added some features might improve responsiveness or usability.": "In der Datenbank fehlen einige optionale Spalten. Da das Hinzufügen von Spalten bei großen Tabellen einige Zeit dauern kann, wurden sie nicht automatisch hinzugefügt, wenn sie optional sein können. Durch Ausführen von \"occ db:add-missing-columns\" können diese fehlenden Spalten manuell hinzugefügt werden, während die Instanz weiter läuft. Sobald die Spalten hinzugefügt sind, könnten einige Funktionen die Reaktionsfähigkeit oder die Benutzerfreundlichkeit verbessern.",
"Database missing indices": "In der Datenbank fehlen Indizes",
"Missing indices:": "Fehlende Indizes:",
"\"%s\" in table \"%s\"": "\"%s\" in Tabelle \"%s\"",
"Detected some missing optional indices. Occasionally new indices are added (by Nextcloud or installed applications) to improve database performance. Adding indices can sometimes take awhile and temporarily hurt performance so this is not done automatically during upgrades. Once the indices are added, queries to those tables should be faster. Use the command `occ db:add-missing-indices` to add them. ": "Einige fehlende optionale Indizes wurden erkannt. Gelegentlich werden neue Indizes hinzugefügt (von Nextcloud oder installierten Anwendungen), um die Datenbankleistung zu verbessern. Das Hinzufügen von Indizes kann manchmal eine Weile dauern und die Leistung vorübergehend beeinträchtigen, daher wird dies bei Upgrades nicht automatisch durchgeführt. Sobald die Indizes hinzugefügt wurden, sollten Abfragen an diese Tabellen schneller sein. Verwende den Befehl `occ db:add-missing-indices`, um sie hinzuzufügen.",
"Database missing primary keys": "In der Datenbank fehlen Primärschlüssel",
"Missing primary key on table \"%s\".": "Fehlender Primärschlüssel in Tabelle \"%s\".",
"The database is missing some primary keys. Due to the fact that adding primary keys on big tables could take some time they were not added automatically. By running \"occ db:add-missing-primary-keys\" those missing primary keys could be added manually while the instance keeps running.": "In der Datenbank fehlen einige Primärschlüssel. Aufgrund der Tatsache, dass das Hinzufügen von Primärschlüsseln bei großen Tabellen einige Zeit dauern konnte, wurden sie nicht automatisch hinzugefügt. Durch Ausführen von \"occ db:add-missing-primary-keys\" können diese fehlenden Primärschlüssel manuell hinzugefügt werden, während die Instanz weiter läuft.",
"Database pending bigint migrations": "Datenbank mit ausstehenden Bigint-Migrationen",
"Some columns in the database are missing a conversion to big int. Due to the fact that changing column types on big tables could take some time they were not changed automatically. By running \"occ db:convert-filecache-bigint\" those pending changes could be applied manually. This operation needs to be made while the instance is offline.": "Bei einigen Spalten in der Datenbank fehlt eine Konvertierung in Big Int. Da die Änderung der Spaltentypen bei großen Tabellen einige Zeit in Anspruch nehmen kann, erfolgt die Änderung nicht automatisch. Durch Ausführen von \"occ db:convert-filecache-bigint“ können diese ausstehenden Änderungen manuell durchgeführt werden. Bei der Durchführung muss die Instanz offline sein.",
"Debug mode": "Debug-Modus",
"This instance is running in debug mode. Only enable this for local development and not in production environments.": "Diese Instanz wird im Debug-Modus ausgeführt. Aktiviere dies nur für die lokale Entwicklung und nicht in Produktionsumgebungen.",
"Debug mode is disabled.": "Debug-Modus ist deaktiviert.",
"Default phone region": "Standard-Telefonregion",
"Your installation has no default phone region set. This is required to validate phone numbers in the profile settings without a country code. To allow numbers without a country code, please add \"default_phone_region\" with the respective ISO 3166-1 code of the region to your config file.": "Für deine Installation ist keine Standard-Telefonregion festgelegt. Dies ist erforderlich, um Telefonnummern in den Profileinstellungen ohne Ländercode überprüfen zu können. Um Nummern ohne Ländervorwahl zuzulassen, füge bitte „default_phone_region“ mit dem entsprechenden ISO 3166-1-Code der Region zu deiner Konfigurationsdatei hinzu.",
"Email test": "E-Mail-Test",
"Email test was successfully sent": "Die Test-E-Mail wurde erfolgreich versandt",
"You have not set or verified your email server configuration, yet. Please head over to the \"Basic settings\" in order to set them. Afterwards, use the \"Send email\" button below the form to verify your settings.": "Du hast deine E-Mail-Serverkonfiguration noch nicht festgelegt oder überprüft. Bitte gehe zu den Grundeinstellungen, um sie einzustellen. Verwende anschließend die Schaltfläche \"E-Mail senden\" unterhalb des Formulars, um deine Einstellungen zu überprüfen.",
"File locking": "Dateisperre",
"Transactional file locking is disabled, this might lead to issues with race conditions. Enable \"filelocking.enabled\" in config.php to avoid these problems.": "Die transaktionale Dateisperre ist deaktiviert, dies kann zu Problemen mit Race Conditions führen. Aktiviere \"filelocking.enabled\" in config.php, um diese Probleme zu vermeiden.",
"The database is used for transactional file locking. To enhance performance, please configure memcache, if available.": "Die Datenbank wird für transaktionale Dateisperren verwendet. Um die Leistung zu verbessern, konfiguriere bitte Memcache, falls verfügbar.",
"Forwarded for headers": "Für Header weitergeleitet",
"Your \"trusted_proxies\" setting is not correctly set, it should be an array.": "Ihre \"trusted_proxies“-Einstellungen sind nicht korrekt, es sollte ein Array sein.",
"Your \"trusted_proxies\" setting is not correctly set, it should be an array of IP addresses - optionally with range in CIDR notation.": "Deine „trusted_proxies“-Einstellung ist nicht richtig eingestellt, es sollte ein Array von IP-Adressen sein optional mit einem Bereich in CIDR-Notation.",
"The reverse proxy header configuration is incorrect. This is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.": "Die Konfiguration des Reverse-Proxy-Headers ist falsch. Dies stellt ein Sicherheitsproblem dar und kann es einem Angreifer ermöglichen, seine IP-Adresse so zu fälschen, dass sie für Nextcloud sichtbar ist.",
"Your IP address was resolved as %s": "Ihre IP-Adresse wurde aufgelöst als %s",
"The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy. If not, this is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.": "Die Konfiguration des Reverse-Proxy-Headers ist falsch oder du greifst über einen vertrauenswürdigen Proxy auf Nextcloud zu. Andernfalls stellt dies ein Sicherheitsproblem dar und kann es einem Angreifer ermöglichen, seine IP-Adresse so zu fälschen, dass sie für Nextcloud sichtbar ist.",
"HTTPS access and URLs": "HTTPS-Zugriff und URLs",
"Accessing site insecurely via HTTP. You are strongly advised to set up your server to require HTTPS instead. Without it some important web functionality like \"copy to clipboard\" or \"service workers\" will not work!": "Unsicherer Zugriff auf die Website über HTTP. Es wird dringend empfohlen, deinen Server so einzurichten, dass HTTPS erforderlich ist. Ohne HTTPS funktionieren einige wichtige Webfunktionen wie \"Kopieren in die Zwischenablage\" oder \"Service Worker\" nicht!",
"Accessing site insecurely via HTTP.": "Unsicherer Zugriff auf die Website über HTTP.",
"You are accessing your instance over a secure connection, however your instance is generating insecure URLs. This likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.": "Du greifst über eine sichere Verbindung auf deine Instanz zu, deine Instanz generiert jedoch unsichere URLs. Dies bedeutet wahrscheinlich, dass sich deine Instanz hinter einem Reverse-Proxy befindet und die Nextcloud-Konfigurationseinstellungen `overwrite*` nicht richtig eingestellt sind.",
"Your instance is generating insecure URLs. If you access your instance over HTTPS, this likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.": "Deine Instanz generiert unsichere URLs. Wenn du über HTTPS auf Ihre Instanz zugreifst, bedeutet dies wahrscheinlich, dass sich dein Instanz hinter einem Reverse-Proxy befindet und die Nextcloud-Konfigurationseinstellungen `overwrite*` nicht richtig eingestellt sind.",
"You are accessing your instance over a secure connection, and your instance is generating secure URLs.": "Du greifst über eine sichere Verbindung auf deine Instanz zu, und deine Instanz erstellt sichere URLs.",
"Internet connectivity": "Internetverbindung",
"Internet connectivity is disabled in configuration file.": "Die Internetverbindung ist in der Konfigurationsdatei deaktiviert.",
"This server has no working internet connection: Multiple endpoints could not be reached. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. Establish a connection from this server to the internet to enjoy all features.": "Dieser Server hat keine funktionierende Internetverbindung: Mehrere Ziele konnten nicht erreicht werden. Dies bedeutet, dass einige Funktionen, wie das Einhängen externer Speicher, Benachrichtigungen über Updates oder die Installation von Drittanbieter-Apps nicht funktionieren. Der Zugriff auf entfernte Dateien und das Senden von E-Mail-Benachrichtigungen wird wahrscheinlich ebenfalls nicht funktionieren. Um alle Funktionen nutzen zu können, stelle bitte eine Internet-Verbindung für diesen Server her.",
"JavaScript modules support": "JavaScript-Modulunterstützung",
"Unable to run check for JavaScript support. Please remedy or confirm manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Prüfung auf JavaScript-Unterstützung konnte nicht ausgeführt werden. Bitte behebe das Problem oder bestätige manuell, dass dein Webserver `.mjs`-Dateien mit dem JavaScript-MIME-Typ bereitstellt.",
"Your webserver does not serve `.mjs` files using the JavaScript MIME type. This will break some apps by preventing browsers from executing the JavaScript files. You should configure your webserver to serve `.mjs` files with either the `text/javascript` or `application/javascript` MIME type.": "Dein Webserver liefert `.mjs`-Dateien nicht mit dem JavaScript MIME-Typ. Dadurch werden einige Apps beeinträchtigt, da Browser die JavaScript-Dateien nicht ausführen können. Konfiguriere deinen Webserver so, dass er `.mjs`-Dateien entweder mit dem MIME-Typ `text/javascript` oder `application/javascript` ausliefert.",
"JavaScript source map support": "Unterstützung für JavaScript-Quellkarten",
"Your webserver is not set up to serve `.js.map` files. Without these files, JavaScript Source Maps won't function properly, making it more challenging to troubleshoot and debug any issues that may arise.": "Dein Webserver ist nicht für die Bereitstellung von `.js.map`-Dateien eingerichtet. Ohne diese Dateien funktionieren JavaScript Source Maps nicht ordnungsgemäß, was die Fehlersuche und -behebung eventuell auftretender Probleme erschwert.",
"Old server-side-encryption": "Alte serverseitige Verschlüsselung",
"Disabled": "Deaktiviert",
"The old server-side-encryption format is enabled. We recommend disabling this.": "Das alte serverseitige Verschlüsselungsformat ist aktiviert. Es wird empfohlen, es zu deaktivieren.",
"Maintenance window start": "Beginn des Wartungsfensters",
"Server has no maintenance window start time configured. This means resource intensive daily background jobs will also be executed during your main usage time. We recommend to set it to a time of low usage, so users are less impacted by the load caused from these heavy tasks.": "Der Server hat keine konfigurierte Startzeit für das Wartungsfenster. Das bedeutet, dass ressourcenintensive tägliche Hintergrundaufgaben auch während deiner Hauptnutzungszeit ausgeführt werden. Wir empfehlen, das Wartungsfenster auf eine Zeit mit geringer Nutzung festzulegen, damit Benutzer weniger von der Belastung durch diese umfangreichen Aufgaben beeinträchtigt werden.",
"Maintenance window to execute heavy background jobs is between {start}:00 UTC and {end}:00 UTC": "Wartungsfenster zur Ausführung von umfangreichen Hintergrundaufgaben liegt zwischen {start}:00 UTC und {end}:00 UTC",
"Memcache": "Memcache",
"Memcached is configured as distributed cache, but the wrong PHP module (\"memcache\") is installed. Please install the PHP module \"memcached\".": "Memcached ist als verteilter Cache konfiguriert, aber das falsche PHP-Modul („memcache“) ist installiert. Bitte installiere das PHP-Modul \"memcached“.",
"Memcached is configured as distributed cache, but the PHP module \"memcached\" is not installed. Please install the PHP module \"memcached\".": "Memcached ist als verteilter Cache konfiguriert, das PHP-Modul \"memcached“ ist jedoch nicht installiert. Bitte installiere das PHP-Modul \"memcached“.",
"No memory cache has been configured. To enhance performance, please configure a memcache, if available.": "Es wurde kein Speichercache konfiguriert. Um die Leistung zu verbessern, konfiguriere bitte Memcache, sofern verfügbar.",
"Configured": "Eingerichtet",
"Mimetype migrations available": "MIME-Type-Migrationen verfügbar",
"One or more mimetype migrations are available. Occasionally new mimetypes are added to better handle certain file types. Migrating the mimetypes take a long time on larger instances so this is not done automatically during upgrades. Use the command `occ maintenance:repair --include-expensive` to perform the migrations.": "Eine oder mehrere MIME-Type-Migrationen sind verfügbar. Gelegentlich werden neue MIME-Typen hinzugefügt, um bestimmte Dateitypen besser handhaben zu können. Die Migration der MIME-Typen dauert bei größeren Instanzen lange, daher erfolgt sie bei Upgrades nicht automatisch. Verwende den Befehl `occ maintenance:repair --include-expensive`, um die Migrationen durchzuführen.",
"MySQL Unicode support": "MySQL Unicode-Unterstützung",
"You are not using MySQL": "Du verwendest kein MySQL",
"MySQL is used as database and does support 4-byte characters": "MySQL wird als Datenbank verwendet und unterstützt 4-Byte-Zeichen",
"MySQL is used as database but does not support 4-byte characters. To be able to handle 4-byte characters (like emojis) without issues in filenames or comments for example it is recommended to enable the 4-byte support in MySQL.": "MySQL wird als Datenbank verwendet, unterstützt jedoch keine 4-Byte-Zeichen. Um 4-Byte-Zeichen (wie Emojis) ohne Probleme z.B. in Dateinamen oder Kommentaren verwenden zu können, wird empfohlen, die 4-Byte-Unterstützung in MySQL zu aktivieren.",
"OCS provider resolving": "OCS Anbieter-Auflösung",
"Could not check if your web server properly resolves the OCM and OCS provider URLs.": "Es konnte nicht überprüft werden, ob dein Web-Server die OCM- und OCS-Anbieter-URLs ordnungsgemäß auflöst.",
"Your web server is not properly set up to resolve %1$s.\nThis is most likely related to a web server configuration that was not updated to deliver this folder directly.\nPlease compare your configuration against the shipped rewrite rules in \".htaccess\" for Apache or the provided one in the documentation for Nginx.\nOn Nginx those are typically the lines starting with \"location ~\" that need an update.": "Dein Webserver ist nicht ordnungsgemäß für die Auflösung von %1$s eingerichtet.\nDies hängt höchstwahrscheinlich mit einer Webserver-Konfiguration zusammen, die nicht dahingehend aktualisiert wurde, diesen Ordner direkt zu auszuliefern.\nBitte vergleiche deine Konfiguration mit den mitgelieferten Rewrite-Regeln in \".htaccess\" für Apache oder den in der Nginx-Dokumentation mitgelieferten.\nAuf Nginx sind das typischerweise die Zeilen, die mit \"location ~\" beginnen und ein Update benötigen.",
"Overwrite CLI URL": "CLI-URL überschreiben",
"The \"overwrite.cli.url\" option in your config.php is correctly set to \"%s\".": "Die Option \"overwrite.cli.url\" in deiner config.php ist korrekt auf \"%s\" festgelegt.",
"The \"overwrite.cli.url\" option in your config.php is set to \"%s\" which is a correct URL. Suggested URL is \"%s\".": "Die Option \"overwrite.cli.url\" in deiner config.php ist auf \"%s\" festgelegt. Dies ist eine gültige URL. Die vorgeschlagene URL lautet \"%s\".",
"Please make sure to set the \"overwrite.cli.url\" option in your config.php file to the URL that your users mainly use to access this Nextcloud. Suggestion: \"%s\". Otherwise there might be problems with the URL generation via cron. (It is possible though that the suggested URL is not the URL that your users mainly use to access this Nextcloud. Best is to double check this in any case.)": "Bitte stelle sicher, dass du die Option \"overwrite.cli.url\" in deiner config.php-Datei auf die URL setzt, die deine Benutzenden hauptsächlich verwenden, um auf diese Nextcloud zuzugreifen. Vorschlag: \"%s\". Andernfalls kann es Probleme bei der URL-Generierung über Cron geben. (Es ist jedoch möglich, dass die vorgeschlagene URL nicht die URL ist, die Ihre Benutzer hauptsächlich verwenden, um auf diese Nextcloud zuzugreifen. Am besten überprüfst du dies in jedem Fall.)",
"PHP default charset": "PHP-Standardzeichensatz",
"PHP configuration option \"default_charset\" should be UTF-8": "Die PHP-Konfigurationsoption \"default_charset\" sollte UTF-8 sein",
"PHP set_time_limit": "PHP set_time_limit",
"The function is available.": "Die Funktion ist verfügbar.",
"The PHP function \"set_time_limit\" is not available. This could result in scripts being halted mid-execution, breaking your installation. Enabling this function is strongly recommended.": "Die PHP-Funktion \"set_time_limit\" ist nicht verfügbar. Dies kann in angehaltenen Skripten oder einer fehlerhaften Installation resultieren. Es wird dringend empfohlen, diese Funktion zu aktivieren.",
"Freetype": "Freetype",
"Supported": "Unterstützt",
"Your PHP does not have FreeType support, resulting in breakage of profile pictures and the settings interface.": "Dein PHP unterstützt Freetype nicht. Dies wird defekte Profilbilder und eine defekte Anzeige der Einstellungen verursachen.",
"PHP getenv": "PHP getenv",
"PHP does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response.": "PHP scheint zur Abfrage von Systemumgebungsvariablen nicht richtig eingerichtet zu sein. Der Test mit getenv(\"PATH\") liefert nur eine leere Antwort zurück.",
"PHP memory limit": "PHP-Speicherlimit",
"The PHP memory limit is below the recommended value of %s.": "Die PHP-Speichergrenze liegt unterhalb des empfohlenen Wertes von %s.",
"PHP modules": "PHP-Module",
"increases language translation performance and fixes sorting of non-ASCII characters": "Erhöht die Sprach-Übersetzungsleistung und behebt ein Problem mit der Sortierung von Nicht-ASCII-Zeichen",
"for Argon2 for password hashing": "für Argon2 zum Passwort-Hashing",
"for WebAuthn passwordless login": "für WebAuthn passwortlose Anmeldung",
"for WebAuthn passwordless login, and SFTP storage": "für WebAuthn passwortlose Anmeldung und SFTP-Speicher",
"for picture rotation in server and metadata extraction in the Photos app": "für Bildrotation im Server und Metadatenextraktion in der Fotos-App",
"This instance is missing some required PHP modules. It is required to install them: %s.": "Dieser Instanz fehlen einige erforderliche PHP-Module. Folgende Module müssen installiert sein:%s .",
"This instance is missing some recommended PHP modules. For improved performance and better compatibility it is highly recommended to install them:\n%s": "Dieser Instanz fehlen einige empfohlene PHP-Module. Für eine verbesserte Leistung und bessere Kompatibilität wird dringend empfohlen, diese zu installieren:\n%s",
"PHP opcache": "PHP OPcache",
"The PHP OPcache module is not loaded. For better performance it is recommended to load it into your PHP installation.": "Das PHP-OPcache-Modul ist nicht geladen. Für eine bessere Leistung empfiehlt es sich, das Modul in deiner PHP-Installation zu laden.",
"OPcache is disabled. For better performance, it is recommended to apply \"opcache.enable=1\" to your PHP configuration.": "OPcache ist deaktiviert. Für eine bessere Leistung empfiehlt es sich, in der PHP-Konfiguration \"opcache.enable=1\" zu setzen.",
"The shared memory based OPcache is disabled. For better performance, it is recommended to apply \"opcache.file_cache_only=0\" to your PHP configuration and use the file cache as second level cache only.": "Der OPcache mit gemeinsamem Speicher ist deaktiviert. Für eine bessere Leistung wird empfohlen, \"opcache.file_cache_only=0\" in die PHP-Konfiguration aufzunehmen und den Dateicache nur als Second Level Cache zu verwenden.",
"OPcache is not working as it should, opcache_get_status() returns false, please check configuration.": "OPcache funktioniert nicht wie erwartet, opcache_get_status() gibt false zurück, bitte die Konfiguration überprüfen.",
"The maximum number of OPcache keys is nearly exceeded. To assure that all scripts can be kept in the cache, it is recommended to apply \"opcache.max_accelerated_files\" to your PHP configuration with a value higher than \"%s\".": "Die maximale Anzahl der OPcache-Schlüssel wird annähernd überschritten. Um sicherzustellen, dass alle Skripte im Cache gespeichert werden können, empfiehlt es sich, \"opcache.max_accelerated_files\" mit einem Wert größer als \"%s\" in der PHP-Konfiguration zu setzen.",
"The OPcache buffer is nearly full. To assure that all scripts can be hold in cache, it is recommended to apply \"opcache.memory_consumption\" to your PHP configuration with a value higher than \"%s\".": "Der OPcache-Puffer ist fast voll. Um sicherzustellen, dass alle Skripte im Cache gehalten werden können, wird empfohlen, \"opcache.memory_consumption\" in der PHP-Konfiguration mit einem Wert höher als \"%s\" zu setzen.",
"The OPcache interned strings buffer is nearly full. To assure that repeating strings can be effectively cached, it is recommended to apply \"opcache.interned_strings_buffer\" to your PHP configuration with a value higher than \"%s\".": "Der \"OPcache interned strings\"-Puffer ist fast voll. Um sicherzustellen, dass sich wiederholende Strings effektiv zwischengespeichert werden können, wird empfohlen, \"opcache.interned_strings_buffer\" mit einem Wert größer als \"%s\" in der PHP-Konfiguration zu setzen.",
"OPcache is configured to remove code comments. With OPcache enabled, \"opcache.save_comments=1\" must be set for Nextcloud to function.": "OPcache ist so konfiguriert, dass Code-Kommentare entfernt werden Mit aktiviertem OPcache muss \"opcache.save_comments=1\" gesetzt werden, damit die Nextcloud funktioniert.",
"Nextcloud is not allowed to use the OPcache API. With OPcache enabled, it is highly recommended to include all Nextcloud directories with \"opcache.restrict_api\" or unset this setting to disable OPcache API restrictions, to prevent errors during Nextcloud core or app upgrades.": "Nextcloud darf die OPcache-API nicht verwenden. Mit aktiviertem OPcache wird empfohlen, alle Nextcloud-Verzeichnisse mit \"opcache.restrict_api\" einzuschließen oder diese Einstellung zu deaktivieren, um OPcache API-Beschränkungen zu deaktivieren und Fehler während Nextcloud-Core- oder App-Aktualisierungen zu vermeiden.",
"The PHP OPcache module is not properly configured. %s.": "Das PHP OPcache-Modul ist nicht ordnungsgemäß konfiguriert. %s.",
"Correctly configured": "Korrekt konfiguriert",
"PHP version": "PHP-Version",
"You are currently running PHP %s. PHP 8.1 is now deprecated in Nextcloud 30. Nextcloud 31 may require at least PHP 8.2. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.": "Du verwendest derzeit PHP %s. PHP 8.1 ist ab Nextcloud 30 veraltet. Nextcloud 31 erfordert möglicherweise mindestens PHP 8.2. Bitte aktualisiere so schnell wie möglich auf eine der offiziell unterstützten PHP-Versionen der PHP-Gruppe.",
"You are currently running PHP %s.": "Du benutzt aktuell PHP %s.",
"PHP \"output_buffering\" option": "PHP-Option \"output_buffering\"",
"PHP configuration option \"output_buffering\" must be disabled": "Die PHP-Konfigurationsoption \"output_buffering“ muss deaktiviert sein",
"Push service": "Push-Dienst",
"Valid enterprise license": "Gültige Unternehmenslizenz",
"Free push service": "Kostenloser Push-Dienst",
"This is the unsupported community build of Nextcloud. Given the size of this instance, performance, reliability and scalability cannot be guaranteed. Push notifications are limited to avoid overloading our free service. Learn more about the benefits of Nextcloud Enterprise at {link}.": "Dies ist der nicht unterstützte Community-Build von Nextcloud. Angesichts der Größe dieser Instanz können Leistung, Zuverlässigkeit und Skalierbarkeit nicht garantiert werden. Push-Benachrichtigungen wurden beschränkt, um eine Überlastung unseres kostenlosen Dienstes zu vermeiden. Erfahre mehr über die Vorteile von Nextcloud Enterprise unter {link}.",
"Random generator": "Zufallsgenerator",
"No suitable source for randomness found by PHP which is highly discouraged for security reasons.": "PHP hat keine geeignete Quelle für Zufälligkeit gefunden, wovon aus Sicherheitsgründen dringend abgeraten wird.",
"Secure": "Sicher",
"Configuration file access rights": "Zugriffsrechte für die Konfigurationsdatei",
"The read-only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update.": "Die schreibgeschützte Konfiguration wurde aktiviert. Dies verhindert das Setzen einiger Einstellungen über die Web-Oberfläche. Weiterhin muss bei jedem Update der Schreibzugriff auf die Datei händisch aktiviert werden.",
"Nextcloud configuration file is writable": "Die Nextcloud-Konfigurationsdatei ist beschreibbar",
"Scheduling objects table size": "Größe der Planungsobjekttabelle",
"You have more than %s rows in the scheduling objects table. Please run the expensive repair jobs via occ maintenance:repair --include-expensive.": "Du hast mehr als %s Zeilen in der Tabelle der geplanten Objekte. Bitte führe umfangreiche Reparaturaufträge mittels occ maintenance:repair --include-expensive aus.",
"Scheduling objects table size is within acceptable range.": "Die Größe der Planungsobjekttabelle liegt im akzeptablen Bereich.",
"HTTP headers": "HTTP-Header",
"- The `%1$s` HTTP header is not set to `%2$s`. Some features might not work correctly, as it is recommended to adjust this setting accordingly.": "- Der `%1$s`-HTTP-Header ist nicht auf `%2$s` gesetzt. Einige Funktionen arbeiten möglicherweise nicht richtig. Es wird daher empfohlen, diese Einstellung entsprechend anzupassen.",
"- The `%1$s` HTTP header is not set to `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.": "- Der HTTP-Header `%1$s` ist nicht auf `%2$s` gesetzt. Dies stellt ein potenzielles Sicherheits- oder Datenschutzrisiko dar und es wird empfohlen, diese Einstellung zu ändern.",
"- The `%1$s` HTTP header does not contain `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.": "- Der HTTP-Header `%1$s` enthält nicht `%2$s`. Dies stellt ein potenzielles Sicherheits- oder Datenschutzrisiko dar und es wird empfohlen, diese Einstellung zu ändern.",
"- The `%1$s` HTTP header is not set to `%2$s`, `%3$s`, `%4$s`, `%5$s` or `%6$s`. This can leak referer information. See the {w3c-recommendation}.": "- Der HTTP-Header `%1$s` ist nicht auf \"%2$s\", \"%3$s\", \"%4$s\", \"%5$s\" oder \"%6$s\" gesetzt. Dadurch können Verweisinformationen preisgegeben werden. Siehe die {w3c-recommendation}.",
"- The `Strict-Transport-Security` HTTP header is not set to at least `%d` seconds (current value: `%d`). For enhanced security, it is recommended to use a long HSTS policy.": "- Der HTTP-Header `Strict-Transport-Security` ist nicht auf mindestens `%d` Sekunden eingestellt (aktueller Wert: `%d`). Für erhöhte Sicherheit wird die Verwendung einer langen HSTS-Richtlinie empfohlen.",
"- The `Strict-Transport-Security` HTTP header is malformed: `%s`. For enhanced security, it is recommended to enable HSTS.": "- Der `Strict-Transport-Security`-HTTP-Header ist fehlerhaft: `%s`. Für erhöhte Sicherheit wird empfohlen, HSTS zu aktivieren.",
"- The `Strict-Transport-Security` HTTP header is not set (should be at least `%d` seconds). For enhanced security, it is recommended to enable HSTS.": "- Der `Strict-Transport-Security`-HTTP-Header ist nicht gesetzt (er sollte mindestens `%d` Sekunden betragen). Für erhöhte Sicherheit wird empfohlen, HSTS zu aktivieren.",
"Some headers are not set correctly on your instance": "Einige Header sind in deiner Instanz nicht richtig eingestellt",
"Could not check that your web server serves security headers correctly. Please check manually.": "Es konnte nicht überprüft werden, ob dein Webserver Sicherheitsheader korrekt bereitstellt. Bitte überprüfen Sie dies manuell.",
"Could not check that your web server serves security headers correctly, unable to query `%s`": "Es konnte nicht überprüft werden, ob dein Webserver Sicherheitsheader korrekt bereitstellt. Die Abfrage von `%s` ist nicht möglich",
"Your server is correctly configured to send security headers.": "Dein Server ist korrekt für das Senden von Sicherheitsheadern konfiguriert.",
"Database version": "Datenbankversion",
"MariaDB version 10.3 detected, this version is end-of-life and only supported as part of Ubuntu 20.04. MariaDB >=%1$s and <=%2$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MariaDB Version 10.3 erkannt, diese Version hat das Ende ihres Lebenszyklus erreicht und wird nur noch als Teil von Ubuntu 20.04 unterstützt. Für optimale Leistung, Stabilität und Funktionalität mit dieser Version von Nextcloud wird MariaDB >= %1$s und %2$s <= empfohlen.",
"MariaDB version \"%1$s\" detected. MariaDB >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MariaDB-Version \"%1$s\" erkannt. Für optimale Leistung, Stabilität und Funktionalität mit dieser Version von Nextcloud wird MariaDB >= %2$s und %3$s <= empfohlen.",
"MySQL version \"%1$s\" detected. MySQL >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MySQL-Version \"%1$s\" erkannt. Für optimale Leistung, Stabilität und Funktionalität mit dieser Version von Nextcloud wird MySQL >= %2$s und %3$s <= empfohlen.",
"PostgreSQL version \"%s\" detected. PostgreSQL >=12 and <=16 is suggested for best performance, stability and functionality with this version of Nextcloud.": "PostgreSQL-Version \"%s\" erkannt. Für optimale Leistung, Stabilität und Funktionalität mit dieser Version von Nextcloud wird PostgreSQL >=12 und <=16 empfohlen.",
"SQLite is currently being used as the backend database. For larger installations we recommend that you switch to a different database backend. This is particularly recommended when using the desktop client for file synchronisation. To migrate to another database use the command line tool: \"occ db:convert-type\".": "Als Backend-Datenbank wird derzeit SQLite verwendet. Bei größeren Installationen empfehlen wir den Wechsel auf ein anderes Datenbank-Backend. Dies empfiehlt sich insbesondere bei der Nutzung des Desktop-Clients zur Dateisynchronisierung. Um zu einer anderen Datenbank zu migrieren, verwende das Befehlszeilentool: \"occ db:convert-type\".",
"Unknown database platform": "Unbekannte Datenbankplattform",
"Architecture": "Architektur",
"64-bit": "64-bit",
"It seems like you are running a 32-bit PHP version. Nextcloud needs 64-bit to run well. Please upgrade your OS and PHP to 64-bit!": "Anscheinend verwendest du eine 32-Bit-PHP-Version. Nextcloud benötigt 64-Bit, um gut zu laufen. Bitte aktualisiere dein Betriebssystem und PHP auf 64-Bit!",
"Temporary space available": "Temporärer Platz verfügbar",
"Error while checking the temporary PHP path - it was not properly set to a directory. Returned value: %s": "Fehler beim Überprüfen des temporären PHP-Pfads - er wurde nicht ordnungsgemäß auf ein Verzeichnis festgelegt. Zurückgegebener Wert: %s",
"The PHP function \"disk_free_space\" is disabled, which prevents the check for enough space in the temporary directories.": "Die PHP-Funktion \"disk_free_space\" ist deaktiviert, was die Überprüfung auf ausreichend Speicherplatz in den temporären Verzeichnissen verhindert.",
"Error while checking the available disk space of temporary PHP path or no free disk space returned. Temporary path: %s": "Fehler beim Prüfen des verfügbaren Festplattenspeichers des temporären PHP-Pfads oder kein freien Festplattenspeicherplatz zurückgegeben. Temporärer Pfad: %s",
"- %.1f GiB available in %s (PHP temporary directory)": "- %.1f GiB verfügbar in %s (PHP temporäres Verzeichnis)",
"- %.1f GiB available in %s (Nextcloud temporary directory)": "- %.1f GiB verfügbar in %s (Nextcloud temporäres Verzeichnis)",
"Temporary directory is correctly configured:\n%s": "Das temporäre Verzeichnis ist korrekt konfiguriert:\n%s",
"This instance uses an S3 based object store as primary storage, and has enough space in the temporary directory.\n%s": "Diese Instanz verwendet einen S3-basierten Objektspeicher als Primärspeicher und verfügt über ausreichend Speicherplatz im temporären Verzeichnis. \n%s",
"This instance uses an S3 based object store as primary storage. The uploaded files are stored temporarily on the server and thus it is recommended to have 50 GiB of free space available in the temp directory of PHP. To improve this please change the temporary directory in the php.ini or make more space available in that path. \nChecking the available space in the temporary path resulted in %.1f GiB instead of the recommended 50 GiB. Path: %s": "Diese Instanz verwendet einen S3-basierten Objektspeicher als Primärspeicher. Die hochgeladenen Dateien werden temporär auf dem Server gespeichert und es wird daher empfohlen, 50 GiB freien Speicherplatz im temp-Verzeichnis von PHP zur Verfügung zu haben. Um dies zu verbessern, ändere bitte das temporäre Verzeichnis in der php.ini oder stelle mehr Platz in diesem Pfad zur Verfügung. \nDie Überprüfung des verfügbaren Speicherplatzes im temporären Pfad ergab %.1f GiB anstelle der empfohlenen 50 GiB. Pfad: %s",
"Database transaction isolation level": "Isolationsstufe der Datenbanktransaktion",
"Your database does not run with \"READ COMMITTED\" transaction isolation level. This can cause problems when multiple actions are executed in parallel.": "Deine Datenbank läuft nicht mit der Transaktionsisolationsstufe \"READ COMMITED\". Dies kann Probleme hervorrufen, wenn mehrere Aktionen parallel ausgeführt werden.",
"Was not able to get transaction isolation level: %s": "Die Isolationsstufe der Transaktion konnte nicht ermittelt werden: %s",
".well-known URLs": ".well-known URLs",
"`check_for_working_wellknown_setup` is set to false in your configuration, so this check was skipped.": "`check_for_working_wellknown_setup` ist in deiner Konfiguration auf „false“ gesetzt, daher wurde diese Prüfung übersprungen.",
"Could not check that your web server serves `.well-known` correctly. Please check manually.": "Es konnte nicht überprüft werden, ob dein Webserver `.well-known` korrekt bereitstellt. Bitte überprüfe dies manuell.",
"Your web server is not properly set up to resolve `.well-known` URLs, failed on:\n`%s`": "Dein Webserver ist nicht ordnungsgemäß für die Auflösung von `.well-known`-URLs eingerichtet. Fehler bei: `%s`",
"Your server is correctly configured to serve `.well-known` URLs.": "Dein Server ist korrekt für die Bereitstellung von `.well-known`-URLs konfiguriert.",
"WOFF2 file loading": "WOFF2-Datei laden",
"Could not check for WOFF2 loading support. Please check manually if your webserver serves `.woff2` files.": "Konnte die Prüfung der WOFF2-Ladeunterstützung nicht durchführen. Bitte überprüfe manuell, ob dein Webserver `.woff2`-Dateien bereitstellt.",
"Your web server is not properly set up to deliver .woff2 files. This is typically an issue with the Nginx configuration. For Nextcloud 15 it needs an adjustement to also deliver .woff2 files. Compare your Nginx configuration to the recommended configuration in our documentation.": "Dein Web-Server ist nicht richtig eingerichtet um .woff2-Dateien auszuliefern. Dies liegt meist an der Nginx-Konfiguration. Für Nextcloud 15 wird eine Anpassung für die Auslieferung von .woff2-Dateien benötigt. Vergleiche deine Nginx-Konfiguration mit der empfohlenen Nginx-Konfiguration in unserer Dokumentation.",
"Profile information": "Profilinformation",
"Profile picture, full name, email, phone number, address, website, Twitter, organisation, role, headline, biography, and whether your profile is enabled": "Profilbild, vollständiger Name, E-Mail-Adresse, Telefonnummer, Adresse, Webseite, X, Organisation, Rolle, Überschrift, Biografie und ob dein Profil aktiviert ist",
"Nextcloud settings": "Nextcloud-Einstellungen",
"Unified task processing": "Vereinheitlichte Aufgabenbearbeitung",
"AI tasks can be implemented by different apps. Here you can set which app should be used for which task.": "KI-Aufgaben können mittels verschiedener Apps umgesetzt werden. Hier kannst du einstellen, welche App für welche Aufgabe verwendet werden soll.",
"Task:": "Aufgabe:",
"None of your currently installed apps provide Task processing functionality": "Keine deiner derzeit installierten Apps stellt Funktionen zur Aufgabenverarbeitung bereit",
"Machine translation": "Maschinelle Übersetzung",
"Machine translation can be implemented by different apps. Here you can define the precedence of the machine translation apps you have installed at the moment.": "Maschinelle Übersetzung kann mittels verschiedener Apps implementiert werden. Hier kannst du die Priorität der von dir aktuell installierten maschinellen Übersetzungs-Apps festlegen.",
"Speech-To-Text": "Sprache-zu-Text",
"Speech-To-Text can be implemented by different apps. Here you can set which app should be used.": "Sprache-zu-Text kann mittels verschiedener Apps implementiert werden. Hier kannst du einstellen, welche App verwendet werden soll.",
"None of your currently installed apps provide Speech-To-Text functionality": "Keine deiner derzeit installierten Apps bietet Sprache-zu-Text-Funktionalität.",
"Image generation": "Bilderstellung",
"Image generation can be implemented by different apps. Here you can set which app should be used.": "Die Bilderstellung kann durch verschiedene Apps implementiert werden. Hier kannst du einstellen, welche App verwendet werden soll.",
"None of your currently installed apps provide image generation functionality": "Keine deiner derzeit installierten Apps bietet Funktionen zur Bilderstellung.",
"Text processing": "Textverarbeitung",
"Text processing tasks can be implemented by different apps. Here you can set which app should be used for which task.": "Textverarbeitungsaufgaben können mittels verschiedener Apps umgesetzt werden. Hier kannst du einstellen, welche App für welche Aufgabe verwendet werden soll.",
"None of your currently installed apps provide Text processing functionality": "Keine deiner derzeit installierten Apps bietet Funktionalität zur Textverarbeitung.",
"Here you can decide which group can access certain sections of the administration settings.": "Hier kannst du festlegen, welche Gruppe auf bestimmte Bereiche der Verwaltungseinstellungen zugreifen kann.",
"None": "Keine",
"Unable to modify setting": "Einstellung konnte nicht geändert werden",
"Allow apps to use the Share API": "Apps die Benutzung der Share-API erlauben",
"Allow resharing": "Weiterverteilen erlauben",
"Allow sharing with groups": "Teilen mit Gruppen erlauben",
"Restrict users to only share with users in their groups": "Benutzer auf das Teilen innerhalb ihrer Gruppen beschränken",
"Ignore the following groups when checking group membership": "Die folgenden Gruppen beim Überprüfen der Gruppenmitgliedschaft ignorieren",
"Allow users to share via link and emails": "Benutzern erlauben, Inhalte über Links und E-Mails zu teilen",
"Allow public uploads": "Öffentliches Hochladen erlauben",
"Always ask for a password": "Immer nach einem Passwort fragen",
"Enforce password protection": "Passwortschutz erzwingen",
"Exclude groups from password requirements": "Gruppen von Passwortanforderungen ausschließen",
"Exclude groups from creating link shares": "Gruppen von der Erstellung von Link-Freigaben ausschließen",
"Limit sharing based on groups": "Freigeben basierend auf Gruppen beschränken",
"Allow sharing for everyone (default)": "Teilen für alle erlauben (Standard)",
"Exclude some groups from sharing": "Einige Gruppen vom Teilen ausschließen",
"Limit sharing to some groups": "Teilen auf einige Gruppen beschränken",
"Groups allowed to share": "Gruppen, die teilen dürfen",
"Groups excluded from sharing": "Von der Linkfreigabe ausgeschlossene Gruppen",
"Not allowed groups will still be able to receive shares, but not to initiate them.": "Nicht zugelassene Gruppen können zwar weiterhin Freigaben empfangen, aber nicht erstellen.",
"Set default expiration date for shares": "Lege das Standardablaufdatum für Freigaben fest",
"Enforce expiration date": "Ablaufdatum erzwingen",
"Default expiration time of new shares in days": "Standardablaufzeit neuer Freigaben in Tagen",
"Expire shares after x days": "Freigaben laufen nach x Tagen ab",
"Set default expiration date for shares to other servers": "Standardablaufdatum für Freigaben an andere Server festlegen",
"Enforce expiration date for remote shares": "Ablaufdatum für Remote-Freigaben erzwingen",
"Default expiration time of remote shares in days": "Standardablaufzeit für Remote-Freigaben in Tagen",
"Expire remote shares after x days": "Remote-Freigaben laufen nach x Tagen ab",
"Set default expiration date for shares via link or mail": "Standardablaufzeit für Link- oder E-Mail-Freigaben festlegen",
"Default expiration time of shares in days": "Standardablaufzeit für Freigaben in Tagen",
"Privacy settings for sharing": "Datenschutzeinstellungen bezüglich des Teilens",
"Allow account name autocompletion in share dialog and allow access to the system address book": "Automatische Vervollständigung des Kontonamens im Freigabedialog und Zugriff auf das Systemadressbuch zulassen",
"If autocompletion \"same group\" and \"phone number integration\" are enabled a match in either is enough to show the user.": "Wenn die Autovervollständigung \"gleiche Gruppe\" und \"Rufnummernintegration\" aktiviert ist, reicht eine Übereinstimmung in einem der beiden Bereiche aus, um den Benutzer anzuzeigen.",
"Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)": "Ermöglicht die automatische Vervollständigung, wenn der vollständigen Namen oder die E-Mail-Adresse eingeben wird (ignoriert fehlende Telefonbuchübereinstimmungen und bei gleicher Gruppenzugehörigkeit)",
"Show disclaimer text on the public link upload page (only shown when the file list is hidden)": "Zeige Haftungsausschluss auf der öffentlichen Upload-Seite (Wird nur gezeigt, wenn die Dateiliste nicht angezeigt wird.) ",
"Disclaimer text": "Haftungsausschlusstext",
"This text will be shown on the public link upload page when the file list is hidden.": "Dieser Text wird auf der öffentlichen Upload-Seite angezeigt wenn die Dateiliste nicht angezeigt wird.",
"Default share permissions": "Standardberechtigungen für das Teilen",
"Changed disclaimer text": "Geänderter Haftungsausschlusstext",
"Deleted disclaimer text": "Haftungsausschlusstext gelöscht",
"Could not set disclaimer text": "Haftungsausschlusstext konnte nicht festgelegt werden",
"Two-Factor Authentication": "Zwei-Faktor-Authentifizierung",
"Two-factor authentication can be enforced for all accounts and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.": "Zwei-Faktor-Authentifizierung kann für alle Konten und spezifische Gruppen erzwungen werden. Wenn du keinen Anbieter für Zwei-Faktor-Authentifizierung konfiguriert hast, kannst du dich nicht am System anmelden.",
"Enforce two-factor authentication": "Zwei-Faktor-Authentifizierung erzwingen",
"Limit to groups": "Auf Gruppen beschränken",
"Enforcement of two-factor authentication can be set for certain groups only.": "Erzwingen der Zwei-Faktor-Authentifizierung kann nur für bestimmte Gruppen eingestellt werden.",
"Two-factor authentication is enforced for all members of the following groups.": "Zwei-Faktor-Authentifizierung wird für alle Mitglieder der folgenden Gruppen erzwungen.",
"Enforced groups": "Erzwungene Gruppen",
"Two-factor authentication is not enforced for members of the following groups.": "Zwei-Faktor-Authentifizierung wird für Mitglieder der folgenden Gruppen nicht erzwungen.",
"Excluded groups": "Ausgeschlossene Gruppen",
"When groups are selected/excluded, they use the following logic to determine if an account has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If an account is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.": "Bei der Auswahl/Abwahl von Gruppen wird folgende Logik verwendet, um festzustellen, ob ein Konto 2FA verwenden muss: Wenn keine Gruppe ausgewählt ist, dann wird 2FA für alle Konten aktiviert, außer für solche der ausgenommenen Gruppen. Sind Gruppen ausgewählt, so wird 2FA für alle Kontendieser Gruppen aktiviert. Ist ein Konto sowohl in einer ausgewählten als auch in einer ausgenommenen Gruppe, so hat die Auswahl Vorrang und 2FA wird aktiviert.",
"Save changes": "Änderungen speichern",
"Show details for {appName} app": "Details für die App {appName} anzeigen",
"Update to {update}": "Aktualisieren auf {update}",
"Remove": "Entfernen",
"Disable": "Deaktivieren",
"Featured": "Vorgestellt",
"This app is supported via your current Nextcloud subscription.": "Diese App wird von deinem aktuellen Nextcloud-Abonnement unterstützt.",
"Featured apps are developed by and within the community. They offer central functionality and are ready for production use.": "Vorgestellte Apps werden von und innerhalb der Nextcloud-Community entwickelt. Sie stellen zentrale Funktionen bereit und sind für den produktiven Einsatz geeignet.",
"Community rating: {score}/5": "Community-Bewertung: {score}/5",
"All apps are up-to-date.": "Alle Apps sind aktuell.",
"Icon": "Symbol",
"Name": "Name",
"Version": "Version",
"Level": "Level",
"Actions": "Aktionen",
"Results from other categories": "Ergebnisse aus anderen Kategorien",
"No apps found for your version": "Es wurden keine Apps für deine Version gefunden",
"Disable all": "Alle deaktivieren",
"Download and enable all": "Alle herunterladen und aktivieren",
"_%n app has an update available_::_%n apps have an update available_": [
"Für eine App ist eine Aktualisierung verfügbar.",
"Für %n Apps sind Aktualisierungen verfügbar."
],
"_Update_::_Update all_": [
"Aktualisieren",
"Alle aktualisieren"
],
"Nothing to show": "Nichts anzuzeigen",
"Could not load section content from app store.": "Abschnittsinhalt konnte nicht aus dem App Store geladen werden.",
"Loading": "Lade",
"Fetching the latest news…": "Aktuelle Nachrichten werden abgerufen…",
"Could not load app discover section": "Der App-Entdeckungsabschnitt konnte nicht geladen werden",
"Could not render element": "Element konnte nicht dargestellt werden",
"Carousel": "Karussell",
"Previous slide": "Vorherige Folie",
"Next slide": "Nächste Folie",
"Choose slide to display": "Folie zum Anzeigen auswählen",
"{index} of {total}": "{index} von {total}",
"Description": "Beschreibung",
"Details": "Details",
"All": "Alle",
"Limit app usage to groups": "App-Verwendung auf Gruppen beschränken",
"No results": "Keine Ergebnisse",
"Update to {version}": "Aktualisieren auf {version}",
"This app has no minimum Nextcloud version assigned. This will be an error in the future.": "Für diese App wurde keine untere Versionsgrenze für Nextcloud gesetzt. Dies wird zukünftig als Fehler behandelt.",
"This app has no maximum Nextcloud version assigned. This will be an error in the future.": "Für diese App wurde keine obere Versionsgrenze für Nextcloud gesetzt. Dies wird zukünftig als Fehler behandelt.",
"This app cannot be installed because the following dependencies are not fulfilled:": "Diese App kann nicht installiert werden, weil die folgenden Abhängigkeiten nicht erfüllt sind:",
"Latest updated": "Zuletzt aktualisiert",
"Author": "Autor",
"Categories": "Kategorien",
"Resources": "Ressourcen",
"Documentation": "Dokumentation",
"Interact": "Interagieren",
"Report a bug": "Einen technischen Fehler melden",
"Request feature": "Funktion vorschlagen",
"Ask questions or discuss": "Fragen stellen oder diskutieren",
"Rate the app": "App bewerten",
"Rate": "Bewerten",
"View in store": "Im Store anzeigen",
"Visit website": "Webseite besuchen",
"Usage documentation": "Nutzungsdokumentation",
"Admin documentation": "Dokumentation für Administratoren",
"Developer documentation": "Dokumentation für Entwickler",
"Changelog": "Liste der Veränderungen",
"Device name": "Gerätename",
"Cancel renaming": "Umbenennen abbrechen",
"Save new name": "Neuen Namen speichern",
"Marked for remote wipe": "Für Fernlöschung markiert",
"Device settings": "Geräteeinstellungen",
"Allow filesystem access": "Erlaube Dateisystem-Zugriff",
"Rename": "Umbenennen",
"Revoke": "Widerrufen",
"Wipe device": "Gerät löschen",
"Revoking this token might prevent the wiping of your device if it has not started the wipe yet.": "Zurückziehen dieses Tokens könnte das Löschen von deinem Gerät verhindern, wenn die Löschung noch nicht gestartet wurde.",
"Google Chrome for Android": "Google Chrome für Android",
"{productName} iOS app": "{productName} iOS-App",
"{productName} Android app": "{productName} Android-App",
"{productName} Talk for iOS": "{productName} Talk für iOS",
"{productName} Talk for Android": "{productName} Talk für Android",
"Sync client": "Sync-Client",
"This session": "Diese Sitzung",
"{client} - {version} ({system})": "{client} - {version} ({system})",
"{client} - {version}": "{client} - {version}",
"Device": "Gerät",
"Last activity": "Letzte Aktivität",
"Devices & sessions": "Geräte & Sitzungen",
"Web, desktop and mobile clients currently logged in to your account.": "Aktuell in deinem Konto angemeldete Web-, Desktop- und Mobil-Clients:",
"App name": "App-Name",
"Create new app password": "Neues App-Passwort erstellen",
"Error while creating device token": "Fehler beim Erstellen des Geräte-Tokens",
"New app password": "Neues App-Passwort",
"Use the credentials below to configure your app or device. For security reasons this password will only be shown once.": "Verwende die unten stehenden Anmeldeinformationen, um deine App oder dein Gerät zu konfigurieren. Aus Sicherheitsgründen wird dieses Passwort nur einmal angezeigt.",
"Login": "Anmelden",
"Password": "Passwort",
"Show QR code for mobile apps": "QR-Code für mobile Apps anzeigen",
"App password copied!": "App-Passwort kopiert!",
"Copy app password": "App-Passwort kopieren",
"Login name copied!": "Anmeldename kopiert!",
"Copy login name": "Anmeldename kopieren",
"Could not copy app password. Please copy it manually.": "Das Passwort für die App konnte nicht kopiert werden. Bitte kopiere es manuell.",
"Could not copy login name. Please copy it manually.": "Der Anmeldename konnte nicht kopiert werden. Bitte kopiere ihn manuell.",
"For the server to work properly, it's important to configure background jobs correctly. Cron is the recommended setting. Please see the documentation for more information.": "Damit der Server ordnungsgemäß funktioniert, ist es wichtig, Hintergrundjobs richtig zu konfigurieren. Cron ist die empfohlene Einstellung. Weitere Informationen findest du in der Dokumentation.",
"Last job execution ran {time}. Something seems wrong.": "Der letzte Job lief {time}. Etwas scheint falsch zu sein.",
"Last job ran {relativeTime}.": "Der letzte Job lief {relativeTime}.",
"Background job did not run yet!": "Hintergrund-Job wurde bislang nicht ausgeführt!",
"AJAX": "AJAX",
"Execute one task with each page loaded. Use case: Single account instance.": "Mit jeder geladenen Seite wird eine Aufgabe ausgeführt. Anwendungsfall: Einzelkonto-Installation.",
"Webcron": "Webcron",
"cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 accounts depending on the usage).": "cron.php ist bei einem Webcron-Dienst registriert, um cron.php alle 5 Minuten über HTTP aufzurufen. Anwendungsfall: Sehr kleine Instanz (15 Konten, je nach Nutzung).",
"Cron (Recommended)": "Cron (Empfohlen)",
"Use system cron service to call the cron.php file every 5 minutes.": "Den System-Cron-Dienst verwenden, um die Datei cron.php alle 5 Minuten aufzurufen.",
"The cron.php needs to be executed by the system account \"{user}\".": "Die cron.php muss von dem Systemkonto \"{user}\" ausgeführt werden.",
"The PHP POSIX extension is required. See {linkstart}PHP documentation{linkend} for more details.": "Die PHP-POSIX-Erweiterung ist erforderlich. Weitere Einzelheiten findest du in der {linkstart}PHP-Dokumentation{linkend}.",
"Unable to update background job mode": "Hintergrund-Job-Modus kann nicht aktualisiert werden",
"Profile": "Profil",
"Enable or disable profile by default for new accounts.": "Profil für neue Konten standardmäßig aktivieren oder deaktivieren.",
"Enable": "Aktivieren",
"Unable to update profile default setting": "Standardeinstellung des Profils kann nicht aktualisiert werden",
"{app}'s declarative setting field: {name}": "Deklaratives Einstellungsfeld von {app}: {name}",
"Failed to save setting": "Einstellung konnte nicht gespeichert werden",
"Server-side encryption": "Serverseitige Verschlüsselung",
"Server-side encryption makes it possible to encrypt files which are uploaded to this server. This comes with limitations like a performance penalty, so enable this only if needed.": "Serverseitige Verschlüsselung ermöglicht es, die auf diesen Server hochgeladenen Dateien zu verschlüsseln. Dies führt allerdings auch zu Nachteilen, wie z. B. einem Geschwindigkeitsverlust. Sie sollte deshalb nur eingeschaltet werden, wenn sie wirklich benötigt wird.",
"Enable server-side encryption": "Serverseitige Verschlüsselung aktivieren",
"Please read carefully before activating server-side encryption:": "Bitte lies sorgfältig vor Aktivierung der serverseitigen Verschlüsselung:",
"Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met.": "Wird die Verschlüsselung einmal aktiviert, so werden alle ab diesem Zeitpunkt hochgeladene Dateien verschlüsselt. Sie kann nur wieder deaktiviert werden, wenn das Verschlüsselungsmodul dies unterstützt und alle Voraussetzungen (wie das Setzen eines Wiederherstellungsschlüssels) im Vorhinein erfüllt wurden.",
"Encryption alone does not guarantee security of the system. Please see documentation for more information about how the encryption app works, and the supported use cases.": "Verschlüsselung alleine garantiert nicht die Systemsicherheit. Bitte lies in der Dokumentation nach, wie die Verschlüsselungs-app funktioniert und welche Anwendungsfälle unterstützt werden.",
"Be aware that encryption always increases the file size.": "Bedenke, dass durch die Verschlüsselung die Dateigröße zunimmt. ",
"It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data.": "Es ist immer gut, regelmäßig Sicherungen von deinen Daten zu erstellen. Falls du die Verschlüsselung nutzt, sollte auch eine Sicherung der Verschlüsselungsschlüssel zusammen mit deinen Daten durchgeführt werden.",
"This is the final warning: Do you really want to enable encryption?": "Dies ist die letzte Warnung: Möchtest du die Verschlüsselung wirklich aktivieren?",
"No encryption module loaded, please enable an encryption module in the app menu.": "Es wurde kein Verschlüsselungs-Modul geladen, bitte ein Verschlüsselungs-Modul im Anwendungs-Menü aktivieren.",
"Select default encryption module:": "Standard-Verschlüsselungs-Modul auswählen:",
"You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run {command}": "Du musst deine Verschlüsselungsschlüssel von der alten Verschlüsselung (ownCloud <= 8.0) auf die neue migrieren. Bitte aktiviere das \"Standardverschlüsselungsmodul\" und führe {command} aus.",
"Unable to update server side encryption config": "Die Serverseitige Verschlüsselungskonfiguration kann nicht aktualisiert werden.",
"Please confirm the group removal": "Bitte bestätige die Löschung der Gruppe ",
"You are about to remove the group \"{group}\". The accounts will NOT be deleted.": "Du bist im Begriff, die Gruppe \"{group}\" zu entfernen. Die Konten werden NICHT gelöscht.",
"Cancel": "Abbrechen",
"Confirm": "Bestätigen",
"Submit": "Übermitteln",
"Rename group": "Gruppe umbenennen",
"Remove group": "Gruppe entfernen",
"Failed to remove group \"{group}\"": "Die Gruppe \"{group}\" konnte nicht entfernt werden.",
"Current password": "Aktuelles Passwort",
"New password": "Neues Passwort",
"Change password": "Passwort ändern",
"Your profile picture": "Dein Profilbild",
"Upload profile picture": "Profilbild hochladen",
"Choose profile picture from Files": "Profilbild aus Dateien wählen",
"Remove profile picture": "Profilbild entfernen",
"The file must be a PNG or JPG": "Die Datei muss im PNG- oder JPG-Format sein",
"Picture provided by original account": "Bild von Original-Konto zur Verfügung gestellt",
"Set as profile picture": "Als Profilbild festlegen",
"Please note that it can take up to 24 hours for your profile picture to be updated everywhere.": "Bitte beachte, dass es bis zu 24 Stunden dauern kann, bis das Profilbild überall aktualisiert wird.",
"Choose your profile picture": "Wähle dein Profilbild aus.",
"Please select a valid png or jpg file": "Bitte eine gültige PNG- oder JPG-Datei auswählen",
"Error setting profile picture": "Fehler beim Einstellen des Profilbilds",
"Error cropping profile picture": "Fehler beim Zuschneiden des Profilbilds",
"Error saving profile picture": "Fehler beim Speichern des Profilbilds",
"Error removing profile picture": "Fehler beim Entfernen des Profilbilds",
"Your biography": "Deine Biografie",
"Enter your date of birth": "Gib dein Geburtsdatum ein",
"Unable to update date of birth": "Geburtsdatum konnte nicht aktualisiert werden",
"You are a member of the following groups:": "Du bist Mitglied folgender Gruppen:",
"You are using <strong>{usage}</strong>": "Du benutzt <strong>{usage}</strong>.",
"You are using <strong>{usage}</strong> of <strong>{totalSpace}</strong> (<strong>{usageRelative}%</strong>)": "Du benutzt <strong>{usage}</strong> von <strong>{totalSpace}</strong> (<strong>{usageRelative}%</strong>).",
"Your full name": "Dein vollständiger Name",
"Primary email for password reset and notifications": "Primäre E-Mail-Adresse für Benachrichtigungen und zum Zurücksetzen des Passworts",
"Email options": "E-Mail-Optionen",
"Options for additional email address {index}": "Optionen für zusätzliche E-Mail-Adresse {index}",
"Remove primary email": "Primäre E-Mail-Adresse entfernen",
"Delete email": "E-Mail löschen",
"This address is not confirmed": "Diese Adresse ist nicht bestätigt",
"Unset as primary email": "Als primäre E-Mail-Adresse deaktivieren",
"Set as primary email": "Als primäre E-Mail-Adresse festlegen",
"Additional email address {index}": "Zusätzliche E-Mail-Adresse {index}",
"Unable to delete primary email address": "Primäre E-Mail-Adresse konnte nicht gelöscht werden",
"Unable to update primary email address": "Primäre E-Mail-Adresse konnte nicht aktualisiert werden",
"Unable to add additional email address": "Zusätzliche E-Mail-Adresse konnte nicht hinzugefügt werden",
"Unable to update additional email address": "Zusätzliche E-Mail-Adresse konnte nicht aktualisiert werden",
"Unable to delete additional email address": "Zusätzliche E-Mail-Adresse konnte nicht gelöscht werden",
"No email address set": "Keine E-Mail-Adresse angegeben",
"Your handle": "Dein Online-Name",
"Day to use as the first day of week": "Tag, der als erster Tag der Woche verwendet werden soll",
"Derived from your locale ({weekDayName})": "Abgeleitet von deinem Gebietsschema ({weekDayName})",
"Unable to update first day of week": "Der erste Tag der Woche kann nicht aktualisiert werden",
"Your headline": "Deine Überschrift",
"Languages": "Sprachen",
"Help translate": "Hilf bei der Übersetzung mit",
"Unable to update language": "Sprache konnte nicht aktualisiert werden",
"No language set": "Keine Sprache eingestellt.",
"Locales": "Gebietsschemen",
"Week starts on {firstDayOfWeek}": "Woche beginnt am {firstDayOfWeek}",
"Unable to update locale": "Gebietsschema konnte nicht aktualisiert werden.",
"No locale set": "Kein Gebietsschema festgelegt",
"Your city": "Deine Stadt",
"Your organisation": "Deine Organisation",
"Your phone number": "Deine Telefonnummer",
"Edit your Profile visibility": "Sichtbarkeit des Profils anpassen",
"Enable profile": "Profil aktivieren",
"Unable to update profile enabled state": "Der Status für aktiviertes Profil konnte nicht aktualisiert werden",
"The more restrictive setting of either visibility or scope is respected on your Profile. For example, if visibility is set to \"Show to everyone\" and scope is set to \"Private\", \"Private\" is respected.": "Die restriktivere Einstellung von Sichtbarkeit oder Bereich wird in deinem Profil berücksichtigt. Wenn beispielsweise die Sichtbarkeit auf \"Für jeden sichtbar\" und der Bereich auf \"Privat\" festgelegt ist, wird \"Privat\" respektiert.",
"Unable to update visibility of {displayId}": "Sichtbarkeit von {displayId} kann nicht aktualisiert werden",
"Your role": "Deine Funktion",
"Your X (formerly Twitter) handle": "Dein X (früher Twitter)-Handle",
"Your website": "Deine Internetseite",
"No {property} set": "Keine {property} eingestellt",
"Invalid value": "Ungültiger Wert",
"Unable to update {property}": "{property} konnte nicht aktualisiert werden.",
"Change scope level of {property}, current scope is {scope}": "Ändern des Geltungsbereich von {property}, aktueller Bereich ist {scope}",
"Unable to update federation scope of the primary {property}": "Der Federations-Bereich des primären {property} kann nicht aktualisiert werden.",
"Unable to update federation scope of additional {property}": "Der Federations-Bereich des zusätzlichen {property} kann nicht aktualisiert werden.",
"Add additional email": "Zusätzliche E-Mail-Adresse hinzufügen",
"Add": "Hinzufügen",
"Create": "Erstellen",
"Change": "Ändern",
"Delete": "Löschen",
"Reshare": "Weiterteilen",
"No accounts": "Keine Konten",
"Loading accounts …": "Lade Konten...",
"List of accounts. This list is not fully rendered for performance reasons. The accounts will be rendered as you navigate through the list.": "Kontenliste. Diese Liste wird aus Performance-Gründen nicht vollständig ausgegeben. Die Konten werden ausgegeben, wenn du durch die Liste navigierst.",
"Default language": "Standard-Sprache",
"Common languages": "Gängige Sprachen",
"Other languages": "Weitere Sprachen",
"Password change is disabled because the master key is disabled": "Das Ändern des Passwortes ist deaktiviert, da der Master-Schlüssel deaktiviert ist",
"New account": "Neues Konto",
"Display name": "Anzeigename",
"Either password or email is required": "Passwort oder E-Mail-Adresse ist erforderlich.",
"Password (required)": "Passwort (erforderlich)",
"Email (required)": "E-Mail-Adresse (erforderlich)",
"Email": "E-Mail-Adresse",
"Member of the following groups (required)": "Mitglied der folgenden Gruppen (erforderlich)",
"Member of the following groups": "Mitglied der folgenden Gruppen",
"Set account groups": "Kontengruppen setzen",
"Admin of the following groups": "Administration der folgenden Gruppen",
"Set account as admin for …": "Setze Konto als Administration für …",
"Quota": "Kontingent",
"Set account quota": "Kontokontigent setzen",
"Language": "Sprache",
"Set default language": "Standard-Sprache einstellen",
"Add new account": "Neues Konto hinzufügen",
"Manager": "Manager",
"Set account manager": "Kontomanager festlegen",
"Account name will be autogenerated": "Kontenname wird automatisch erstellt",
"Account name (required)": "Kontoname (erforderlich)",
"Total rows summary": "Zusammenfassung aller Zeilen",
"Scroll to load more rows": "Scrollen, um weitere Zeilen zu laden",
"_{userCount} account …_::_{userCount} accounts …_": [
"{userCount} Konto …",
"{userCount} Konten …"
],
"_{userCount} account_::_{userCount} accounts_": [
"{userCount} Konto",
"{userCount} Konten"
],
"Avatar": "Avatar",
"Account name": "Name des Kontos",
"Group admin for": "Gruppenadministrator für",
"Account backend": "Konto-Backend",
"Storage location": "Speicherort",
"Last login": "Letzte Anmeldung",
"Account actions": "Konto-Aktionen",
"Password or insufficient permissions message": "Passwort oder unzureichende Berechtigungen Nachricht",
"Loading account …": "Lade Konto …",
"Change display name": "Anzeigename ändern",
"Set new password": "Neues Passwort setzen",
"You do not have permissions to see the details of this account": "Du hast nicht die Berechtigung, die Details dieses Kontos anzusehen.",
"Set new email address": "Neue E-Mail-Adresse setzen",
"Add account to group": "Konto zur Gruppe hinzufügen",
"Set account as admin for": "Konto als Administration festlegen für",
"Select account quota": "Kontokontigent auswählen",
"Set the language": "Sprache einstellen",
"Set line manager": "Manager festlegen",
"{size} used": "{size} verwendet",
"Delete account": "Konto löschen",
"Disconnect all devices and delete local data": "Alle Geräte trennen und lokale Daten löschen",
"Disable account": "Konto deaktivieren",
"Enable account": "Konto aktivieren",
"Resend welcome email": "Willkommens-E-Mail erneut senden",
"In case of lost device or exiting the organization, this can remotely wipe the Nextcloud data from all devices associated with {userid}. Only works if the devices are connected to the internet.": "Im Falle des Verlusts des Gerätes oder der Verlassens der Organisation können mit dieser Funktion sämtliche Nextcloud-Daten von allen Geräten die mit {userid} verbunden sind gelöscht werden. Funktioniert nur wenn das Gerät mit dem Internet verbunden ist.",
"Remote wipe of devices": "Fernlöschung von Geräten",
"Wipe {userid}'s devices": "Lösche {userid}s Geräte",
"Wiped {userid}'s devices": "{userid}'s Geräte bereinigt",
"Failed to update line manager": "Fehler beim Aktualisieren des Managers",
"Fully delete {userid}'s account including all their personal files, app data, etc.": "Vollständig {userid}s Konto löschen inklusive aller persönlichen Dateien, App-Daten, usw.",
"Account deletion": "Löschung des Kontos",
"Delete {userid}'s account": "Konto von {userid} löschen",
"Display name was successfully changed": "Der Anzeigename wurde erfolgreich geändert\n ",
"Password was successfully changed": "Das Passwort wurde erfolgreich geändert",
"Email was successfully changed": "E-Mail wurde erfolgreich geändert",
"Welcome mail sent!": "Willkommens-E-Mail gesendet!",
"Toggle account actions menu": "Kontenaktionsmenü umschalten",
"Done": "Erledigt",
"Edit": "Bearbeiten",
"Account management settings": "Kontoverwaltungseinstellungen",
"Visibility": "Sichtbarkeit",
"Show language": "Sprache anzeigen",
"Show account backend": "Konto-Backend anzeigen",
"Show storage path": "Zeige Speicherpfad",
"Show last login": "Letzte Anmeldung anzeigen",
"Sorting": "Sortiere",
"The system config enforces sorting the groups by name. This also disables showing the member count.": "Die Systemkonfiguration erzwingt die Sortierung der Gruppen nach Namen. Dadurch wird auch die Anzeige der Mitgliederzahl deaktiviert.",
"Group list sorting": "Sortierung der Gruppenliste",
"By member count": "Nach Mitgliederzahl",
"By name": "Nach Name",
"Send email": "E-Mail senden",
"Send welcome email to new accounts": "Begrüßungs-E-Mail an neuen Konten senden",
"Defaults": "Standardeinstellungen",
"Default quota": "Standardkontingent",
"Select default quota": "Standardkontingent auswählen",
"Passwordless authentication requires a secure connection.": "Die Anmeldung ohne Passwort erfordert eine sichere Verbindung.",
"Add WebAuthn device": "WebAuthn-Gerät hinzufügen",
"Please authorize your WebAuthn device.": "Bitte autorisiere dein WebAuthn-Gerät.",
"Adding your device …": "Füge dein Gerät hinzu …",
"Server error while trying to complete WebAuthn device registration": "Server-Fehler beim Versuch die WebAuthn-Geräte-Registrierung abzuschließen",
"Unnamed device": "Unbenanntes Gerät",
"Passwordless Authentication": "Authentifizierung ohne Passwort",
"Set up your account for passwordless authentication following the FIDO2 standard.": "Richte dein Konto für die Authentifizierung ohne Passwort nach dem FIDO2-Standard ein.",
"No devices configured.": "Keine Geräte eingerichtet.",
"The following devices are configured for your account:": "Die folgenden Geräte sind für dein Konto eingerichtet:",
"Your browser does not support WebAuthn.": "Dein Browser unterstützt kein WebAuthn.",
"As admin you can fine-tune the sharing behavior. Please see the documentation for more information.": "Als Administrator kannst du das Teilen-Verhalten feinabstimmen. Weitere Informationen findest du in der Dokumentation.",
"You need to enable the File sharing App.": "Du musst die File sharing App aktivieren.",
"Loading app list": "Lade App-Liste",
"App Store": "App Store",
"Loading categories": "Lade Kategorien",
"Developer documentation ↗": "Entwickler-Dokumentation ↗",
"Version {version}, {license}-licensed": "Version {version}, {license}-lizensiert",
"All accounts": "Alle Konten",
"Admins": "Administratoren",
"Account group: {group}": "Kontengruppe: {group}",
"Account management": "Kontoverwaltung",
"Creating group…": "Erstelle Gruppe…",
"Create group": "Gruppe erstellen",
"Group name": "Gruppenname",
"Please enter a valid group name": "Bitte einen gültigen Gruppennamen eingeben",
"Failed to create group": "Fehler beim Erstellen der Gruppe",
"Sending…": "Senden …",
"Email sent": "E-Mail gesendet",
"Location": "Ort",
"Profile picture": "Profilbild",
"About": "Über",
"Full name": "Vollständiger Name",
"Additional email": "Zusätzliche E-Mail-Adresse",
"Headline": "Überschrift",
"Organisation": "Organisation",
"Phone number": "Telefonnummer",
"Role": "Funktion",
"X (formerly Twitter)": "X (früher Twitter)",
"Fediverse (e.g. Mastodon)": "Fediverse (wie z. B. Mastodon)",
"Website": "Webseite",
"Date of birth": "Geburtsdatum",
"Profile visibility": "Sichtbarkeit deines Profils",
"Locale": "Gebietsschema",
"First day of week": "Erster Tag der Woche",
"Not available as this property is required for core functionality including file sharing and calendar invitations": "Nicht verfügbar, da diese Eigenschaft für Kernfunktionen wie Dateifreigabe und Kalendereinladungen erforderlich ist.",
"Not available as federation has been disabled for your account, contact your system administration if you have any questions": "Nicht verfügbar, da Federation für dein Konto deaktiviert ist. Wende dich an deinen Administrator, wenn du Fragen hast.",
"Not available as publishing account specific data to the lookup server is not allowed, contact your system administration if you have any questions": "Nicht verfügbar, da die Veröffentlichung benutzerspezifischer Daten auf dem Lookup-Server nicht zulässig ist. Wende dich bei Fragen an deine Systemadministration.",
"Discover": "Entdecken",
"Your apps": "Deine Apps",
"Active apps": "Aktive Apps",
"Disabled apps": "Deaktivierte Apps",
"Updates": "Aktualisierungen",
"App bundles": "App-Pakete",
"Featured apps": "Vorgestellte Apps",
"Supported apps": "Unterstützte Apps",
"Show to everyone": "Für jeden sichtbar",
"Show to logged in accounts only": "Nur angemeldeten Konten anzeigen",
"Hide": "Ausblenden",
"Download and enable": "Herunterladen und aktivieren",
"Allow untested app": "Ungetestete App zulassen",
"The app will be downloaded from the App Store": "Die App wird aus dem App-Store heruntergeladen",
"This app is not marked as compatible with your Nextcloud version. If you continue you will still be able to install the app. Note that the app might not work as expected.": "Diese App ist als nicht-kompatibel mit deiner Nextcloud-Version markiert. Wenn du fortfährst, so kannst du die App installieren. Bitte beachte, dass die App nicht wie erwartet funktionieren könnte.",
"Never": "Niemals",
"Could not register device: Network error": "Gerät konnte nicht registriert werden: Netzwerkfehler",
"Could not register device: Probably already registered": "Gerät konnte nicht registriert werden: Wahrscheinlich bereits registriert",
"Could not register device": "Gerät konnte nicht registriert werden",
"An error occurred during the request. Unable to proceed.": "Es ist ein Fehler bei der Anfrage aufgetreten. Es kann nicht fortgefahren werden.",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.": "Die App wurde aktiviert, muss aber aktualisiert werden. Du wirst in 5 Sekunden zur Aktualisierungsseite weitergeleitet.",
"Error: This app cannot be enabled because it makes the server unstable": "Fehler: Diese App kann nicht aktiviert werden, da sie den Server instabil macht. ",
"Do you really want to wipe your data from this device?": "Möchtest du wirklich alle Daten von diesem Gerät löschen?",
"Confirm wipe": "Löschen bestätigen",
"Could not delete the app token": "App-Token konnte nicht gelöscht werden",
"Error while wiping the device with the token": "Fehler während des Löschens des Geräts mit dem Token",
"Error while updating device token name": "Fehler bei der Aktualisierung des Geräte-Token-Namens",
"Error while updating device token scope": "Fehler bei der Aktualisierung des Geräte-Token-Scope",
"Could not set group sorting": "Die Gruppensortierung konnte nicht festgelegt werden",
"There were too many requests from your network. Retry later or contact your administrator if this is an error.": "Zu viele Anfragen aus deinem Netzwerk. Versuche es später erneut oder wende dich an deinen Administrator, wenn dies ein Fehler sein sollte.",
"Error": "Fehler",
"Account documentation": "Kontodokumentation",
"Administration documentation": "Administrationsdokumentation",
"Forum": "Forum",
"Nextcloud help & privacy resources": "Nextcloud-Hilfe & Datenschutz-Ressourcen",
"General documentation": "Allgemeine Dokumentation",
"Legal notice": "Impressum",
"Privacy policy": "Datenschutzerklärung ",
"None/STARTTLS": "Keine/STARTTLS",
"SSL": "SSL",
"Open documentation": "Dokumentation öffnen",
"It is important to set up this server to be able to send emails, like for password reset and notifications.": "Es ist wichtig, diesen Server so zu konfigurieren, dass E-Mails versandt werden können, z. B. zum Zurücksetzen des Passworts und für Benachrichtigungen.",
"Send mode": "Sendemodus",
"Encryption": "Verschlüsselung",
"Sendmail mode": "Sendmail-Modus",
"From address": "Absenderadresse",
"Server address": "Serveradresse",
"Port": "Port",
"Authentication": "Authentifizierung",
"Authentication required": "Authentifizierung benötigt",
"Credentials": "Zugangsdaten",
"SMTP Login": "SMTP-Anmeldung",
"SMTP Password": "SMTP-Passwort",
"Save": "Speichern",
"Test and verify email settings": "Testen und überprüfen der E-Mail-Einstellungen",
"It's important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the linked documentation for more information.": "Für die Sicherheit und Performance deiner Instanz ist es wichtig, dass alles richtig konfiguriert ist. Um dir dabei zu helfen, werden einige automatische Prüfungen durchgeführt. Weitere Informationen kannst du der verlinkten Dokumentation entnehmen.",
"All checks passed.": "Alle Überprüfungen bestanden.",
"There are some errors regarding your setup.": "Es gibt einige Fehler bei deiner Systemkonfiguration.",
"There are some warnings regarding your setup.": "Es gibt einige Warnungen bei deiner Systemkonfiguration.",
"Checking for system and security issues.": "Prüfung auf System- und Sicherheitsprobleme.",
"Please double check the <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%1$s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"%2$s\">log</a>.": "Bitte überprüfe noch einmal die <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%1$s\">Installationsanleitungen ↗</a> und kontrolliere das <a href=\"%2$s\">Protokoll</a> auf mögliche Fehler oder Warnungen.",
"Check the security of your Nextcloud over <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">our security scan ↗</a>.": "Überprüfe die Sicherheit deiner Nextcloud über den <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">Sicherheitsscanner der Nextcloud GmbH ↗</a>.",
"Reasons to use Nextcloud in your organization": "Gründe für die Verwendung von Nextcloud in deiner Organisation",
"Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}.": "Entwickelt von der {communityopen}Nextcloud Community{linkclose}, der {githubopen}Quellcode{linkclose} ist lizensiert unter {licenseopen}AGPL{linkclose}-Lizenz.",
"Like our Facebook page": "Like uns auf unserer Facebook-Seite",
"Follow us on Twitter": "Folge uns auf X",
"Follow us on Mastodon": " Folge uns auf Mastodon",
"Check out our blog": "Sieh dir unseren Blog an",
"Subscribe to our newsletter": "Abonniere unseren Newsletter",
"This community release of Nextcloud is unsupported and instant notifications are unavailable.": "Diese Community-Version von Nextcloud wird nicht unterstützt und sofortige Benachrichtigungen sind nicht verfügbar.",
"Use a second factor besides your password to increase security for your account.": "Verwende neben deinem Passwort einen zweiten Faktor, um die Sicherheit für dein Konto zu erhöhen.",
"If you use third party applications to connect to Nextcloud, please make sure to create and configure an app password for each before enabling second factor authentication.": "Wenn du Anwendungen von Drittanbietern verwendest, um dich mit Nextcloud zu verbinden, stelle bitte sicher, dass du für jede Anwendung ein Anwendungspasswort erstellst und einrichtest, bevor du die Zwei-Faktor-Authentifizierung aktivierst.",
"No user supplied": "Kein Benutzer angegeben",
"Please provide an admin recovery password; otherwise, all user data will be lost.": "Bitte gib ein Wiederherstellungspasswort für das Administratorkonto an, da sonst alle Benutzerdaten verlorengehen.",
"Backend does not support password change, but the user's encryption key was updated.": "Das Backend unterstützt die Passwortänderung nicht, aber das Verschlüsselungspasswort des Benutzers wurde aktualisiert",
"You need to set your user email before being able to send test emails. Go to %s for that.": "Du musst deine Benutzer-E-Mail-Adresse festlegen, bevor du Test-E-Mails senden kannst. Gehe dazu zu %s.",
"Invalid user": "Ungültiger Benutzer",
"Your username is: %s": "Dein Benutzername lautet: %s",
"Logged in user must be a subadmin": "Der angemeldete Benutzer muss ein Administrator sein",
"Old user imported certificates": "Alte vom Benutzer importierte Zertifikate",
"A background job is pending that checks for user imported SSL certificates. Please check back later.": "Ein Hintergrundjob, der nach vom Benutzer importierten SSL-Zertifikaten sucht, läuft noch. Bitte versuche es später erneut.",
"There are some user imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.": "Es sind einige vom Benutzer importierte SSL-Zertifikate vorhanden, die von Nextcloud 21 nicht mehr verwendet werden. Du kannst über den Befehl \"occ security:certificates:import\" in der Befehlszeile importiert werden. Ihre Pfade innerhalb des Datenverzeichnisses werden unten angezeigt.",
"Missing optional index \"%s\" in table \"%s\".": "Fehlende optionaler Index \"%s\" in der Tabelle \"%s\".",
"The database is missing some indexes. Due to the fact that adding indexes on big tables could take some time they were not added automatically. By running \"occ db:add-missing-indices\" those missing indexes could be added manually while the instance keeps running. Once the indexes are added queries to those tables are usually much faster.": "In der Datenbank fehlen einige Indizes. Auf Grund der Tatsache, dass das Hinzufügen von Indizes in großen Tabellen einige Zeit in Anspruch nehmen kann, wurden diese nicht automatisch erzeugt. Durch das Ausführen von \"occ db:add-missing-indices\" können die fehlenden Indizes manuell hinzugefügt werden, während die Instanz weiter läuft. Nachdem die Indizes hinzugefügt wurden, sind Anfragen auf die Tabellen normalerweise schneller.",
"Could not check for JavaScript support. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Konnte die JavaScript-Unterstützung nicht überprüfen. Bitte überprüfe manuell, ob dein Webserver `.mjs`-Dateien mit dem JavaScript-MIME-Typ bereitstellt.",
"MySQL unicode support": "MySQL Unicode-Unterstützung",
"Overwrite cli URL": "CLI-URL überschreiben",
"You are currently running PHP %s. PHP 8.0 is now deprecated in Nextcloud 27. Nextcloud 28 may require at least PHP 8.1. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.": "Du verwendest derzeit PHP %s. PHP 8.0 ist ab Nextcloud 27 veraltet. Nextcloud 28 erfordert mindestens PHP 8.1. Bitte aktualisiere so schnell wie möglich auf eine der offiziell unterstützten PHP-Versionen der PHP Gruppe.",
"MariaDB version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MariaDB 10.2 or higher.": "MariaDB Version \"%s\" wird verwendet. Nextcloud 21 und neuer unterstützen diese Version nicht und benötigen MariaDB 10.2 oder neuer.",
"MySQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MySQL 8.0 or MariaDB 10.2 or higher.": "MySQL Version \"%s\" wird verwendet. Nextcloud 21 und neuer unterstützten diese Version nicht und benötigen MySQL 8.0 oder MariaDB 10.2 oder neuer.",
"PostgreSQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require PostgreSQL 9.6 or higher.": "PostgreSQL Version \"%s\" wird verwendet. Nextcloud 21 und neuer unterstützen diese Version nicht und beötigen PostgreSQL 9.6 oder neuer.",
"Exclude groups from sharing": "Gruppen von Freigaben ausschließen",
"These groups will still be able to receive shares, but not to initiate them.": "Diese Gruppen können weiterhin Freigaben empfangen, aber selbst keine mehr initiieren.",
"Allow username autocompletion in share dialog and allow access to the system address book": "Die automatische Vervollständigung des Benutzernamens im Freigabedialog und den Zugriff auf das Systemadressbuch erlauben",
"Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.": "Zwei-Faktor-Authentifizierung kann für alle Benutzer und Gruppen erzwungen werden. Dann können Benutzer, für die keine Zwei-Faktor-Authentifizierung eingerichtet ist, sich nicht am System anmelden.",
"When groups are selected/excluded, they use the following logic to determine if a user has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If a user is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.": "Bei der Auswahl/Abwahl von Gruppen wird folgende Logik verwendet, um festzustellen, ob ein Benutzer 2FA verwenden muss: Wenn keine Gruppe ausgewählt ist, dann wird 2FA für alle Benutzer aktiviert, außer für Mitglieder der ausgenommenen Gruppen. Sind Gruppen ausgewählt, so wird 2FA für alle Mitglieder dieser Gruppen aktiviert. Ist ein Benutzer Mitglied der ausgewählten und ausgenommenen Gruppe, so hat die Auswahl Vorrang und 2FA wird aktiviert. ",
"Rating: {score}/10": "Bewertung: {score}/10",
"Username": "Benutzername",
"Execute one task with each page loaded. Use case: Single user instance.": "Mit jeder geladenen Seite wird eine Aufgabe ausgeführt. Anwendungsfall: Einzelbenutzer-Installation.",
"cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 users depending on the usage).": "cron.php ist bei einem Webcron-Dienst registriert, um cron.php alle 5 Minuten über HTTP aufzurufen. Anwendungsfall: Sehr kleine Instanz (15 Benutzer je nach Nutzung).",
"The cron.php needs to be executed by the system user \"{user}\".": "Die cron.php muss durch den Systembenutzer \"{user}\" ausgeführt werden.",
"Enable or disable profile by default for new users.": "Profil für neue Benutzer standardmäßig aktivieren oder deaktivieren",
"You are about to remove the group \"{group}\". The users will NOT be deleted.": "Du bist dabei die Gruppe \"{group}\" zu löschen. Die Benutzer werden NICHT gelöscht.",
"Additional emails": "Zusätzliche E-Mail-Adressen ",
"Enable Profile": "Profil aktivieren",
"No users": "Keine Benutzer",
"Loading users …": "Lade Benutzer …",
"List of users. This list is not fully rendered for performance reasons. The users will be rendered as you navigate through the list.": "Liste aller Benutzer. Diese Liste wird aus Performance-Gründen nicht vollständig angezeigt. Die Benutzer werden angezeigt, wenn du durch die Liste navigierst.",
"New user": "Neuer Benutzer",
"Groups (required)": "Gruppen (erforderlich)",
"Set user groups": "Benutzergruppen einstellen",
"Administered groups": "Administrierte Gruppen",
"Set user as admin for …": "Benutzer als Administrator setzen für …",
"Set user quota": "Benutzerkontingent einstellen",
"Add new user": "Neuen Benutzer hinzufügen",
"Set user manager": "Benutzermanager setzen",
"Username will be autogenerated": "Benutzername wird automatisch erzeugt.",
"Username (required)": "Benutzername (erforderlich)",
"_{userCount} user …_::_{userCount} users …_": [
"{userCount} Benutzer …",
"{userCount} Benutzer …"
],
"_{userCount} user_::_{userCount} users_": [
"{userCount} Benutzer",
"{userCount} Benutzer"
],
"User backend": "Benutzer-Backend",
"User actions": "Benutzeraktionen",
"Loading user …": "Lade Benutzer …",
"You do not have permissions to see the details of this user": "Du hast keine Berechtigung, um auf die Details dieses Benutzers zu sehen",
"Add user to group": "Benutzer der Gruppe hinzufügen",
"Set user as admin for": "Benutzer als Administrator setzen für",
"Select user quota": "Kontingent auswählen",
"Delete user": "Benutzer löschen",
"Wipe all devices": "Alle Geräte löschen",
"Disable user": "Benutzer deaktivieren",
"Enable user": "Benutzer aktivieren",
"Failed to update user manager": "Fehler beim Aktualisieren des Benutzermanagers",
"Toggle user actions menu": "Menü für Benutzeraktionen umschalten",
"User management settings": "Einstellungen für Benutzerverwaltung",
"Show user backend": "Benutzer-Backend anzeigen",
"Send welcome email to new users": "Begrüßungs-E-Mail an neue Benutzer senden",
"Name your device": "Gerät benennen",
"Server error while trying to add WebAuthn device": "Server-Fehler beim Versuch ein WebAuthn-Gerät hinzuzufügen",
"{license}-licensed": "{license}-Lizenziert",
"by {author}\n{license}": "von {author}\n{license}",
"User management": "Benutzerverwaltung",
"Active users": "Aktive Benutzer",
"Disabled users": "Deaktivierte Benutzer",
"Creating group …": "Erstelle Gruppe …",
"User group: {group}": "Benutzergruppe: {group}",
"Not available as federation has been disabled for your account, contact your system administrator if you have any questions": "Nicht verfügbar, da Federation für dein Konto deaktiviert ist. Wende dich an deinen Administrator, wenn du Fragen hast.",
"Not available as publishing user specific data to the lookup server is not allowed, contact your system administrator if you have any questions": "Nicht verfügbar, da die Veröffentlichung benutzerspezifischer Daten auf dem Lookup-Server nicht zulässig ist. Wende dich bei Fragen an deinen Systemadministrator",
"Show to logged in users only": "Nur für angemeldete Benutzer sichtbar",
"Nextcloud help resources": "Nextcloud-Hilferessourcen",
"SMTP Username": "SMTP-Benutzername",
"To allow this check to run you have to make sure that your webserver can connect to itself. Therefor it must be able to resolve and connect to at least one its `trusted_domains` or the `overwrite.cli.url`.": "Um diese Prüfung auszuführen, musst du sicherstellen, dass dein Webserver eine Verbindung zu sich selbst herstellen kann. Dafür muss dieser in der Lage sein, sich mit mindestens einer seiner \"trusted_domains\" oder der \"overwrite.cli.url\" zu verbinden und diese aufzulösen.",
"Could not check for JavaScript support via any of your `trusted_domains` nor `overwrite.cli.url`. This may be the result of a server-side DNS mismatch or outbound firewall rule. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Es konnte weder über Ihre `trusted_domains` noch über `overwrite.cli.url` nach JavaScript-Unterstützung gesucht werden. Dies kann auf eine serverseitige DNS-Nichtübereinstimmung oder eine ausgehende Firewall-Regel zurückzuführen sein. Bitte überprüfe manuell, ob dein Webserver `.mjs`-Dateien mit dem JavaScript-MIME-Typ bereitstellt.",
"Active accounts": "Aktive Konten"
},
"pluralForm": "nplurals=2; plural=(n != 1);"
}

View File

@ -0,0 +1,905 @@
export default {
"translations": {
"Private": "Private",
"Only visible to people matched via phone number integration through Talk on mobile": "Only visible to people matched via phone number integration through Talk on mobile",
"Local": "Local",
"Only visible to people on this instance and guests": "Only visible to people on this instance and guests",
"Federated": "Federated",
"Only synchronize to trusted servers": "Only synchronize to trusted servers",
"Published": "Published",
"Synchronize to trusted servers and the global and public address book": "Synchronize to trusted servers and the global and public address book",
"Verify": "Verify",
"Verifying …": "Verifying …",
"Unable to change password": "Unable to change password",
"Very weak password": "Very weak password",
"Weak password": "Weak password",
"So-so password": "So-so password",
"Good password": "Good password",
"Strong password": "Strong password",
"Groups": "Groups",
"Group list is empty": "Group list is empty",
"Unable to retrieve the group list": "Unable to retrieve the group list",
"{actor} added you to group {group}": "{actor} added you to group {group}",
"You added {user} to group {group}": "You added {user} to group {group}",
"{actor} added {user} to group {group}": "{actor} added {user} to group {group}",
"An administrator added you to group {group}": "An administrator added you to group {group}",
"An administrator added {user} to group {group}": "An administrator added {user} to group {group}",
"{actor} removed you from group {group}": "{actor} removed you from group {group}",
"You removed {user} from group {group}": "You removed {user} from group {group}",
"{actor} removed {user} from group {group}": "{actor} removed {user} from group {group}",
"An administrator removed you from group {group}": "An administrator removed you from group {group}",
"An administrator removed {user} from group {group}": "An administrator removed {user} from group {group}",
"Your <strong>group memberships</strong> were modified": "Your <strong>group memberships</strong> were modified",
"{actor} changed your password": "{actor} changed your password",
"You changed your password": "You changed your password",
"Your password was reset by an administrator": "Your password was reset by an administrator",
"Your password was reset": "Your password was reset",
"{actor} changed your email address": "{actor} changed your email address",
"You changed your email address": "You changed your email address",
"Your email address was changed by an administrator": "Your email address was changed by an administrator",
"You created an app password for a session named \"{token}\"": "You created an app password for a session named \"{token}\"",
"An administrator created an app password for a session named \"{token}\"": "An administrator created an app password for a session named \"{token}\"",
"You deleted app password \"{token}\"": "You deleted app password \"{token}\"",
"You renamed app password \"{token}\" to \"{newToken}\"": "You renamed app password \"{token}\" to \"{newToken}\"",
"You granted filesystem access to app password \"{token}\"": "You granted filesystem access to app password \"{token}\"",
"You revoked filesystem access from app password \"{token}\"": "You revoked filesystem access from app password \"{token}\"",
"Security": "Security",
"You successfully logged in using two-factor authentication (%1$s)": "You successfully logged in using two-factor authentication (%1$s)",
"A login attempt using two-factor authentication failed (%1$s)": "A login attempt using two-factor authentication failed (%1$s)",
"Remote wipe was started on %1$s": "Remote wipe was started on %1$s",
"Remote wipe has finished on %1$s": "Remote wipe has finished on %1$s",
"Your <strong>password</strong> or <strong>email</strong> was modified": "Your <strong>password</strong> or <strong>email</strong> was modified",
"Settings": "Settings",
"Could not remove app.": "Could not remove app.",
"Could not update app.": "Could not update app.",
"Wrong password": "Incorrect password",
"Unable to change personal password": "Unable to change personal password",
"Saved": "Saved",
"No Login supplied": "No Login supplied",
"Unable to change password. Password too long.": "Unable to change password. Password too long.",
"Authentication error": "Authentication error",
"Please provide an admin recovery password; otherwise, all account data will be lost.": "Please provide an admin recovery password; otherwise, all account data will be lost.",
"Wrong admin recovery password. Please check the password and try again.": "Incorrect admin recovery password. Please check the password and try again.",
"Backend does not support password change, but the encryption of the account key was updated.": "Backend does not support password change, but the encryption of the account key was updated.",
"Administrator documentation": "Administrator documentation",
"User documentation": "User documentation",
"Nextcloud help overview": "Nextcloud help overview",
"Invalid SMTP password.": "Invalid SMTP password.",
"Email setting test": "Email setting test",
"Well done, %s!": "Well done, %s!",
"If you received this email, the email configuration seems to be correct.": "If you received this email, the email configuration seems to be correct.",
"Email could not be sent. Check your mail server log": "Email could not be sent. Check your mail server log",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)": "A problem occurred while sending the email. Please revise your settings. (Error: %s)",
"You need to set your account email before being able to send test emails. Go to %s for that.": "You need to set your account email before being able to send test emails. Go to %s for that.",
"Recently active": "Recently active",
"Disabled accounts": "Disabled accounts",
"Invalid account": "Invalid account",
"Invalid mail address": "Invalid mail address",
"Settings saved": "Settings saved",
"Unable to change full name": "Unable to change full name",
"Unable to change email address": "Unable to change email address",
"Unable to set invalid phone number": "Unable to set invalid phone number",
"Unable to set invalid website": "Unable to set invalid website",
"Some account data was invalid": "Some account data was invalid",
"In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):": "In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):",
"In order to verify your Website, store the following content in your web-root at '.well-known/CloudIdVerificationCode.txt' (please make sure that the complete text is in one line):": "In order to verify your Website, store the following content in your web-root at '.well-known/CloudIdVerificationCode.txt' (please make sure that the complete text is in one line):",
"%1$s changed your password on %2$s.": "%1$s changed your password on %2$s.",
"Your password on %s was changed.": "Your password on %s was changed.",
"Your password on %s was reset by an administrator.": "Your password on %s was reset by an administrator.",
"Your password on %s was reset.": "Your password on %s was reset.",
"Password for %1$s changed on %2$s": "Password for %1$s changed on %2$s",
"Password changed for %s": "Password changed for %s",
"If you did not request this, please contact an administrator.": "If you did not request this, please contact an administrator.",
"Your email address on %s was changed.": "Your email address on %s was changed.",
"Your email address on %s was changed by an administrator.": "Your email address on %s was changed by an administrator.",
"Email address for %1$s changed on %2$s": "Email address for %1$s changed on %2$s",
"Email address changed for %s": "Email address changed for %s",
"The new email address is %s": "The new email address is %s",
"Your %s account was created": "Your %s account was created",
"Welcome aboard": "Welcome aboard",
"Welcome aboard %s": "Welcome aboard %s",
"Welcome to your %s account, you can add, protect, and share your data.": "Welcome to your %s account, you can add, protect, and share your data.",
"Your Login is: %s": "Your Login is: %s",
"Set your password": "Set your password",
"Go to %s": "Go to %s",
"Install Client": "Install Client",
"Logged in account must be a subadmin": "Logged in account must be a subadmin",
"Apps": "Apps",
"Personal": "Personal",
"Administration": "Administration",
"Users": "Users",
"Additional settings": "Additional settings",
"Artificial Intelligence": "Artificial Intelligence",
"Administration privileges": "Administration privileges",
"Groupware": "Groupware",
"Overview": "Overview",
"Basic settings": "Basic settings",
"Sharing": "Sharing",
"Availability": "Availability",
"Calendar": "Calendar",
"Personal info": "Personal info",
"Mobile & desktop": "Mobile & desktop",
"Email server": "Email server",
"Security & setup warnings": "Security & setup warnings",
"Background jobs": "Background jobs",
"Unlimited": "Unlimited",
"Verifying": "Verifying",
"Allowed admin IP ranges": "Allowed admin IP ranges",
"Admin IP filtering isnt applied.": "Admin IP filtering isnt applied.",
"Configuration key \"%1$s\" expects an array (%2$s found). Admin IP range validation will not be applied.": "Configuration key \"%1$s\" expects an array (%2$s found). Admin IP range validation will not be applied.",
"Configuration key \"%1$s\" contains invalid IP range(s): \"%2$s\"": "Configuration key \"%1$s\" contains invalid IP range(s): \"%2$s\"",
"Admin IP filtering is correctly configured.": "Admin IP filtering is correctly configured.",
"App directories owner": "App directories owner",
"Some app directories are owned by a different user than the web server one. This may be the case if apps have been installed manually. Check the permissions of the following app directories:\n%s": "Some app directories are owned by a different user than the web server one. This may be the case if apps have been installed manually. Check the permissions of the following app directories:\n%s",
"App directories have the correct owner \"%s\"": "App directories have the correct owner \"%s\"",
"Brute-force Throttle": "Brute-force Throttle",
"Your remote address could not be determined.": "Your remote address could not be determined.",
"Your remote address was identified as \"%s\" and is brute-force throttled at the moment slowing down the performance of various requests. If the remote address is not your address this can be an indication that a proxy is not configured correctly.": "Your remote address was identified as \"%s\" and is brute-force throttled at the moment slowing down the performance of various requests. If the remote address is not your address this can be an indication that a proxy is not configured correctly.",
"Your remote address \"%s\" is not brute-force throttled.": "Your remote address \"%s\" is not brute-force throttled.",
"To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule.": "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule.",
"Old administration imported certificates": "Old administration imported certificates",
"A background job is pending that checks for administration imported SSL certificates. Please check back later.": "A background job is pending that checks for administration imported SSL certificates. Please check back later.",
"There are some administration imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.": "There are some administration imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.",
"Code integrity": "Code integrity",
"Integrity checker has been disabled. Integrity cannot be verified.": "Integrity checker has been disabled. Integrity cannot be verified.",
"No altered files": "No altered files",
"Some files have not passed the integrity check. {link1} {link2}": "Some files have not passed the integrity check. {link1} {link2}",
"Cron errors": "Cron errors",
"It was not possible to execute the cron job via CLI. The following technical errors have appeared:\n%s": "It was not possible to execute the cron job via CLI. The following technical errors have appeared:\n%s",
"The last cron job ran without errors.": "The last cron job ran without errors.",
"Cron last run": "Cron last ran",
"Last background job execution ran %s. Something seems wrong. {link}.": "Last background job execution ran %s. Something seems wrong. {link}.",
"Last background job execution ran %s.": "Last background job execution ran %s.",
"Data directory protected": "Data directory protected",
"Your data directory and files are probably accessible from the internet. The .htaccess file is not working. It is strongly recommended that you configure your web server so that the data directory is no longer accessible, or move the data directory outside the web server document root.": "Your data directory and files are probably accessible from the internet. The .htaccess file is not working. It is strongly recommended that you configure your web server so that the data directory is no longer accessible, or move the data directory outside the web server document root.",
"Could not check that the data directory is protected. Please check manually that your server does not allow access to the data directory.": "Could not check that the data directory is protected. Please check manually that your server does not allow access to the data directory.",
"Database missing columns": "Database missing columns",
"Missing optional column \"%s\" in table \"%s\".": "Missing optional column \"%s\" in table \"%s\".",
"The database is missing some optional columns. Due to the fact that adding columns on big tables could take some time they were not added automatically when they can be optional. By running \"occ db:add-missing-columns\" those missing columns could be added manually while the instance keeps running. Once the columns are added some features might improve responsiveness or usability.": "The database is missing some optional columns. Due to the fact that adding columns on big tables could take some time they were not added automatically when they can be optional. By running \"occ db:add-missing-columns\" those missing columns could be added manually while the instance keeps running. Once the columns are added some features might improve responsiveness or usability.",
"Database missing indices": "Database missing indices",
"Missing indices:": "Missing indices:",
"\"%s\" in table \"%s\"": "\"%s\" in table \"%s\"",
"Detected some missing optional indices. Occasionally new indices are added (by Nextcloud or installed applications) to improve database performance. Adding indices can sometimes take awhile and temporarily hurt performance so this is not done automatically during upgrades. Once the indices are added, queries to those tables should be faster. Use the command `occ db:add-missing-indices` to add them. ": "Detected some missing optional indices. Occasionally new indices are added (by Nextcloud or installed applications) to improve database performance. Adding indices can sometimes take awhile and temporarily hurt performance so this is not done automatically during upgrades. Once the indices are added, queries to those tables should be faster. Use the command `occ db:add-missing-indices` to add them. ",
"Database missing primary keys": "Database missing primary keys",
"Missing primary key on table \"%s\".": "Missing primary key on table \"%s\".",
"The database is missing some primary keys. Due to the fact that adding primary keys on big tables could take some time they were not added automatically. By running \"occ db:add-missing-primary-keys\" those missing primary keys could be added manually while the instance keeps running.": "The database is missing some primary keys. Due to the fact that adding primary keys on big tables could take some time they were not added automatically. By running \"occ db:add-missing-primary-keys\" those missing primary keys could be added manually while the instance keeps running.",
"Database pending bigint migrations": "Database pending bigint migrations",
"Some columns in the database are missing a conversion to big int. Due to the fact that changing column types on big tables could take some time they were not changed automatically. By running \"occ db:convert-filecache-bigint\" those pending changes could be applied manually. This operation needs to be made while the instance is offline.": "Some columns in the database are missing a conversion to big int. Due to the fact that changing column types on big tables could take some time they were not changed automatically. By running \"occ db:convert-filecache-bigint\" those pending changes could be applied manually. This operation needs to be made while the instance is offline.",
"Debug mode": "Debug mode",
"This instance is running in debug mode. Only enable this for local development and not in production environments.": "This instance is running in debug mode. Only enable this for local development and not in production environments.",
"Debug mode is disabled.": "Debug mode is disabled.",
"Default phone region": "Default phone region",
"Your installation has no default phone region set. This is required to validate phone numbers in the profile settings without a country code. To allow numbers without a country code, please add \"default_phone_region\" with the respective ISO 3166-1 code of the region to your config file.": "Your installation has no default phone region set. This is required to validate phone numbers in the profile settings without a country code. To allow numbers without a country code, please add \"default_phone_region\" with the respective ISO 3166-1 code of the region to your config file.",
"Email test": "Email test",
"Email test was successfully sent": "Email test was successfully sent",
"You have not set or verified your email server configuration, yet. Please head over to the \"Basic settings\" in order to set them. Afterwards, use the \"Send email\" button below the form to verify your settings.": "You have not set or verified your email server configuration, yet. Please head over to the \"Basic settings\" in order to set them. Afterwards, use the \"Send email\" button below the form to verify your settings.",
"File locking": "File locking",
"Transactional file locking is disabled, this might lead to issues with race conditions. Enable \"filelocking.enabled\" in config.php to avoid these problems.": "Transactional file locking is disabled, this might lead to issues with race conditions. Enable \"filelocking.enabled\" in config.php to avoid these problems.",
"The database is used for transactional file locking. To enhance performance, please configure memcache, if available.": "The database is used for transactional file locking. To enhance performance, please configure memcache, if available.",
"Forwarded for headers": "Forwarded for headers",
"Your \"trusted_proxies\" setting is not correctly set, it should be an array.": "Your \"trusted_proxies\" setting is not correctly set, it should be an array.",
"Your \"trusted_proxies\" setting is not correctly set, it should be an array of IP addresses - optionally with range in CIDR notation.": "Your \"trusted_proxies\" setting is not correctly set, it should be an array of IP addresses - optionally with range in CIDR notation.",
"The reverse proxy header configuration is incorrect. This is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.": "The reverse proxy header configuration is incorrect. This is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.",
"Your IP address was resolved as %s": "Your IP address was resolved as %s",
"The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy. If not, this is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.": "The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy. If not, this is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.",
"HTTPS access and URLs": "HTTPS access and URLs",
"Accessing site insecurely via HTTP. You are strongly advised to set up your server to require HTTPS instead. Without it some important web functionality like \"copy to clipboard\" or \"service workers\" will not work!": "Accessing site insecurely via HTTP. You are strongly advised to set up your server to require HTTPS instead. Without it some important web functionality like \"copy to clipboard\" or \"service workers\" will not work!",
"Accessing site insecurely via HTTP.": "Accessing site insecurely via HTTP.",
"You are accessing your instance over a secure connection, however your instance is generating insecure URLs. This likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.": "You are accessing your instance over a secure connection, however your instance is generating insecure URLs. This likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.",
"Your instance is generating insecure URLs. If you access your instance over HTTPS, this likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.": "Your instance is generating insecure URLs. If you access your instance over HTTPS, this likely means that your instance is behind a reverse proxy and the Nextcloud `overwrite*` config values are not set correctly.",
"You are accessing your instance over a secure connection, and your instance is generating secure URLs.": "You are accessing your instance over a secure connection, and your instance is generating secure URLs.",
"Internet connectivity": "Internet connectivity",
"Internet connectivity is disabled in configuration file.": "Internet connectivity is disabled in configuration file.",
"This server has no working internet connection: Multiple endpoints could not be reached. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. Establish a connection from this server to the internet to enjoy all features.": "This server has no working internet connection: Multiple endpoints could not be reached. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. Establish a connection from this server to the internet to enjoy all features.",
"JavaScript modules support": "JavaScript modules support",
"Unable to run check for JavaScript support. Please remedy or confirm manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Unable to run check for JavaScript support. Please remedy or confirm manually if your webserver serves `.mjs` files using the JavaScript MIME type.",
"Your webserver does not serve `.mjs` files using the JavaScript MIME type. This will break some apps by preventing browsers from executing the JavaScript files. You should configure your webserver to serve `.mjs` files with either the `text/javascript` or `application/javascript` MIME type.": "Your webserver does not serve `.mjs` files using the JavaScript MIME type. This will break some apps by preventing browsers from executing the JavaScript files. You should configure your webserver to serve `.mjs` files with either the `text/javascript` or `application/javascript` MIME type.",
"JavaScript source map support": "JavaScript source map support",
"Your webserver is not set up to serve `.js.map` files. Without these files, JavaScript Source Maps won't function properly, making it more challenging to troubleshoot and debug any issues that may arise.": "Your webserver is not set up to serve `.js.map` files. Without these files, JavaScript Source Maps won't function properly, making it more challenging to troubleshoot and debug any issues that may arise.",
"Old server-side-encryption": "Old server-side-encryption",
"Disabled": "Disabled",
"The old server-side-encryption format is enabled. We recommend disabling this.": "The old server-side-encryption format is enabled. We recommend disabling this.",
"Maintenance window start": "Maintenance window start",
"Server has no maintenance window start time configured. This means resource intensive daily background jobs will also be executed during your main usage time. We recommend to set it to a time of low usage, so users are less impacted by the load caused from these heavy tasks.": "Server has no maintenance window start time configured. This means resource intensive daily background jobs will also be executed during your main usage time. We recommend to set it to a time of low usage, so users are less impacted by the load caused from these heavy tasks.",
"Maintenance window to execute heavy background jobs is between {start}:00 UTC and {end}:00 UTC": "Maintenance window to execute heavy background jobs is between {start}:00 UTC and {end}:00 UTC",
"Memcache": "Memcache",
"Memcached is configured as distributed cache, but the wrong PHP module (\"memcache\") is installed. Please install the PHP module \"memcached\".": "Memcached is configured as distributed cache, but the wrong PHP module (\"memcache\") is installed. Please install the PHP module \"memcached\".",
"Memcached is configured as distributed cache, but the PHP module \"memcached\" is not installed. Please install the PHP module \"memcached\".": "Memcached is configured as distributed cache, but the PHP module \"memcached\" is not installed. Please install the PHP module \"memcached\".",
"No memory cache has been configured. To enhance performance, please configure a memcache, if available.": "No memory cache has been configured. To enhance performance, please configure a memcache, if available.",
"Configured": "Configured",
"Mimetype migrations available": "Mimetype migrations available",
"One or more mimetype migrations are available. Occasionally new mimetypes are added to better handle certain file types. Migrating the mimetypes take a long time on larger instances so this is not done automatically during upgrades. Use the command `occ maintenance:repair --include-expensive` to perform the migrations.": "One or more mimetype migrations are available. Occasionally new mimetypes are added to better handle certain file types. Migrating the mimetypes take a long time on larger instances so this is not done automatically during upgrades. Use the command `occ maintenance:repair --include-expensive` to perform the migrations.",
"MySQL Unicode support": "MySQL Unicode support",
"You are not using MySQL": "You are not using MySQL",
"MySQL is used as database and does support 4-byte characters": "MySQL is used as database and does support 4-byte characters",
"MySQL is used as database but does not support 4-byte characters. To be able to handle 4-byte characters (like emojis) without issues in filenames or comments for example it is recommended to enable the 4-byte support in MySQL.": "MySQL is used as database but does not support 4-byte characters. To be able to handle 4-byte characters (like emojis) without issues in filenames or comments for example it is recommended to enable the 4-byte support in MySQL.",
"OCS provider resolving": "OCS provider resolving",
"Could not check if your web server properly resolves the OCM and OCS provider URLs.": "Could not check if your web server properly resolves the OCM and OCS provider URLs.",
"Your web server is not properly set up to resolve %1$s.\nThis is most likely related to a web server configuration that was not updated to deliver this folder directly.\nPlease compare your configuration against the shipped rewrite rules in \".htaccess\" for Apache or the provided one in the documentation for Nginx.\nOn Nginx those are typically the lines starting with \"location ~\" that need an update.": "Your web server is not properly set up to resolve %1$s.\nThis is most likely related to a web server configuration that was not updated to deliver this folder directly.\nPlease compare your configuration against the shipped rewrite rules in \".htaccess\" for Apache or the provided one in the documentation for Nginx.\nOn Nginx those are typically the lines starting with \"location ~\" that need an update.",
"Overwrite CLI URL": "Overwrite CLI URL",
"The \"overwrite.cli.url\" option in your config.php is correctly set to \"%s\".": "The \"overwrite.cli.url\" option in your config.php is correctly set to \"%s\".",
"The \"overwrite.cli.url\" option in your config.php is set to \"%s\" which is a correct URL. Suggested URL is \"%s\".": "The \"overwrite.cli.url\" option in your config.php is set to \"%s\" which is a correct URL. Suggested URL is \"%s\".",
"Please make sure to set the \"overwrite.cli.url\" option in your config.php file to the URL that your users mainly use to access this Nextcloud. Suggestion: \"%s\". Otherwise there might be problems with the URL generation via cron. (It is possible though that the suggested URL is not the URL that your users mainly use to access this Nextcloud. Best is to double check this in any case.)": "Please make sure to set the \"overwrite.cli.url\" option in your config.php file to the URL that your users mainly use to access this Nextcloud. Suggestion: \"%s\". Otherwise there might be problems with the URL generation via cron. (It is possible though that the suggested URL is not the URL that your users mainly use to access this Nextcloud. Best is to double check this in any case.)",
"PHP default charset": "PHP default charset",
"PHP configuration option \"default_charset\" should be UTF-8": "PHP configuration option \"default_charset\" should be UTF-8",
"PHP set_time_limit": "PHP set_time_limit",
"The function is available.": "The function is available.",
"The PHP function \"set_time_limit\" is not available. This could result in scripts being halted mid-execution, breaking your installation. Enabling this function is strongly recommended.": "The PHP function \"set_time_limit\" is not available. This could result in scripts being halted mid-execution, breaking your installation. Enabling this function is strongly recommended.",
"Freetype": "Freetype",
"Supported": "Supported",
"Your PHP does not have FreeType support, resulting in breakage of profile pictures and the settings interface.": "Your PHP does not have FreeType support, resulting in breakage of profile pictures and the settings interface.",
"PHP getenv": "PHP getenv",
"PHP does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response.": "PHP does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response.",
"PHP memory limit": "PHP memory limit",
"The PHP memory limit is below the recommended value of %s.": "The PHP memory limit is below the recommended value of %s.",
"PHP modules": "PHP modules",
"increases language translation performance and fixes sorting of non-ASCII characters": "increases language translation performance and fixes sorting of non-ASCII characters",
"for Argon2 for password hashing": "for Argon2 for password hashing",
"for WebAuthn passwordless login": "for WebAuthn passwordless login",
"for WebAuthn passwordless login, and SFTP storage": "for WebAuthn passwordless login, and SFTP storage",
"for picture rotation in server and metadata extraction in the Photos app": "for picture rotation in server and metadata extraction in the Photos app",
"This instance is missing some required PHP modules. It is required to install them: %s.": "This instance is missing some required PHP modules. It is required to install them: %s.",
"This instance is missing some recommended PHP modules. For improved performance and better compatibility it is highly recommended to install them:\n%s": "This instance is missing some recommended PHP modules. For improved performance and better compatibility it is highly recommended to install them:\n%s",
"PHP opcache": "PHP opcache",
"The PHP OPcache module is not loaded. For better performance it is recommended to load it into your PHP installation.": "The PHP OPcache module is not loaded. For better performance it is recommended to load it into your PHP installation.",
"OPcache is disabled. For better performance, it is recommended to apply \"opcache.enable=1\" to your PHP configuration.": "OPcache is disabled. For better performance, it is recommended to apply \"opcache.enable=1\" to your PHP configuration.",
"The shared memory based OPcache is disabled. For better performance, it is recommended to apply \"opcache.file_cache_only=0\" to your PHP configuration and use the file cache as second level cache only.": "The shared memory based OPcache is disabled. For better performance, it is recommended to apply \"opcache.file_cache_only=0\" to your PHP configuration and use the file cache as second level cache only.",
"OPcache is not working as it should, opcache_get_status() returns false, please check configuration.": "OPcache is not working as it should, opcache_get_status() returns false, please check configuration.",
"The maximum number of OPcache keys is nearly exceeded. To assure that all scripts can be kept in the cache, it is recommended to apply \"opcache.max_accelerated_files\" to your PHP configuration with a value higher than \"%s\".": "The maximum number of OPcache keys is nearly exceeded. To assure that all scripts can be kept in the cache, it is recommended to apply \"opcache.max_accelerated_files\" to your PHP configuration with a value higher than \"%s\".",
"The OPcache buffer is nearly full. To assure that all scripts can be hold in cache, it is recommended to apply \"opcache.memory_consumption\" to your PHP configuration with a value higher than \"%s\".": "The OPcache buffer is nearly full. To assure that all scripts can be hold in cache, it is recommended to apply \"opcache.memory_consumption\" to your PHP configuration with a value higher than \"%s\".",
"The OPcache interned strings buffer is nearly full. To assure that repeating strings can be effectively cached, it is recommended to apply \"opcache.interned_strings_buffer\" to your PHP configuration with a value higher than \"%s\".": "The OPcache interned strings buffer is nearly full. To assure that repeating strings can be effectively cached, it is recommended to apply \"opcache.interned_strings_buffer\" to your PHP configuration with a value higher than \"%s\".",
"OPcache is configured to remove code comments. With OPcache enabled, \"opcache.save_comments=1\" must be set for Nextcloud to function.": "OPcache is configured to remove code comments. With OPcache enabled, \"opcache.save_comments=1\" must be set for Nextcloud to function.",
"Nextcloud is not allowed to use the OPcache API. With OPcache enabled, it is highly recommended to include all Nextcloud directories with \"opcache.restrict_api\" or unset this setting to disable OPcache API restrictions, to prevent errors during Nextcloud core or app upgrades.": "Nextcloud is not allowed to use the OPcache API. With OPcache enabled, it is highly recommended to include all Nextcloud directories with \"opcache.restrict_api\" or unset this setting to disable OPcache API restrictions, to prevent errors during Nextcloud core or app upgrades.",
"Checking from CLI, OPcache checks have been skipped.": "Checking from CLI, OPcache checks have been skipped.",
"The PHP OPcache module is not properly configured. %s.": "The PHP OPcache module is not properly configured. %s.",
"Correctly configured": "Correctly configured",
"PHP version": "PHP version",
"You are currently running PHP %s. PHP 8.1 is now deprecated in Nextcloud 30. Nextcloud 31 may require at least PHP 8.2. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.": "You are currently running PHP %s. PHP 8.1 is now deprecated in Nextcloud 30. Nextcloud 31 may require at least PHP 8.2. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.",
"You are currently running PHP %s.": "You are currently running PHP %s.",
"PHP \"output_buffering\" option": "PHP \"output_buffering\" option",
"PHP configuration option \"output_buffering\" must be disabled": "PHP configuration option \"output_buffering\" must be disabled",
"Push service": "Push service",
"Valid enterprise license": "Valid enterprise license",
"Free push service": "Free push service",
"This is the unsupported community build of Nextcloud. Given the size of this instance, performance, reliability and scalability cannot be guaranteed. Push notifications are limited to avoid overloading our free service. Learn more about the benefits of Nextcloud Enterprise at {link}.": "This is the unsupported community build of Nextcloud. Given the size of this instance, performance, reliability and scalability cannot be guaranteed. Push notifications are limited to avoid overloading our free service. Learn more about the benefits of Nextcloud Enterprise at {link}.",
"Random generator": "Random generator",
"No suitable source for randomness found by PHP which is highly discouraged for security reasons.": "No suitable source for randomness found by PHP which is highly discouraged for security reasons.",
"Secure": "Secure",
"Configuration file access rights": "Configuration file access rights",
"The read-only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update.": "The read-only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update.",
"Nextcloud configuration file is writable": "Nextcloud configuration file is writable",
"Scheduling objects table size": "Scheduling objects table size",
"You have more than %s rows in the scheduling objects table. Please run the expensive repair jobs via occ maintenance:repair --include-expensive.": "You have more than %s rows in the scheduling objects table. Please run the expensive repair jobs via occ maintenance:repair --include-expensive.",
"Scheduling objects table size is within acceptable range.": "Scheduling objects table size is within acceptable range.",
"HTTP headers": "HTTP headers",
"- The `%1$s` HTTP header is not set to `%2$s`. Some features might not work correctly, as it is recommended to adjust this setting accordingly.": "- The `%1$s` HTTP header is not set to `%2$s`. Some features might not work correctly, as it is recommended to adjust this setting accordingly.",
"- The `%1$s` HTTP header is not set to `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.": "- The `%1$s` HTTP header is not set to `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.",
"- The `%1$s` HTTP header does not contain `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.": "- The `%1$s` HTTP header does not contain `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.",
"- The `%1$s` HTTP header is not set to `%2$s`, `%3$s`, `%4$s`, `%5$s` or `%6$s`. This can leak referer information. See the {w3c-recommendation}.": "- The `%1$s` HTTP header is not set to `%2$s`, `%3$s`, `%4$s`, `%5$s` or `%6$s`. This can leak referer information. See the {w3c-recommendation}.",
"- The `Strict-Transport-Security` HTTP header is not set to at least `%d` seconds (current value: `%d`). For enhanced security, it is recommended to use a long HSTS policy.": "- The `Strict-Transport-Security` HTTP header is not set to at least `%d` seconds (current value: `%d`). For enhanced security, it is recommended to use a long HSTS policy.",
"- The `Strict-Transport-Security` HTTP header is malformed: `%s`. For enhanced security, it is recommended to enable HSTS.": "- The `Strict-Transport-Security` HTTP header is malformed: `%s`. For enhanced security, it is recommended to enable HSTS.",
"- The `Strict-Transport-Security` HTTP header is not set (should be at least `%d` seconds). For enhanced security, it is recommended to enable HSTS.": "- The `Strict-Transport-Security` HTTP header is not set (should be at least `%d` seconds). For enhanced security, it is recommended to enable HSTS.",
"Some headers are not set correctly on your instance": "Some headers are not set correctly on your instance",
"Could not check that your web server serves security headers correctly. Please check manually.": "Could not check that your web server serves security headers correctly. Please check manually.",
"Could not check that your web server serves security headers correctly, unable to query `%s`": "Could not check that your web server serves security headers correctly, unable to query `%s`",
"Your server is correctly configured to send security headers.": "Your server is correctly configured to send security headers.",
"Database version": "Database version",
"MariaDB version 10.3 detected, this version is end-of-life and only supported as part of Ubuntu 20.04. MariaDB >=%1$s and <=%2$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MariaDB version 10.3 detected, this version is end-of-life and only supported as part of Ubuntu 20.04. MariaDB >=%1$s and <=%2$s is suggested for best performance, stability and functionality with this version of Nextcloud.",
"MariaDB version \"%1$s\" detected. MariaDB >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MariaDB version \"%1$s\" detected. MariaDB >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.",
"MySQL version \"%1$s\" detected. MySQL >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.": "MySQL version \"%1$s\" detected. MySQL >=%2$s and <=%3$s is suggested for best performance, stability and functionality with this version of Nextcloud.",
"PostgreSQL version \"%s\" detected. PostgreSQL >=12 and <=16 is suggested for best performance, stability and functionality with this version of Nextcloud.": "PostgreSQL version \"%s\" detected. PostgreSQL >=12 and <=16 is suggested for best performance, stability and functionality with this version of Nextcloud.",
"SQLite is currently being used as the backend database. For larger installations we recommend that you switch to a different database backend. This is particularly recommended when using the desktop client for file synchronisation. To migrate to another database use the command line tool: \"occ db:convert-type\".": "SQLite is currently being used as the backend database. For larger installations we recommend that you switch to a different database backend. This is particularly recommended when using the desktop client for file synchronisation. To migrate to another database use the command line tool: \"occ db:convert-type\".",
"Unknown database platform": "Unknown database platform",
"Architecture": "Architecture",
"64-bit": "64-bit",
"It seems like you are running a 32-bit PHP version. Nextcloud needs 64-bit to run well. Please upgrade your OS and PHP to 64-bit!": "It seems like you are running a 32-bit PHP version. Nextcloud needs 64-bit to run well. Please upgrade your OS and PHP to 64-bit!",
"Temporary space available": "Temporary space available",
"Error while checking the temporary PHP path - it was not properly set to a directory. Returned value: %s": "Error while checking the temporary PHP path - it was not properly set to a directory. Returned value: %s",
"The PHP function \"disk_free_space\" is disabled, which prevents the check for enough space in the temporary directories.": "The PHP function \"disk_free_space\" is disabled, preventing the system from checking for sufficient space in the temporary directories.",
"Error while checking the available disk space of temporary PHP path or no free disk space returned. Temporary path: %s": "Error while checking the available disk space of temporary PHP path or no free disk space returned. Temporary path: %s",
"- %.1f GiB available in %s (PHP temporary directory)": "- %.1f GiB available in %s (PHP temporary directory)",
"- %.1f GiB available in %s (Nextcloud temporary directory)": "- %.1f GiB available in %s (Nextcloud temporary directory)",
"Temporary directory is correctly configured:\n%s": "Temporary directory is correctly configured:\n%s",
"This instance uses an S3 based object store as primary storage, and has enough space in the temporary directory.\n%s": "This instance uses an S3 based object store as primary storage, and has enough space in the temporary directory.\n%s",
"This instance uses an S3 based object store as primary storage. The uploaded files are stored temporarily on the server and thus it is recommended to have 50 GiB of free space available in the temp directory of PHP. To improve this please change the temporary directory in the php.ini or make more space available in that path. \nChecking the available space in the temporary path resulted in %.1f GiB instead of the recommended 50 GiB. Path: %s": "This instance uses an S3 based object store as primary storage. The uploaded files are stored temporarily on the server and thus it is recommended to have 50 GiB of free space available in the temp directory of PHP. To improve this please change the temporary directory in the php.ini or make more space available in that path. \nChecking the available space in the temporary path resulted in %.1f GiB instead of the recommended 50 GiB. Path: %s",
"Database transaction isolation level": "Database transaction isolation level",
"Your database does not run with \"READ COMMITTED\" transaction isolation level. This can cause problems when multiple actions are executed in parallel.": "Your database does not run with \"READ COMMITTED\" transaction isolation level. This can cause problems when multiple actions are executed in parallel.",
"Was not able to get transaction isolation level: %s": "Was not able to get transaction isolation level: %s",
".well-known URLs": ".well-known URLs",
"`check_for_working_wellknown_setup` is set to false in your configuration, so this check was skipped.": "`check_for_working_wellknown_setup` is set to false in your configuration, so this check was skipped.",
"Could not check that your web server serves `.well-known` correctly. Please check manually.": "Could not check that your web server serves `.well-known` correctly. Please check manually.",
"Your web server is not properly set up to resolve `.well-known` URLs, failed on:\n`%s`": "Your web server is not properly set up to resolve `.well-known` URLs, failed on:\n`%s`",
"Your server is correctly configured to serve `.well-known` URLs.": "Your server is correctly configured to serve `.well-known` URLs.",
"WOFF2 file loading": "WOFF2 file loading",
"Could not check for WOFF2 loading support. Please check manually if your webserver serves `.woff2` files.": "Could not check for WOFF2 loading support. Please check manually if your webserver serves `.woff2` files.",
"Your web server is not properly set up to deliver .woff2 files. This is typically an issue with the Nginx configuration. For Nextcloud 15 it needs an adjustement to also deliver .woff2 files. Compare your Nginx configuration to the recommended configuration in our documentation.": "Your web server is not properly set up to deliver .woff2 files. This is typically an issue with the Nginx configuration. For Nextcloud 15 it needs an adjustement to also deliver .woff2 files. Compare your Nginx configuration to the recommended configuration in our documentation.",
"Profile information": "Profile information",
"Profile picture, full name, email, phone number, address, website, Twitter, organisation, role, headline, biography, and whether your profile is enabled": "Profile picture, full name, email, phone number, address, website, Twitter, organisation, role, headline, biography, and whether your profile is enabled",
"Nextcloud settings": "Nextcloud settings",
"Unified task processing": "Unified task processing",
"AI tasks can be implemented by different apps. Here you can set which app should be used for which task.": "AI tasks can be implemented by different apps. Here you can set which app should be used for which task.",
"Task:": "Task:",
"None of your currently installed apps provide Task processing functionality": "None of your currently installed apps provide Task processing functionality",
"Machine translation": "Machine translation",
"Machine translation can be implemented by different apps. Here you can define the precedence of the machine translation apps you have installed at the moment.": "Machine translation can be implemented by different apps. Here you can define the precedence of the machine translation apps you have installed at the moment.",
"Speech-To-Text": "Speech-To-Text",
"Speech-To-Text can be implemented by different apps. Here you can set which app should be used.": "Speech-To-Text can be implemented by different apps. Here you can set which app should be used.",
"None of your currently installed apps provide Speech-To-Text functionality": "None of your currently installed apps provide Speech-To-Text functionality",
"Image generation": "Image generation",
"Image generation can be implemented by different apps. Here you can set which app should be used.": "Image generation can be implemented by different apps. Here you can set which app should be used.",
"None of your currently installed apps provide image generation functionality": "None of your currently installed apps provide image generation functionality",
"Text processing": "Text processing",
"Text processing tasks can be implemented by different apps. Here you can set which app should be used for which task.": "Text processing tasks can be implemented by different apps. Here you can set which app should be used for which task.",
"None of your currently installed apps provide Text processing functionality": "None of your currently installed apps provide Text processing functionality",
"Here you can decide which group can access certain sections of the administration settings.": "Here you can decide which group can access certain sections of the administration settings.",
"None": "None",
"Unable to modify setting": "Unable to modify setting",
"Allow apps to use the Share API": "Allow apps to use the Share API",
"Allow resharing": "Allow resharing",
"Allow sharing with groups": "Allow sharing with groups",
"Restrict users to only share with users in their groups": "Restrict users to only share with users in their groups",
"Ignore the following groups when checking group membership": "Ignore the following groups when checking group membership",
"Allow users to share via link and emails": "Allow users to share via link and emails",
"Allow public uploads": "Allow public uploads",
"Always ask for a password": "Always ask for a password",
"Enforce password protection": "Enforce password protection",
"Exclude groups from password requirements": "Exclude groups from password requirements",
"Exclude groups from creating link shares": "Exclude groups from creating link shares",
"Limit sharing based on groups": "Limit sharing based on groups",
"Allow sharing for everyone (default)": "Allow sharing for everyone (default)",
"Exclude some groups from sharing": "Exclude some groups from sharing",
"Limit sharing to some groups": "Limit sharing to some groups",
"Groups allowed to share": "Groups allowed to share",
"Groups excluded from sharing": "Groups excluded from sharing",
"Not allowed groups will still be able to receive shares, but not to initiate them.": "Not allowed groups will still be able to receive shares, but not to initiate them.",
"Set default expiration date for shares": "Set default expiration date for shares",
"Enforce expiration date": "Enforce expiry date",
"Default expiration time of new shares in days": "Default expiration time of new shares in days",
"Expire shares after x days": "Expire shares after x days",
"Set default expiration date for shares to other servers": "Set default expiration date for shares to other servers",
"Enforce expiration date for remote shares": "Enforce expiration date for remote shares",
"Default expiration time of remote shares in days": "Default expiration time of remote shares in days",
"Expire remote shares after x days": "Expire remote shares after x days",
"Set default expiration date for shares via link or mail": "Set default expiration date for shares via link or mail",
"Default expiration time of shares in days": "Default expiration time of shares in days",
"Privacy settings for sharing": "Privacy settings for sharing",
"Allow account name autocompletion in share dialog and allow access to the system address book": "Allow account name autocompletion in share dialog and allow access to the system address book",
"If autocompletion \"same group\" and \"phone number integration\" are enabled a match in either is enough to show the user.": "If autocompletion \"same group\" and \"phone number integration\" are enabled a match in either is enough to show the user.",
"Restrict account name autocompletion and system address book access to users within the same groups": "Restrict account name autocompletion and system address book access to users within the same groups",
"Restrict account name autocompletion to users based on phone number integration": "Restrict account name autocompletion to users based on phone number integration",
"Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)": "Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)",
"Show disclaimer text on the public link upload page (only shown when the file list is hidden)": "Show disclaimer text on the public link upload page (only shown when the file list is hidden)",
"Disclaimer text": "Disclaimer text",
"This text will be shown on the public link upload page when the file list is hidden.": "This text will be shown on the public link upload page when the file list is hidden.",
"Default share permissions": "Default share permissions",
"Changed disclaimer text": "Changed disclaimer text",
"Deleted disclaimer text": "Deleted disclaimer text",
"Could not set disclaimer text": "Could not set disclaimer text",
"Two-Factor Authentication": "Two-Factor Authentication",
"Two-factor authentication can be enforced for all accounts and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.": "Two-factor authentication can be enforced for all accounts and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.",
"Enforce two-factor authentication": "Enforce two-factor authentication",
"Limit to groups": "Limit to groups",
"Enforcement of two-factor authentication can be set for certain groups only.": "Enforcement of two-factor authentication can be set for certain groups only.",
"Two-factor authentication is enforced for all members of the following groups.": "Two-factor authentication is enforced for all members of the following groups.",
"Enforced groups": "Enforced groups",
"Two-factor authentication is not enforced for members of the following groups.": "Two-factor authentication is not enforced for members of the following groups.",
"Excluded groups": "Excluded groups",
"When groups are selected/excluded, they use the following logic to determine if an account has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If an account is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.": "When groups are selected/excluded, they use the following logic to determine if an account has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If an account is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.",
"Save changes": "Save changes",
"Show details for {appName} app": "Show details for {appName} app",
"Update to {update}": "Update to {update}",
"Remove": "Remove",
"Disable": "Disable",
"Featured": "Featured",
"This app is supported via your current Nextcloud subscription.": "This app is supported via your current Nextcloud subscription.",
"Featured apps are developed by and within the community. They offer central functionality and are ready for production use.": "Featured apps are developed by and within the community. They offer central functionality and are ready for production use.",
"Community rating: {score}/5": "Community rating: {score}/5",
"All apps are up-to-date.": "All apps are up-to-date.",
"Icon": "Icon",
"Name": "Surname",
"Version": "Version",
"Level": "Level",
"Actions": "Actions",
"Results from other categories": "Results from other categories",
"No apps found for your version": "No apps found for your version",
"Disable all": "Disable all",
"Download and enable all": "Download and enable all",
"_%n app has an update available_::_%n apps have an update available_": [
"%n app has an update available",
"%n apps have an update available"
],
"_Update_::_Update all_": [
"Update",
"Update all"
],
"Nothing to show": "Nothing to show",
"Could not load section content from app store.": "Could not load section content from app store.",
"Loading": "Loading",
"Fetching the latest news…": "Fetching the latest news…",
"Could not load app discover section": "Could not load app discover section",
"Could not render element": "Could not render element",
"Carousel": "Carousel",
"Previous slide": "Previous slide",
"Next slide": "Next slide",
"Choose slide to display": "Choose slide to display",
"{index} of {total}": "{index} of {total}",
"Description": "Description",
"Details": "Details",
"All": "All",
"Limit app usage to groups": "Limit app usage to groups",
"No results": "No results",
"Update to {version}": "Update to {version}",
"This app has no minimum Nextcloud version assigned. This will be an error in the future.": "This app has no minimum Nextcloud version assigned. This will cause an error in the future.",
"This app has no maximum Nextcloud version assigned. This will be an error in the future.": "This app has no maximum Nextcloud version assigned. This will cause an error in the future.",
"This app cannot be installed because the following dependencies are not fulfilled:": "This app cannot be installed because the following dependencies are not fulfilled:",
"Latest updated": "Latest updated",
"Author": "Author",
"Categories": "Categories",
"Resources": "Resources",
"Documentation": "Documentation",
"Interact": "Interact",
"Report a bug": "Report a bug",
"Request feature": "Request feature",
"Ask questions or discuss": "Ask questions or discuss",
"Rate the app": "Rate the app",
"Rate": "Rate",
"View in store": "View in store",
"Visit website": "Visit website",
"Usage documentation": "Usage documentation",
"Admin documentation": "Admin documentation",
"Developer documentation": "Developer documentation",
"Changelog": "Changelog",
"Device name": "Device name",
"Cancel renaming": "Cancel renaming",
"Save new name": "Save new name",
"Marked for remote wipe": "Marked for remote wipe",
"Device settings": "Device settings",
"Allow filesystem access": "Allow filesystem access",
"Rename": "Rename",
"Revoke": "Revoke",
"Wipe device": "Wipe device",
"Revoking this token might prevent the wiping of your device if it has not started the wipe yet.": "Revoking this token might prevent the wiping of your device if it has not started the wipe yet.",
"Google Chrome for Android": "Google Chrome for Android",
"{productName} iOS app": "{productName} iOS app",
"{productName} Android app": "{productName} Android app",
"{productName} Talk for iOS": "{productName} Talk for iOS",
"{productName} Talk for Android": "{productName} Talk for Android",
"Sync client": "Sync client",
"This session": "This session",
"{client} - {version} ({system})": "{client} - {version} ({system})",
"{client} - {version}": "{client} - {version}",
"Device": "Device",
"Last activity": "Last activity",
"Devices & sessions": "Devices & sessions",
"Web, desktop and mobile clients currently logged in to your account.": "Web, desktop and mobile clients currently logged in to your account.",
"App name": "App name",
"Create new app password": "Create new app password",
"Error while creating device token": "Error while creating device token",
"New app password": "New app password",
"Use the credentials below to configure your app or device. For security reasons this password will only be shown once.": "Use the credentials below to configure your app or device. For security reasons this password will only be shown once.",
"Login": "Login",
"Password": "Password",
"Show QR code for mobile apps": "Show QR code for mobile apps",
"App password copied!": "App password copied!",
"Copy app password": "Copy app password",
"Login name copied!": "Login name copied!",
"Copy login name": "Copy login name",
"Could not copy app password. Please copy it manually.": "Could not copy app password. Please copy it manually.",
"Could not copy login name. Please copy it manually.": "Could not copy login name. Please copy it manually.",
"For the server to work properly, it's important to configure background jobs correctly. Cron is the recommended setting. Please see the documentation for more information.": "For the server to work properly, it's important to configure background jobs correctly. Cron is the recommended setting. Please see the documentation for more information.",
"Last job execution ran {time}. Something seems wrong.": "Last job execution ran {time}. Something seems wrong.",
"Last job ran {relativeTime}.": "Last job ran {relativeTime}.",
"Background job did not run yet!": "Background job did not run yet!",
"AJAX": "AJAX",
"Execute one task with each page loaded. Use case: Single account instance.": "Execute one task with each page loaded. Use case: Single account instance.",
"Webcron": "Webcron",
"cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 accounts depending on the usage).": "cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 accounts depending on the usage).",
"Cron (Recommended)": "Cron (Recommended)",
"Use system cron service to call the cron.php file every 5 minutes.": "Use system cron service to call the cron.php file every 5 minutes.",
"The cron.php needs to be executed by the system account \"{user}\".": "The cron.php needs to be executed by the system account \"{user}\".",
"The PHP POSIX extension is required. See {linkstart}PHP documentation{linkend} for more details.": "The PHP POSIX extension is required. See {linkstart}PHP documentation{linkend} for more details.",
"Unable to update background job mode": "Unable to update background job mode",
"Profile": "Profile",
"Enable or disable profile by default for new accounts.": "Enable or disable profile by default for new accounts.",
"Enable": "Enable",
"Unable to update profile default setting": "Unable to update profile default setting",
"{app}'s declarative setting field: {name}": "{app}'s declarative setting field: {name}",
"Failed to save setting": "Failed to save setting",
"Server-side encryption": "Server-side encryption",
"Server-side encryption makes it possible to encrypt files which are uploaded to this server. This comes with limitations like a performance penalty, so enable this only if needed.": "Server-side encryption makes it possible to encrypt files which are uploaded to this server. This comes with limitations like a performance penalty, so enable this only if needed.",
"Enable server-side encryption": "Enable server-side encryption",
"Please read carefully before activating server-side encryption:": "Please read carefully before activating server-side encryption:",
"Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met.": "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met.",
"Encryption alone does not guarantee security of the system. Please see documentation for more information about how the encryption app works, and the supported use cases.": "Encryption alone does not guarantee complete security. Please read the documentation for information on how the encryption app works, and supported use cases.",
"Be aware that encryption always increases the file size.": "Be aware that encryption always increases the file size.",
"It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data.": "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data.",
"This is the final warning: Do you really want to enable encryption?": "This is the final warning: Do you really want to enable encryption?",
"No encryption module loaded, please enable an encryption module in the app menu.": "No encryption module loaded, please enable an encryption module in the app menu.",
"Select default encryption module:": "Select default encryption module:",
"You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run {command}": "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run {command}",
"Unable to update server side encryption config": "Unable to update server side encryption config",
"Please confirm the group removal": "Please confirm the group removal",
"You are about to remove the group \"{group}\". The accounts will NOT be deleted.": "You are about to remove the group \"{group}\". The accounts will NOT be deleted.",
"Cancel": "Cancel",
"Confirm": "Confirm",
"Submit": "Submit",
"Rename group": "Rename group",
"Remove group": "Remove group",
"Failed to remove group \"{group}\"": "Failed to remove group \"{group}\"",
"Current password": "Current password",
"New password": "New password",
"Change password": "Change password",
"Your profile picture": "Your profile picture",
"Upload profile picture": "Upload profile picture",
"Choose profile picture from Files": "Choose profile picture from Files",
"Remove profile picture": "Remove profile picture",
"The file must be a PNG or JPG": "The file must be a PNG or JPG",
"Picture provided by original account": "Picture provided by original account",
"Set as profile picture": "Set as profile picture",
"Please note that it can take up to 24 hours for your profile picture to be updated everywhere.": "Please note that it can take up to 24 hours for your profile picture to be updated everywhere.",
"Choose your profile picture": "Choose your profile picture",
"Please select a valid png or jpg file": "Please select a valid png or jpg file",
"Error setting profile picture": "Error setting profile picture",
"Error cropping profile picture": "Error cropping profile picture",
"Error saving profile picture": "Error saving profile picture",
"Error removing profile picture": "Error removing profile picture",
"Your biography": "Your biography",
"Enter your date of birth": "Enter your date of birth",
"Unable to update date of birth": "Unable to update date of birth",
"You are a member of the following groups:": "You are a member of the following groups:",
"You are using <strong>{usage}</strong>": "You are using <strong>{usage}</strong>",
"You are using <strong>{usage}</strong> of <strong>{totalSpace}</strong> (<strong>{usageRelative}%</strong>)": "You are using <strong>{usage}</strong> of <strong>{totalSpace}</strong> (<strong>{usageRelative}%</strong>)",
"Your full name": "Your full name",
"Primary email for password reset and notifications": "Primary email for password reset and notifications",
"Email options": "Email options",
"Options for additional email address {index}": "Options for additional email address {index}",
"Remove primary email": "Remove primary email",
"Delete email": "Delete email",
"This address is not confirmed": "This address is not confirmed",
"Unset as primary email": "Unset as primary email",
"Set as primary email": "Set as primary email",
"Additional email address {index}": "Additional email address {index}",
"Unable to delete primary email address": "Unable to delete primary email address",
"Unable to update primary email address": "Unable to update primary email address",
"Unable to add additional email address": "Unable to add additional email address",
"Unable to update additional email address": "Unable to update additional email address",
"Unable to delete additional email address": "Unable to delete additional email address",
"No email address set": "No email address set",
"Your handle": "Your handle",
"Day to use as the first day of week": "Day to use as the first day of week",
"Derived from your locale ({weekDayName})": "Derived from your locale ({weekDayName})",
"Unable to update first day of week": "Unable to update first day of week",
"Your headline": "Your headline",
"Languages": "Languages",
"Help translate": "Help translate",
"Unable to update language": "Unable to update language",
"No language set": "No language set",
"Locales": "Locales",
"Week starts on {firstDayOfWeek}": "Week starts on {firstDayOfWeek}",
"Unable to update locale": "Unable to update locale",
"No locale set": "No locale set",
"Your city": "Your city",
"Your organisation": "Your organisation",
"Your phone number": "Your phone number",
"Edit your Profile visibility": "Edit your Profile visibility",
"Enable profile": "Enable profile",
"Unable to update profile enabled state": "Unable to update profile enabled state",
"The more restrictive setting of either visibility or scope is respected on your Profile. For example, if visibility is set to \"Show to everyone\" and scope is set to \"Private\", \"Private\" is respected.": "The more restrictive setting of either visibility or scope is respected on your Profile. For example, if visibility is set to \"Show to everyone\" and scope is set to \"Private\", \"Private\" is respected.",
"Unable to update visibility of {displayId}": "Unable to update visibility of {displayId}",
"Your role": "Your role",
"Your X (formerly Twitter) handle": "Your X (formerly Twitter) handle",
"Your website": "Your website",
"No {property} set": "No {property} set",
"Invalid value": "Invalid value",
"Unable to update {property}": "Unable to update {property}",
"Change scope level of {property}, current scope is {scope}": "Change scope level of {property}, current scope is {scope}",
"Unable to update federation scope of the primary {property}": "Unable to update federation scope of the primary {property}",
"Unable to update federation scope of additional {property}": "Unable to update federation scope of additional {property}",
"Add additional email": "Add additional email",
"Add": "Add",
"Create": "Create",
"Change": "Change",
"Delete": "Delete",
"Reshare": "Reshare",
"No accounts": "No accounts",
"Loading accounts …": "Loading accounts …",
"List of accounts. This list is not fully rendered for performance reasons. The accounts will be rendered as you navigate through the list.": "List of accounts. This list is not fully rendered for performance reasons. The accounts will be rendered as you navigate through the list.",
"Default language": "Default language",
"Common languages": "Common languages",
"Other languages": "Other languages",
"Password change is disabled because the master key is disabled": "Password change is disabled because the master key is disabled",
"New account": "New account",
"Display name": "Display name",
"Either password or email is required": "Either password or email is required",
"Password (required)": "Password (required)",
"Email (required)": "Email (required)",
"Email": "Email",
"Member of the following groups (required)": "Member of the following groups (required)",
"Member of the following groups": "Member of the following groups",
"Set account groups": "Set account groups",
"Admin of the following groups": "Admin of the following groups",
"Set account as admin for …": "Set account as admin for …",
"Quota": "Quota",
"Set account quota": "Set account quota",
"Language": "Language",
"Set default language": "Set default language",
"Add new account": "Add new account",
"Manager": "Manager",
"Set account manager": "Set account manager",
"Account name will be autogenerated": "Account name will be autogenerated",
"Account name (required)": "Account name (required)",
"Total rows summary": "Total rows summary",
"Scroll to load more rows": "Scroll to load more rows",
"_{userCount} account …_::_{userCount} accounts …_": [
"{userCount} account …",
"{userCount} accounts …"
],
"_{userCount} account_::_{userCount} accounts_": [
"{userCount} account",
"{userCount} accounts"
],
"Avatar": "Avatar",
"Account name": "Account name",
"Group admin for": "Group admin for",
"Account backend": "Account backend",
"Storage location": "Storage location",
"Last login": "Last login",
"Account actions": "Account actions",
"Password or insufficient permissions message": "Password or insufficient permissions message",
"Loading account …": "Loading account …",
"Change display name": "Change display name",
"Set new password": "Set new password",
"You do not have permissions to see the details of this account": "You do not have permissions to see the details of this account",
"Set new email address": "Set new email address",
"Add account to group": "Add account to group",
"Set account as admin for": "Set account as admin for",
"Select account quota": "Select account quota",
"Set the language": "Set the language",
"Set line manager": "Set line manager",
"{size} used": "{size} used",
"Delete account": "Delete account",
"Disconnect all devices and delete local data": "Disconnect all devices and delete local data",
"Disable account": "Disable account",
"Enable account": "Enable account",
"Resend welcome email": "Resend welcome email",
"In case of lost device or exiting the organization, this can remotely wipe the Nextcloud data from all devices associated with {userid}. Only works if the devices are connected to the internet.": "In case of lost device or exiting the organization, this can remotely wipe the Nextcloud data from all devices associated with {userid}. Only works if the devices are connected to the internet.",
"Remote wipe of devices": "Remote wipe of devices",
"Wipe {userid}'s devices": "Wipe {userid}'s devices",
"Wiped {userid}'s devices": "Wiped {userid}'s devices",
"Failed to update line manager": "Failed to update line manager",
"Fully delete {userid}'s account including all their personal files, app data, etc.": "Fully delete {userid}'s account including all their personal files, app data, etc.",
"Account deletion": "Account deletion",
"Delete {userid}'s account": "Delete {userid}'s account",
"Display name was successfully changed": "Display name was successfully changed",
"Password was successfully changed": "Password was successfully changed",
"Email was successfully changed": "Email was successfully changed",
"Welcome mail sent!": "Welcome mail sent!",
"Toggle account actions menu": "Toggle account actions menu",
"Done": "Done",
"Edit": "Edit",
"Account management settings": "Account management settings",
"Visibility": "Visibility",
"Show language": "Show language",
"Show account backend": "Show account backend",
"Show storage path": "Show storage path",
"Show last login": "Show last login",
"Sorting": "Sorting",
"The system config enforces sorting the groups by name. This also disables showing the member count.": "The system config enforces sorting the groups by name. This also disables showing the member count.",
"Group list sorting": "Group list sorting",
"By member count": "By member count",
"By name": "By name",
"Send email": "Send email",
"Send welcome email to new accounts": "Send welcome email to new accounts",
"Defaults": "Defaults",
"Default quota": "Default quota",
"Select default quota": "Select default quota",
"Passwordless authentication requires a secure connection.": "Passwordless authentication requires a secure connection.",
"Add WebAuthn device": "Add WebAuthn device",
"Please authorize your WebAuthn device.": "Please authorise your WebAuthn device.",
"Adding your device …": "Adding your device …",
"Server error while trying to complete WebAuthn device registration": "Server error while trying to complete WebAuthn device registration",
"Unnamed device": "Unnamed device",
"Passwordless Authentication": "Passwordless Authentication",
"Set up your account for passwordless authentication following the FIDO2 standard.": "Set up your account for passwordless authentication following the FIDO2 standard.",
"No devices configured.": "No devices configured.",
"The following devices are configured for your account:": "The following devices are configured for your account:",
"Your browser does not support WebAuthn.": "Your browser does not support WebAuthn.",
"As admin you can fine-tune the sharing behavior. Please see the documentation for more information.": "As admin you can fine-tune the sharing behavior. Please see the documentation for more information.",
"You need to enable the File sharing App.": "You need to enable the File sharing App.",
"Loading app list": "Loading app list",
"App Store": "App Store",
"Loading categories": "Loading categories",
"Developer documentation ↗": "Developer documentation ↗",
"Version {version}, {license}-licensed": "Version {version}, {license}-licensed",
"All accounts": "All accounts",
"Admins": "Admins",
"Account group: {group}": "Account group: {group}",
"Account management": "Account management",
"Creating group…": "Creating group…",
"Create group": "Create group",
"Group name": "Group name",
"Please enter a valid group name": "Please enter a valid group name",
"Failed to create group": "Failed to create group",
"Sending…": "Sending…",
"Email sent": "Email sent",
"Location": "Location",
"Profile picture": "Profile picture",
"About": "About",
"Full name": "Full name",
"Additional email": "Additional email",
"Headline": "Headline",
"Organisation": "Organisation",
"Phone number": "Phone number",
"Role": "Role",
"X (formerly Twitter)": "X (formerly Twitter)",
"Fediverse (e.g. Mastodon)": "Fediverse (e.g. Mastodon)",
"Website": "Website",
"Date of birth": "Date of birth",
"Profile visibility": "Profile visibility",
"Locale": "Locale",
"First day of week": "First day of week",
"Not available as this property is required for core functionality including file sharing and calendar invitations": "Not available as this property is required for core functionality including file sharing and calendar invitations",
"Not available as federation has been disabled for your account, contact your system administration if you have any questions": "Not available as federation has been disabled for your account, contact your system administration if you have any questions",
"Not available as publishing account specific data to the lookup server is not allowed, contact your system administration if you have any questions": "Not available as publishing account specific data to the lookup server is not allowed, contact your system administration if you have any questions",
"Discover": "Discover",
"Your apps": "Your apps",
"Active apps": "Active apps",
"Disabled apps": "Disabled apps",
"Updates": "Updates",
"App bundles": "App bundles",
"Featured apps": "Featured apps",
"Supported apps": "Supported apps",
"Show to everyone": "Show to everyone",
"Show to logged in accounts only": "Show to logged in accounts only",
"Hide": "Hide",
"Download and enable": "Download and enable",
"Allow untested app": "Allow untested app",
"The app will be downloaded from the App Store": "The app will be downloaded from the App Store",
"This app is not marked as compatible with your Nextcloud version. If you continue you will still be able to install the app. Note that the app might not work as expected.": "This app is not marked as compatible with your Nextcloud version. If you continue you will still be able to install the app. Note that the app might not work as expected.",
"Never": "Never",
"Could not register device: Network error": "Could not register device: Network error",
"Could not register device: Probably already registered": "Could not register device: Probably already registered",
"Could not register device": "Could not register device",
"An error occurred during the request. Unable to proceed.": "An error occurred during the request. Unable to proceed.",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.": "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.",
"Error: This app cannot be enabled because it makes the server unstable": "Error: This app cannot be enabled because it makes the server unstable",
"Do you really want to wipe your data from this device?": "Do you really want to wipe your data from this device?",
"Confirm wipe": "Confirm wipe",
"Could not delete the app token": "Could not delete the app token",
"Error while wiping the device with the token": "Error while wiping the device with the token",
"Error while updating device token name": "Error while updating device token name",
"Error while updating device token scope": "Error while updating device token scope",
"Could not set group sorting": "Could not set group sorting",
"There were too many requests from your network. Retry later or contact your administrator if this is an error.": "There were too many requests from your network. Retry later or contact your administrator if this is an error.",
"Error": "Error",
"Account documentation": "Account documentation",
"Administration documentation": "Administration documentation",
"Forum": "Forum",
"Nextcloud help & privacy resources": "Nextcloud help & privacy resources",
"General documentation": "General documentation",
"Legal notice": "Legal notice",
"Privacy policy": "Privacy policy",
"None/STARTTLS": "None/STARTTLS",
"SSL": "SSL",
"Open documentation": "Open documentation",
"It is important to set up this server to be able to send emails, like for password reset and notifications.": "It is important to set up this server to be able to send emails, like for password reset and notifications.",
"Send mode": "Send mode",
"Encryption": "Encryption",
"Sendmail mode": "Sendmail mode",
"From address": "From address",
"Server address": "Server address",
"Port": "Port",
"Authentication": "Authentication",
"Authentication required": "Authentication required",
"Credentials": "Credentials",
"SMTP Login": "SMTP Login",
"SMTP Password": "SMTP Password",
"Save": "Save",
"Test and verify email settings": "Test and verify email settings",
"It's important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the linked documentation for more information.": "It's important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the linked documentation for more information.",
"All checks passed.": "All checks passed.",
"There are some errors regarding your setup.": "There are some errors regarding your setup.",
"There are some warnings regarding your setup.": "There are some warnings regarding your setup.",
"Checking for system and security issues.": "Checking for system and security issues.",
"Please double check the <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%1$s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"%2$s\">log</a>.": "Please double check the <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%1$s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"%2$s\">log</a>.",
"Check the security of your Nextcloud over <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">our security scan ↗</a>.": "Check the security of your Nextcloud over <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">our security scan ↗</a>.",
"Reasons to use Nextcloud in your organization": "Reasons to use Nextcloud in your organization",
"Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}.": "Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}.",
"Like our Facebook page": "Like our Facebook page",
"Follow us on Twitter": "Follow us on Twitter",
"Follow us on Mastodon": "Follow us on Mastodon",
"Check out our blog": "Check out our blog",
"Subscribe to our newsletter": "Subscribe to our newsletter",
"This community release of Nextcloud is unsupported and instant notifications are unavailable.": "This community release of Nextcloud is unsupported and instant notifications are unavailable.",
"Use a second factor besides your password to increase security for your account.": "Use a second factor besides your password to increase security for your account.",
"If you use third party applications to connect to Nextcloud, please make sure to create and configure an app password for each before enabling second factor authentication.": "If you use third party applications to connect to Nextcloud, please make sure to create and configure an app password for each before enabling second factor authentication.",
"No user supplied": "No user supplied",
"Please provide an admin recovery password; otherwise, all user data will be lost.": "Please provide an admin recovery password; otherwise, all user data will be lost.",
"Backend does not support password change, but the user's encryption key was updated.": "Backend does not support password change, but the user's encryption key was updated.",
"You need to set your user email before being able to send test emails. Go to %s for that.": "You need to set your user email before being able to send test emails. Go to %s for that.",
"Invalid user": "Invalid user",
"Your username is: %s": "Your username is: %s",
"Logged in user must be a subadmin": "Logged in user must be a subadmin",
"Old user imported certificates": "Old user imported certificates",
"A background job is pending that checks for user imported SSL certificates. Please check back later.": "A background job is pending that checks for user imported SSL certificates. Please check back later.",
"There are some user imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.": "There are some user imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below.",
"Missing optional index \"%s\" in table \"%s\".": "Missing optional index \"%s\" in table \"%s\".",
"The database is missing some indexes. Due to the fact that adding indexes on big tables could take some time they were not added automatically. By running \"occ db:add-missing-indices\" those missing indexes could be added manually while the instance keeps running. Once the indexes are added queries to those tables are usually much faster.": "The database is missing some indexes. Due to the fact that adding indexes on big tables could take some time they were not added automatically. By running \"occ db:add-missing-indices\" those missing indexes could be added manually while the instance keeps running. Once the indexes are added queries to those tables are usually much faster.",
"Could not check for JavaScript support. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Could not check for JavaScript support. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.",
"MySQL unicode support": "MySQL unicode support",
"Overwrite cli URL": "Overwrite CLI URL",
"You are currently running PHP %s. PHP 8.0 is now deprecated in Nextcloud 27. Nextcloud 28 may require at least PHP 8.1. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.": "You are currently running PHP %s. PHP 8.0 is now deprecated in Nextcloud 27. Nextcloud 28 may require at least PHP 8.1. Please upgrade to one of the officially supported PHP versions provided by the PHP Group as soon as possible.",
"MariaDB version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MariaDB 10.2 or higher.": "MariaDB version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MariaDB 10.2 or higher.",
"MySQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MySQL 8.0 or MariaDB 10.2 or higher.": "MySQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require MySQL 8.0 or MariaDB 10.2 or higher.",
"PostgreSQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require PostgreSQL 9.6 or higher.": "PostgreSQL version \"%s\" is used. Nextcloud 21 and higher do not support this version and require PostgreSQL 9.6 or higher.",
"Exclude groups from sharing": "Exclude groups from sharing",
"These groups will still be able to receive shares, but not to initiate them.": "These groups will still be able to receive shares, but not to initiate them.",
"Allow username autocompletion in share dialog and allow access to the system address book": "Allow username autocompletion in share dialogue and allow access to the system address book",
"Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.": "Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.",
"When groups are selected/excluded, they use the following logic to determine if a user has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If a user is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.": "When groups are selected/excluded, they use the following logic to determine if a user has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If a user is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.",
"Rating: {score}/10": "Rating: {score}/10",
"Username": "Username",
"Execute one task with each page loaded. Use case: Single user instance.": "Execute one task with each page loaded. Use case: Single user instance.",
"cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 users depending on the usage).": "cron.php is registered at a webcron service to call cron.php every 5 minutes over HTTP. Use case: Very small instance (15 users depending on the usage).",
"The cron.php needs to be executed by the system user \"{user}\".": "The cron.php needs to be executed by the system user \"{user}\".",
"Enable or disable profile by default for new users.": "Enable or disable profile by default for new users.",
"You are about to remove the group \"{group}\". The users will NOT be deleted.": "You are about to remove the group \"{group}\". The users will NOT be deleted.",
"Additional emails": "Additional emails",
"Enable Profile": "Enable Profile",
"No users": "No users",
"Loading users …": "Loading users …",
"List of users. This list is not fully rendered for performance reasons. The users will be rendered as you navigate through the list.": "List of users. This list is not fully rendered for performance reasons. The users will be rendered as you navigate through the list.",
"New user": "New user",
"Groups (required)": "Groups (required)",
"Set user groups": "Set user groups",
"Administered groups": "Administered groups",
"Set user as admin for …": "Set user as admin for …",
"Set user quota": "Set user quota",
"Add new user": "Add new user",
"Set user manager": "Set user manager",
"Username will be autogenerated": "Username will be autogenerated",
"Username (required)": "Username (required)",
"_{userCount} user …_::_{userCount} users …_": [
"{userCount} user …",
"{userCount} users …"
],
"_{userCount} user_::_{userCount} users_": [
"{userCount} user",
"{userCount} users"
],
"User backend": "User backend",
"User actions": "User actions",
"Loading user …": "Loading user …",
"You do not have permissions to see the details of this user": "You do not have permissions to see the details of this user",
"Add user to group": "Add user to group",
"Set user as admin for": "Set user as admin for",
"Select user quota": "Select user quota",
"Delete user": "Delete user",
"Wipe all devices": "Wipe all devices",
"Disable user": "Disable user",
"Enable user": "Enable user",
"Failed to update user manager": "Failed to update user manager",
"Toggle user actions menu": "Toggle user actions menu",
"User management settings": "User management settings",
"Show user backend": "Show user backend",
"Send welcome email to new users": "Send welcome email to new users",
"Name your device": "Name your device",
"Server error while trying to add WebAuthn device": "Server error while trying to add WebAuthn device",
"{license}-licensed": "{license}-licensed",
"by {author}\n{license}": "by {author}\n{license}",
"User management": "User management",
"Active users": "Active users",
"Disabled users": "Disabled users",
"Creating group …": "Creating group …",
"User group: {group}": "User group: {group}",
"Not available as federation has been disabled for your account, contact your system administrator if you have any questions": "Not available as federation has been disabled for your account, contact your system administrator if you have any questions",
"Not available as publishing user specific data to the lookup server is not allowed, contact your system administrator if you have any questions": "Not available as publishing user specific data to the lookup server is not allowed, contact your system administrator if you have any questions",
"Show to logged in users only": "Show to logged in users only",
"Nextcloud help resources": "Nextcloud help resources",
"SMTP Username": "SMTP Username",
"To allow this check to run you have to make sure that your webserver can connect to itself. Therefor it must be able to resolve and connect to at least one its `trusted_domains` or the `overwrite.cli.url`.": "To allow this check to run you have to make sure that your webserver can connect to itself. Therefor it must be able to resolve and connect to at least one its `trusted_domains` or the `overwrite.cli.url`.",
"Could not check for JavaScript support via any of your `trusted_domains` nor `overwrite.cli.url`. This may be the result of a server-side DNS mismatch or outbound firewall rule. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.": "Could not check for JavaScript support via any of your `trusted_domains` nor `overwrite.cli.url`. This may be the result of a server-side DNS mismatch or outbound firewall rule. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type.",
"Active accounts": "Active accounts"
},
"pluralForm": "nplurals=2; plural=(n != 1);"
}

View File

@ -1,17 +0,0 @@
import { createI18n } from 'vue-i18n';
const i18n = createI18n({
// default locale
locale: 'en',
// translations
messages: {
en: {
appTitle: 'Mushahed',
twofactor_backupcodes: '',
},
de: {
appTitle: 'مشاهد',
twofactor_backupcodes: '',
},
},
});
export default i18n;

View File

@ -0,0 +1,56 @@
import axios from 'axios';
// import { getCurrentUser } from '@nextcloud/auth'
// import { generateOcsUrl } from '@nextcloud/router'
import { stardust } from '@eidellev/adonis-stardust/client';
// import { confirmPassword } from '@nextcloud/password-confirmation'
import '@nextcloud/password-confirmation/dist/style.css'
/**
* Save the visibility of the profile parameter
*
* @param {string} paramId the profile parameter ID
* @param {string} visibility the visibility
* @return {object}
*/
// export const saveProfileParameterVisibility = async (paramId, visibility) => {
// const userId = getCurrentUser().uid
// const url = generateOcsUrl('/profile/{userId}', { userId })
// await confirmPassword()
// const res = await axios.put(url, {
// paramId,
// visibility,
// })
// return res.data
// }
/**
* Save profile default
*
* @param {boolean} isEnabled the default
* @return {object}
*/
export const saveProfileDefault = async (isEnabled: boolean) => {
// Convert to string for compatibility
let isEnabledString = isEnabled ? '1' : '0'
// https://rhea.geosphere.at/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/settings/profile_enabled_by_default
// const url = generateOcsUrl('/apps/provisioning_api/api/v1/config/apps/{appId}/{key}', {
// appId: 'settings',
// key: 'profile_enabled_by_default',
// })
let appId= 'settings';
let key= 'profile_enabled_by_default';
const url = stardust.route('settings.role.show', [appId, key]);
// await confirmPassword()
const res = await axios.post(url, {
value: isEnabledString,
})
return res.data
}

View File

@ -1,4 +1,4 @@
const GenRandomId = (length) => { const GenRandomId = (length: number) => {
return Math.random() return Math.random()
.toString(36) .toString(36)
.replace(/[^a-z]+/g, '') .replace(/[^a-z]+/g, '')

View File

@ -0,0 +1,16 @@
// src/plugins/dayjs.ts
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/de';
import 'dayjs/locale/en';
const extendedDayjs = dayjs.extend(relativeTime);
export const setDayjsLocale = (locale: string) => {
extendedDayjs.locale(locale);
};
// // Set a default locale initially
// setDayjsLocale('en');
export default extendedDayjs;

View File

@ -0,0 +1,118 @@
/**
* Get the first day of the week
*
* @return {number}
*/
export function getFirstDay(): number {
if (typeof window.firstDay === 'undefined') {
console.warn('No firstDay found')
return 1
}
return window.firstDay
}
/**
* Get a list of day names (full names)
*
* @return {string[]}
*/
export function getDayNames(): string[] {
if (typeof window.dayNames === 'undefined') {
console.warn('No dayNames found')
return [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
]
}
return window.dayNames
}
/**
* Get a list of day names (short names)
*
* @return {string[]}
*/
export function getDayNamesShort(): string[] {
if (typeof window.dayNamesShort === 'undefined') {
console.warn('No dayNamesShort found')
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
}
return window.dayNamesShort
}
/**
* Get a list of day names (minified names)
*
* @return {string[]}
*/
export function getDayNamesMin(): string[] {
if (typeof window.dayNamesMin === 'undefined') {
console.warn('No dayNamesMin found')
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
}
return window.dayNamesMin
}
/**
* Get a list of month names (full names)
*
* @return {string[]}
*/
export function getMonthNames(): string[] {
if (typeof window.monthNames === 'undefined') {
console.warn('No monthNames found')
return [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
}
return window.monthNames
}
/**
* Get a list of month names (short names)
*
* @return {string[]}
*/
export function getMonthNamesShort(): string[] {
if (typeof window.monthNamesShort === 'undefined') {
console.warn('No monthNamesShort found')
return [
'Jan.',
'Feb.',
'Mar.',
'Apr.',
'May.',
'Jun.',
'Jul.',
'Aug.',
'Sep.',
'Oct.',
'Nov.',
'Dec.',
]
}
return window.monthNamesShort
}

View File

@ -0,0 +1,5 @@
export type { Translations } from './registry';
export * from './date';
export * from './locale';
export { translate, loadTranslations } from './translation';

View File

@ -0,0 +1,83 @@
/**
* Returns the user's locale
*/
export function getLocale(): string {
return document.documentElement.dataset.locale || 'en'
}
/**
* Returns user's locale in canonical form
* E.g. `en-US` instead of `en_US`
*/
export function getCanonicalLocale(): string {
return getLocale().replace(/_/g, '-')
}
/**
* Returns the user's language
*/
export function getLanguage(): string {
return document.documentElement.lang || 'en'
}
/**
* Check whether the current, or a given, language is read right-to-left
*
* @param language Language code to check, defaults to current language
*/
export function isRTL(language?: string): boolean {
const languageCode = language || getLanguage()
// Source: https://meta.wikimedia.org/wiki/Template:List_of_language_names_ordered_by_code
const rtlLanguages = [
/* eslint-disable no-multi-spaces */
'ae', // Avestan
'ar', // 'العربية', Arabic
'arc', // Aramaic
'arz', // 'مصرى', Egyptian
'bcc', // 'بلوچی مکرانی', Southern Balochi
'bqi', // 'بختياري', Bakthiari
'ckb', // 'Soranî / کوردی', Sorani
'dv', // Dhivehi
'fa', // 'فارسی', Persian
'glk', // 'گیلکی', Gilaki
'ha', // 'هَوُسَ', Hausa
'he', // 'עברית', Hebrew
'khw', // 'کھوار', Khowar
'ks', // 'कॉशुर / کٲشُر', Kashmiri
'ku', // 'Kurdî / كوردی', Kurdish
'mzn', // 'مازِرونی', Mazanderani
'nqo', // 'ߒߞߏ', NKo
'pnb', // 'پنجابی', Western Punjabi
'ps', // 'پښتو', Pashto,
'sd', // 'سنڌي', Sindhi
'ug', // 'Uyghurche / ئۇيغۇرچە', Uyghur
'ur', // 'اردو', Urdu
'uzs', // 'اوزبیکی', Uzbek Afghan
'yi', // 'ייִדיש', Yiddish
/* eslint-enable no-multi-spaces */
]
// special case for Uzbek Afghan
if ((language || getCanonicalLocale()).startsWith('uz-AF')) {
return true
}
return rtlLanguages.includes(languageCode)
}
export function getBrowserLocale(options?: { languageCodeOnly: boolean }): string {
const navigatorLocale = navigator.languages !== undefined
? navigator.languages[0]
: navigator.language;
if (!navigatorLocale) {
return 'en'; // Fallback to 'en' if no locale is detected
}
const locale = options?.languageCodeOnly
? navigatorLocale.trim().split(/-|_/)[0]
: navigatorLocale.trim();
return locale;
}

View File

@ -0,0 +1,115 @@
/// <reference types="@nextcloud/typings" />
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/**
* Translation bundle
*
* @example For German translation
* ```json
{
"some": "einige",
"_%n tree_::_%n trees_": [
"%n Baum",
"%n Bäume"
]
}
```
*/
export type Translations = Record<string, string | string[] | undefined>
/**
* Function for getting plural form index from translated number
*
* @param number Input number to translate
* @return Index of translation plural form
* @example For most languages, like English or German
* ```js
(number:number) => number === 1 ? 0 : 1
```
*/
export type PluralFunction = (number: number) => number
/**
* Extended window interface with translation registry
* Exported just for internal testing purpose
*
* @private
*/
export interface NextcloudWindowWithRegistry {
_tc_l10n_registry_translations?: Record<string, Translations>
_tc_l10n_registry_plural_functions?: Record<string, PluralFunction>
}
declare const window: NextcloudWindowWithRegistry
interface AppTranslations {
translations: Translations
pluralFunction: PluralFunction
}
/**
* Check if translations and plural function are set for given app
*
* @param {string} appId the app id
* @return {boolean}
*/
export function hasAppTranslations(appId: string) {
return (
window._tc_l10n_registry_translations?.[appId] !== undefined
&& window._tc_l10n_registry_plural_functions?.[appId] !== undefined
)
}
/**
* Register new, or extend available, translations for an app
*
* @param {string} appId the app id
* @param {object} translations the translations list
* @param {Function} pluralFunction the plural function
*/
export function registerAppTranslations(
appId: string,
translations: Translations,
pluralFunction: PluralFunction,
) {
window._tc_l10n_registry_translations = Object.assign(
window._tc_l10n_registry_translations || {},
{
[appId]: Object.assign(window._tc_l10n_registry_translations?.[appId] || {}, translations),
},
)
window._tc_l10n_registry_plural_functions = Object.assign(
window._tc_l10n_registry_plural_functions || {},
{
[appId]: pluralFunction,
},
)
}
/**
* Unregister all translations and plural function for given app
*
* @param {string} appId the app id
*/
export function unregisterAppTranslations(appId: string) {
delete window._tc_l10n_registry_translations?.[appId]
delete window._tc_l10n_registry_plural_functions?.[appId]
}
/**
* Get translations bundle for given app and current locale
*
* @param {string} appId the app id
* @return {object}
*/
export function getAppTranslations(appId: string): AppTranslations {
return {
translations: window._tc_l10n_registry_translations?.[appId] ?? {},
pluralFunction: window._tc_l10n_registry_plural_functions?.[appId] ?? ((number: number) => number),
}
}

View File

@ -0,0 +1,423 @@
import type { Translations } from './registry';
import { getLanguage, getBrowserLocale } from './locale';
import { getAppTranslations, hasAppTranslations, registerAppTranslations, unregisterAppTranslations } from './registry';
// import { generateFilePath } from '@nextcloud/router';
import axios from 'axios';
// import DOMPurify from 'dompurify';
import escapeHTML from 'escape-html';
import { LocaleStore } from '@/Stores/locale';
/** @notExported */
interface TranslationOptions {
/** enable/disable auto escape of placeholders (by default enabled) */
escape?: boolean;
/** enable/disable sanitization (by default enabled) */
sanitize?: boolean;
}
/** @notExported */
interface TranslationVariableReplacementObject<T> {
/** The value to use for the replacement */
value: T;
/** Overwrite the `escape` option just for this replacement */
escape: boolean;
}
/** @notExported */
type TranslationVariables = Record<string, string | number | TranslationVariableReplacementObject<string | number>>;
/**
* Translate a string
*
* @param {string} app the id of the app for which to translate the string
* @param {string} text the string to translate
* @param {object} vars map of placeholder key to value
* @param {number} number to replace %n with
* @param {object} [options] options object
* @param {boolean} options.escape enable/disable auto escape of placeholders (by default enabled)
* @param {boolean} options.sanitize enable/disable sanitization (by default enabled)
*
* @return {string}
*/
export function translate(app: string, text: string, vars?: TranslationVariables, number?: number, options?: TranslationOptions): string {
const allOptions = {
// defaults
escape: true,
sanitize: true,
// overwrite with user config
...(options || {}),
};
const identity = <T>(value: T): T => value;
const optSanitize = identity; // allOptions.sanitize ? DOMPurify.sanitize : identity;
const optEscape = allOptions.escape ? escapeHTML : identity;
const isValidReplacement = (value: unknown) => typeof value === 'string' || typeof value === 'number';
// TODO: cache this function to avoid inline recreation
// of the same function over and over again in case
// translate() is used in a loop
const _build = (text: string, vars?: TranslationVariables, number?: number) => {
return text.replace(/%n/g, '' + number).replace(/{([^{}]*)}/g, (match, key) => {
if (vars === undefined || !(key in vars)) {
return optEscape(match);
}
const replacement = vars[key];
if (isValidReplacement(replacement)) {
return optEscape(`${replacement}`);
} else if (typeof replacement === 'object' && isValidReplacement(replacement.value)) {
// Replacement is an object so indiviual escape handling
const escape = replacement.escape !== false ? escapeHTML : identity;
return escape(`${replacement.value}`);
} else {
/* This should not happen,
* but the variables are used defined so not allowed types could still be given,
* in this case ignore the replacement and use the placeholder
*/
return optEscape(match);
}
});
};
const bundle = getAppTranslations(app);
let translation = bundle.translations[text] || text;
translation = Array.isArray(translation) ? translation[0] : translation;
if (typeof vars === 'object' || number !== undefined) {
return optSanitize(_build(translation, vars, number));
} else {
return optSanitize(translation);
}
}
/**
* Translate a string containing an object which possibly requires a plural form
*
* @param {string} app the id of the app for which to translate the string
* @param {string} textSingular the string to translate for exactly one object
* @param {string} textPlural the string to translate for n objects
* @param {number} number number to determine whether to use singular or plural
* @param {object} vars of placeholder key to value
* @param {object} options options object
*/
export function translatePlural(
app: string,
textSingular: string,
textPlural: string,
number: number,
vars?: Record<string, string | number>,
options?: TranslationOptions,
): string {
const identifier = '_' + textSingular + '_::_' + textPlural + '_';
const bundle = getAppTranslations(app);
const value = bundle.translations[identifier];
if (typeof value !== 'undefined') {
const translation = value;
if (Array.isArray(translation)) {
const plural = bundle.pluralFunction(number);
return translate(app, translation[plural], vars, number, options);
}
}
if (number === 1) {
return translate(app, textSingular, vars, number, options);
} else {
return translate(app, textPlural, vars, number, options);
}
}
/**
* Load an app's translation bundle if not loaded already.
*
* @param {string} appName name of the app
* @param {Function} callback callback to be called when
* the translations are loaded
* @return {Promise} promise
*/
export async function loadTranslationsOld(appName: string) {
interface TranslationBundle {
translations: Translations;
pluralForm: string;
}
// if (hasAppTranslations(appName) || getLocale() === 'en') {
// return Promise.resolve().then(callback);
// }
// const url = generateFilePath(appName, 'l10n', getLocale() + '.json');
let test = 'de'; //getLocale();
const url = `../../Components/settings/l10n/${test}.json`;
const promise = new Promise<TranslationBundle>((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onerror = () => {
reject(new Error(request.statusText || 'Network error'));
};
request.onload = () => {
if (request.status >= 200 && request.status < 300) {
try {
const bundle = JSON.parse(request.responseText);
if (typeof bundle.translations === 'object') resolve(bundle);
} catch (error) {
// error is probably a SyntaxError due to invalid response text, this is handled by next line
}
reject(new Error('Invalid content of translation bundle'));
} else {
reject(new Error(request.statusText));
}
};
request.send();
});
// load JSON translation bundle per AJAX
// return promise
// .then((result) => {
// register(appName, result.translations);
// return result;
// });
// .then(callback);
let result = await promise;
register(appName, result.translations);
return result;
}
export async function loadTranslations(appName: string) {
// interface TranslationBundle {
// translations: Translations;
// pluralForm: string;
// }
// if (hasAppTranslations(appName) || getLocale() === 'en') {
// return Promise.resolve().then(callback);
// }
// const url = generateFilePath(appName, 'l10n', getLocale() + '.json');
const localeService = LocaleStore();
let locale = localeService.locale;
// const url = `/apps/${appName}/l10n/${locale}.json`;
try {
// Making a GET request using Axios
// const response = await axios.get(url);
const response = await import(`@/apps/settings/l18n/${locale}`);
// Check if the response data contains translations
const bundle = response.default;
if (typeof bundle.translations === 'object') {
// Register the translations
register(appName, bundle.translations);
return bundle;
} else {
throw new Error('Invalid content of translation bundle');
}
} catch (error) {
// Handle errors (network errors, invalid response, etc.)
throw new Error(error.response ? error.response.statusText : 'Error loading translations');
}
}
/**
* Register an app's translation bundle.
*
* @param {string} appName name of the app
* @param {Record<string, string>} bundle translation bundle
*/
export function register(appName: string, bundle: Translations) {
registerAppTranslations(appName, bundle, getPlural);
}
/**
* Unregister all translations of an app
*
* @param appName name of the app
* @since 2.1.0
*/
export function unregister(appName: string) {
return unregisterAppTranslations(appName);
}
/**
* Get array index of translations for a plural form
*
*
* @param {number} number the number of elements
* @return {number} 0 for the singular form(, 1 for the first plural form, ...)
*/
export function getPlural(number: number) {
let language = getLanguage();
if (language === 'pt-BR') {
// temporary set a locale for brazilian
language = 'xbr';
}
if (language.length > 3) {
language = language.substring(0, language.lastIndexOf('-'));
}
/*
* The plural rules are derived from code of the Zend Framework (2010-09-25),
* which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
*/
switch (language) {
case 'az':
case 'bo':
case 'dz':
case 'id':
case 'ja':
case 'jv':
case 'ka':
case 'km':
case 'kn':
case 'ko':
case 'ms':
case 'th':
case 'tr':
case 'vi':
case 'zh':
return 0;
case 'af':
case 'bn':
case 'bg':
case 'ca':
case 'da':
case 'de':
case 'el':
case 'en':
case 'eo':
case 'es':
case 'et':
case 'eu':
case 'fa':
case 'fi':
case 'fo':
case 'fur':
case 'fy':
case 'gl':
case 'gu':
case 'ha':
case 'he':
case 'hu':
case 'is':
case 'it':
case 'ku':
case 'lb':
case 'ml':
case 'mn':
case 'mr':
case 'nah':
case 'nb':
case 'ne':
case 'nl':
case 'nn':
case 'no':
case 'oc':
case 'om':
case 'or':
case 'pa':
case 'pap':
case 'ps':
case 'pt':
case 'so':
case 'sq':
case 'sv':
case 'sw':
case 'ta':
case 'te':
case 'tk':
case 'ur':
case 'zu':
return number === 1 ? 0 : 1;
case 'am':
case 'bh':
case 'fil':
case 'fr':
case 'gun':
case 'hi':
case 'hy':
case 'ln':
case 'mg':
case 'nso':
case 'xbr':
case 'ti':
case 'wa':
return number === 0 || number === 1 ? 0 : 1;
case 'be':
case 'bs':
case 'hr':
case 'ru':
case 'sh':
case 'sr':
case 'uk':
return number % 10 === 1 && number % 100 !== 11
? 0
: number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20)
? 1
: 2;
case 'cs':
case 'sk':
return number === 1 ? 0 : number >= 2 && number <= 4 ? 1 : 2;
case 'ga':
return number === 1 ? 0 : number === 2 ? 1 : 2;
case 'lt':
return number % 10 === 1 && number % 100 !== 11 ? 0 : number % 10 >= 2 && (number % 100 < 10 || number % 100 >= 20) ? 1 : 2;
case 'sl':
return number % 100 === 1 ? 0 : number % 100 === 2 ? 1 : number % 100 === 3 || number % 100 === 4 ? 2 : 3;
case 'mk':
return number % 10 === 1 ? 0 : 1;
case 'mt':
return number === 1
? 0
: number === 0 || (number % 100 > 1 && number % 100 < 11)
? 1
: number % 100 > 10 && number % 100 < 20
? 2
: 3;
case 'lv':
return number === 0 ? 0 : number % 10 === 1 && number % 100 !== 11 ? 1 : 2;
case 'pl':
return number === 1 ? 0 : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 12 || number % 100 > 14) ? 1 : 2;
case 'cy':
return number === 1 ? 0 : number === 2 ? 1 : number === 8 || number === 11 ? 2 : 3;
case 'ro':
return number === 1 ? 0 : number === 0 || (number % 100 > 0 && number % 100 < 20) ? 1 : 2;
case 'ar':
return number === 0
? 0
: number === 1
? 1
: number === 2
? 2
: number % 100 >= 3 && number % 100 <= 10
? 3
: number % 100 >= 11 && number % 100 <= 99
? 4
: 5;
default:
return 0;
}
}
// Export short-hand
export { translate as t, translatePlural as n };

View File

@ -150,6 +150,16 @@ export function showMessage(data: string | Node, options?: ToastOptions): Toast
return toast; return toast;
} }
/**
* Show a toast message with error styling
*
* @param text Message to be shown in the toast, any HTML is removed by default
* @param options
*/
export function showError(text: string, options?: ToastOptions): Toast {
return showMessage(text, { ...options, type: ToastType.ERROR })
}
export default { export default {
updatableNotification: null, updatableNotification: null,

View File

@ -10,6 +10,19 @@
<!-- <link rel="icon" href="/apps/theming/favicon/settings?v=ad28c447"> --> <!-- <link rel="icon" href="/apps/theming/favicon/settings?v=ad28c447"> -->
<input type="hidden" id="initial-state-firstrunwizard-desktop" <input type="hidden" id="initial-state-firstrunwizard-desktop"
value="Imh0dHBzOi8vZ2l0ZWEuZ2VvbG9naWUuYWMuYXQvZ2VvbGJhL3RldGh5cy5iYWNrZW5kIg=="> value="Imh0dHBzOi8vZ2l0ZWEuZ2VvbG9naWUuYWMuYXQvZ2VvbGJhL3RldGh5cy5iYWNrZW5kIg==">
<input type="hidden" id="initial-state-settings-profileEnabledGlobally" value="dHJ1ZQ==">
<input type="hidden" id="initial-state-settings-profileEnabledByDefault" value="dHJ1ZQ==">
<input type="hidden" id="initial-state-settings-backgroundJobsDocUrl"
value="Imh0dHBzOlwvXC9kb2NzLm5leHRjbG91ZC5jb21cL3NlcnZlclwvMjlcL2dvLnBocD90bz1hZG1pbi1iYWNrZ3JvdW5kLWpvYnMi">
<input type="hidden" id="initial-state-settings-backgroundJobsMode" value="ImNyb24i">
<input type="hidden" id="initial-state-settings-lastCron" value="MTcyMzgwNzIwMQ==">
<input type="hidden" id="initial-state-settings-cronErrors" value="IiI=">
<input type="hidden" id="initial-state-settings-cliBasedCronPossible" value="dHJ1ZQ==">
<input type="hidden" id="initial-state-settings-cliBasedCronUser" value="Ind3dy1kYXRhIg==">
@routes('test') @routes('test')
</head> </head>

View File

@ -19,7 +19,7 @@ export default await Env.create(new URL("../", import.meta.url), {
APP_KEY: Env.schema.string(), APP_KEY: Env.schema.string(),
APP_NAME: Env.schema.string(), APP_NAME: Env.schema.string(),
CACHE_VIEWS: Env.schema.boolean(), CACHE_VIEWS: Env.schema.boolean(),
SESSION_DRIVER: Env.schema.enum(["cookie" ,"memory"] as const), SESSION_DRIVER: Env.schema.enum(["cookie", "memory"] as const),
DRIVE_DISK: Env.schema.enum(['local'] as const), DRIVE_DISK: Env.schema.enum(['local'] as const),
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const), NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
@ -32,8 +32,18 @@ export default await Env.create(new URL("../", import.meta.url), {
REDIS_HOST: Env.schema.string({ format: 'host' }), REDIS_HOST: Env.schema.string({ format: 'host' }),
REDIS_PORT: Env.schema.number(), REDIS_PORT: Env.schema.number(),
HASH_DRIVER: Env.schema.enum(["scrypt", "argon", "bcrypt", "laravel", undefined] as const), HASH_DRIVER: Env.schema.enum(["scrypt", "argon", "bcrypt", "laravel", undefined] as const),
OAI_LIST_SIZE: Env.schema.number() OAI_LIST_SIZE: Env.schema.number(),
/*
|----------------------------------------------------------
| Variables for configuring the mail package
|----------------------------------------------------------
*/
SMTP_HOST: Env.schema.string.optional(),
SMTP_PORT: Env.schema.string.optional(),
RESEND_API_KEY: Env.schema.string.optional()
}) })

View File

@ -34,6 +34,7 @@ import AdminuserController from '#controllers/Http/Admin/AdminuserController';
import RoleController from '#controllers/Http/Admin/RoleController'; import RoleController from '#controllers/Http/Admin/RoleController';
import LicenseController from '#controllers/Http/Admin/LicenseController'; import LicenseController from '#controllers/Http/Admin/LicenseController';
import MimetypeController from '#controllers/Http/Admin/MimetypeController'; import MimetypeController from '#controllers/Http/Admin/MimetypeController';
import MailSettingsController from '#controllers/Http/Admin/mailsettings_controller';
import DatasetController from '#app/Controllers/Http/Submitter/DatasetController'; import DatasetController from '#app/Controllers/Http/Submitter/DatasetController';
import PersonController from '#app/Controllers/Http/Submitter/PersonController'; import PersonController from '#app/Controllers/Http/Submitter/PersonController';
@ -42,7 +43,7 @@ import ReviewerDatasetController from '#app/Controllers/Http/Reviewer/DatasetCo
import './routes/api.js'; import './routes/api.js';
import { middleware } from './kernel.js' import { middleware } from './kernel.js'
import db from '@adonisjs/lucid/services/db'; // Import the DB service
// router.get('health', async ({ response }) => { // router.get('health', async ({ response }) => {
// const report = await HealthCheck.getReport(); // const report = await HealthCheck.getReport();
@ -129,9 +130,31 @@ router.post('/signout', [AuthController, 'logout']).as('logout');
// administrator // administrator
router.group(() => { router.group(() => {
router.get('/settings', async ({ inertia }: HttpContext) => { router.get('/settings', async ({ inertia }: HttpContext) => {
return inertia.render('Admin/Settings'); const updatedConfigValue = await db.from('appconfigs')
.select('configvalue')
.where('appid', 'backgroundjob')
.where('configkey', 'lastjob')
.first();
// return inertia.render('Admin/Settings', {
// lastCron: updatedConfigValue.configvalue,
// });
if (updatedConfigValue != null) {
return inertia.render('Admin/Settings', {
lastCron: updatedConfigValue.configvalue,
});
} else {
// Handle the case where the config value is null
// For example, you can return a default value or render an error view
return inertia.render('Admin/Settings', {
lastCron: '', // Provide a default value if necessary
// error: 'Configuration not found', // Optional: provide an error message
});
}
}) })
.as('overview'); .as('overview');
router.post('/mail/store', [MailSettingsController, 'setMailSettings']).as('mail.store').use(middleware.can(['user-create']));
router.post('/mail/send', [MailSettingsController, 'sendTestMail']).as('mail.send').use(middleware.can(['user-create']));
// user routes // user routes
router.get('/user', [AdminuserController, 'index']).as('user.index').use(middleware.can(['user-list'])); router.get('/user', [AdminuserController, 'index']).as('user.index').use(middleware.can(['user-list']));
@ -254,6 +277,15 @@ router.group(() => {
.where('id', router.matchers.number()) .where('id', router.matchers.number())
.use([middleware.auth(), middleware.can(['dataset-approve'])]); .use([middleware.auth(), middleware.can(['dataset-approve'])]);
router.get('dataset/:id/reject', [EditorDatasetController, 'reject'])
.as('editor.dataset.reject')
.where('id', router.matchers.number())
.use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
router.put('dataset/:id/reject', [EditorDatasetController, 'rejectUpdate'])
.as('editor.dataset.rejectUpdate')
.where('id', router.matchers.number())
.use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
router.get('dataset/:id/publish', [EditorDatasetController, 'publish']) router.get('dataset/:id/publish', [EditorDatasetController, 'publish'])
.as('editor.dataset.publish') .as('editor.dataset.publish')
.where('id', router.matchers.number()) .where('id', router.matchers.number())

View File

@ -17,11 +17,11 @@ module.exports = {
'inprogress': 'rgb(94 234 212)', 'inprogress': 'rgb(94 234 212)',
'released': 'rgb(52 211 153)', 'released': 'rgb(52 211 153)',
'editor-accepted': 'rgb(125 211 252)', 'editor-accepted': 'rgb(125 211 252)',
'approved': '#BFCE40', 'approved': '#FFEB3B', //A lighter yellow, which is cheerful and can indicate that something is in a pending state.
'rejected-editor': '#f97316', 'rejected-editor': '#f97316',
'rejected-reviewer': '#f97316', 'rejected-reviewer': '#f97316',
'reviewed': '#34d399', // emerald 'reviewed': '#FFC107', // warm amber, suggesting caution but still positive
'published': '#34d399', // sky 'published': '#8BC34A', // lighter green, which is also fresh and positive
'primary-dark': '#DCFCE7', 'primary-dark': '#DCFCE7',
'lime': { 'lime': {
DEFAULT: '#BFCE40', DEFAULT: '#BFCE40',