mirror of
https://github.com/HeyPuter/puter.git
synced 2026-02-12 08:49:23 -06:00
Merge branch 'main' into main
This commit is contained in:
@@ -25,6 +25,7 @@ const PuterDriversModule = require("./src/PuterDriversModule.js");
|
||||
const { testlaunch } = require("./src/index.js");
|
||||
const BaseService = require("./src/services/BaseService.js");
|
||||
const { Context } = require("./src/util/context.js");
|
||||
const { TestDriversModule } = require("./src/modules/test-drivers/TestDriversModule.js");
|
||||
|
||||
|
||||
module.exports = {
|
||||
@@ -46,4 +47,5 @@ module.exports = {
|
||||
PuterDriversModule,
|
||||
LocalDiskStorageModule,
|
||||
SelfHostedModule,
|
||||
TestDriversModule,
|
||||
};
|
||||
|
||||
@@ -72,6 +72,9 @@ const policy_perm = selector => ({
|
||||
|
||||
const hardcoded_user_group_permissions = {
|
||||
system: {
|
||||
'ca342a5e-b13d-4dee-9048-58b11a57cc55': {
|
||||
'service': {},
|
||||
},
|
||||
'b7220104-7905-4985-b996-649fdcdb3c8f': {
|
||||
'service:hello-world:ii:hello-world': policy_perm('temp.es'),
|
||||
'driver:puter-kvstore': policy_perm('temp.kv'),
|
||||
|
||||
16
src/backend/src/modules/test-drivers/TestAssetHostService.js
Normal file
16
src/backend/src/modules/test-drivers/TestAssetHostService.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const BaseService = require("../../services/BaseService");
|
||||
|
||||
class TestAssetHostService extends BaseService {
|
||||
async ['__on_install.routes'] () {
|
||||
const { app } = this.services.get('web-server');
|
||||
const path_ = require('node:path');
|
||||
|
||||
app.use('/test-assets', require('express').static(
|
||||
path_.join(__dirname, 'assets')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TestAssetHostService
|
||||
};
|
||||
17
src/backend/src/modules/test-drivers/TestDriversModule.js
Normal file
17
src/backend/src/modules/test-drivers/TestDriversModule.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const { AdvancedBase } = require("@heyputer/puter-js-common");
|
||||
|
||||
class TestDriversModule extends AdvancedBase {
|
||||
async install (context) {
|
||||
const services = context.get('services');
|
||||
|
||||
const { TestAssetHostService } = require('./TestAssetHostService')
|
||||
services.registerService('__test-assets', TestAssetHostService);
|
||||
|
||||
const { TestImageService } = require('./TestImageService');
|
||||
services.registerService('test-image', TestImageService);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TestDriversModule,
|
||||
};
|
||||
85
src/backend/src/modules/test-drivers/TestImageService.js
Normal file
85
src/backend/src/modules/test-drivers/TestImageService.js
Normal file
@@ -0,0 +1,85 @@
|
||||
const config = require("../../config");
|
||||
const BaseService = require("../../services/BaseService");
|
||||
const { TypedValue } = require("../../services/drivers/meta/Runtime");
|
||||
const { buffer_to_stream } = require("../../util/streamutil");
|
||||
|
||||
const PUBLIC_DOMAIN_IMAGES = [
|
||||
{
|
||||
name: 'starry-night',
|
||||
url: 'https://upload.wikimedia.org/wikipedia/commons/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg',
|
||||
file: 'starry.jpg',
|
||||
},
|
||||
];
|
||||
|
||||
class TestImageService extends BaseService {
|
||||
async ['__on_driver.register.interfaces'] () {
|
||||
const svc_registry = this.services.get('registry');
|
||||
const col_interfaces = svc_registry.get('interfaces');
|
||||
|
||||
col_interfaces.set('test-image', {
|
||||
methods: {
|
||||
echo_image: {
|
||||
parameters: {
|
||||
source: {
|
||||
type: 'file',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
type: {
|
||||
$: 'stream',
|
||||
content_type: 'image'
|
||||
},
|
||||
},
|
||||
},
|
||||
get_image: {
|
||||
parameters: {
|
||||
source_type: {
|
||||
type: 'string'
|
||||
},
|
||||
},
|
||||
result: {
|
||||
type: {
|
||||
$: 'stream',
|
||||
content_type: 'image'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static IMPLEMENTS = {
|
||||
['version']: {
|
||||
get_version () {
|
||||
return 'v1.0.0';
|
||||
}
|
||||
},
|
||||
['test-image']: {
|
||||
async echo_image ({
|
||||
source,
|
||||
}) {
|
||||
const stream = await source.get('stream');
|
||||
return new TypedValue({
|
||||
$: 'stream',
|
||||
content_type: 'image/jpeg'
|
||||
}, stream);
|
||||
},
|
||||
async get_image ({
|
||||
source_type,
|
||||
}) {
|
||||
const image = PUBLIC_DOMAIN_IMAGES[0];
|
||||
if ( source_type === 'string:url:web' ) {
|
||||
return new TypedValue({
|
||||
$: 'string:url:web',
|
||||
content_type: 'image',
|
||||
}, `${config.origin}/test-assets/${image.file}`);
|
||||
}
|
||||
throw new Error('not implemented yet');
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TestImageService
|
||||
};
|
||||
BIN
src/backend/src/modules/test-drivers/assets/starry.jpg
Normal file
BIN
src/backend/src/modules/test-drivers/assets/starry.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
src/backend/src/modules/test-drivers/assets/wave.jpg
Normal file
BIN
src/backend/src/modules/test-drivers/assets/wave.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 950 KiB |
98
src/backend/src/modules/test-drivers/doc/requests.md
Normal file
98
src/backend/src/modules/test-drivers/doc/requests.md
Normal file
@@ -0,0 +1,98 @@
|
||||
```javascript
|
||||
blob = await (await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'test-image',
|
||||
method: 'get_image',
|
||||
args: {
|
||||
source_type: 'string:url:web'
|
||||
}
|
||||
}),
|
||||
"method": "POST",
|
||||
})).blob();
|
||||
dataurl = await new Promise((y, n) => {
|
||||
a = new FileReader();
|
||||
a.onload = _ => y(a.result);
|
||||
a.onerror = _ => n(a.error);
|
||||
a.readAsDataURL(blob)
|
||||
});
|
||||
URL.createObjectURL(await (await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'test-image',
|
||||
method: 'echo_image',
|
||||
args: {
|
||||
source: dataurl,
|
||||
}
|
||||
}),
|
||||
"method": "POST",
|
||||
})).blob());
|
||||
```
|
||||
|
||||
```javascript
|
||||
await(async () => {
|
||||
|
||||
blob = await (await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'test-image',
|
||||
method: 'get_image',
|
||||
args: {
|
||||
source_type: 'string:url:web'
|
||||
}
|
||||
}),
|
||||
"method": "POST",
|
||||
})).blob();
|
||||
|
||||
const endpoint = 'http://api.puter.localhost:4100/drivers/call';
|
||||
|
||||
const body = {
|
||||
object: {
|
||||
interface: 'test-image',
|
||||
method: 'echo_image',
|
||||
['args.source']: {
|
||||
$: 'file',
|
||||
size: blob.size,
|
||||
type: blob.type,
|
||||
},
|
||||
},
|
||||
file: [
|
||||
blob,
|
||||
]
|
||||
};
|
||||
|
||||
const formData = new FormData();
|
||||
for ( const k in body ) {
|
||||
console.log('k', k);
|
||||
const append = v => {
|
||||
if ( v instanceof Blob ) {
|
||||
formData.append(k, v, 'filename');
|
||||
} else {
|
||||
formData.append(k, JSON.stringify(v));
|
||||
}
|
||||
};
|
||||
if ( Array.isArray(body[k]) ) {
|
||||
for ( const v of body[k] ) append(v);
|
||||
} else {
|
||||
append(body[k]);
|
||||
}
|
||||
}
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${puter.authToken}` },
|
||||
body: formData
|
||||
});
|
||||
const echo_blob = await response.blob();
|
||||
const echo_url = URL.createObjectURL(echo_blob);
|
||||
return echo_url;
|
||||
})();
|
||||
```
|
||||
@@ -16,12 +16,15 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
const APIError = require("../../api/APIError");
|
||||
const eggspress = require("../../api/eggspress");
|
||||
const { FileFacade } = require("../../services/drivers/FileFacade");
|
||||
const { TypeSpec } = require("../../services/drivers/meta/Construct");
|
||||
const { TypedValue } = require("../../services/drivers/meta/Runtime");
|
||||
const { Context } = require("../../util/context");
|
||||
const { whatis } = require("../../util/langutil");
|
||||
const { TeePromise } = require("../../util/promise");
|
||||
const { valid_file_size } = require("../../util/validutil");
|
||||
|
||||
let _handle_multipart;
|
||||
|
||||
@@ -55,12 +58,14 @@ module.exports = eggspress('/drivers/call', {
|
||||
const x = Context.get();
|
||||
const svc_driver = x.get('services').get('driver');
|
||||
|
||||
const interface_name = req.body.interface;
|
||||
const test_mode = req.body.test_mode;
|
||||
let p_request = null;
|
||||
let body;
|
||||
if ( req.headers['content-type'].includes('multipart/form-data') ) {
|
||||
({ params: body, p_data_end: p_request } = await _handle_multipart(req));
|
||||
} else body = req.body;
|
||||
|
||||
const args = req.headers['content-type'].includes('multipart/form-data')
|
||||
? await _handle_multipart(req)
|
||||
: req.body.args;
|
||||
const interface_name = body.interface;
|
||||
const test_mode = body.test_mode;
|
||||
|
||||
let context = Context.get();
|
||||
if ( test_mode ) context = context.sub({ test_mode: true });
|
||||
@@ -68,12 +73,22 @@ module.exports = eggspress('/drivers/call', {
|
||||
const result = await context.arun(async () => {
|
||||
return await svc_driver.call({
|
||||
iface: interface_name,
|
||||
method: req.body.method,
|
||||
args
|
||||
method: body.method,
|
||||
format: body.format,
|
||||
args: body.args,
|
||||
});
|
||||
});
|
||||
|
||||
// We can't wait for the request to finish before responding;
|
||||
// consider the case where a driver method implements a
|
||||
// stream transformation, thus the stream from the request isn't
|
||||
// consumed until the response is being sent.
|
||||
|
||||
_respond(res, result);
|
||||
|
||||
// What we _can_ do is await the request promise while responding
|
||||
// to ensure errors are caught here.
|
||||
await p_request;
|
||||
});
|
||||
|
||||
const _respond = (res, result) => {
|
||||
@@ -96,49 +111,86 @@ const _respond = (res, result) => {
|
||||
};
|
||||
|
||||
_handle_multipart = async (req) => {
|
||||
const busboy = require('busboy');
|
||||
const { Readable } = require('stream');
|
||||
const Busboy = require('busboy');
|
||||
const { PassThrough } = require('stream');
|
||||
|
||||
const params = {};
|
||||
const files = [];
|
||||
let file_index = 0;
|
||||
|
||||
const bb = new busboy({
|
||||
const bb = Busboy({
|
||||
headers: req.headers,
|
||||
});
|
||||
|
||||
const p_ready = new TeePromise();
|
||||
const p_data_end = new TeePromise();
|
||||
const p_nonfile_data_end = new TeePromise();
|
||||
bb.on('file', (fieldname, stream, details) => {
|
||||
const file_facade = new FileFacade();
|
||||
file_facade.values.set('stream', stream);
|
||||
file_facade.values.set('busboy:details', details);
|
||||
if ( params.hasOwnProperty(fieldname) ) {
|
||||
if ( ! Array.isArray(params[fieldname]) ) {
|
||||
params[fieldname] = [params[fieldname]];
|
||||
}
|
||||
params[fieldname].push(file_facade);
|
||||
} else {
|
||||
params[fieldname] = file_facade;
|
||||
}
|
||||
p_nonfile_data_end.resolve();
|
||||
const fileinfo = files[file_index++];
|
||||
stream.pipe(fileinfo.stream);
|
||||
});
|
||||
bb.on('field', (fieldname, value, details) => {
|
||||
if ( params.hasOwnProperty(fieldname) ) {
|
||||
if ( ! Array.isArray(params[fieldname]) ) {
|
||||
params[fieldname] = [params[fieldname]];
|
||||
|
||||
const on_field = (fieldname, value) => {
|
||||
const key_parts = fieldname.split('.');
|
||||
const last_key = key_parts.pop();
|
||||
let dst = params;
|
||||
for ( let i = 0; i < key_parts.length; i++ ) {
|
||||
if ( ! dst.hasOwnProperty(key_parts[i]) ) {
|
||||
dst[key_parts[i]] = {};
|
||||
}
|
||||
params[fieldname].push(value);
|
||||
if ( whatis(dst[key_parts[i]]) !== 'object' ) {
|
||||
throw new Error(
|
||||
`Tried to set member of non-object: ${key_parts[i]} in ${fieldname}`
|
||||
);
|
||||
}
|
||||
dst = dst[key_parts[i]];
|
||||
}
|
||||
if ( whatis(value) === 'object' && value.$ === 'file' ) {
|
||||
const fileinfo = value;
|
||||
const { v: size, ok: size_ok } =
|
||||
valid_file_size(fileinfo.size);
|
||||
if ( ! size_ok ) {
|
||||
throw APIError.create('invalid_file_metadata');
|
||||
}
|
||||
fileinfo.size = size;
|
||||
fileinfo.stream = new PassThrough();
|
||||
const file_facade = new FileFacade();
|
||||
file_facade.values.set('stream', fileinfo.stream);
|
||||
fileinfo.facade = file_facade,
|
||||
files.push(fileinfo);
|
||||
value = file_facade;
|
||||
}
|
||||
if ( dst.hasOwnProperty(last_key) ) {
|
||||
if ( ! Array.isArray(dst[last_key]) ) {
|
||||
dst[last_key] = [dst[last_key]];
|
||||
}
|
||||
dst[last_key].push(value);
|
||||
} else {
|
||||
params[fieldname] = value;
|
||||
dst[last_key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
bb.on('field', (fieldname, value, details) => {
|
||||
const o = JSON.parse(value);
|
||||
for ( const k in o ) {
|
||||
on_field(k, o[k]);
|
||||
}
|
||||
});
|
||||
bb.on('error', (err) => {
|
||||
p_ready.reject(err);
|
||||
p_data_end.reject(err);
|
||||
});
|
||||
bb.on('close', () => {
|
||||
p_ready.resolve();
|
||||
p_data_end.resolve();
|
||||
});
|
||||
|
||||
req.pipe(bb);
|
||||
|
||||
await p_ready;
|
||||
(async () => {
|
||||
await p_data_end;
|
||||
p_nonfile_data_end.resolve();
|
||||
})();
|
||||
|
||||
return params;
|
||||
}
|
||||
await p_nonfile_data_end;
|
||||
|
||||
return { params, p_data_end };
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ class CoercionService extends BaseService {
|
||||
content_type: 'image'
|
||||
},
|
||||
coerce: async typed_value => {
|
||||
this.log.noticeme('coercion is running!');
|
||||
const response = await CoercionService.MODULES.axios.get(typed_value.value, {
|
||||
responseType: 'stream',
|
||||
});
|
||||
|
||||
@@ -111,6 +111,7 @@ class DriverService extends BaseService {
|
||||
}
|
||||
|
||||
async _call ({ driver, iface, method, args }) {
|
||||
console.log('??', driver, iface, method, args);
|
||||
const processed_args = await this._process_args(iface, method, args);
|
||||
if ( Context.get('test_mode') ) {
|
||||
processed_args.test_mode = true;
|
||||
@@ -293,7 +294,7 @@ class DriverService extends BaseService {
|
||||
{
|
||||
name: 'enforce logical rate-limit',
|
||||
on_call: async args => {
|
||||
if ( ! effective_policy['rate-limit'] ) return args;
|
||||
if ( ! effective_policy?.['rate-limit'] ) return args;
|
||||
const svc_su = this.services.get('su');
|
||||
const svc_rateLimit = this.services.get('rate-limit');
|
||||
await svc_su.sudo(policy_holder, async () => {
|
||||
@@ -309,7 +310,7 @@ class DriverService extends BaseService {
|
||||
{
|
||||
name: 'enforce monthly usage limit',
|
||||
on_call: async args => {
|
||||
if ( ! effective_policy['monthly-limit'] ) return args;
|
||||
if ( ! effective_policy?.['monthly-limit'] ) return args;
|
||||
const svc_monthlyUsage = services.get('monthly-usage');
|
||||
const count = await svc_monthlyUsage.check_2(
|
||||
actor, method_key
|
||||
@@ -356,9 +357,18 @@ class DriverService extends BaseService {
|
||||
name: 'result coercion',
|
||||
on_return: async (result) => {
|
||||
if ( result instanceof TypedValue ) {
|
||||
const svc_registry = this.services.get('registry');
|
||||
const c_interfaces = svc_registry.get('interfaces');
|
||||
|
||||
console.log('????--1', iface);
|
||||
const interface_ = c_interfaces.get(iface);
|
||||
let desired_type = interface_.methods[method]
|
||||
.result_choices[0].type;
|
||||
console.log('????--2', interface_);
|
||||
const method_spec = interface_.methods[method];
|
||||
let desired_type =
|
||||
method_spec.result_choices
|
||||
? method_spec.result_choices[0].type
|
||||
: method_spec.result.type
|
||||
;
|
||||
const svc_coercion = services.get('coercion');
|
||||
result = await svc_coercion.coerce(desired_type, result);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,10 @@ class File extends BaseType {
|
||||
}
|
||||
|
||||
async consolidate (ctx, input, { arg_name }) {
|
||||
if ( input instanceof FileFacade ) {
|
||||
return input;
|
||||
}
|
||||
|
||||
const result = new FileFacade();
|
||||
// DRY: Part of this is duplicating FSNodeParam, but FSNodeParam is
|
||||
// subject to change in PR #647, so this should be updated later.
|
||||
|
||||
@@ -349,4 +349,4 @@ const ko = {
|
||||
},
|
||||
};
|
||||
|
||||
export default ko;
|
||||
export default ko;
|
||||
@@ -18,190 +18,334 @@
|
||||
*/
|
||||
|
||||
const nl = {
|
||||
name: "Nederlands",
|
||||
english_name: "Dutch",
|
||||
code: "nl",
|
||||
name: 'Nederlands',
|
||||
english_name: 'Dutch',
|
||||
code: 'nl',
|
||||
dictionary: {
|
||||
about: "Over",
|
||||
account: "Account",
|
||||
access_granted_to: "Toegang gegeven aan",
|
||||
add_existing_account: "Bestaand Account Toevoegen",
|
||||
about: 'Over',
|
||||
account: 'Account',
|
||||
account_password: 'Verifieer Account Wachtwoord',
|
||||
access_granted_to: 'Toegang gegeven aan',
|
||||
add_existing_account: 'Bestaand Account Toevoegen',
|
||||
all_fields_required: 'Alle velden zijn vereist.',
|
||||
apply: "Toepassen",
|
||||
allow: 'Toestaan',
|
||||
apply: 'Toepassen',
|
||||
ascending: 'Oplopend',
|
||||
associated_websites: 'Geassocieerde Websites',
|
||||
auto_arrange: 'Automatisch sorteren',
|
||||
background: "Achtergrond",
|
||||
browse: "Verkennen",
|
||||
background: 'Achtergrond',
|
||||
browse: 'Bladeren',
|
||||
cancel: 'Annuleren',
|
||||
center: 'Centreren',
|
||||
change_desktop_background: 'Achtergrond veranderen…',
|
||||
change_language: "Taal veranderen",
|
||||
change_password: "Wachtwoord veranderen",
|
||||
change_username: "Gebruikersnaam veranderen",
|
||||
close_all_windows: "Alle schermen sluiten",
|
||||
close_all_windows_and_log_out: 'Alle schermen sluiten en afmelden',
|
||||
change_always_open_with: "Dit type bestand altijd openen met",
|
||||
change_desktop_background: 'Bureaubladachtergrond veranderen…',
|
||||
change_email: 'E-mail Wijzigen',
|
||||
change_language: 'Taal veranderen',
|
||||
change_password: 'Wachtwoord veranderen',
|
||||
change_ui_colors: 'UI Kleuren veranderen',
|
||||
change_username: 'Gebruikersnaam veranderen',
|
||||
close: 'Sluiten',
|
||||
close_all_windows: 'Alle vensters sluiten',
|
||||
close_all_windows_confirm: 'Weet u zeker dat u alle vensters wilt sluiten?',
|
||||
close_all_windows_and_log_out: 'Vensters sluiten en afmelden',
|
||||
change_always_open_with: 'Wilt u dit bestandstype altijd openen met',
|
||||
color: 'Kleur',
|
||||
confirm: 'Bevestig',
|
||||
confirm_account_for_free_referral_storage_c2a: 'Maak een account en bevestig uw emailadres om 1 GB aan gratis opslag te ontvangen. Uw vriend krijgt ook 1 GB aan gratis opslag.',
|
||||
confirm_delete_multiple_items: 'Weet u zeker dat u deze bestanden permanent wilt verwijderen?',
|
||||
confirm_delete_single_item: 'Weet u zeker dat u dit bestand permanent wilt verwijderen?',
|
||||
confirm_delete_user: 'Weet u zeker dat u uw account wilt verwijderen? Al uw bestanden en gegevens zal permanent verwijderd worden. Deze actie kan niet ongedaan gemaakt worden.',
|
||||
confirm_open_apps_log_out: 'U heeft nog geopende applicaties. Weet u zeker dat u wilt uitloggen?',
|
||||
confirm_new_password: "Bevestig Nieuw Wachtwoord",
|
||||
contact_us: "Neem contact met ons op",
|
||||
confirm_2fa_setup: 'Ik heb de code toegevoegd aan mijn authenticatie-app',
|
||||
confirm_2fa_recovery: 'Ik heb mijn herstelcodes op een veilige plaats opgeslagen',
|
||||
confirm_account_for_free_referral_storage_c2a: 'Maak een account aan en bevestig uw e-mailadres om 1 GB gratis opslag te ontvangen. Uw vriend krijgt ook 1 GB gratis opslag.',
|
||||
confirm_code_generic_incorrect: 'Onjuiste code.',
|
||||
confirm_code_generic_too_many_requests: 'Te veel aanvragen. Wacht een paar minuten.',
|
||||
confirm_code_generic_submit: 'Code invoeren',
|
||||
confirm_code_generic_try_again: 'Probeer opnieuw',
|
||||
confirm_code_generic_title: 'Bevestigingscode Invoeren',
|
||||
confirm_code_2fa_instruction: 'Voer de 6-cijferige code in van uw authenticatie-app.',
|
||||
confirm_code_2fa_submit_btn: 'Verzenden',
|
||||
confirm_code_2fa_title: 'Voer 2FA Code In',
|
||||
confirm_delete_multiple_items: 'Weet u zeker dat u deze items permanent wilt verwijderen?',
|
||||
confirm_delete_single_item: 'Wilt u dit item permanent verwijderen?',
|
||||
confirm_open_apps_log_out: 'U heeft geopende apps. Weet u zeker dat u wilt uitloggen?',
|
||||
confirm_new_password: 'Bevestig Nieuw Wachtwoord',
|
||||
confirm_delete_user: 'Weet u zeker dat u uw account wilt verwijderen? Al uw bestanden en gegevens worden permanent verwijderd. Deze actie kan niet ongedaan worden gemaakt.',
|
||||
confirm_delete_user_title: 'Account Verwijderen?',
|
||||
confirm_session_revoke: 'Weet u zeker dat u deze sessie wilt intrekken?',
|
||||
confirm_your_email_address: 'Bevestig Uw E-mailadres',
|
||||
contact_us: 'Neem Contact Op',
|
||||
contact_us_verification_required: 'U moet een geverifieerd e-mailadres hebben om dit te gebruiken.',
|
||||
contain: 'Bevatten',
|
||||
continue: "Doorgaan",
|
||||
continue: 'Doorgaan',
|
||||
copy: 'Kopiëren',
|
||||
copy_link: "Kopieer koppeling",
|
||||
copying: "Kopiëren",
|
||||
copy_link: 'Link Kopiëren',
|
||||
copying: 'Kopiëren',
|
||||
copying_file: 'Bestand Kopiëren %%',
|
||||
cover: 'Omslag',
|
||||
create_account: "Maak Account",
|
||||
create_free_account: "Maak Gratis Account",
|
||||
create_shortcut: "Maak Snelkoppeling",
|
||||
credits: "Credits",
|
||||
current_password: "Huidig Wachtwoord",
|
||||
create_account: 'Account Aanmaken',
|
||||
create_free_account: 'Gratis Account Aanmaken',
|
||||
create_shortcut: 'Snelkoppeling Maken',
|
||||
credits: 'Credits',
|
||||
current_password: 'Huidig Wachtwoord',
|
||||
cut: 'Knippen',
|
||||
date_modified: 'Datum gewijzigd',
|
||||
clock: 'Klok',
|
||||
clock_visible_hide: 'Verbergen - Altijd verborgen',
|
||||
clock_visible_show: 'Weergeven - Altijd zichtbaar',
|
||||
clock_visible_auto: 'Auto - Standaard, alleen zichtbaar in de volledige schermmodus.',
|
||||
close_all: 'Alles Sluiten',
|
||||
created: 'Gemaakt',
|
||||
date_modified: 'Datum Gewijzigd',
|
||||
default: 'Standaard',
|
||||
delete: 'Verwijderen',
|
||||
delete_account: "Account Verwijderen",
|
||||
delete_permanently: "Permanent Verwijderen",
|
||||
deploy_as_app: 'Uitrollen als applicatie',
|
||||
delete_account: 'Account Verwijderen',
|
||||
delete_permanently: 'Permanent Verwijderen',
|
||||
deleting_file: 'Bestand Verwijderen %%',
|
||||
deploy_as_app: 'Uitrollen als app',
|
||||
descending: 'Aflopend',
|
||||
desktop_background_fit: "Passend",
|
||||
developers: "Ontwikkelaars",
|
||||
dir_published_as_website: `%strong% is gepubliceerd naar:`,
|
||||
disassociate_dir: "Map Ontkoppelen",
|
||||
desktop: 'Bureaublad',
|
||||
desktop_background_fit: 'Aanpassen',
|
||||
developers: 'Ontwikkelaars',
|
||||
dir_published_as_website: `%strong% is gepubliceerd op:`,
|
||||
disable_2fa: '2FA Uitschakelen',
|
||||
disable_2fa_confirm: 'Weet u zeker dat u 2FA wilt uitschakelen?',
|
||||
disable_2fa_instructions: 'Voer uw wachtwoord in om 2FA uit te schakelen.',
|
||||
disassociate_dir: 'Map Loskoppelen',
|
||||
documents: 'Documenten',
|
||||
dont_allow: 'Niet Toestaan',
|
||||
download: 'Downloaden',
|
||||
download_file: 'Bestand Downloaden',
|
||||
downloading: "Aan het downloaden",
|
||||
email: "Emailadres",
|
||||
email_or_username: "Emailadres of Gebruikersnaam",
|
||||
empty_trash: 'Prullenbak Legen',
|
||||
empty_trash_confirmation: `Weet u zeker dat u alle bestanden in de Prullenbak permanent wilt verwijderen?`,
|
||||
downloading: 'Downloaden',
|
||||
email: 'E-mail',
|
||||
email_change_confirmation_sent: 'Er is een bevestigingsmail gestuurd naar uw nieuwe e-mailadres. Controleer uw inbox en volg de instructies om het proces te voltooien.',
|
||||
email_invalid: 'E-mail is ongeldig.',
|
||||
email_or_username: 'E-mail of Gebruikersnaam',
|
||||
email_required: 'E-mail is verplicht.',
|
||||
empty_trash: 'Prullenbak Leegmaken',
|
||||
empty_trash_confirmation: `Weet u zeker dat u de items in de prullenbak permanent wilt verwijderen?`,
|
||||
emptying_trash: 'Prullenbak Legen…',
|
||||
enter_password_to_confirm_delete_user: "Voer uw wachtwoord in om te bevestigen dat uw account verwijderd wordt",
|
||||
feedback: "Feedback",
|
||||
feedback_c2a: "Gebruik alstublieft het onderstaande formulier om ons uw feedback, opmerkingen en foutmeldingsrapporten te sturen.",
|
||||
feedback_sent_confirmation: "Bedankt dat u contact met ons opneemt. Als er een emailadres aan uw account is gekoppeld, hoort u zo snel mogelijk van ons terug.",
|
||||
forgot_pass_c2a: "Wachtwoord Vergeten?",
|
||||
from: "Van",
|
||||
general: "Algemeen",
|
||||
get_a_copy_of_on_puter: `Bemachtig een kopie van '%%' op Puter.com!`,
|
||||
get_copy_link: 'Krijg Kopieer Koppeling',
|
||||
hide_all_windows: "Verberg alle Vensters",
|
||||
enable_2fa: '2FA Inschakelen',
|
||||
end_hard: 'Hard Stoppen',
|
||||
end_process_force_confirm: 'Weet u zeker dat u dit proces geforceerd wilt beëindigen?',
|
||||
end_soft: 'Zacht Stoppen',
|
||||
enlarged_qr_code: 'Vergrote QR Code',
|
||||
enter_password_to_confirm_delete_user: 'Voer uw wachtwoord in om de verwijdering van het account te bevestigen',
|
||||
error_message_is_missing: 'Foutbericht ontbreekt.',
|
||||
error_unknown_cause: 'Er is een onbekende fout opgetreden.',
|
||||
error_uploading_files: 'Bestanden uploaden mislukt',
|
||||
favorites: 'Favorieten',
|
||||
feedback: 'Feedback',
|
||||
feedback_c2a: 'Gebruik het onderstaande formulier om ons uw feedback, opmerkingen en bugrapporten te sturen.',
|
||||
feedback_sent_confirmation: 'Bedankt dat u contact met ons heeft opgenomen. Als u een e-mail heeft gekoppeld aan uw account, hoort u zo snel mogelijk van ons.',
|
||||
fit: 'Aanpassen',
|
||||
folder: 'Map',
|
||||
force_quit: 'Geforceerd Stoppen',
|
||||
forgot_pass_c2a: 'Wachtwoord vergeten?',
|
||||
from: 'Van',
|
||||
general: 'Algemeen',
|
||||
get_a_copy_of_on_puter: `Krijg een kopie van '%%' op Puter.com!`,
|
||||
get_copy_link: 'Krijg Kopieerlink',
|
||||
hide_all_windows: 'Alle Vensters Verbergen',
|
||||
home: 'Home',
|
||||
html_document: 'HTML document',
|
||||
hue: 'Tint',
|
||||
image: 'Afbeelding',
|
||||
invite_link: "Uitnodiging Koppeling",
|
||||
item: 'Bestand',
|
||||
items_in_trash_cannot_be_renamed: `Dit bestand kan niet hernoemd worden omdat het in de Prullenbak zit. Om dit bestand te hernoemen, verplaats het eerst uit de Prullenbak.`,
|
||||
incorrect_password: 'Onjuist wachtwoord',
|
||||
invite_link: 'Uitnodigingslink',
|
||||
item: 'item',
|
||||
items_in_trash_cannot_be_renamed: `Dit item kan niet worden hernoemd omdat het in de prullenbak zit. Om dit item te hernoemen, sleept u het eerst uit de prullenbak.`,
|
||||
jpeg_image: 'JPEG afbeelding',
|
||||
keep_in_taskbar: 'In Taakbalk houden',
|
||||
language: "Taal",
|
||||
license: "Licentie",
|
||||
keep_in_taskbar: 'In Taakbalk Houden',
|
||||
language: 'Taal',
|
||||
license: 'Licentie',
|
||||
lightness: 'Helderheid',
|
||||
link_copied: 'Link gekopieerd',
|
||||
loading: 'Laden',
|
||||
log_in: "Inloggen",
|
||||
log_into_another_account_anyway: 'Alsnog met ander account inloggen',
|
||||
log_in: 'Inloggen',
|
||||
log_into_another_account_anyway: 'Log toch in op een ander account',
|
||||
log_out: 'Uitloggen',
|
||||
looks_good: 'Ziet er goed uit!',
|
||||
manage_sessions: 'Sessies Beheren',
|
||||
menubar_style: 'Menubalk Stijl',
|
||||
menubar_style_desktop: 'Bureaublad',
|
||||
menubar_style_system: 'Systeem',
|
||||
menubar_style_window: 'Venster',
|
||||
mobile_device: 'Mobiel apparaat',
|
||||
modified: 'Gewijzigd',
|
||||
move: 'Verplaatsen',
|
||||
moving_file: "Aan het verplaatsen %%",
|
||||
my_websites: "Mijn Websites",
|
||||
moving_file: 'Verplaatsen %%',
|
||||
my_websites: 'Mijn Websites',
|
||||
name: 'Naam',
|
||||
name_cannot_be_empty: 'Naam kan niet leeg zijn.',
|
||||
name_cannot_contain_double_period: "Naam mag geen '..'-karakter bevatten.",
|
||||
name_cannot_contain_period: "Naam mag geen '.'-karakter bevatten.",
|
||||
name_cannot_contain_slash: "Naam mag geen '/'-karakter bevatten.",
|
||||
name_must_be_string: "Naam kan alleen een tekenreeks zijn.",
|
||||
name_too_long: `Naam kan niet langer zijn dan %% karakters.`,
|
||||
name_cannot_contain_double_period: 'Naam mag geen dubbele punt \'..\' bevatten.',
|
||||
name_cannot_contain_period: 'Naam mag geen punt \' . \' bevatten.',
|
||||
name_cannot_contain_slash: 'Naam mag geen schuine streep \' / \' bevatten.',
|
||||
name_must_be_string: 'Naam moet een alfanumerieke tekenreeks zijn.',
|
||||
name_too_long: 'Naam mag niet langer zijn dan %% karakters.',
|
||||
new: 'Nieuw',
|
||||
new_email: 'Nieuwe E-mail',
|
||||
new_folder: 'Nieuwe Map',
|
||||
new_password: "Nieuw Wachtwoord",
|
||||
new_username: "Nieuwe Gebruikersnaam",
|
||||
new_password: 'Nieuw Wachtwoord',
|
||||
new_username: 'Nieuwe Gebruikersnaam',
|
||||
no: 'Nee',
|
||||
no_dir_associated_with_site: 'Er is geen map gekoppeld aan dit adres.',
|
||||
no_websites_published: "U heeft nog geen websites gepubliceerd.",
|
||||
ok: 'Oke',
|
||||
open: "Open",
|
||||
open_in_new_tab: "Open in Nieuw Tabblad",
|
||||
open_in_new_window: "Open in Nieuw Scherm",
|
||||
open_with: "Openen met",
|
||||
oss_code_and_content: "Open source-software en inhoud",
|
||||
password: "Wachtwoord",
|
||||
password_changed: "Wachtwoord veranderd.",
|
||||
passwords_do_not_match: '`Nieuw Wachtwoord` en `Bevestig Nieuw Wachtwoord` komen niet overeen.',
|
||||
no_dir_associated_with_site: 'Geen map geassocieerd met dit adres.',
|
||||
no_websites_published: 'Je hebt nog geen websites gepubliceerd. Klik met de rechtermuisknop op een map om te beginnen.',
|
||||
ok: 'OK',
|
||||
open: 'Openen',
|
||||
open_in_new_tab: 'Openen in Nieuw Tabblad',
|
||||
open_in_new_window: 'Openen in Nieuw Venster',
|
||||
open_with: 'Openen met',
|
||||
original_name: 'Originele Naam',
|
||||
original_path: 'Origineel Pad',
|
||||
oss_code_and_content: 'Open Source Software Code en Inhoud',
|
||||
password: 'Wachtwoord',
|
||||
password_changed: 'Wachtwoord gewijzigd',
|
||||
password_recovery_rate_limit: 'U heeft te veel verzoeken ingediend. Wacht een paar minuten voordat u het opnieuw probeert.',
|
||||
password_recovery_token_invalid: 'Wachtwoord hersteltoken is verlopen of ongeldig.',
|
||||
password_recovery_unknown_error: 'Onbekende fout opgetreden bij het herstellen van het wachtwoord. Probeer het opnieuw.',
|
||||
password_required: 'Wachtwoord is verplicht.',
|
||||
password_strength_error: 'Wachtwoord moet minimaal 8 tekens lang zijn en minimaal één hoofdletter, één kleine letter, één cijfer en één speciaal teken bevatten.',
|
||||
passwords_do_not_match: 'Wachtwoorden komen niet overeen.',
|
||||
paste: 'Plakken',
|
||||
paste_into_folder: "Plakken in Map",
|
||||
pick_name_for_website: "Kies een naam voor uw website:",
|
||||
picture: "Foto",
|
||||
powered_by_puter_js: `Aangedreven door {{link=docs}}Puter.js{{/link}}`,
|
||||
preparing: "Voorbereiden...",
|
||||
preparing_for_upload: "Upload voorbereiden...",
|
||||
proceed_to_login: 'Doorgaan naar Inloggen',
|
||||
properties: "Eigenschappen",
|
||||
privacy: "Privacy",
|
||||
proceed_with_account_deletion: "Doorgaan met Account Verwijderen",
|
||||
publish: "Publiceren",
|
||||
publish_as_website: 'Publiceren als website',
|
||||
puter_description: `Puter is een persoonlijke cloud waarin privacy centraal staat en waarmee u al uw bestanden, apps en games in één veilige plek kunt bewaren die altijd en overal toegankelijk.`,
|
||||
recent: "Recent",
|
||||
recover_password: "Wachtwoord herstellen",
|
||||
refer_friends_c2a: "Krijg 1 GB voor elke vriend die een account maakt en bevestigt bij Puter. uw vriend ontvangt ook 1 GB!",
|
||||
refer_friends_social_media_c2a: `Krijg 1 GB gratig opslag op Puter.com!`,
|
||||
refresh: 'Verversen',
|
||||
release_address_confirmation: `Weet u zeker dat u dit adres wilt vrijgeven?`,
|
||||
remove_from_taskbar:'Losmaken van Taakbalk',
|
||||
paste_into_folder: 'Plakken in Map',
|
||||
path: 'Pad',
|
||||
personalization: 'Personalisatie',
|
||||
pick_name_for_website: 'Kies een naam voor uw website',
|
||||
picture: 'Afbeelding',
|
||||
pictures: 'Afbeeldingen',
|
||||
plural_suffix: 'en',
|
||||
powered_by_puter_js: 'Aangedreven door {{link=docs}}Puter.js{{/link}}',
|
||||
preparing: 'Voorbereiden...',
|
||||
preparing_for_upload: 'Voorbereiden voor upload...',
|
||||
print: 'Afdrukken',
|
||||
privacy: 'Privacy',
|
||||
proceed_to_login: 'Doorgaan naar inloggen',
|
||||
proceed_with_account_deletion: 'Doorgaan met accountverwijdering',
|
||||
process_status_initializing: 'Initialiseren',
|
||||
process_status_running: 'Bezig',
|
||||
process_type_app: 'App',
|
||||
process_type_init: 'Init',
|
||||
process_type_ui: 'UI',
|
||||
properties: 'Eigenschappen',
|
||||
public: 'Openbaar',
|
||||
publish: 'Publiceren',
|
||||
publish_as_website: 'Publiceer als website',
|
||||
puter_description: `Puter is een privacy-first persoonlijke cloud om al je bestanden, apps en games op één veilige plek te bewaren, overal en altijd toegankelijk.`,
|
||||
reading_file: 'Lezen %strong%',
|
||||
recent: 'Recent',
|
||||
recommended: 'Aanbevolen',
|
||||
recover_password: 'Wachtwoord herstellen',
|
||||
refer_friends_c2a: 'Krijg 1 GB voor elke vriend die een account aanmaakt en bevestigt op Puter. Je vriend krijgt ook 1 GB!',
|
||||
refer_friends_social_media_c2a: `Krijg 1 GB gratis opslagruimte op Puter.com!`,
|
||||
refresh: 'Vernieuwen',
|
||||
release_address_confirmation: `Weet je zeker dat je dit adres wilt vrijgeven?`,
|
||||
remove_from_taskbar: 'Verwijderen van taakbalk',
|
||||
rename: 'Hernoemen',
|
||||
repeat: 'Herhalen',
|
||||
replace: 'Vervangen',
|
||||
replace_all: 'Alles Vervangen',
|
||||
resend_confirmation_code: "Confirmatie Code opnieuw verzenden",
|
||||
restore: "Herstellen",
|
||||
replace_all: 'Alles vervangen',
|
||||
resend_confirmation_code: 'Bevestigingscode opnieuw verzenden',
|
||||
reset_colors: 'Kleuren resetten',
|
||||
restart_puter_confirm: 'Weet je zeker dat je Puter wilt herstarten?',
|
||||
restore: 'Herstellen',
|
||||
save: 'Opslaan',
|
||||
saturation: 'Verzadiging',
|
||||
save_account: 'Account opslaan',
|
||||
save_account_to_get_copy_link: "Maak alstublieft een account om door te gaan.",
|
||||
save_account_to_publish: 'Maak alstublieft een account om door te gaan.',
|
||||
save_session: 'Sessie Opslaan',
|
||||
save_session_c2a: 'Maak een account aan om uw huidige sessie op te slaan en te voorkomen dat u uw werk kwijtraakt.',
|
||||
scan_qr_c2a: 'Scan de onderstaande QR-code om op deze sessie in te loggen op een ander apparaat',
|
||||
select: "Selecteren",
|
||||
save_account_to_get_copy_link: 'Maak een account aan om verder te gaan.',
|
||||
save_account_to_publish: 'Maak een account aan om verder te gaan.',
|
||||
save_session: 'Sessie opslaan',
|
||||
save_session_c2a: 'Maak een account aan om je huidige sessie op te slaan en verlies van werk te voorkomen.',
|
||||
scan_qr_c2a: 'Scan de onderstaande code\nom in te loggen op deze sessie vanaf andere apparaten',
|
||||
scan_qr_2fa: 'Scan de QR-code met je authenticator-app',
|
||||
scan_qr_generic: 'Scan deze QR-code met je telefoon of een ander apparaat',
|
||||
search: 'Zoeken',
|
||||
seconds: 'seconden',
|
||||
security: 'Beveiliging',
|
||||
select: 'Selecteren',
|
||||
selected: 'geselecteerd',
|
||||
select_color: 'Selecteer kleur…',
|
||||
send: "Versturen",
|
||||
send_password_recovery_email: "Verstuur Wachtwoord Herstel Email",
|
||||
session_saved: "Bedankt voor het maken van een account. Deze sessie is nu opgeslagen.",
|
||||
sessions: 'Sessies',
|
||||
send: 'Verzenden',
|
||||
send_password_recovery_email: 'Wachtwoordherstelsmail verzenden',
|
||||
session_saved: 'Bedankt voor het aanmaken van een account. Deze sessie is opgeslagen.',
|
||||
settings: 'Instellingen',
|
||||
set_new_password: "Stel een nieuw wachtwoord in",
|
||||
share_to: "Delen naar",
|
||||
show_all_windows: "Toon alle vensters",
|
||||
show_hidden: 'Toon Verborgen',
|
||||
sign_in_with_puter: "Inloggen met Puter",
|
||||
sign_up: "Aanmelden",
|
||||
signing_in: "Aan het inloggen…",
|
||||
set_new_password: 'Nieuw wachtwoord instellen',
|
||||
share: 'Delen',
|
||||
share_to: 'Delen met',
|
||||
share_with: 'Delen met:',
|
||||
shortcut_to: 'Snelkoppeling naar',
|
||||
show_all_windows: 'Toon alle vensters',
|
||||
show_hidden: 'Toon verborgen',
|
||||
sign_in_with_puter: 'Inloggen met Puter',
|
||||
sign_up: 'Aanmelden',
|
||||
signing_in: 'Inloggen…',
|
||||
size: 'Grootte',
|
||||
skip: 'Overslaan',
|
||||
something_went_wrong: 'Er is iets misgegaan.',
|
||||
sort_by: 'Sorteren op',
|
||||
start: 'Start',
|
||||
status: "Status",
|
||||
storage_usage: "Opslaggebruik",
|
||||
taking_longer_than_usual: 'Het duurt iets langer dan normaal. Even geduld aub...',
|
||||
terms: "Voorwaarden",
|
||||
text_document: 'Tekst document',
|
||||
tos_fineprint: `Door te klikken op 'Maak Gratis Account' gaat u akkoord met Puter's {{link=terms}}Gebruiksvoorwaarden{{/link}} en {{link=privacy}}Privacybeleid{{/link}}.`,
|
||||
status: 'Status',
|
||||
storage_usage: 'Opslaggebruik',
|
||||
storage_puter_used: 'gebruikt door Puter',
|
||||
taking_longer_than_usual: 'Het duurt langer dan normaal. Even geduld alstublieft...',
|
||||
task_manager: 'Taakbeheer',
|
||||
taskmgr_header_name: 'Naam',
|
||||
taskmgr_header_status: 'Status',
|
||||
taskmgr_header_type: 'Type',
|
||||
terms: 'Voorwaarden',
|
||||
text_document: 'Tekstdocument',
|
||||
tos_fineprint: `Door op 'Gratis Account Aanmaken' te klikken, ga je akkoord met de {{link=terms}}Servicevoorwaarden{{/link}} en de {{link=privacy}}Privacybeleid{{/link}} van Puter.`,
|
||||
transparency: 'Transparantie',
|
||||
trash: 'Prullenbak',
|
||||
two_factor: 'Tweestapsverificatie',
|
||||
two_factor_disabled: '2FA Uitgeschakeld',
|
||||
two_factor_enabled: '2FA Ingeschakeld',
|
||||
type: 'Type',
|
||||
type_confirm_to_delete_account: "Type 'bevestig' om uw account te verwijderen.",
|
||||
type_confirm_to_delete_account: 'Typ \'bevestigen\' om je account te verwijderen.',
|
||||
ui_colors: 'UI Kleuren',
|
||||
ui_manage_sessions: 'Sessiebeheer',
|
||||
ui_revoke: 'Intrekken',
|
||||
undo: 'Ongedaan maken',
|
||||
unlimited: 'Onbeperkt',
|
||||
unzip: "Uitpakken",
|
||||
unzip: 'Uitpakken',
|
||||
upload: 'Uploaden',
|
||||
upload_here: 'Hier Uploaden',
|
||||
upload_here: 'Hier uploaden',
|
||||
usage: 'Gebruik',
|
||||
username: "Gebruikersnaam",
|
||||
username_changed: 'Gebruikersnaam succesvol aangepast.',
|
||||
versions: "Versies",
|
||||
username: 'Gebruikersnaam',
|
||||
username_changed: 'Gebruikersnaam succesvol bijgewerkt.',
|
||||
username_required: 'Gebruikersnaam is vereist.',
|
||||
versions: 'Versies',
|
||||
videos: 'Video\'s',
|
||||
visibility: 'Zichtbaarheid',
|
||||
yes: 'Ja',
|
||||
yes_release_it: 'Ja, Geef het vrij',
|
||||
you_have_been_referred_to_puter_by_a_friend: "Je bent door een vriend naar Puter verwezen!",
|
||||
zip: "Inpakken",
|
||||
yes_release_it: 'Ja, vrijgeven',
|
||||
you_have_been_referred_to_puter_by_a_friend: 'Je bent door een vriend doorverwezen naar Puter!',
|
||||
zip: 'Zip',
|
||||
zipping_file: 'Bestand inpakken %strong%',
|
||||
|
||||
// === 2FA Setup ===
|
||||
setup2fa_1_step_heading: 'Open je authenticator-app',
|
||||
setup2fa_1_instructions: `
|
||||
Je kunt elke authenticator-app gebruiken die het Time-based One-Time Password (TOTP) protocol ondersteunt.
|
||||
Er zijn veel opties om uit te kiezen, maar als je twijfelt,
|
||||
<a target="_blank" href="https://authy.com/download">Authy</a>
|
||||
is een goede keuze voor Android en iOS.
|
||||
`,
|
||||
setup2fa_2_step_heading: 'Scan de QR-code',
|
||||
setup2fa_3_step_heading: 'Voer de 6-cijferige code in',
|
||||
setup2fa_4_step_heading: 'Kopieer je herstelcodes',
|
||||
setup2fa_4_instructions: `
|
||||
Deze herstelcodes zijn de enige manier om toegang te krijgen tot je account als je je telefoon kwijtraakt of je authenticator-app niet kunt gebruiken.
|
||||
Zorg ervoor dat je ze op een veilige plaats bewaart.
|
||||
`,
|
||||
setup2fa_5_step_heading: 'Bevestig 2FA-instelling',
|
||||
setup2fa_5_confirmation_1: 'Ik heb mijn herstelcodes op een veilige plaats opgeslagen',
|
||||
setup2fa_5_confirmation_2: 'Ik ben klaar om 2FA in te schakelen',
|
||||
setup2fa_5_button: '2FA inschakelen',
|
||||
|
||||
// === 2FA Login ===
|
||||
login2fa_otp_title: 'Voer 2FA-code in',
|
||||
login2fa_otp_instructions: 'Voer de 6-cijferige code in uit je authenticator-app.',
|
||||
login2fa_recovery_title: 'Voer een herstelcode in',
|
||||
login2fa_recovery_instructions: 'Voer een van je herstelcodes in om toegang te krijgen tot je account.',
|
||||
login2fa_use_recovery_code: 'Gebruik een herstelcode',
|
||||
login2fa_recovery_back: 'Terug',
|
||||
login2fa_recovery_placeholder: 'XXXXXXXX',
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -83,7 +83,8 @@ const main = async () => {
|
||||
CoreModule,
|
||||
DatabaseModule,
|
||||
LocalDiskStorageModule,
|
||||
SelfHostedModule
|
||||
SelfHostedModule,
|
||||
TestDriversModule,
|
||||
} = (await import('@heyputer/backend')).default;
|
||||
|
||||
const k = new Kernel({
|
||||
@@ -93,6 +94,7 @@ const main = async () => {
|
||||
k.add_module(new DatabaseModule());
|
||||
k.add_module(new LocalDiskStorageModule());
|
||||
k.add_module(new SelfHostedModule());
|
||||
k.add_module(new TestDriversModule());
|
||||
k.boot();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user