mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Merge branch 'development' into release
This commit is contained in:
commit
fc13e56cea
7
.github/translators.txt
vendored
7
.github/translators.txt
vendored
@ -347,7 +347,7 @@ Taygun Yıldırım (yildirimtaygun) :: Turkish
|
||||
robing29 :: German
|
||||
Bruno Eduardo de Jesus Barroso (brunoejb) :: Portuguese, Brazilian
|
||||
Igor V Belousov (biv) :: Russian
|
||||
David Bauer (davbauer) :: German
|
||||
David Bauer (davbauer) :: German; German Informal
|
||||
Guttorm Hveem (guttormhveem) :: Norwegian Nynorsk; Norwegian Bokmal
|
||||
Minh Giang Truong (minhgiang1204) :: Vietnamese
|
||||
Ioannis Ioannides (i.ioannides) :: Greek
|
||||
@ -389,7 +389,7 @@ Marc Hagen (MarcHagen) :: Dutch
|
||||
Kasper Alsøe (zeonos) :: Danish
|
||||
sultani :: Persian
|
||||
renge :: Korean
|
||||
Tim (thegatesdev) :: Dutch; German Informal; Romanian; French; Catalan; Czech; Danish; German; Finnish; Hungarian; Italian; Japanese; Korean; Polish; Russian; Ukrainian; Chinese Simplified; Chinese Traditional; Portuguese, Brazilian; Persian; Spanish, Argentina; Croatian; Norwegian Nynorsk; Estonian; Uzbek; Norwegian Bokmal
|
||||
Tim (thegatesdev) :: Dutch; German Informal; French; Romanian; Catalan; Czech; Danish; German; Finnish; Hungarian; Italian; Japanese; Korean; Polish; Russian; Ukrainian; Chinese Simplified; Chinese Traditional; Portuguese, Brazilian; Persian; Spanish, Argentina; Croatian; Norwegian Nynorsk; Estonian; Uzbek; Norwegian Bokmal
|
||||
Irdi (irdiOL) :: Albanian
|
||||
KateBarber :: Welsh
|
||||
Twister (theuncles75) :: Hebrew
|
||||
@ -422,3 +422,6 @@ crow_ :: Latvian
|
||||
JocelynDelalande :: French
|
||||
Jan (JW-CH) :: German Informal
|
||||
Timo B (lommes) :: German Informal
|
||||
Erik Lundstedt (Erik.Lundstedt) :: Swedish
|
||||
yngams (younessmouhid) :: Arabic
|
||||
Ohadp :: Hebrew
|
||||
|
@ -32,13 +32,17 @@ class ConfirmEmailController extends Controller
|
||||
|
||||
/**
|
||||
* Shows a notice that a user's email address has not been confirmed,
|
||||
* Also has the option to re-send the confirmation email.
|
||||
* along with the option to re-send the confirmation email.
|
||||
*/
|
||||
public function showAwaiting()
|
||||
{
|
||||
$user = $this->loginService->getLastLoginAttemptUser();
|
||||
if ($user === null) {
|
||||
$this->showErrorNotification(trans('errors.login_user_not_found'));
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
return view('auth.user-unconfirmed', ['user' => $user]);
|
||||
return view('auth.register-confirm-awaiting');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,19 +94,24 @@ class ConfirmEmailController extends Controller
|
||||
/**
|
||||
* Resend the confirmation email.
|
||||
*/
|
||||
public function resend(Request $request)
|
||||
public function resend()
|
||||
{
|
||||
$this->validate($request, [
|
||||
'email' => ['required', 'email', 'exists:users,email'],
|
||||
]);
|
||||
$user = $this->userRepo->getByEmail($request->get('email'));
|
||||
$user = $this->loginService->getLastLoginAttemptUser();
|
||||
if ($user === null) {
|
||||
$this->showErrorNotification(trans('errors.login_user_not_found'));
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->emailConfirmationService->sendConfirmation($user);
|
||||
} catch (ConfirmationEmailException $e) {
|
||||
$this->showErrorNotification($e->getMessage());
|
||||
|
||||
return redirect('/login');
|
||||
} catch (Exception $e) {
|
||||
$this->showErrorNotification(trans('auth.email_confirm_send_error'));
|
||||
|
||||
return redirect('/register/confirm');
|
||||
return redirect('/register/awaiting');
|
||||
}
|
||||
|
||||
$this->showSuccessNotification(trans('auth.email_confirm_resent'));
|
||||
|
@ -6,6 +6,7 @@ use BookStack\Activity\ActivityType;
|
||||
use BookStack\Http\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Sleep;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
@ -32,6 +33,10 @@ class ForgotPasswordController extends Controller
|
||||
'email' => ['required', 'email'],
|
||||
]);
|
||||
|
||||
// Add random pause to the response to help avoid time-base sniffing
|
||||
// of valid resets via slower email send handling.
|
||||
Sleep::for(random_int(1000, 3000))->milliseconds();
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
// to send the link, we will examine the response then see the message we
|
||||
// need to show to the user. Finally, we'll send out a proper response.
|
||||
|
@ -17,7 +17,7 @@ trait HandlesPartialLogins
|
||||
$user = auth()->user() ?? $loginService->getLastLoginAttemptUser();
|
||||
|
||||
if (!$user) {
|
||||
throw new NotFoundException('A user for this action could not be found');
|
||||
throw new NotFoundException(trans('errors.login_user_not_found'));
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
@ -15,14 +15,11 @@ use Illuminate\Validation\Rules\Password as PasswordRule;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
protected LoginService $loginService;
|
||||
|
||||
public function __construct(LoginService $loginService)
|
||||
{
|
||||
public function __construct(
|
||||
protected LoginService $loginService
|
||||
) {
|
||||
$this->middleware('guest');
|
||||
$this->middleware('guard:standard');
|
||||
|
||||
$this->loginService = $loginService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ class EmailConfirmationService extends UserTokenService
|
||||
*
|
||||
* @throws ConfirmationEmailException
|
||||
*/
|
||||
public function sendConfirmation(User $user)
|
||||
public function sendConfirmation(User $user): void
|
||||
{
|
||||
if ($user->email_confirmed) {
|
||||
throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login');
|
||||
|
@ -43,7 +43,7 @@ abstract class BaseActivityNotification extends MailNotification
|
||||
protected function buildReasonFooterLine(LocaleDefinition $locale): LinkedMailMessageLine
|
||||
{
|
||||
return new LinkedMailMessageLine(
|
||||
url('/preferences/notifications'),
|
||||
url('/my-account/notifications'),
|
||||
$locale->trans('notifications.footer_reason'),
|
||||
$locale->trans('notifications.footer_reason_link'),
|
||||
);
|
||||
|
@ -81,5 +81,9 @@ class RouteServiceProvider extends ServiceProvider
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
|
||||
});
|
||||
|
||||
RateLimiter::for('public', function (Request $request) {
|
||||
return Limit::perMinute(10)->by($request->ip());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ return [
|
||||
|
||||
'file' => [
|
||||
'driver' => 'file',
|
||||
'path' => storage_path('framework/cache/data'),
|
||||
'lock_path' => storage_path('framework/cache/data'),
|
||||
'path' => storage_path('framework/cache'),
|
||||
'lock_path' => storage_path('framework/cache'),
|
||||
],
|
||||
|
||||
'memcached' => [
|
||||
|
@ -9,16 +9,10 @@ use Illuminate\Http\Request;
|
||||
|
||||
class StoppedAuthenticationException extends \Exception implements Responsable
|
||||
{
|
||||
protected $user;
|
||||
protected $loginService;
|
||||
|
||||
/**
|
||||
* StoppedAuthenticationException constructor.
|
||||
*/
|
||||
public function __construct(User $user, LoginService $loginService)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->loginService = $loginService;
|
||||
public function __construct(
|
||||
protected User $user,
|
||||
protected LoginService $loginService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
122
composer.lock
generated
122
composer.lock
generated
@ -62,16 +62,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.305.9",
|
||||
"version": "3.307.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "a611af9a40a5d93f2f04427b322dbb6044e90327"
|
||||
"reference": "cc79f16e1a1bd3feee421401ba2f21915abfdf91"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a611af9a40a5d93f2f04427b322dbb6044e90327",
|
||||
"reference": "a611af9a40a5d93f2f04427b322dbb6044e90327",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cc79f16e1a1bd3feee421401ba2f21915abfdf91",
|
||||
"reference": "cc79f16e1a1bd3feee421401ba2f21915abfdf91",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -151,9 +151,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.305.9"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.307.1"
|
||||
},
|
||||
"time": "2024-05-03T18:09:03+00:00"
|
||||
"time": "2024-05-17T18:07:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -1167,26 +1167,26 @@
|
||||
},
|
||||
{
|
||||
"name": "firebase/php-jwt",
|
||||
"version": "v6.10.0",
|
||||
"version": "v6.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/firebase/php-jwt.git",
|
||||
"reference": "a49db6f0a5033aef5143295342f1c95521b075ff"
|
||||
"reference": "500501c2ce893c824c801da135d02661199f60c5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff",
|
||||
"reference": "a49db6f0a5033aef5143295342f1c95521b075ff",
|
||||
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/500501c2ce893c824c801da135d02661199f60c5",
|
||||
"reference": "500501c2ce893c824c801da135d02661199f60c5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4||^8.0"
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^6.5||^7.4",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psr/cache": "^1.0||^2.0",
|
||||
"psr/cache": "^2.0||^3.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0"
|
||||
},
|
||||
@ -1224,9 +1224,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/firebase/php-jwt/issues",
|
||||
"source": "https://github.com/firebase/php-jwt/tree/v6.10.0"
|
||||
"source": "https://github.com/firebase/php-jwt/tree/v6.10.1"
|
||||
},
|
||||
"time": "2023-12-01T16:26:39+00:00"
|
||||
"time": "2024-05-18T18:05:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fruitcake/php-cors",
|
||||
@ -1838,16 +1838,16 @@
|
||||
},
|
||||
{
|
||||
"name": "intervention/image",
|
||||
"version": "3.6.3",
|
||||
"version": "3.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Intervention/image.git",
|
||||
"reference": "2dbfb53bf8909257e710cf6091d10a9ca7500742"
|
||||
"reference": "193324ec88bc5ad4039e57ce9b926ae28dfde813"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Intervention/image/zipball/2dbfb53bf8909257e710cf6091d10a9ca7500742",
|
||||
"reference": "2dbfb53bf8909257e710cf6091d10a9ca7500742",
|
||||
"url": "https://api.github.com/repos/Intervention/image/zipball/193324ec88bc5ad4039e57ce9b926ae28dfde813",
|
||||
"reference": "193324ec88bc5ad4039e57ce9b926ae28dfde813",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1894,7 +1894,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Intervention/image/issues",
|
||||
"source": "https://github.com/Intervention/image/tree/3.6.3"
|
||||
"source": "https://github.com/Intervention/image/tree/3.6.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1906,7 +1906,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-02T09:03:18+00:00"
|
||||
"time": "2024-05-08T13:53:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/knp-snappy",
|
||||
@ -2302,16 +2302,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/socialite",
|
||||
"version": "v5.13.2",
|
||||
"version": "v5.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/socialite.git",
|
||||
"reference": "278d4615f68205722b3a129135774b3764b28a90"
|
||||
"reference": "c7b0193a3753a29aff8ce80aa2f511917e6ed68a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/278d4615f68205722b3a129135774b3764b28a90",
|
||||
"reference": "278d4615f68205722b3a129135774b3764b28a90",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/c7b0193a3753a29aff8ce80aa2f511917e6ed68a",
|
||||
"reference": "c7b0193a3753a29aff8ce80aa2f511917e6ed68a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2370,7 +2370,7 @@
|
||||
"issues": "https://github.com/laravel/socialite/issues",
|
||||
"source": "https://github.com/laravel/socialite"
|
||||
},
|
||||
"time": "2024-04-26T13:48:16+00:00"
|
||||
"time": "2024-05-03T20:31:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/tinker",
|
||||
@ -3822,16 +3822,16 @@
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v2.6.3",
|
||||
"version": "v2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938"
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3885,7 +3885,7 @@
|
||||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2022-06-14T06:56:20+00:00"
|
||||
"time": "2024-05-08T12:18:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
@ -4579,20 +4579,20 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35"
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"php": ">=7.1",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
@ -4616,7 +4616,7 @@
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for PSR-7 HTTP message factories",
|
||||
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
|
||||
"keywords": [
|
||||
"factory",
|
||||
"http",
|
||||
@ -4628,9 +4628,9 @@
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
|
||||
"source": "https://github.com/php-fig/http-factory"
|
||||
},
|
||||
"time": "2023-04-10T20:10:41+00:00"
|
||||
"time": "2024-04-15T12:06:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
@ -8326,16 +8326,16 @@
|
||||
},
|
||||
{
|
||||
"name": "larastan/larastan",
|
||||
"version": "v2.9.5",
|
||||
"version": "v2.9.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/larastan/larastan.git",
|
||||
"reference": "101f1a4470f87326f4d3995411d28679d8800abe"
|
||||
"reference": "93d5b95d2e29cdb8203363d44abfdbc0bc7ef57f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/larastan/larastan/zipball/101f1a4470f87326f4d3995411d28679d8800abe",
|
||||
"reference": "101f1a4470f87326f4d3995411d28679d8800abe",
|
||||
"url": "https://api.github.com/repos/larastan/larastan/zipball/93d5b95d2e29cdb8203363d44abfdbc0bc7ef57f",
|
||||
"reference": "93d5b95d2e29cdb8203363d44abfdbc0bc7ef57f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8404,7 +8404,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/larastan/larastan/issues",
|
||||
"source": "https://github.com/larastan/larastan/tree/v2.9.5"
|
||||
"source": "https://github.com/larastan/larastan/tree/v2.9.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -8424,20 +8424,20 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-16T19:13:34+00:00"
|
||||
"time": "2024-05-09T11:53:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.6.11",
|
||||
"version": "1.6.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mockery/mockery.git",
|
||||
"reference": "81a161d0b135df89951abd52296adf97deb0723d"
|
||||
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mockery/mockery/zipball/81a161d0b135df89951abd52296adf97deb0723d",
|
||||
"reference": "81a161d0b135df89951abd52296adf97deb0723d",
|
||||
"url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699",
|
||||
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8507,7 +8507,7 @@
|
||||
"security": "https://github.com/mockery/mockery/security/advisories",
|
||||
"source": "https://github.com/mockery/mockery"
|
||||
},
|
||||
"time": "2024-03-21T18:34:15+00:00"
|
||||
"time": "2024-05-16T03:13:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@ -8872,16 +8872,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.67",
|
||||
"version": "1.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493"
|
||||
"reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493",
|
||||
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e524358f930e41a2b4cca1320e3b04fc26b39e0b",
|
||||
"reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8926,7 +8926,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-16T07:22:02+00:00"
|
||||
"time": "2024-05-15T08:00:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -10268,16 +10268,16 @@
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.9.2",
|
||||
"version": "3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480"
|
||||
"reference": "57e09801c2fbae2d257b8b75bebb3deeb7e9deb2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/aac1f6f347a5c5ac6bc98ad395007df00990f480",
|
||||
"reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/57e09801c2fbae2d257b8b75bebb3deeb7e9deb2",
|
||||
"reference": "57e09801c2fbae2d257b8b75bebb3deeb7e9deb2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -10344,7 +10344,7 @@
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-23T20:25:34+00:00"
|
||||
"time": "2024-05-20T08:11:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ssddanbrown/asserthtml",
|
||||
@ -10541,5 +10541,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ This theme system itself is maintained and supported but usages of this system,
|
||||
|
||||
## Getting Started
|
||||
|
||||
*[Video Guide](https://www.youtube.com/watch?v=gLy_2GBse48)*
|
||||
*[Video Guide](https://foss.video/w/ibNY6bGmKFV1tva3Jz4KfA)*
|
||||
|
||||
This makes use of the theme system. Create a folder for your theme within your BookStack `themes` directory. As an example we'll use `my_theme`, so we'd create a `themes/my_theme` folder.
|
||||
You'll need to tell BookStack to use your theme via the `APP_THEME` option in your `.env` file. For example: `APP_THEME=my_theme`.
|
||||
|
||||
## Customizing View Files
|
||||
|
||||
Content placed in your `themes/<theme_name>/` folder will override the original view files found in the `resources/views` folder. These files are typically [Laravel Blade](https://laravel.com/docs/8.x/blade) files.
|
||||
Content placed in your `themes/<theme_name>/` folder will override the original view files found in the `resources/views` folder. These files are typically [Laravel Blade](https://laravel.com/docs/10.x/blade) files.
|
||||
As an example, I could override the `resources/views/books/parts/list-item.blade.php` file with my own template at the path `themes/<theme_name>/books/parts/list-item.blade.php`.
|
||||
|
||||
## Customizing Icons
|
||||
@ -22,7 +22,7 @@ SVG files placed in a `themes/<theme_name>/icons` folder will override any icons
|
||||
|
||||
## Customizing Text Content
|
||||
|
||||
Folders with PHP translation files placed in a `themes/<theme_name>/lang` folder will override translations defined within the `resources/lang` folder. Custom translations are merged with the original files so you only need to override the select translations you want to override, you don't need to copy the whole original file. Note that you'll need to include the language folder.
|
||||
Folders with PHP translation files placed in a `themes/<theme_name>/lang` folder will override translations defined within the `lang` folder. Custom translations are merged with the original files, so you only need to override the select translations you want to override, you don't need to copy the whole original file. Note that you'll need to include the language folder.
|
||||
|
||||
As an example, Say I wanted to change 'Search' to 'Find'; Within a `themes/<theme_name>/lang/en/common.php` file I'd set the following:
|
||||
|
||||
|
@ -20,7 +20,7 @@ return [
|
||||
'description' => 'الوصف',
|
||||
'role' => 'الدور',
|
||||
'cover_image' => 'صورة الغلاف',
|
||||
'cover_image_description' => 'This image should be approximately 440x250px although it will be flexibly scaled & cropped to fit the user interface in different scenarios as required, so actual dimensions for display will differ.',
|
||||
'cover_image_description' => 'يجب أن يكون حجم هذه الصورة تقريبًا 440x250 بكسل، على الرغم من أنه سيتم تحجيمها وقصها بشكل مرن لتناسب واجهة المستخدم في سيناريوهات مختلفة حسب الحاجة، لذا فإن الأبعاد الفعلية للعرض ستختلف.',
|
||||
|
||||
// Actions
|
||||
'actions' => 'إجراءات',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'لم يتم العثور على السوشيال درايفر "Social driver"',
|
||||
'social_driver_not_configured' => 'لم يتم تهيئة إعدادات حسابك الاجتماعي بشكل صحيح.',
|
||||
'invite_token_expired' => 'انتهت صلاحية رابط هذه الدعوة. يمكنك بدلاً من ذلك محاولة إعادة تعيين كلمة مرور حسابك.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'لا يمكن الرفع إلى مسار :filePath. الرجاء التأكد من قابلية الكتابة إلى الخادم.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Кодът за връзка със социалната мрежа не съществува',
|
||||
'social_driver_not_configured' => 'Социалните настройки на твоя :socialAccount не са конфигурирани правилно.',
|
||||
'invite_token_expired' => 'Твоята покана е изтекла. Вместо това може да пробваш да възстановиш паролата на профила си.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Не може да се качи файл в :filePath. Увери се на сървъра, че в пътя може да се записва.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Driver društvene mreže nije pronađen',
|
||||
'social_driver_not_configured' => 'Vaše :socialAccount postavke nisu konfigurisane ispravno.',
|
||||
'invite_token_expired' => 'Pozivni link je istekao. Možete umjesto toga pokušati da resetujete lozinku.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Na putanju fajla :filePath se ne može učitati. Potvrdite da je omogućeno pisanje na server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'No s’ha trobat el controlador social',
|
||||
'social_driver_not_configured' => 'La configuració social de :socialAccount no és correcta.',
|
||||
'invite_token_expired' => 'Aquest enllaç d’invitació ha caducat. Podeu provar de restablir la contrasenya del vostre compte.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'No s’ha pogut pujar al camí del fitxer :filePath. Assegureu-vos que el servidor hi té permisos d’escriptura.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Doplněk pro tohoto správce identity nebyl nalezen.',
|
||||
'social_driver_not_configured' => 'Nastavení vašeho účtu na :socialAccount není správné. :socialAccount musí mít vaše svolení pro naší aplikaci vás přihlásit.',
|
||||
'invite_token_expired' => 'Odkaz v pozvánce již bohužel vypršel. Namísto toho ale můžete zkusit resetovat heslo do Vašeho účtu.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Nelze zapisovat na cestu k souboru :filePath. Zajistěte aby se dalo nahrávat na server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Gyrrwr cymdeithasol heb ei ganfod',
|
||||
'social_driver_not_configured' => 'Nid yw eich gosodiadau cymdeithasol :socialAccount wedi\'u ffurfweddu\'n gywir.',
|
||||
'invite_token_expired' => 'Mae\'r ddolen wahoddiad hon wedi dod i ben. Yn lle hynny, gallwch chi geisio ailosod cyfrinair eich cyfrif.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Nid oedd modd uwchlwytho llwybr ffeil :filePath. Sicrhewch ei fod yn ysgrifenadwy i\'r gweinydd.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Socialdriver ikke fundet',
|
||||
'social_driver_not_configured' => 'Dine :socialAccount indstillinger er ikke konfigureret korret.',
|
||||
'invite_token_expired' => 'Dette invitationslink er udløbet. I stedet kan du prøve at nulstille din kontos kodeord.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Filsti :filePath kunne ikke uploades til. Sørg for at den kan skrives til af webserveren.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden',
|
||||
'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.',
|
||||
'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen Ihr Passwort zurückzusetzen.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden',
|
||||
'social_driver_not_configured' => 'Dein :socialAccount-Konto ist nicht korrekt konfiguriert.',
|
||||
'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Du kannst stattdessen versuchen, dein Passwort zurückzusetzen.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stelle sicher, dass dieser Ordner auf dem Server beschreibbar ist.',
|
||||
|
@ -279,7 +279,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
|
||||
|
||||
// Licensing
|
||||
'licenses' => 'Lizenzen',
|
||||
'licenses_desc' => 'Diese Seite beschreibt Lizenzinformationen für BookStack zusätzlich zu den Projekten und Bibliotheken, die in BookStack verwendet werden. Viele aufgelistete Projekte dürfen nur in einem Entwicklungskontext verwendet werden.',
|
||||
'licenses_desc' => 'Diese Seite beschreibt Lizenzinformationen für BookStack zusätzlich zu den Projekten und Bibliotheken, die in BookStack verwendet werden. Viele aufgelistete Projekte werden nur in einem Entwicklungskontext verwendet.',
|
||||
'licenses_bookstack' => 'BookStack-Lizenz',
|
||||
'licenses_php' => 'PHP-Bibliothekslizenzen',
|
||||
'licenses_js' => 'JavaScript-Bibliothekslizenzen',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Δεν βρέθηκε κοινωνικός οδηγός',
|
||||
'social_driver_not_configured' => 'Οι κοινωνικές ρυθμίσεις του :socialAccount δεν έχουν ρυθμιστεί σωστά.',
|
||||
'invite_token_expired' => 'Αυτός ο σύνδεσμος πρόσκλησης έχει λήξει. Αντ\' αυτού μπορείτε να προσπαθήσετε να επαναφέρετε τον κωδικό πρόσβασής σας.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Η διαδρομή αρχείου :filePath δεν μπόρεσε να μεταφορτωθεί. Βεβαιωθείτε ότι είναι εγγράψιμη στο διακομιστή.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Driver social no encontrado',
|
||||
'social_driver_not_configured' => 'Su configuración :socialAccount no es correcta.',
|
||||
'invite_token_expired' => 'Este enlace de invitación ha expirado. Puede resetear la contraseña de su cuenta como alternativa.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'El fichero no pudo ser subido a la ruta :filePath . Asegúrese de que es escribible por el servidor.',
|
||||
|
@ -97,7 +97,7 @@ return [
|
||||
'api_token_create_notification' => 'Token de API creado correctamente',
|
||||
'api_token_update' => 'token de API actualizado',
|
||||
'api_token_update_notification' => 'Token de API actualizado correctamente',
|
||||
'api_token_delete' => 'token de API borrado',
|
||||
'api_token_delete' => 'API token eliminado',
|
||||
'api_token_delete_notification' => 'Token de API eliminado correctamente',
|
||||
|
||||
// Roles
|
||||
@ -115,9 +115,9 @@ return [
|
||||
|
||||
// Comments
|
||||
'commented_on' => 'comentado',
|
||||
'comment_create' => 'comentario añadido',
|
||||
'comment_create' => 'comentario agregado',
|
||||
'comment_update' => 'comentario actualizado',
|
||||
'comment_delete' => 'comentario borrado',
|
||||
'comment_delete' => 'comentario eliminado',
|
||||
|
||||
// Other
|
||||
'permissions_update' => 'permisos actualizados',
|
||||
|
@ -12,7 +12,7 @@ return [
|
||||
'save' => 'Guardar',
|
||||
'continue' => 'Continuar',
|
||||
'select' => 'Seleccionar',
|
||||
'toggle_all' => 'Alternar todo',
|
||||
'toggle_all' => 'Mostrar/Ocultar Todo',
|
||||
'more' => 'Más',
|
||||
|
||||
// Form Labels
|
||||
@ -20,7 +20,7 @@ return [
|
||||
'description' => 'Descripción',
|
||||
'role' => 'Rol',
|
||||
'cover_image' => 'Imagen de cubierta',
|
||||
'cover_image_description' => 'Esta imagen debe ser de aproximadamente 440x250px aunque será escalada y recortada para adaptarse a la interfaz de usuario en diferentes escenarios según sea necesario, por lo que las dimensiones en pantalla diferirán.',
|
||||
'cover_image_description' => 'Esta imagen debe ser de 440x250px aproximadamente, aunque será escalada y recortada para adaptarse a la interfaz de usuario en los diferentes escenarios según sea necesario, por lo que las dimensiones en pantalla serán diferentes.',
|
||||
|
||||
// Actions
|
||||
'actions' => 'Acciones',
|
||||
@ -42,7 +42,7 @@ return [
|
||||
'remove' => 'Remover',
|
||||
'add' => 'Agregar',
|
||||
'configure' => 'Configurar',
|
||||
'manage' => 'Gestionar',
|
||||
'manage' => 'Administra',
|
||||
'fullscreen' => 'Pantalla completa',
|
||||
'favourite' => 'Favoritos',
|
||||
'unfavourite' => 'Eliminar de favoritos',
|
||||
@ -70,8 +70,8 @@ return [
|
||||
'no_items' => 'No hay elementos disponibles',
|
||||
'back_to_top' => 'Volver arriba',
|
||||
'skip_to_main_content' => 'Ir al contenido principal',
|
||||
'toggle_details' => 'Alternar detalles',
|
||||
'toggle_thumbnails' => 'Alternar miniaturas',
|
||||
'toggle_details' => 'Mostrar/Ocultar Detalles',
|
||||
'toggle_thumbnails' => 'Mostrar/Ocultar Miniaturas',
|
||||
'details' => 'Detalles',
|
||||
'grid_view' => 'Vista de grilla',
|
||||
'list_view' => 'Vista de lista',
|
||||
|
@ -34,7 +34,7 @@ return [
|
||||
'image_delete_success' => 'Imagen borrada exitosamente',
|
||||
'image_replace' => 'Reemplazar imagen',
|
||||
'image_replace_success' => 'Imagen actualizada correctamente',
|
||||
'image_rebuild_thumbs' => 'Regenerar distintos tamaños',
|
||||
'image_rebuild_thumbs' => 'Regenerar Variaciones de Tamaño',
|
||||
'image_rebuild_thumbs_success' => '¡Imágenes de distinto tamaño regeneradas correctamente!',
|
||||
|
||||
// Code Editor
|
||||
|
@ -81,9 +81,9 @@ return [
|
||||
'table_properties' => 'Propiedades de tabla',
|
||||
'table_properties_title' => 'Propiedades de Tabla',
|
||||
'delete_table' => 'Eliminar tabla',
|
||||
'table_clear_formatting' => 'Limpiar formato de tabla',
|
||||
'table_clear_formatting' => 'Limpiar el formato de tabla',
|
||||
'resize_to_contents' => 'Redimensionar al contenido',
|
||||
'row_header' => 'Fila de cabecera',
|
||||
'row_header' => 'Cabecera de fila',
|
||||
'insert_row_before' => 'Insertar fila arriba',
|
||||
'insert_row_after' => 'Insertar fila abajo',
|
||||
'delete_row' => 'Eliminar fila',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Driver social no encontrado',
|
||||
'social_driver_not_configured' => 'Su configuración :socialAccount no es correcta.',
|
||||
'invite_token_expired' => 'El enace de la esta invitación expiró. Puede intentar restablecer la contraseña de su cuenta',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'La ruta :filePath no pudo ser cargada. Asegurese de que es escribible por el servidor.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Sotsiaalmeedia kontode draiverit ei leitud',
|
||||
'social_driver_not_configured' => 'Sinu :socialAccount konto seaded ei ole korrektsed.',
|
||||
'invite_token_expired' => 'Link on aegunud. Võid selle asemel proovida oma konto parooli lähtestada.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Faili asukohaga :filePath ei õnnestunud üles laadida. Veendu, et serveril on kirjutusõigused.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'درایور شبکه اجتماعی یافت نشد',
|
||||
'social_driver_not_configured' => 'تنظیمات شبکه اجتماعی :socialAccount به درستی پیکربندی نشده است.',
|
||||
'invite_token_expired' => 'این پیوند دعوت منقضی شده است. در عوض می توانید سعی کنید رمز عبور حساب خود را بازنشانی کنید.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'مسیر فایل :filePath را نمی توان در آن آپلود کرد. مطمئن شوید که روی سرور قابل نوشتن است.',
|
||||
|
@ -38,6 +38,7 @@ Sovellus ei tunnista ulkoisen todennuspalvelun pyyntöä. Ongelman voi aiheuttaa
|
||||
'social_driver_not_found' => 'Sosiaalisen median tilin ajuria ei löytynyt',
|
||||
'social_driver_not_configured' => ':socialAccount-tilin asetuksia ei ole määritetty oikein.',
|
||||
'invite_token_expired' => 'Tämä kutsulinkki on vanhentunut. Voit sen sijaan yrittää palauttaa tilisi salasanan.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Tiedostopolkuun :filePath ei voitu ladata tiedostoa. Tarkista polun kirjoitusoikeudet.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Pilote de compte de réseaux sociaux absent',
|
||||
'social_driver_not_configured' => 'Vos préférences pour le compte :socialAccount sont incorrectes.',
|
||||
'invite_token_expired' => 'Le lien de cette invitation a expiré. Vous pouvez essayer de réinitialiser votre mot de passe.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Impossible d\'écrire dans :filePath. Assurez-vous d\'avoir les droits d\'écriture sur le serveur',
|
||||
|
@ -222,7 +222,7 @@ return [
|
||||
'users_api_tokens_desc' => 'Créer et gérer les jetons d\'accès utilisés pour s\'authentifier avec l\'API REST de BookStack. Les permissions pour l\'API sont gérées par l\'utilisateur auquel le jeton appartient.',
|
||||
'users_api_tokens_none' => 'Aucun jeton API n\'a été créé pour cet utilisateur',
|
||||
'users_api_tokens_create' => 'Créer un jeton',
|
||||
'users_api_tokens_expires' => 'Expiré',
|
||||
'users_api_tokens_expires' => 'Expire',
|
||||
'users_api_tokens_docs' => 'Documentation de l\'API',
|
||||
'users_mfa' => 'Authentification multi-facteurs',
|
||||
'users_mfa_desc' => 'Configurer l\'authentification multi-facteurs ajoute une couche supplémentaire de sécurité à votre compte utilisateur.',
|
||||
|
@ -6,13 +6,13 @@
|
||||
return [
|
||||
|
||||
// Pages
|
||||
'page_create' => 'דף נוצר',
|
||||
'page_create' => 'הדף נוצר',
|
||||
'page_create_notification' => 'הדף נוצר בהצלחה',
|
||||
'page_update' => 'דף עודכן',
|
||||
'page_update' => 'הדף עודכן',
|
||||
'page_update_notification' => 'הדף עודכן בהצלחה',
|
||||
'page_delete' => 'דף נמחק',
|
||||
'page_delete' => 'הדף נמחק',
|
||||
'page_delete_notification' => 'הדף הוסר בהצלחה',
|
||||
'page_restore' => 'דף שוחזר',
|
||||
'page_restore' => 'הדף שוחזר',
|
||||
'page_restore_notification' => 'הדף שוחזר בהצלחה',
|
||||
'page_move' => 'דף הועבר',
|
||||
'page_move_notification' => 'Page successfully moved',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'הגדרות ה :socialAccount אינן מוגדרות כראוי',
|
||||
'invite_token_expired' => 'לינק ההזמנה פג. אתה יכול לנסות לאפס את סיסמת החשבון שלך במקום.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'לא ניתן להעלות את :filePath אנא ודא שניתן לכתוב למיקום זה',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Nije pronađeno',
|
||||
'social_driver_not_configured' => 'Postavke vašeg :socialAccount računa nisu ispravno postavljene.',
|
||||
'invite_token_expired' => 'Vaša pozivnica je istekla. Pokušajte ponovno postaviti lozinku.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Datoteka :filePath ne može se prenijeti. Učinite je lakše prepoznatljivom vašem serveru.',
|
||||
|
@ -20,7 +20,7 @@ return [
|
||||
'description' => 'Leírás',
|
||||
'role' => 'Szerepkör',
|
||||
'cover_image' => 'Borítókép',
|
||||
'cover_image_description' => 'This image should be approximately 440x250px although it will be flexibly scaled & cropped to fit the user interface in different scenarios as required, so actual dimensions for display will differ.',
|
||||
'cover_image_description' => 'Ennek a képnek körülbelül 440 x 250 képpont méretűnek kell lennie, bár rugalmasan méretezhető és levágható, hogy a felhasználói felülethez illeszkedjen a különböző lehetőségek esetén, így a megjelenítés tényleges méretei eltérőek lesznek.',
|
||||
|
||||
// Actions
|
||||
'actions' => 'Műveletek',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Közösségi meghajtó nem található',
|
||||
'social_driver_not_configured' => ':socialAccount közösségi beállítások nem megfelelőek.',
|
||||
'invite_token_expired' => 'Ez a meghívó hivatkozás lejárt. Helyette meg lehet próbálni új jelszót megadni a fiókhoz.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => ':filePath elérési út nem tölthető fel. Ellenőrizni kell, hogy az útvonal a kiszolgáló számára írható.',
|
||||
|
@ -27,7 +27,7 @@ return [
|
||||
'notifications_save' => 'Beállítások mentése',
|
||||
'notifications_update_success' => 'Az értesítési beállítások frissítve lettek!',
|
||||
'notifications_watched' => 'Megfigyelt és figyelmen kívül hagyott elemek',
|
||||
'notifications_watched_desc' => 'Az alábbi elemekre egyedi figyelési beállítások vannak alkalmazva. A beállítások frissítéséhez tekintsd meg az elemet, majd keress a figyelési lehetőségeket az oldalsávban.',
|
||||
'notifications_watched_desc' => 'Az alábbi elemekre egyedi figyelési beállítások vannak alkalmazva. A beállítások frissítéséhez tekintsd meg az elemet, majd keresd a figyelési lehetőségeket az oldalsávban.',
|
||||
|
||||
'auth' => 'Hozzáférés és Biztonság',
|
||||
'auth_change_password' => 'Jelszó módosítása',
|
||||
|
@ -109,7 +109,7 @@ return [
|
||||
'recycle_bin_contents_empty' => 'A lomtár jelenleg üres',
|
||||
'recycle_bin_empty' => 'Lomtár kiürítése',
|
||||
'recycle_bin_empty_confirm' => 'Ezzel véglegesen megsemmisíti a lomtárban lévő összes elemet, beleértve az egyes tételekben található tartalmat is. Biztos benne, hogy ki akarja üríteni a lomtárat?',
|
||||
'recycle_bin_destroy_confirm' => 'This action will permanently delete this item from the system, along with any child elements listed below, and you will not be able to restore this content. Are you sure you want to permanently delete this item?',
|
||||
'recycle_bin_destroy_confirm' => 'Ez a művelet véglegesen törli ezt az elemet a rendszerből az alább felsorolt összes alárendelt elemmel együtt, és nem fogja tudni visszaállítani ezt a tartalmat. Biztosan véglegesen törli ezt az elemet?',
|
||||
'recycle_bin_destroy_list' => 'Megsemmisítendő elemek',
|
||||
'recycle_bin_restore_list' => 'Visszaállítandó elemek',
|
||||
'recycle_bin_restore_confirm' => 'Ez a művelet visszaállítja a törölt elemet, beleértve az utódelemeket is, az eredeti helyükre. Ha az eredeti helyet azóta törölték, és most a lomtárban van, akkor a szülőelemet is vissza kell állítani.',
|
||||
@ -277,13 +277,13 @@ return [
|
||||
'webhooks_last_error_message' => 'Utolsó hibaüzenet:',
|
||||
|
||||
// Licensing
|
||||
'licenses' => 'Licenses',
|
||||
'licenses_desc' => 'This page details license information for BookStack in addition to the projects & libraries that are used within BookStack. Many projects listed may only be used in a development context.',
|
||||
'licenses_bookstack' => 'BookStack License',
|
||||
'licenses_php' => 'PHP Library Licenses',
|
||||
'licenses_js' => 'JavaScript Library Licenses',
|
||||
'licenses_other' => 'Other Licenses',
|
||||
'license_details' => 'License Details',
|
||||
'licenses' => 'Licenszek',
|
||||
'licenses_desc' => 'Ez az oldal a BookStack licencinformációit részletezi, a BookStackben használt projekteken és könyvtárakon kívül. Sok felsorolt projekt csak fejlesztési környezetben használható.',
|
||||
'licenses_bookstack' => 'BookStack Licensz',
|
||||
'licenses_php' => 'PHP könyvtár licencek',
|
||||
'licenses_js' => 'JavaScript könyvtár licencek',
|
||||
'licenses_other' => 'Egyéb licencek',
|
||||
'license_details' => 'Licenc részletek',
|
||||
|
||||
//! If editing translations files directly please ignore this in all
|
||||
//! languages apart from en. Content will be auto-copied from en.
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Pengemudi sosial tidak ditemukan',
|
||||
'social_driver_not_configured' => 'Pengaturan sosial :socialAccount Anda tidak dikonfigurasi dengan benar.',
|
||||
'invite_token_expired' => 'Tautan undangan ini telah kedaluwarsa. Sebagai gantinya, Anda dapat mencoba mengatur ulang kata sandi akun Anda.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Jalur berkas :filePath tidak dapat diunggah. Pastikan berkas tersebut dapat ditulis ke server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Driver social non trovato',
|
||||
'social_driver_not_configured' => 'Le impostazioni di :socialAccount non sono configurate correttamente.',
|
||||
'invite_token_expired' => 'Il link di invito è scaduto. Puoi provare a resettare la password del tuo account.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Il percorso :filePath non è scrivibile. Controlla che abbia i permessi corretti.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driverが見つかりません',
|
||||
'social_driver_not_configured' => 'あなたの:socialAccount設定は正しく構成されていません。',
|
||||
'invite_token_expired' => 'この招待リンクの有効期限が切れています。 代わりにアカウントのパスワードをリセットしてみてください。',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'ファイルパス :filePath へアップロードできませんでした。サーバ上での書き込みが許可されているか確認してください。',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => '소셜 드라이버를 찾을 수 없습니다.',
|
||||
'social_driver_not_configured' => '소셜 계정 :socialAccount 가(이) 올바르게 구성되지 않았습니다.',
|
||||
'invite_token_expired' => '이 초대 링크가 만료되었습니다. 대신 계정 비밀번호 재설정을 시도해 보세요.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => '파일 경로 :filePath 에 업로드할 수 없습니다. 서버에 저장이 가능한지 확인하세요.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Socialinis diskas nerastas',
|
||||
'social_driver_not_configured' => 'Jūsų :socialAccount socaliniai nustatymai sukonfigūruoti neteisingai.',
|
||||
'invite_token_expired' => 'Ši kvietimo nuoroda baigė galioti. Vietoj to, jūs galite bandyti iš naujo nustatyti savo paskyros slaptažodį.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Į failo kelią :filePath negalima įkelti. Įsitikinkite, kad jis yra įrašomas į serverį.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Sociālā tīkla savienojums nav atrasts',
|
||||
'social_driver_not_configured' => 'Jūsu :socialAccount sociālie iestatījumi nav uzstādīti pareizi.',
|
||||
'invite_token_expired' => 'Šī uzaicinājuma saite ir novecojusi. Tā vietā jūs varat mēģināt atiestatīt sava konta paroli.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Faila ceļā :filePath nav iespējams ielādēt failus. Lūdzu pārliecinieties, ka serverim tur ir rakstīšanas tiesības.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Autentiseringstjeneste fra sosiale medier er ikke installert',
|
||||
'social_driver_not_configured' => 'Dine :socialAccount innstilliner er ikke angitt.',
|
||||
'invite_token_expired' => 'Invitasjonslenken har utgått, du kan forsøke å be om nytt passord istede.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Filstien :filePath aksepterer ikke filer, du må sjekke filstitilganger i systemet.',
|
||||
|
@ -52,7 +52,7 @@ return [
|
||||
// Revisions
|
||||
'revision_restore' => 'herstelde revisie',
|
||||
'revision_delete' => 'verwijderde revisie',
|
||||
'revision_delete_notification' => 'Revisie met succes verwijderd',
|
||||
'revision_delete_notification' => 'Revisie succesvol verwijderd',
|
||||
|
||||
// Favourites
|
||||
'favourite_add_notification' => '":name" is toegevoegd aan je favorieten',
|
||||
@ -66,14 +66,14 @@ return [
|
||||
'auth_register' => 'registreerde als nieuwe gebruiker',
|
||||
'auth_password_reset_request' => 'vraagde een nieuw gebruikerswachtwoord aan',
|
||||
'auth_password_reset_update' => 'stelde gebruikerswachtwoord opnieuw in',
|
||||
'mfa_setup_method' => 'heeft zijn meervoudige verificatie methode ingesteld',
|
||||
'mfa_setup_method' => 'stelde meervoudige verificatie methode in',
|
||||
'mfa_setup_method_notification' => 'Meervoudige verificatie methode succesvol geconfigureerd',
|
||||
'mfa_remove_method' => 'heeft zijn meervoudige verificatie methode verwijderd',
|
||||
'mfa_remove_method' => 'verwijderde meervoudige verificatie methode',
|
||||
'mfa_remove_method_notification' => 'Meervoudige verificatie methode is succesvol verwijderd',
|
||||
|
||||
// Settings
|
||||
'settings_update' => 'werkte instellingen bij',
|
||||
'settings_update_notification' => 'Instellingen met succes bijgewerkt',
|
||||
'settings_update_notification' => 'Instellingen succesvol bijgewerkt',
|
||||
'maintenance_action_run' => 'voerde onderhoudsactie uit',
|
||||
|
||||
// Webhooks
|
||||
@ -86,7 +86,7 @@ return [
|
||||
|
||||
// Users
|
||||
'user_create' => 'maakte gebruiker aan',
|
||||
'user_create_notification' => 'Gebruiker met succes aangemaakt',
|
||||
'user_create_notification' => 'Gebruiker succesvol aangemaakt',
|
||||
'user_update' => 'werkte gebruiker bij',
|
||||
'user_update_notification' => 'Gebruiker succesvol bijgewerkt',
|
||||
'user_delete' => 'verwijderde gebruiker',
|
||||
@ -95,9 +95,9 @@ return [
|
||||
// API Tokens
|
||||
'api_token_create' => 'API-token aangemaakt',
|
||||
'api_token_create_notification' => 'API-token met succes aangemaakt',
|
||||
'api_token_update' => 'geüpdatet API-token',
|
||||
'api_token_update' => 'wijzigde API-token',
|
||||
'api_token_update_notification' => 'API-token met succes bijgewerkt',
|
||||
'api_token_delete' => 'verwijderd API-token',
|
||||
'api_token_delete' => 'verwijderde API-token',
|
||||
'api_token_delete_notification' => 'API-token met succes verwijderd',
|
||||
|
||||
// Roles
|
||||
|
@ -36,15 +36,15 @@ return [
|
||||
'register_confirm' => 'Controleer je e-mail en klik op de bevestigingsknop om toegang te krijgen tot :appName.',
|
||||
'registrations_disabled' => 'Registratie is momenteel niet mogelijk',
|
||||
'registration_email_domain_invalid' => 'Dit e-maildomein wordt niet toegelaten tot deze applicatie',
|
||||
'register_success' => 'Bedankt voor het aanmelden! Je bent nu geregistreerd en aangemeld.',
|
||||
'register_success' => 'Bedankt voor het aanmelden! Je bent nu geregistreerd en ingelogd.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Poging tot inloggen',
|
||||
'auto_init_starting_desc' => 'We maken contact met jouw authenticatiesysteem om het inlogproces te starten. Als er na 5 seconden geen vooruitgang is, kun je proberen op de onderstaande link te klikken.',
|
||||
'auto_init_starting' => 'Proberen in te loggen',
|
||||
'auto_init_starting_desc' => 'We maken contact met je authenticatiesysteem om het inlogproces te starten. Als er na 5 seconden geen vooruitgang is, kun je proberen op de onderstaande link te klikken.',
|
||||
'auto_init_start_link' => 'Ga verder met authenticatie',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Wachtwoord herstellen',
|
||||
'reset_password' => 'Wachtwoord Herstellen',
|
||||
'reset_password_send_instructions' => 'Geef je e-mailadres op en er wordt een link gestuurd om je wachtwoord te herstellen.',
|
||||
'reset_password_send_button' => 'Stuur Herstel Link',
|
||||
'reset_password_sent' => 'Een link om het wachtwoord te resetten zal verstuurd worden naar :email als dat e-mailadres in het systeem gevonden is.',
|
||||
@ -62,7 +62,7 @@ return [
|
||||
'email_confirm_success' => 'Je e-mailadres is bevestigd! Je zou nu moeten kunnen inloggen met dit e-mailadres.',
|
||||
'email_confirm_resent' => 'Bevestigingsmail opnieuw verzonden, controleer je inbox.',
|
||||
'email_confirm_thanks' => 'Bedankt voor de bevestiging!',
|
||||
'email_confirm_thanks_desc' => 'Wacht even terwijl jouw bevestiging wordt behandeld. Als je na 3 seconden niet wordt doorverwezen, druk dan op de onderstaande link "Doorgaan" om verder te gaan.',
|
||||
'email_confirm_thanks_desc' => 'Wacht even terwijl je bevestiging wordt behandeld. Als je na 3 seconden niet wordt doorverwezen, druk dan op de onderstaande link "Doorgaan" om verder te gaan.',
|
||||
|
||||
'email_not_confirmed' => 'E-mailadres nog niet bevestigd',
|
||||
'email_not_confirmed_text' => 'Je e-mailadres is nog niet bevestigd.',
|
||||
@ -76,20 +76,20 @@ return [
|
||||
'user_invite_email_text' => 'Klik op de onderstaande knop om een account wachtwoord in te stellen en toegang te krijgen:',
|
||||
'user_invite_email_action' => 'Account wachtwoord instellen',
|
||||
'user_invite_page_welcome' => 'Welkom bij :appName!',
|
||||
'user_invite_page_text' => 'Om je account af te ronden en toegang te krijgen moet je een wachtwoord instellen dat gebruikt wordt om in te loggen op :appName bij toekomstige bezoeken.',
|
||||
'user_invite_page_confirm_button' => 'Bevestig wachtwoord',
|
||||
'user_invite_page_text' => 'Om je registratie af te ronden en toegang te krijgen moet je een wachtwoord instellen dat gebruikt zal worden om in te loggen op :appName bij toekomstige bezoeken.',
|
||||
'user_invite_page_confirm_button' => 'Wachtwoord Bevestigen',
|
||||
'user_invite_success_login' => 'Wachtwoord ingesteld, je zou nu moeten kunnen inloggen met je ingestelde wachtwoord om toegang te krijgen tot :appName!',
|
||||
|
||||
// Multi-factor Authentication
|
||||
'mfa_setup' => 'Multi-factor authenticatie instellen',
|
||||
'mfa_setup_desc' => 'Stel multi-factor authenticatie in als een extra beveiligingslaag voor je gebruikersaccount.',
|
||||
'mfa_setup_configured' => 'Reeds geconfigureerd',
|
||||
'mfa_setup' => 'Meervoudige verificatie instellen',
|
||||
'mfa_setup_desc' => 'Stel meervoudige verificatie in als een extra beveiligingslaag voor je gebruikersaccount.',
|
||||
'mfa_setup_configured' => 'Is al geconfigureerd',
|
||||
'mfa_setup_reconfigure' => 'Herconfigureren',
|
||||
'mfa_setup_remove_confirmation' => 'Weet je zeker dat je deze multi-factor authenticatie methode wilt verwijderen?',
|
||||
'mfa_setup_action' => 'Instellen',
|
||||
'mfa_backup_codes_usage_limit_warning' => 'Je hebt minder dan 5 back-upcodes over. Genereer en sla een nieuwe set op voordat je geen codes meer hebt om te voorkomen dat je buiten je account wordt gesloten.',
|
||||
'mfa_option_totp_title' => 'Mobiele app',
|
||||
'mfa_option_totp_desc' => 'Om multi-factor authenticatie te gebruiken heb je een mobiele applicatie nodig die TOTP ondersteunt, zoals Google Authenticator, Authy of Microsoft Authenticator.',
|
||||
'mfa_option_totp_desc' => 'Om meervoudige verificatie te gebruiken heb je een mobiele applicatie nodig die TOTP ondersteunt, zoals Google Authenticator, Authy of Microsoft Authenticator.',
|
||||
'mfa_option_backup_codes_title' => 'Back-up Codes',
|
||||
'mfa_option_backup_codes_desc' => 'Bewaar veilig een set eenmalige back-upcodes die je kunt invoeren om je identiteit te verifiëren.',
|
||||
'mfa_gen_confirm_and_enable' => 'Bevestigen en inschakelen',
|
||||
@ -98,13 +98,13 @@ return [
|
||||
'mfa_gen_backup_codes_download' => 'Download Codes',
|
||||
'mfa_gen_backup_codes_usage_warning' => 'Elke code kan slechts eenmaal gebruikt worden',
|
||||
'mfa_gen_totp_title' => 'Mobiele app installatie',
|
||||
'mfa_gen_totp_desc' => 'Om multi-factor authenticatie te gebruiken heb je een mobiele applicatie nodig die TOTP ondersteunt, zoals Google Authenticator, Authy of Microsoft Authenticator.',
|
||||
'mfa_gen_totp_desc' => 'Om meervoudige verificatie te gebruiken heb je een mobiele applicatie nodig die TOTP ondersteunt, zoals Google Authenticator, Authy of Microsoft Authenticator.',
|
||||
'mfa_gen_totp_scan' => 'Scan de onderstaande QR-code door gebruik te maken van je favoriete authenticatie-app om aan de slag te gaan.',
|
||||
'mfa_gen_totp_verify_setup' => 'Installatie verifiëren',
|
||||
'mfa_gen_totp_verify_setup_desc' => 'Controleer of alles werkt door het invoeren van een code, die wordt gegenereerd binnen je authenticatie-app, in het onderstaande invoerveld:',
|
||||
'mfa_gen_totp_provide_code_here' => 'Vul je app-gegenereerde code hier in',
|
||||
'mfa_verify_access' => 'Verifieer toegang',
|
||||
'mfa_verify_access_desc' => 'Je moet jouw identiteit bevestigen via een extra verificatieniveau voordat je toegang krijgt tot je gebruikersaccount. Verifieer met een van de door u geconfigureerde methoden om verder te gaan.',
|
||||
'mfa_verify_access_desc' => 'Je moet je identiteit bevestigen via een extra verificatieniveau voordat je toegang krijgt tot je gebruikersaccount. Verifieer met een van de door jou geconfigureerde methoden om verder te gaan.',
|
||||
'mfa_verify_no_methods' => 'Geen methode geconfigureerd',
|
||||
'mfa_verify_no_methods_desc' => 'Er konden geen meervoudige verificatie methoden voor je account gevonden worden. Je zult minstens één methode moeten instellen voordat je toegang krijgt.',
|
||||
'mfa_verify_use_totp' => 'Verifieer met een mobiele app',
|
||||
|
@ -143,7 +143,7 @@ return [
|
||||
'source' => 'Bron',
|
||||
'alt_desc' => 'Alternatieve beschrijving',
|
||||
'embed' => 'Insluiten',
|
||||
'paste_embed' => 'Plak jouw insluitcode hieronder:',
|
||||
'paste_embed' => 'Plak je insluitcode hieronder:',
|
||||
'url' => 'URL',
|
||||
'text_to_display' => 'Weer te geven tekst',
|
||||
'title' => 'Titel',
|
||||
|
@ -91,8 +91,8 @@ return [
|
||||
'shelves_popular' => 'Populaire boekenplanken',
|
||||
'shelves_new' => 'Nieuwe boekenplanken',
|
||||
'shelves_new_action' => 'Nieuwe boekenplank',
|
||||
'shelves_popular_empty' => 'De meest populaire boekenplanken worden hier weergegeven.',
|
||||
'shelves_new_empty' => 'De meest recent gemaakte boekenplanken worden hier weergeven.',
|
||||
'shelves_popular_empty' => 'Hier worden de meest populaire boekenplanken weergegeven.',
|
||||
'shelves_new_empty' => 'Hier worden de meest recent gemaakte boekenplanken weergegeven.',
|
||||
'shelves_save' => 'Boekenplank opslaan',
|
||||
'shelves_books' => 'Boeken op deze plank',
|
||||
'shelves_add_books' => 'Voeg boeken toe aan deze plank',
|
||||
@ -124,8 +124,8 @@ return [
|
||||
'books_recent' => 'Recente boeken',
|
||||
'books_new' => 'Nieuwe boeken',
|
||||
'books_new_action' => 'Nieuw boek',
|
||||
'books_popular_empty' => 'De meest populaire boeken worden hier weergegeven.',
|
||||
'books_new_empty' => 'De meest recent gemaakte boeken verschijnen hier.',
|
||||
'books_popular_empty' => 'Hier worden de meest populaire boeken weergegeven.',
|
||||
'books_new_empty' => 'Hier worden de meest recent gemaakte boeken weergegeven.',
|
||||
'books_create' => 'Nieuw boek maken',
|
||||
'books_delete' => 'Boek verwijderen',
|
||||
'books_delete_named' => 'Verwijder boek :bookName',
|
||||
@ -309,7 +309,7 @@ return [
|
||||
'tags_index_desc' => 'Labels kunnen worden toegepast op inhoud binnen het systeem om een flexibele vorm van categorisering toe te passen. Labels kunnen zowel een sleutel als een waarde hebben, waarbij de waarde optioneel is. Eenmaal toegepast, kan de inhoud worden opgevraagd aan de hand van de naam en de waarde van het label.',
|
||||
'tag_name' => 'Labelnaam',
|
||||
'tag_value' => 'Labelwaarde (Optioneel)',
|
||||
'tags_explain' => "Voeg enkele labels toe om jouw inhoud beter te categoriseren. \nJe kunt een waarde aan een label toekennen voor een meer gedetailleerde organisatie.",
|
||||
'tags_explain' => "Voeg enkele labels toe om je inhoud beter te categoriseren.\nJe kunt een waarde aan een label toekennen voor een meer gedetailleerde organisatie.",
|
||||
'tags_add' => 'Voeg nog een label toe',
|
||||
'tags_remove' => 'Verwijder deze label',
|
||||
'tags_usages' => 'Totaal aantal label-toepassingen',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver niet gevonden',
|
||||
'social_driver_not_configured' => 'Je :socialAccount instellingen zijn niet correct geconfigureerd.',
|
||||
'invite_token_expired' => 'Deze uitnodigingslink is verlopen. Je kunt in plaats daarvan proberen je wachtwoord opnieuw in te stellen.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Bestandspad :filePath kon niet naar geüpload worden. Zorg dat je schrijfrechten op de server hebt.',
|
||||
|
@ -95,7 +95,7 @@ return [
|
||||
'maint_regen_references' => 'Verwijzingen opnieuw genereren',
|
||||
'maint_regen_references_desc' => 'Deze actie zal de kruisverwijzingen index binnen de database opnieuw opbouwen. Dit wordt doorgaans automatisch gedaan, maar deze actie kan nuttig zijn om oude inhoud of inhoud die via onofficiële methoden is toegevoegd te indexeren.',
|
||||
'maint_regen_references_success' => 'Verwijzingen index is opnieuw gegenereerd!',
|
||||
'maint_timeout_command_note' => 'Opmerking: Het uitvoeren van deze actie kan enige tijd in beslag nemen, wat in sommige webomgevingen kan leiden tot time-outs. Als alternatief kan deze actie ook worden uitgevoerd met een terminal commando.',
|
||||
'maint_timeout_command_note' => 'Let op: Het uitvoeren van deze actie kan enige tijd in beslag nemen, wat in sommige webomgevingen kan leiden tot time-outs. Als alternatief kan deze actie ook worden uitgevoerd met een terminal-commando.',
|
||||
|
||||
// Recycle Bin
|
||||
'recycle_bin' => 'Prullenbak',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Autentiseringstjeneste fra sosiale medier er ikke installert',
|
||||
'social_driver_not_configured' => 'Dine :socialAccount innstilliner er ikke angitt.',
|
||||
'invite_token_expired' => 'Invitasjonslenken har utgått, du kan forsøke å be om nytt passord istede.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Filstien :filePath aksepterer ikkje filer, du må sjekke filstitilganger i systemet.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Funkcja społecznościowa nie została odnaleziona',
|
||||
'social_driver_not_configured' => 'Ustawienia konta :socialAccount nie są poprawne.',
|
||||
'invite_token_expired' => 'Zaproszenie wygasło. Możesz spróować zresetować swoje hasło.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Zapis do ścieżki :filePath jest niemożliwy. Upewnij się że aplikacja ma prawa do zapisu plików na serwerze.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver não encontrado',
|
||||
'social_driver_not_configured' => 'Os seus parâmetros sociais de :socialAccount não estão corretamente configurados.',
|
||||
'invite_token_expired' => 'Este link de convite expirou. Alternativamente, pode tentar redefinir a senha da sua conta.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'O caminho do arquivo :filePath não pôde ser carregado. Certifique-se de que tem permissões de escrita no servidor.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver não encontrado',
|
||||
'social_driver_not_configured' => 'Seus parâmetros socials de :socialAccount não estão configurados corretamente.',
|
||||
'invite_token_expired' => 'Esse link de convite expirou. Alternativamente, você pode tentar redefinir a senha da sua conta.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'O caminho de destino (:filePath) de upload de arquivo não possui permissão de escrita. Certifique-se que ele possui direitos de escrita no servidor.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Driver social negăsit',
|
||||
'social_driver_not_configured' => 'Setările tale sociale :socialAccount nu sunt configurate corect.',
|
||||
'invite_token_expired' => 'Acest link de invitație a expirat. Poți încerca să îți resetezi parola contului.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Calea fișierului :filePath nu a putut fi încărcată. Asigurați-vă că poate fi scrisă pe server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Драйвер для Соцсети не найден',
|
||||
'social_driver_not_configured' => 'Настройки вашего :socialAccount заданы неправильно.',
|
||||
'invite_token_expired' => 'Срок действия приглашения истек. Вместо этого вы можете попытаться сбросить пароль своей учетной записи.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Невозможно загрузить файл по пути :filePath. Убедитесь что сервер доступен для записи.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Ovládač socialnych sietí nebol nájdený',
|
||||
'social_driver_not_configured' => 'Nastavenia Vášho :socialAccount účtu nie sú správne.',
|
||||
'invite_token_expired' => 'Platnosť tohto odkazu na pozvánku vypršala. Namiesto toho sa môžete pokúsiť obnoviť heslo účtu.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Do cesty :filePath sa nedá nahrávať. Uistite sa, že je zapisovateľná serverom.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Socialni vtičnik ni najden',
|
||||
'social_driver_not_configured' => 'Vaše nastavitve :socialAccount niso pravilo nastavljene.',
|
||||
'invite_token_expired' => 'Ta povezava je potekla. Namesto tega lahko ponastavite vaše geslo računa.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Poti :filePath ni bilo mogoče naložiti. Prepričajte se, da je zapisljiva na strežnik.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver not found',
|
||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||
|
@ -81,9 +81,9 @@ return [
|
||||
'table_properties' => 'Tabellegenskaper',
|
||||
'table_properties_title' => 'Tabellegenskaper',
|
||||
'delete_table' => 'Ta bort tabell',
|
||||
'table_clear_formatting' => 'Clear table formatting',
|
||||
'table_clear_formatting' => 'Rensa tabell-formatering',
|
||||
'resize_to_contents' => 'Resize to contents',
|
||||
'row_header' => 'Row header',
|
||||
'row_header' => 'Radrubrik',
|
||||
'insert_row_before' => 'Infoga rad före',
|
||||
'insert_row_after' => 'Infoga rad efter',
|
||||
'delete_row' => 'Ta bort rad',
|
||||
@ -147,11 +147,11 @@ return [
|
||||
'url' => 'URL',
|
||||
'text_to_display' => 'Text som ska visas',
|
||||
'title' => 'Titel',
|
||||
'open_link' => 'Open link',
|
||||
'open_link_in' => 'Open link in...',
|
||||
'open_link' => 'Öppna länk',
|
||||
'open_link_in' => 'Öppna länk i...',
|
||||
'open_link_current' => 'Aktuellt fönster',
|
||||
'open_link_new' => 'Nytt fönster',
|
||||
'remove_link' => 'Remove link',
|
||||
'remove_link' => 'Radera länk',
|
||||
'insert_collapsible' => 'Infoga hopfällbart block',
|
||||
'collapsible_unwrap' => 'Expandera',
|
||||
'edit_label' => 'Redigera etikett',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Drivrutinen för den här tjänsten hittades inte',
|
||||
'social_driver_not_configured' => 'Dina inställningar för :socialAccount är inte korrekta.',
|
||||
'invite_token_expired' => 'Denna inbjudningslänk har löpt ut. Du kan istället försöka återställa ditt kontos lösenord.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Kunde inte ladda upp till sökvägen :filePath. Kontrollera att webbservern har skrivåtkomst.',
|
||||
|
@ -32,7 +32,7 @@ return [
|
||||
'app_custom_html_desc' => 'Innehåll i det här fältet placeras längst ner i <head>-sektionen på varje sida. Detta kan användas för att skriva över stilmallar eller lägga in spårningskoder.',
|
||||
'app_custom_html_disabled_notice' => 'Anpassat innehåll i HTML-huvudet är inaktiverat på denna inställningssida för att säkerställa att eventuella ändringar som påverkar funktionaliteten kan återställas.',
|
||||
'app_logo' => 'Applikationslogotyp',
|
||||
'app_logo_desc' => 'This is used in the application header bar, among other areas. This image should be 86px in height. Large images will be scaled down.',
|
||||
'app_logo_desc' => 'Detta används bland annat i applikationshuvudet. Bilden bör vara 86 pixlar i höjd. Stora bilder skalas ned.',
|
||||
'app_icon' => 'Application Icon',
|
||||
'app_icon_desc' => 'This icon is used for browser tabs and shortcut icons. This should be a 256px square PNG image.',
|
||||
'app_homepage' => 'Startsida',
|
||||
@ -48,11 +48,11 @@ return [
|
||||
'app_disable_comments_desc' => 'Inaktivera kommentarer på alla sidor i applikationen. Befintliga kommentarer visas inte.',
|
||||
|
||||
// Color settings
|
||||
'color_scheme' => 'Application Color Scheme',
|
||||
'color_scheme_desc' => 'Set the colors to use in the application user interface. Colors can be configured separately for dark and light modes to best fit the theme and ensure legibility.',
|
||||
'ui_colors_desc' => 'Set the application primary color and default link color. The primary color is mainly used for the header banner, buttons and interface decorations. The default link color is used for text-based links and actions, both within written content and in the application interface.',
|
||||
'app_color' => 'Primary Color',
|
||||
'link_color' => 'Default Link Color',
|
||||
'color_scheme' => 'Programmets färgschema',
|
||||
'color_scheme_desc' => 'Ställ in de färger som ska användas i applikationens användargränssnitt. Färger kan konfigureras separat för mörka och ljusa lägen för att bäst passa temat och säkerställa läsbarhet.',
|
||||
'ui_colors_desc' => 'Ange applikationens primära färg och standard färg för länkar. Den primära färgen används främst för huvudrubriken, knappar och gränssnitt dekorationer. Standardfärgen på länken används för textbaserade länkar och åtgärder, både inom skriftligt innehåll och i applikationsgränssnittet.',
|
||||
'app_color' => 'Primärfärg',
|
||||
'link_color' => 'Standardfärg för länkar',
|
||||
'content_colors_desc' => 'Set colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
|
||||
'bookshelf_color' => 'Hyllfärg',
|
||||
'book_color' => 'Bokfärg',
|
||||
@ -214,8 +214,8 @@ return [
|
||||
'users_social_accounts_info' => 'Här kan du ansluta dina andra konton för snabbare och smidigare inloggning. Om du kopplar från en tjänst här kommer de behörigheter som tidigare givits inte att tas bort - ta bort behörigheter genom att logga in på ditt konto på tjänsten i fråga.',
|
||||
'users_social_connect' => 'Anslut konto',
|
||||
'users_social_disconnect' => 'Koppla från konto',
|
||||
'users_social_status_connected' => 'Connected',
|
||||
'users_social_status_disconnected' => 'Disconnected',
|
||||
'users_social_status_connected' => 'Ansluten',
|
||||
'users_social_status_disconnected' => 'Bortkopplad',
|
||||
'users_social_connected' => ':socialAccount har kopplats till ditt konto.',
|
||||
'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.',
|
||||
'users_api_tokens' => 'API-nyckel',
|
||||
@ -277,12 +277,12 @@ return [
|
||||
'webhooks_last_error_message' => 'Senaste felmeddelande:',
|
||||
|
||||
// Licensing
|
||||
'licenses' => 'Licenses',
|
||||
'licenses' => 'Licenser',
|
||||
'licenses_desc' => 'This page details license information for BookStack in addition to the projects & libraries that are used within BookStack. Many projects listed may only be used in a development context.',
|
||||
'licenses_bookstack' => 'BookStack License',
|
||||
'licenses_php' => 'PHP Library Licenses',
|
||||
'licenses_js' => 'JavaScript Library Licenses',
|
||||
'licenses_other' => 'Other Licenses',
|
||||
'licenses_other' => 'Andra licenser',
|
||||
'license_details' => 'License Details',
|
||||
|
||||
//! If editing translations files directly please ignore this in all
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Social driver bulunamadı',
|
||||
'social_driver_not_configured' => ':socialAccount ayarlarınız doğru bir şekilde ayarlanmadı.',
|
||||
'invite_token_expired' => 'Davetiye bağlantısının süresi doldu. Bunun yerine parolanızı sıfırlamayı deneyebilirsiniz.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => ':filePath dosya yolu yüklenemedi. Sunucuya yazılabilir olduğundan emin olun.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Драйвер для СоціальноїМережі не знайдено',
|
||||
'social_driver_not_configured' => 'Ваші соціальні настройки :socialAccount не правильно налаштовані.',
|
||||
'invite_token_expired' => 'Термін дії цього запрошення закінчився. Замість цього ви можете спробувати скинути пароль свого облікового запису.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Не вдається завантажити шлях до файлу :filePath. Переконайтеся, що він доступний для запису на сервер.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Ijtimoiy haydovchi topilmadi',
|
||||
'social_driver_not_configured' => 'Sizning :socialAccount ijtimoiy sozlamalaringiz toʻgʻri sozlanmagan.',
|
||||
'invite_token_expired' => 'Bu taklif havolasi muddati tugagan. Buning oʻrniga hisobingiz parolini tiklashga urinib koʻrishingiz mumkin.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Fayl yoʻli :filePath faylini yuklab boʻlmadi. Uning serverga yozilishi mumkinligiga ishonch hosil qiling.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => 'Không tìm thấy driver cho MXH',
|
||||
'social_driver_not_configured' => 'Cài đặt MXH :socialAccount của bạn đang không được cấu hình hợp lệ.',
|
||||
'invite_token_expired' => 'Liên kết mời này đã hết hạn. Bạn có thể thử đặt lại mật khẩu của tài khoản.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Đường dẫn tệp tin :filePath không thể tải đến được. Đảm bảo rằng đường dẫn này có thể ghi được ở trên máy chủ.',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => '未找到社交驱动程序',
|
||||
'social_driver_not_configured' => '您的:socialAccount社交设置不正确。',
|
||||
'invite_token_expired' => '此邀请链接已过期。 您可以尝试重置您的账户密码。',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => '无法上传到文件路径“:filePath”,请确保它可写入服务器。',
|
||||
|
@ -37,6 +37,7 @@ return [
|
||||
'social_driver_not_found' => '找不到社交驅動程式',
|
||||
'social_driver_not_configured' => '您的 :socialAccount 社交設定不正確。',
|
||||
'invite_token_expired' => '此邀請連結已過期。您可以嘗試重設您的帳號密碼。',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => '無法上傳到 :filePath 檔案路徑。請確定其對伺服器來說是可寫入的。',
|
||||
|
@ -136,7 +136,8 @@ return [
|
||||
// Role Settings
|
||||
'roles' => '角色',
|
||||
'role_user_roles' => '使用者角色',
|
||||
'roles_index_desc' => 'Roles are used to group users & provide system permission to their members. When a user is a member of multiple roles the privileges granted will stack and the user will inherit all abilities.',
|
||||
'roles_index_desc' => '「角色」用於將系統權限套用至使用者群組。當使用者擁有多角色時,
|
||||
使用者會自動繼承角色中的所有系統權限',
|
||||
'roles_x_users_assigned' => ':count user assigned|:count users assigned',
|
||||
'roles_x_permissions_provided' => ':count permission|:count permissions',
|
||||
'roles_assigned_users' => 'Assigned Users',
|
||||
@ -277,13 +278,13 @@ return [
|
||||
'webhooks_last_error_message' => '上次錯誤信息',
|
||||
|
||||
// Licensing
|
||||
'licenses' => 'Licenses',
|
||||
'licenses_desc' => 'This page details license information for BookStack in addition to the projects & libraries that are used within BookStack. Many projects listed may only be used in a development context.',
|
||||
'licenses' => '授權',
|
||||
'licenses_desc' => '本頁提供 BookStack 使用到的專案以及函式庫的詳細授權資料,其中部份專案及函式庫僅開開發環境中使用。',
|
||||
'licenses_bookstack' => 'BookStack 授權',
|
||||
'licenses_php' => 'PHP Library Licenses',
|
||||
'licenses_js' => 'JavaScript Library Licenses',
|
||||
'licenses_php' => 'PHP 函式庫授權',
|
||||
'licenses_js' => 'JavaScript 函式庫授權',
|
||||
'licenses_other' => '其它授權',
|
||||
'license_details' => 'License Details',
|
||||
'license_details' => '詳細授權資料',
|
||||
|
||||
//! If editing translations files directly please ignore this in all
|
||||
//! languages apart from en. Content will be auto-copied from en.
|
||||
|
@ -181,10 +181,7 @@ export class Dropzone extends Component {
|
||||
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
|
||||
upload.markSuccess(component.successMessage);
|
||||
} else if (this.readyState === XMLHttpRequest.DONE && this.status >= 400) {
|
||||
const content = this.responseText;
|
||||
const data = content.startsWith('{') ? JSON.parse(content) : {message: content};
|
||||
const message = data?.message || data?.error || content;
|
||||
upload.markError(message);
|
||||
upload.markError(window.$http.formatErrorResponseText(this.responseText));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -207,3 +207,32 @@ async function performDelete(url, data = null) {
|
||||
}
|
||||
|
||||
export {performDelete as delete};
|
||||
|
||||
/**
|
||||
* Parse the response text for an error response to a user
|
||||
* presentable string. Handles a range of errors responses including
|
||||
* validation responses & server response text.
|
||||
* @param {String} text
|
||||
* @returns {String}
|
||||
*/
|
||||
export function formatErrorResponseText(text) {
|
||||
const data = text.startsWith('{') ? JSON.parse(text) : {message: text};
|
||||
if (!data) {
|
||||
return text;
|
||||
}
|
||||
|
||||
if (data.message || data.error) {
|
||||
return data.message || data.error;
|
||||
}
|
||||
|
||||
const values = Object.values(data);
|
||||
const isValidation = values.every(val => {
|
||||
return Array.isArray(val) || val.every(x => typeof x === 'string');
|
||||
});
|
||||
|
||||
if (isValidation) {
|
||||
return values.flat().join(' ');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
@ -55,6 +55,19 @@ export function handleEmbedAlignmentChanges(editor) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up and removes text-alignment specific properties on all child elements.
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function cleanChildAlignment(element) {
|
||||
const alignedChildren = element.querySelectorAll('[align],[style*="text-align"],.align-center,.align-left,.align-right');
|
||||
for (const child of alignedChildren) {
|
||||
child.removeAttribute('align');
|
||||
child.style.textAlign = null;
|
||||
child.classList.remove('align-center', 'align-right', 'align-left');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the direction property for an element.
|
||||
* Removes all inline direction control from child elements.
|
||||
@ -62,16 +75,23 @@ export function handleEmbedAlignmentChanges(editor) {
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function cleanElementDirection(element) {
|
||||
const directionChildren = element.querySelectorAll('[dir],[style*="direction"],[style*="text-align"]');
|
||||
const directionChildren = element.querySelectorAll('[dir],[style*="direction"]');
|
||||
for (const child of directionChildren) {
|
||||
child.removeAttribute('dir');
|
||||
child.style.direction = null;
|
||||
child.style.textAlign = null;
|
||||
}
|
||||
|
||||
cleanChildAlignment(element);
|
||||
element.style.direction = null;
|
||||
element.style.textAlign = null;
|
||||
element.removeAttribute('align');
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Function} TableCellHandler
|
||||
* @param {HTMLTableCellElement} cell
|
||||
*/
|
||||
|
||||
/**
|
||||
* This tracks table cell range selection, so we can apply custom handling where
|
||||
* required to actions applied to such selections.
|
||||
@ -90,34 +110,51 @@ export function handleTableCellRangeEvents(editor) {
|
||||
selectedCells = [];
|
||||
});
|
||||
|
||||
// TinyMCE does not seem to do a great job on clearing styles in complex
|
||||
// scenarios (like copied word content) when a range of table cells
|
||||
// are selected. Here we watch for clear formatting events, so some manual
|
||||
// cleanup can be performed.
|
||||
const attrsToRemove = ['class', 'style', 'width', 'height'];
|
||||
editor.on('ExecCommand', event => {
|
||||
if (event.command === 'RemoveFormat') {
|
||||
for (const cell of selectedCells) {
|
||||
for (const attr of attrsToRemove) {
|
||||
cell.removeAttribute(attr);
|
||||
}
|
||||
/**
|
||||
* @type {Object<String, TableCellHandler>}
|
||||
*/
|
||||
const actionByCommand = {
|
||||
// TinyMCE does not seem to do a great job on clearing styles in complex
|
||||
// scenarios (like copied word content) when a range of table cells
|
||||
// are selected. Here we watch for clear formatting events, so some manual
|
||||
// cleanup can be performed.
|
||||
RemoveFormat: cell => {
|
||||
const attrsToRemove = ['class', 'style', 'width', 'height', 'align'];
|
||||
for (const attr of attrsToRemove) {
|
||||
cell.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// TinyMCE does not apply direction events to table cell range selections
|
||||
// so here we hastily patch in that ability by setting the direction ourselves
|
||||
// when a direction event is fired.
|
||||
editor.on('ExecCommand', event => {
|
||||
const command = event.command;
|
||||
if (command !== 'mceDirectionLTR' && command !== 'mceDirectionRTL') {
|
||||
return;
|
||||
}
|
||||
|
||||
const dir = command === 'mceDirectionLTR' ? 'ltr' : 'rtl';
|
||||
for (const cell of selectedCells) {
|
||||
cell.setAttribute('dir', dir);
|
||||
// TinyMCE does not apply direction events to table cell range selections
|
||||
// so here we hastily patch in that ability by setting the direction ourselves
|
||||
// when a direction event is fired.
|
||||
mceDirectionLTR: cell => {
|
||||
cell.setAttribute('dir', 'ltr');
|
||||
cleanElementDirection(cell);
|
||||
},
|
||||
mceDirectionRTL: cell => {
|
||||
cell.setAttribute('dir', 'rtl');
|
||||
cleanElementDirection(cell);
|
||||
},
|
||||
|
||||
// The "align" attribute can exist on table elements so this clears
|
||||
// the attribute, and also clears common child alignment properties,
|
||||
// when a text direction action is made for a table cell range.
|
||||
JustifyLeft: cell => {
|
||||
cell.removeAttribute('align');
|
||||
cleanChildAlignment(cell);
|
||||
},
|
||||
JustifyRight: this.JustifyLeft,
|
||||
JustifyCenter: this.JustifyLeft,
|
||||
JustifyFull: this.JustifyLeft,
|
||||
};
|
||||
|
||||
editor.on('ExecCommand', event => {
|
||||
const action = actionByCommand[event.command];
|
||||
if (action) {
|
||||
for (const cell of selectedCells) {
|
||||
action(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -321,6 +321,10 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||
background-color: var(--color-primary);
|
||||
transition: width ease-in-out 240ms;
|
||||
}
|
||||
.dropzone-file-item-label {
|
||||
line-height: 1.2;
|
||||
margin-bottom: .2rem;
|
||||
}
|
||||
.dropzone-file-item-label,
|
||||
.dropzone-file-item-status {
|
||||
align-items: center;
|
||||
|
@ -321,6 +321,7 @@ input[type=color] {
|
||||
}
|
||||
}
|
||||
.setting-list-label {
|
||||
@include lightDark(color, #222, #DDD);
|
||||
color: #222;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
@ -14,15 +14,7 @@
|
||||
</p>
|
||||
|
||||
<form action="{{ url("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
|
||||
{!! csrf_field() !!}
|
||||
<div class="form-group">
|
||||
<label for="email">{{ trans('auth.email') }}</label>
|
||||
@if($user)
|
||||
@include('form.text', ['name' => 'email', 'model' => $user])
|
||||
@else
|
||||
@include('form.text', ['name' => 'email'])
|
||||
@endif
|
||||
</div>
|
||||
{{ csrf_field() }}
|
||||
<div class="form-group text-right mt-m">
|
||||
<button type="submit" class="button">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
|
||||
</div>
|
@ -317,8 +317,8 @@ Route::get('/register/confirm', [AccessControllers\ConfirmEmailController::class
|
||||
Route::get('/register/confirm/awaiting', [AccessControllers\ConfirmEmailController::class, 'showAwaiting']);
|
||||
Route::post('/register/confirm/resend', [AccessControllers\ConfirmEmailController::class, 'resend']);
|
||||
Route::get('/register/confirm/{token}', [AccessControllers\ConfirmEmailController::class, 'showAcceptForm']);
|
||||
Route::post('/register/confirm/accept', [AccessControllers\ConfirmEmailController::class, 'confirm']);
|
||||
Route::post('/register', [AccessControllers\RegisterController::class, 'postRegister']);
|
||||
Route::post('/register/confirm/accept', [AccessControllers\ConfirmEmailController::class, 'confirm'])->middleware('throttle:public');
|
||||
Route::post('/register', [AccessControllers\RegisterController::class, 'postRegister'])->middleware('throttle:public');
|
||||
|
||||
// SAML routes
|
||||
Route::post('/saml2/login', [AccessControllers\Saml2Controller::class, 'login']);
|
||||
@ -338,16 +338,16 @@ Route::get('/oidc/callback', [AccessControllers\OidcController::class, 'callback
|
||||
Route::post('/oidc/logout', [AccessControllers\OidcController::class, 'logout']);
|
||||
|
||||
// User invitation routes
|
||||
Route::get('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'showSetPassword']);
|
||||
Route::post('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'setPassword']);
|
||||
Route::get('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'showSetPassword'])->middleware('throttle:public');
|
||||
Route::post('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'setPassword'])->middleware('throttle:public');
|
||||
|
||||
// Password reset link request routes
|
||||
Route::get('/password/email', [AccessControllers\ForgotPasswordController::class, 'showLinkRequestForm']);
|
||||
Route::post('/password/email', [AccessControllers\ForgotPasswordController::class, 'sendResetLinkEmail']);
|
||||
Route::post('/password/email', [AccessControllers\ForgotPasswordController::class, 'sendResetLinkEmail'])->middleware('throttle:public');
|
||||
|
||||
// Password reset routes
|
||||
Route::get('/password/reset/{token}', [AccessControllers\ResetPasswordController::class, 'showResetForm']);
|
||||
Route::post('/password/reset', [AccessControllers\ResetPasswordController::class, 'reset']);
|
||||
Route::post('/password/reset', [AccessControllers\ResetPasswordController::class, 'reset'])->middleware('throttle:public');
|
||||
|
||||
// Metadata routes
|
||||
Route::view('/help/wysiwyg', 'help.wysiwyg');
|
||||
|
@ -25,6 +25,9 @@ class RegistrationTest extends TestCase
|
||||
$resp->assertRedirect('/register/confirm');
|
||||
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
|
||||
|
||||
$resp = $this->get('/register/confirm');
|
||||
$resp->assertSee('Thanks for registering!');
|
||||
|
||||
// Ensure notification sent
|
||||
/** @var User $dbUser */
|
||||
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||
@ -203,4 +206,88 @@ class RegistrationTest extends TestCase
|
||||
$resp = $this->followRedirects($resp);
|
||||
$this->withHtml($resp)->assertElementExists('form input[name="username"].text-neg');
|
||||
}
|
||||
|
||||
public function test_registration_endpoint_throttled()
|
||||
{
|
||||
$this->setSettings(['registration-enabled' => 'true']);
|
||||
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->post('/register/', [
|
||||
'name' => "Barry{$i}",
|
||||
'email' => "barry{$i}@example.com",
|
||||
'password' => "barryIsTheBest{$i}",
|
||||
]);
|
||||
auth()->logout();
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
|
||||
public function test_registration_confirmation_throttled()
|
||||
{
|
||||
$this->setSettings(['registration-enabled' => 'true']);
|
||||
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->post('/register/confirm/accept', [
|
||||
'token' => "token{$i}",
|
||||
]);
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
|
||||
public function test_registration_confirmation_resend()
|
||||
{
|
||||
Notification::fake();
|
||||
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||
$user = User::factory()->make();
|
||||
|
||||
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
|
||||
$resp->assertRedirect('/register/confirm');
|
||||
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||
|
||||
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
|
||||
$resp->assertRedirect('/register/confirm/awaiting');
|
||||
|
||||
$resp = $this->post('/register/confirm/resend');
|
||||
$resp->assertRedirect('/register/confirm');
|
||||
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
|
||||
}
|
||||
|
||||
public function test_registration_confirmation_expired_resend()
|
||||
{
|
||||
Notification::fake();
|
||||
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||
$user = User::factory()->make();
|
||||
|
||||
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
|
||||
$resp->assertRedirect('/register/confirm');
|
||||
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||
|
||||
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
|
||||
$resp->assertRedirect('/register/confirm/awaiting');
|
||||
|
||||
$emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
|
||||
$this->travel(2)->days();
|
||||
|
||||
$resp = $this->post("/register/confirm/accept", [
|
||||
'token' => $emailConfirmation->token,
|
||||
]);
|
||||
$resp->assertRedirect('/register/confirm');
|
||||
$this->assertSessionError('The confirmation token has expired, A new confirmation email has been sent.');
|
||||
|
||||
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
|
||||
}
|
||||
|
||||
public function test_registration_confirmation_awaiting_and_resend_returns_to_log_if_no_login_attempt_user_found()
|
||||
{
|
||||
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||
|
||||
$this->get('/register/confirm/awaiting')->assertRedirect('/login');
|
||||
$this->assertSessionError('A user for this action could not be found.');
|
||||
$this->flushSession();
|
||||
|
||||
$this->post('/register/confirm/resend')->assertRedirect('/login');
|
||||
$this->assertSessionError('A user for this action could not be found.');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,19 @@ namespace Tests\Auth;
|
||||
|
||||
use BookStack\Access\Notifications\ResetPasswordNotification;
|
||||
use BookStack\Users\Models\User;
|
||||
use Carbon\CarbonInterval;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Sleep;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ResetPasswordTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Sleep::fake();
|
||||
}
|
||||
|
||||
public function test_reset_flow()
|
||||
{
|
||||
Notification::fake();
|
||||
@ -75,6 +83,17 @@ class ResetPasswordTest extends TestCase
|
||||
->assertSee('The password reset token is invalid for this email address.');
|
||||
}
|
||||
|
||||
public function test_reset_request_with_not_found_user_still_has_delay()
|
||||
{
|
||||
$this->followingRedirects()->post('/password/email', [
|
||||
'email' => 'barrynotfoundrandomuser@example.com',
|
||||
]);
|
||||
|
||||
Sleep::assertSlept(function (CarbonInterval $duration): bool {
|
||||
return $duration->totalMilliseconds > 999;
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public function test_reset_page_shows_sign_links()
|
||||
{
|
||||
$this->setSettings(['registration-enabled' => 'true']);
|
||||
@ -98,4 +117,27 @@ class ResetPasswordTest extends TestCase
|
||||
Notification::assertSentTimes(ResetPasswordNotification::class, 1);
|
||||
$resp->assertSee('A password reset link will be sent to ' . $editor->email . ' if that email address is found in the system.');
|
||||
}
|
||||
|
||||
public function test_reset_request_with_not_found_user_is_throttled()
|
||||
{
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->post('/password/email', [
|
||||
'email' => 'barrynotfoundrandomuser@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
|
||||
public function test_reset_call_is_throttled()
|
||||
{
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->post('/password/reset', [
|
||||
'email' => "arandomuser{$i}@example.com",
|
||||
'token' => "randomtoken{$i}",
|
||||
]);
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
}
|
||||
|
@ -137,4 +137,24 @@ class UserInviteTest extends TestCase
|
||||
$setPasswordPageResp->assertRedirect('/password/email');
|
||||
$setPasswordPageResp->assertSessionHas('error', 'This invitation link has expired. You can instead try to reset your account password.');
|
||||
}
|
||||
|
||||
public function test_set_password_view_is_throttled()
|
||||
{
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->get("/register/invite/tokenhere{$i}");
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
|
||||
public function test_set_password_post_is_throttled()
|
||||
{
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$response = $this->post("/register/invite/tokenhere{$i}", [
|
||||
'password' => 'my test password',
|
||||
]);
|
||||
}
|
||||
|
||||
$response->assertStatus(429);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user